新增通知接口与业务功能,添加聊天示例页面

This commit is contained in:
wanggeng 2021-09-14 00:23:19 +08:00
parent d93cd3042c
commit c278217585
19 changed files with 2067 additions and 2 deletions

View File

@ -0,0 +1,72 @@
package ink.wgink.module.instantmessage.controller.api;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.instantmessage.pojo.bos.NoticeBO;
import ink.wgink.module.instantmessage.pojo.bos.NoticeTargetBO;
import ink.wgink.module.instantmessage.pojo.vos.MessageVO;
import ink.wgink.module.instantmessage.service.IMessageService;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.pojo.result.SuccessResult;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: MessageController
* @Description: 消息
* @Author: wanggeng
* @Date: 2021/1/14 3:25 下午
* @Version: 1.0
*/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "消息接口")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/websocket/message")
public class WebSocketMessageController {
@Autowired
private IMessageService messageService;
@ApiOperation(value = "通知消息", notes = "通知消息接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PostMapping("notice/{clientName}")
@CheckRequestBodyAnnotation
public SuccessResult notice(@PathVariable("clientName") String clientName, @RequestBody MessageVO messageVO) {
NoticeBO noticeBO = new NoticeBO();
noticeBO.setTitle(messageVO.getTitle());
noticeBO.setContent(messageVO.getContent());
noticeBO.setTo(messageVO.getTo());
messageService.notice(clientName, noticeBO);
return new SuccessResult();
}
@ApiOperation(value = "通知消息", notes = "通知消息接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PostMapping("notice-target/{clientName}")
@CheckRequestBodyAnnotation
public SuccessResult saveNoticeWithTargetAndSave(@PathVariable("clientName") String clientName, @RequestBody MessageVO messageVO) {
NoticeTargetBO noticeTargetBO = new NoticeTargetBO();
noticeTargetBO.setTitle(messageVO.getTitle());
noticeTargetBO.setContent(messageVO.getContent());
noticeTargetBO.setTo(messageVO.getTo());
noticeTargetBO.setTarget(messageVO.getTarget());
messageService.notice(clientName, noticeTargetBO);
return new SuccessResult();
}
@ApiOperation(value = "删除通知", notes = "删除通知接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "serviceIds", value = "业务ID", paramType = "path"),
})
@DeleteMapping("delete/{serviceIds}")
public SuccessResult delete(@PathVariable("serviceIds") String serviceIds) {
messageService.delete(Arrays.asList(serviceIds.split("\\_")));
return new SuccessResult();
}
}

View File

@ -0,0 +1,38 @@
package ink.wgink.module.instantmessage.controller.route;
import ink.wgink.common.component.SecurityComponent;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.properties.websocket.WebSocketProperties;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @ClassName: WebSocketDemoStaticController
* @Description: websocket示例资源
* @Author: wanggeng
* @Date: 2021/9/13 11:08 下午
* @Version: 1.0
*/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "用户路由接口")
@Controller
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/websocket")
public class WebSocketDemoRouteController {
@Autowired
private SecurityComponent securityComponent;
@Autowired
private WebSocketProperties webSocketProperties;
@GetMapping("chat-demo")
public ModelAndView chatDemo() {
ModelAndView modelAndView = new ModelAndView("chat-demo");
modelAndView.addObject("currentUserId", securityComponent.getCurrentUser().getUserId());
modelAndView.addObject("webSocketUrl", String.format("%s:%s/%s", webSocketProperties.getUrl(), webSocketProperties.getPort(), webSocketProperties.getContext()));
return modelAndView;
}
}

View File

@ -0,0 +1,104 @@
package ink.wgink.module.instantmessage.dao;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.UpdateException;
import ink.wgink.interfaces.init.IInitBaseTable;
import ink.wgink.module.instantmessage.pojo.pos.NoticePO;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: INoticeDao
* @Description: 消息通知
* @Author: wanggeng
* @Date: 2021/3/29 4:37 下午
* @Version: 1.0
*/
@Repository
public interface INoticeDao extends IInitBaseTable {
/**
* 保存
*
* @param params
* @throws SaveException
*/
void save(Map<String, Object> params) throws SaveException;
/**
* 修改已办
*
* @param params
* @throws UpdateException
*/
void updateHandle(Map<String, Object> params) throws UpdateException;
/**
* 详情
*
* @param params
* @return
* @throws SearchException
*/
NoticePO getPO(Map<String, Object> params) throws SearchException;
/**
* 列表
*
* @param params
* @return
* @throws SearchException
*/
List<NoticePO> listPO(Map<String, Object> params) throws SearchException;
/**
* 系统列表
*
* @param params
* @return
* @throws SearchException
*/
List<String> listSystems(Map<String, Object> params) throws SearchException;
/**
* 模块列表
*
* @param params
* @return
* @throws SearchException
*/
List<String> listModules(Map<String, Object> params) throws SearchException;
/**
* 菜单列表
*
* @param params
* @return
* @throws SearchException
*/
List<String> listMenus(Map<String, Object> params) throws SearchException;
/**
* 统计
*
* @param params
* @return
* @throws SearchException
*/
Integer count(Map<String, Object> params) throws SearchException;
/**
* 删除
*
* @param params
* @throws RemoveException
*/
void delete(Map<String, Object> params) throws RemoveException;
}

View File

@ -0,0 +1,47 @@
package ink.wgink.module.instantmessage.pojo.bos;
import ink.wgink.annotation.CheckEmptyAnnotation;
/**
* @ClassName: MessageSimpleBO
* @Description: 简单消息
* @Author: wanggeng
* @Date: 2021/9/13 6:00 下午
* @Version: 1.0
*/
public class NoticeBO {
/**
* 接收人用户ID多个用英文逗号分割
*/
@CheckEmptyAnnotation(name = "接收人")
private String to;
@CheckEmptyAnnotation(name = "标题")
private String title;
@CheckEmptyAnnotation(name = "内容")
private String content;
public String getTo() {
return to == null ? "" : to.trim();
}
public void setTo(String to) {
this.to = to;
}
public String getTitle() {
return title == null ? "" : title.trim();
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content == null ? "" : content.trim();
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -0,0 +1,24 @@
package ink.wgink.module.instantmessage.pojo.bos;
import ink.wgink.annotation.CheckEmptyAnnotation;
/**
* @ClassName: NoticeTargetBO
* @Description: 带目标通知
* @Author: wanggeng
* @Date: 2021/9/13 6:02 下午
* @Version: 1.0
*/
public class NoticeTargetBO extends NoticeBO {
@CheckEmptyAnnotation(name = "目标")
private String target;
public String getTarget() {
return target == null ? "" : target.trim();
}
public void setTarget(String target) {
this.target = target;
}
}

View File

@ -0,0 +1,198 @@
package ink.wgink.module.instantmessage.pojo.pos;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: NoticePO
* @Description: 消息通知
* @Author: wanggeng
* @Date: 2021/3/29 4:39 下午
* @Version: 1.0
*/
public class NoticePO {
private Long id;
private String noticeId;
private String noticeTitle;
private String noticeMsg;
private String noticeTarget;
private String noticeSystem;
private String noticeModule;
private String noticeMenu;
private String noticeServiceId;
private String userId;
private Integer isHandle;
private String gmtCreate;
private String creator;
private String gmtModified;
private String modifier;
private Integer isDelete;
public Long getId() {
return id == null ? 0 : id;
}
public void setId(Long id) {
this.id = id;
}
public String getNoticeId() {
return noticeId == null ? "" : noticeId;
}
public void setNoticeId(String noticeId) {
this.noticeId = noticeId;
}
public String getNoticeTitle() {
return noticeTitle == null ? "" : noticeTitle;
}
public void setNoticeTitle(String noticeTitle) {
this.noticeTitle = noticeTitle;
}
public String getNoticeMsg() {
return noticeMsg == null ? "" : noticeMsg;
}
public void setNoticeMsg(String noticeMsg) {
this.noticeMsg = noticeMsg;
}
public String getNoticeTarget() {
return noticeTarget == null ? "" : noticeTarget;
}
public void setNoticeTarget(String noticeTarget) {
this.noticeTarget = noticeTarget;
}
public String getNoticeSystem() {
return noticeSystem == null ? "" : noticeSystem;
}
public void setNoticeSystem(String noticeSystem) {
this.noticeSystem = noticeSystem;
}
public String getNoticeModule() {
return noticeModule == null ? "" : noticeModule;
}
public void setNoticeModule(String noticeModule) {
this.noticeModule = noticeModule;
}
public String getNoticeMenu() {
return noticeMenu == null ? "" : noticeMenu;
}
public void setNoticeMenu(String noticeMenu) {
this.noticeMenu = noticeMenu;
}
public String getNoticeServiceId() {
return noticeServiceId == null ? "" : noticeServiceId;
}
public void setNoticeServiceId(String noticeServiceId) {
this.noticeServiceId = noticeServiceId;
}
public String getUserId() {
return userId == null ? "" : userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getIsHandle() {
return isHandle == null ? 0 : isHandle;
}
public void setIsHandle(Integer isHandle) {
this.isHandle = isHandle;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate;
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
public String getCreator() {
return creator == null ? "" : creator;
}
public void setCreator(String creator) {
this.creator = creator;
}
public String getGmtModified() {
return gmtModified == null ? "" : gmtModified;
}
public void setGmtModified(String gmtModified) {
this.gmtModified = gmtModified;
}
public String getModifier() {
return modifier == null ? "" : modifier;
}
public void setModifier(String modifier) {
this.modifier = modifier;
}
public Integer getIsDelete() {
return isDelete == null ? 0 : isDelete;
}
public void setIsDelete(Integer isDelete) {
this.isDelete = isDelete;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"id\":")
.append(id);
sb.append(",\"noticeId\":\"")
.append(noticeId).append('\"');
sb.append(",\"noticeTitle\":\"")
.append(noticeTitle).append('\"');
sb.append(",\"noticeMsg\":\"")
.append(noticeMsg).append('\"');
sb.append(",\"noticeTarget\":\"")
.append(noticeTarget).append('\"');
sb.append(",\"noticeSystem\":\"")
.append(noticeSystem).append('\"');
sb.append(",\"noticeModule\":\"")
.append(noticeModule).append('\"');
sb.append(",\"noticeMenu\":\"")
.append(noticeMenu).append('\"');
sb.append(",\"noticeServiceId\":\"")
.append(noticeServiceId).append('\"');
sb.append(",\"userId\":\"")
.append(userId).append('\"');
sb.append(",\"isHandle\":")
.append(isHandle);
sb.append(",\"gmtCreate\":\"")
.append(gmtCreate).append('\"');
sb.append(",\"creator\":\"")
.append(creator).append('\"');
sb.append(",\"gmtModified\":\"")
.append(gmtModified).append('\"');
sb.append(",\"modifier\":\"")
.append(modifier).append('\"');
sb.append(",\"isDelete\":")
.append(isDelete);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,53 @@
package ink.wgink.module.instantmessage.pojo.vos;
import ink.wgink.annotation.CheckEmptyAnnotation;
/**
* @ClassName: MessageVO
* @Description: 消息VO
* @Author: wanggeng
* @Date: 2021/9/13 9:40 下午
* @Version: 1.0
*/
public class MessageVO {
@CheckEmptyAnnotation(name = "接收人")
private String to;
@CheckEmptyAnnotation(name = "标题")
private String title;
@CheckEmptyAnnotation(name = "内容")
private String content;
private String target;
public String getTo() {
return to == null ? "" : to.trim();
}
public void setTo(String to) {
this.to = to;
}
public String getTitle() {
return title == null ? "" : title.trim();
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content == null ? "" : content.trim();
}
public void setContent(String content) {
this.content = content;
}
public String getTarget() {
return target == null ? "" : target.trim();
}
public void setTarget(String target) {
this.target = target;
}
}

View File

@ -0,0 +1,42 @@
package ink.wgink.module.instantmessage.pojo.vos;
import ink.wgink.annotation.CheckListAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: NoticeMessageVO
* @Description: 通知消息
* @Author: wanggeng
* @Date: 2021/1/19 5:04 下午
* @Version: 1.0
*/
@ApiModel
public class NoticeDeleteServiceVO {
@ApiModelProperty(name = "serviceIds", value = "业务ID列表")
@CheckListAnnotation(name = "业务ID列表")
private List<String> serviceIds;
public List<String> getServiceIds() {
return serviceIds;
}
public void setServiceIds(List<String> serviceIds) {
this.serviceIds = serviceIds;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"serviceIds\":")
.append(serviceIds);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,119 @@
package ink.wgink.module.instantmessage.pojo.vos;
import ink.wgink.annotation.CheckListAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.ArrayList;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: NoticeMessageVO
* @Description: 通知消息
* @Author: wanggeng
* @Date: 2021/1/19 5:04 下午
* @Version: 1.0
*/
@ApiModel
public class NoticeVO {
@ApiModelProperty(name = "noticies", value = "通知列表")
@CheckListAnnotation(name = "通知列表")
private List<Notice> notices;
public List<Notice> getNotices() {
return notices == null ? new ArrayList<>() : notices;
}
public void setNotices(List<Notice> notices) {
this.notices = notices;
}
@ApiModel
public static class Notice {
@ApiModelProperty(name = "userIds", value = "用户ID列表")
private List<String> userIds;
@ApiModelProperty(name = "title", value = "消息标题")
private String title;
@ApiModelProperty(name = "msg", value = "消息体")
private String msg;
@ApiModelProperty(name = "target", value = "目标字符串")
private String target;
@ApiModelProperty(name = "system", value = "系统")
private String system;
@ApiModelProperty(name = "module", value = "模块")
private String module;
@ApiModelProperty(name = "menu", value = "菜单")
private String menu;
@ApiModelProperty(name = "serviceId", value = "业务ID")
private String serviceId;
public List<String> getUserIds() {
return userIds == null ? new ArrayList<>() : userIds;
}
public void setUserIds(List<String> userIds) {
this.userIds = userIds;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
public String getSystem() {
return system == null ? "" : system;
}
public void setSystem(String system) {
this.system = system;
}
public String getModule() {
return module == null ? "" : module;
}
public void setModule(String module) {
this.module = module;
}
public String getMenu() {
return menu == null ? "" : menu;
}
public void setMenu(String menu) {
this.menu = menu;
}
public String getServiceId() {
return serviceId == null ? "" : serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
}
}

View File

@ -0,0 +1,64 @@
package ink.wgink.module.instantmessage.service;
import ink.wgink.module.instantmessage.pojo.bos.NoticeBO;
import ink.wgink.module.instantmessage.pojo.bos.NoticeTargetBO;
import ink.wgink.module.instantmessage.pojo.vos.NoticeVO;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: IMessageService
* @Description: 消息
* @Author: wanggeng
* @Date: 2021/1/14 3:28 下午
* @Version: 1.0
*/
public interface IMessageService {
/**
* 通知
*
* @param noticeBO 通知内容
*/
void notice(NoticeBO noticeBO);
/**
* 通知
*
* @param clientName 客户端名称
* @param noticeBO 通知内容
*/
void notice(String clientName, NoticeBO noticeBO);
/**
* 通知
*
* @param noticeTargetBO 通知内容
*/
void notice(NoticeTargetBO noticeTargetBO);
/**
* 通知
*
* @param clientName 客户端名称
* @param noticeTargetBO 通知内容
*/
void notice(String clientName, NoticeTargetBO noticeTargetBO);
/**
* 通知并保存
*
* @param noticeBO
*/
void saveNotice(NoticeVO noticeVO, boolean isSave) throws Exception;
/**
* 删除通知
*
* @param serviceIds
*/
void delete(List<String> serviceIds);
}

View File

@ -0,0 +1,172 @@
package ink.wgink.module.instantmessage.service;
import ink.wgink.module.instantmessage.pojo.bos.NoticeBO;
import ink.wgink.module.instantmessage.pojo.bos.NoticeTargetBO;
import ink.wgink.module.instantmessage.pojo.pos.NoticePO;
import ink.wgink.module.instantmessage.pojo.vos.NoticeVO;
import ink.wgink.module.instantmessage.websocket.pojo.body.CountNeedToDealWithBody;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: INoticeService
* @Description: 消息通知
* @Author: wanggeng
* @Date: 2021/3/29 4:36 下午
* @Version: 1.0
*/
public interface INoticeService {
/**
* 保存
*
* @param userId
* @param notice
*/
void save(String userId, NoticeVO.Notice notice) throws Exception;
/**
* 更新已办状态
*
* @param userId
* @param countNeedToDealWithBody
*/
void updateHandleStatus(String userId, CountNeedToDealWithBody countNeedToDealWithBody);
/**
* 通知详情
*
* @param params
* @return
*/
NoticePO getPO(Map<String, Object> params);
/**
* 通知详情
*
* @param serviceId
* @param userId
* @return
*/
NoticePO getPO(String serviceId, String userId);
/**
* 通知详情
*
* @param system
* @param serviceId
* @param userId
* @return
*/
NoticePO getPO(String system, String serviceId, String userId);
/**
* 通知详情
*
* @param system
* @param module
* @param serviceId
* @param userId
* @return
*/
NoticePO getPO(String system, String module, String serviceId, String userId);
/**
* 通知详情
*
* @param system
* @param module
* @param menu
* @param serviceId
* @param userId
* @return
*/
NoticePO getPO(String system, String module, String menu, String serviceId, String userId);
/**
* 通知列表
*
* @param params
* @return
*/
List<NoticePO> listPO(Map<String, Object> params);
/**
* 通知列表
*
* @param serviceId
* @param userId
* @return
*/
List<NoticePO> listPO(String serviceId, String userId);
/**
* 通知列表
*
* @param system
* @param serviceId
* @param userId
* @return
*/
List<NoticePO> listPO(String system, String serviceId, String userId);
/**
* 通知列表
*
* @param system
* @param module
* @param serviceId
* @param userId
* @return
*/
List<NoticePO> listPO(String system, String module, String serviceId, String userId);
/**
* 通知列表
*
* @param system
* @param module
* @param menu
* @param serviceId
* @param userId
* @return
*/
List<NoticePO> listPO(String system, String module, String menu, String serviceId, String userId);
/**
* 通知数量
*
* @param userId
* @param countNeedToDealWithBody
* @return
*/
List<CountNeedToDealWithBody> listNoticeCount(String userId, CountNeedToDealWithBody countNeedToDealWithBody);
/**
* 统计
*
* @param params
* @return
*/
Integer count(Map<String, Object> params);
/**
* 删除
*
* @param serviceIds
*/
void deleteByServiceIds(List<String> serviceIds);
/**
* 通知列表
*
* @param serviceIds
* @return
*/
List<NoticePO> listPO(List<String> serviceIds);
}

View File

@ -0,0 +1,190 @@
package ink.wgink.module.instantmessage.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.module.instantmessage.pojo.bos.NoticeBO;
import ink.wgink.module.instantmessage.pojo.bos.NoticeTargetBO;
import ink.wgink.module.instantmessage.pojo.pos.NoticePO;
import ink.wgink.module.instantmessage.pojo.vos.NoticeVO;
import ink.wgink.module.instantmessage.service.IMessageService;
import ink.wgink.module.instantmessage.service.INoticeService;
import ink.wgink.module.instantmessage.websocket.enums.ClientSocketTypeEnum;
import ink.wgink.module.instantmessage.websocket.manager.WebSocketChannelManager;
import ink.wgink.module.instantmessage.websocket.pojo.WebSocketClientMessage;
import ink.wgink.module.instantmessage.websocket.pojo.WebSocketSession;
import ink.wgink.module.instantmessage.websocket.pojo.body.CountNeedToDealWithBody;
import ink.wgink.module.instantmessage.websocket.pojo.body.NoticeBody;
import ink.wgink.util.BeanPropertyCheckUtil;
import io.netty.channel.Channel;
import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: MessageServiceImpl
* @Description: 消息
* @Author: wanggeng
* @Date: 2021/1/14 3:28 下午
* @Version: 1.0
*/
@Service
public class MessageServiceImpl extends DefaultBaseService implements IMessageService {
@Autowired
private INoticeService noticeService;
private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(2);
@Override
public void notice(NoticeBO noticeBO) {
notice(null, noticeBO);
}
@Override
public void notice(String clientName, NoticeBO noticeBO) {
List<WebSocketSession> webSocketSessions = listWebSocketSessions(clientName, noticeBO);
NoticeBody noticeBody = new NoticeBody(noticeBO.getTitle(), noticeBO.getContent());
WebSocketClientMessage webSocketClientMessage = new WebSocketClientMessage(ClientSocketTypeEnum.NOTICE.getValue(),
true,
WebSocketChannelManager.FORM_SYSTEM,
noticeBO.getTo(),
JSONObject.toJSONString(noticeBody));
notice(webSocketSessions, webSocketClientMessage);
}
@Override
public void notice(NoticeTargetBO noticeTargetBO) {
notice(null, noticeTargetBO);
}
@Override
public void notice(String clientName, NoticeTargetBO noticeTargetBO) {
List<WebSocketSession> webSocketSessions = listWebSocketSessions(clientName, noticeTargetBO);
NoticeBody noticeBody = new NoticeBody(noticeTargetBO.getTitle(), noticeTargetBO.getContent(), noticeTargetBO.getTarget());
WebSocketClientMessage webSocketClientMessage = new WebSocketClientMessage(ClientSocketTypeEnum.NOTICE_TARGET_MESSAGE.getValue(),
true,
WebSocketChannelManager.FORM_SYSTEM,
noticeTargetBO.getTo(),
JSONObject.toJSONString(noticeBody));
notice(webSocketSessions, webSocketClientMessage);
}
@Override
public void saveNotice(NoticeVO noticeVO, boolean isSave) throws Exception {
for (NoticeVO.Notice notice : noticeVO.getNotices()) {
if (notice.getUserIds() == null || notice.getUserIds().isEmpty()) {
continue;
}
if (StringUtils.isBlank(notice.getTitle())) {
notice.setTitle("系统消息");
}
if (StringUtils.isBlank(notice.getMsg())) {
notice.setMsg("您有一条系统消息");
}
List<WebSocketSession> webSocketSessions = WebSocketChannelManager.getInstance().listOnlineUser(notice.getUserIds());
scheduledExecutorService.schedule(() -> {
for (WebSocketSession webSocketSession : webSocketSessions) {
NoticeBody noticeBody = new NoticeBody(notice.getTitle(), notice.getMsg(), notice.getTarget());
WebSocketClientMessage webSocketClientMessage = new WebSocketClientMessage(ClientSocketTypeEnum.NOTICE_TARGET_MESSAGE.getValue(),
true,
WebSocketChannelManager.FORM_SYSTEM,
webSocketSession.getUserId(),
JSONObject.toJSONString(noticeBody));
// 发送通知
WebSocketChannelManager.getInstance().sendText(webSocketSession.getChannel(), webSocketClientMessage);
}
}, 3, TimeUnit.SECONDS);
if (isSave) {
// 保存通知记录
List<String> userIds = notice.getUserIds();
for (String userId : userIds) {
noticeService.save(userId, notice);
}
}
}
}
/**
* 会话列表
*
* @param clientName
* @param noticeBO
* @return
*/
private List<WebSocketSession> listWebSocketSessions(String clientName, NoticeBO noticeBO) {
BeanPropertyCheckUtil.checkField(noticeBO);
List<String> userIds = new ArrayList<>(Sets.newHashSet(noticeBO.getTo().split(",")));
List<WebSocketSession> webSocketSessions;
if (StringUtils.isBlank(clientName)) {
webSocketSessions = WebSocketChannelManager.getInstance().listOnlineUser(userIds);
} else {
webSocketSessions = WebSocketChannelManager.getInstance().listOnlineUser(userIds, clientName);
}
if (webSocketSessions.isEmpty()) {
throw new SearchException("用户不存在");
}
return webSocketSessions;
}
/**
* 通知
*
* @param webSocketSessions
* @param webSocketClientMessage
*/
private void notice(List<WebSocketSession> webSocketSessions, WebSocketClientMessage webSocketClientMessage) {
for (WebSocketSession webSocketSession : webSocketSessions) {
WebSocketChannelManager.getInstance().sendText(webSocketSession.getChannel(), webSocketClientMessage);
}
}
@Override
public void delete(List<String> serviceIds) {
List<NoticePO> noticePOs = noticeService.listPO(serviceIds);
Set<String> noticeUserIdSet = new HashSet<>();
noticePOs.forEach(noticePO -> {
noticeUserIdSet.add(noticePO.getUserId());
});
// 删除通知
noticeService.deleteByServiceIds(serviceIds);
// 重新推送数量
List<WebSocketSession> webSocketSessions = WebSocketChannelManager.getInstance().listOnlineUser(new ArrayList<>(noticeUserIdSet));
// 3s后通知保证事务提交
scheduledExecutorService.schedule(() -> {
// 更新状态待办
for (WebSocketSession webSocketSession : webSocketSessions) {
for (NoticePO noticePO : noticePOs) {
if (StringUtils.equals(webSocketSession.getUserId(), noticePO.getUserId())) {
Channel channel = webSocketSession.getChannel();
CountNeedToDealWithBody countNeedToDealWithBody = new CountNeedToDealWithBody();
countNeedToDealWithBody.setSystem(noticePO.getNoticeSystem());
// 查询待办状态
List<CountNeedToDealWithBody> counts = noticeService.listNoticeCount(webSocketSession.getUserId(), countNeedToDealWithBody);
WebSocketClientMessage webSocketClientMessage = new WebSocketClientMessage(ClientSocketTypeEnum.SEARCH_COUNT_NEED_TO_DEALT_WITH.getValue(),
true,
WebSocketChannelManager.FORM_SYSTEM,
webSocketSession.getUserId(),
JSONArray.toJSONString(counts));
WebSocketChannelManager.getInstance().sendText(channel, webSocketClientMessage);
break;
}
}
}
}, 3, TimeUnit.SECONDS);
}
}

View File

@ -0,0 +1,285 @@
package ink.wgink.module.instantmessage.service.impl;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.module.instantmessage.dao.INoticeDao;
import ink.wgink.module.instantmessage.pojo.pos.NoticePO;
import ink.wgink.module.instantmessage.pojo.vos.NoticeVO;
import ink.wgink.module.instantmessage.service.INoticeService;
import ink.wgink.module.instantmessage.websocket.pojo.body.CountNeedToDealWithBody;
import ink.wgink.util.UUIDUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: NoticeServiceImpl
* @Description: 消息通知
* @Author: wanggeng
* @Date: 2021/3/29 4:36 下午
* @Version: 1.0
*/
@Service
public class NoticeServiceImpl extends DefaultBaseService implements INoticeService {
@Autowired
private INoticeDao noticeDao;
@Override
public void save(String userId, NoticeVO.Notice notice) throws Exception {
if (StringUtils.isBlank(userId)) {
return;
}
if (StringUtils.isBlank(notice.getSystem())) {
return;
}
if (StringUtils.isBlank(notice.getServiceId())) {
return;
}
List<NoticePO> noticePOs = listPO(notice.getSystem(), notice.getModule(), notice.getMenu(), notice.getServiceId(), userId);
if (!noticePOs.isEmpty()) {
LOG.debug("通知已经存在");
return;
}
Map<String, Object> params = getHashMap(16);
params.put("noticeId", UUIDUtil.getUUID());
params.put("userId", userId);
params.put("noticeTitle", notice.getTitle());
params.put("noticeMsg", notice.getMsg());
params.put("noticeTarget", notice.getTarget());
params.put("noticeSystem", notice.getSystem());
params.put("noticeModule", notice.getModule());
params.put("noticeMenu", notice.getMenu());
params.put("noticeServiceId", notice.getServiceId());
params.put("isHandle", 0);
setSaveInfoByUserId(params, "1");
noticeDao.save(params);
}
@Override
public void updateHandleStatus(String userId, CountNeedToDealWithBody countNeedToDealWithBody) {
if (StringUtils.isBlank(countNeedToDealWithBody.getSystem())) {
return;
}
if (StringUtils.isBlank(countNeedToDealWithBody.getServiceId())) {
return;
}
Map<String, Object> params = getHashMap(6);
params.put("isHandle", 1);
params.put("noticeSystem", countNeedToDealWithBody.getSystem());
params.put("noticeServiceId", countNeedToDealWithBody.getServiceId());
setUpdateInfoByUserId(params, userId);
noticeDao.updateHandle(params);
}
@Override
public NoticePO getPO(Map<String, Object> params) {
return noticeDao.getPO(params);
}
@Override
public NoticePO getPO(String serviceId, String userId) {
Map<String, Object> params = getHashMap(4);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return getPO(params);
}
@Override
public NoticePO getPO(String system, String serviceId, String userId) {
Map<String, Object> params = getHashMap(6);
params.put("noticeSystem", system);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return getPO(params);
}
@Override
public NoticePO getPO(String system, String module, String serviceId, String userId) {
Map<String, Object> params = getHashMap(8);
params.put("noticeSystem", system);
params.put("noticeModule", module);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return getPO(params);
}
@Override
public NoticePO getPO(String system, String module, String menu, String serviceId, String userId) {
Map<String, Object> params = getHashMap(10);
params.put("noticeSystem", system);
params.put("noticeModule", module);
params.put("noticeMenu", menu);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return getPO(params);
}
@Override
public List<NoticePO> listPO(Map<String, Object> params) {
return noticeDao.listPO(params);
}
@Override
public List<NoticePO> listPO(String serviceId, String userId) {
Map<String, Object> params = getHashMap(4);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return listPO(params);
}
@Override
public List<NoticePO> listPO(String system, String serviceId, String userId) {
Map<String, Object> params = getHashMap(6);
params.put("noticeSystem", system);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return listPO(params);
}
@Override
public List<NoticePO> listPO(String system, String module, String serviceId, String userId) {
Map<String, Object> params = getHashMap(8);
params.put("noticeSystem", system);
params.put("noticeModule", module);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return listPO(params);
}
@Override
public List<NoticePO> listPO(String system, String module, String menu, String serviceId, String userId) {
Map<String, Object> params = getHashMap(10);
params.put("noticeSystem", system);
params.put("noticeModule", module);
params.put("noticeMenu", menu);
params.put("noticeServiceId", serviceId);
params.put("userId", userId);
return listPO(params);
}
@Override
public List<CountNeedToDealWithBody> listNoticeCount(String userId, CountNeedToDealWithBody countNeedToDealWithBody) {
List<CountNeedToDealWithBody> noticeCounts = new ArrayList<>();
Map<String, Object> params = getHashMap(10);
params.put("userId", userId);
params.put("isHandle", 0);
if (StringUtils.isBlank(countNeedToDealWithBody.getSystem())) {
// 系统为空按系统统计
List<String> systems = listSystems(userId);
for (String system : systems) {
params.put("noticeSystem", system);
CountNeedToDealWithBody systemCount = new CountNeedToDealWithBody();
systemCount.setSystem(system);
systemCount.setCount(count(params));
noticeCounts.add(systemCount);
}
} else if (StringUtils.isBlank(countNeedToDealWithBody.getModule())) {
// 模块为空按模块统计
List<String> modules = listModules(userId, countNeedToDealWithBody.getSystem());
params.put("noticeSystem", countNeedToDealWithBody.getSystem());
for (String module : modules) {
CountNeedToDealWithBody systemCount = new CountNeedToDealWithBody();
systemCount.setSystem(countNeedToDealWithBody.getSystem());
systemCount.setModule(module);
params.put("noticeModule", module);
systemCount.setCount(count(params));
noticeCounts.add(systemCount);
}
} else if (StringUtils.isBlank(countNeedToDealWithBody.getMenu())) {
// 菜单为空按菜单统计
List<String> menus = listMenus(userId, countNeedToDealWithBody.getSystem(), countNeedToDealWithBody.getModule());
params.put("noticeSystem", countNeedToDealWithBody.getSystem());
params.put("noticeModule", countNeedToDealWithBody.getModule());
for (String menu : menus) {
CountNeedToDealWithBody systemCount = new CountNeedToDealWithBody();
systemCount.setSystem(countNeedToDealWithBody.getSystem());
systemCount.setModule(countNeedToDealWithBody.getModule());
systemCount.setMenu(menu);
params.put("noticeMenu", menu);
systemCount.setCount(count(params));
noticeCounts.add(systemCount);
}
} else {
// 都不为空具体菜单数量
CountNeedToDealWithBody systemCount = new CountNeedToDealWithBody();
systemCount.setSystem(countNeedToDealWithBody.getSystem());
systemCount.setModule(countNeedToDealWithBody.getModule());
systemCount.setMenu(countNeedToDealWithBody.getMenu());
params.put("noticeSystem", countNeedToDealWithBody.getSystem());
params.put("noticeModule", countNeedToDealWithBody.getModule());
params.put("noticeModule", countNeedToDealWithBody.getModule());
params.put("noticeMenu", countNeedToDealWithBody.getMenu());
systemCount.setCount(count(params));
noticeCounts.add(systemCount);
}
return noticeCounts;
}
@Override
public Integer count(Map<String, Object> params) {
Integer count = noticeDao.count(params);
return count == null ? 0 : count;
}
@Override
public void deleteByServiceIds(List<String> serviceIds) {
Map<String, Object> params = getHashMap(2);
params.put("serviceIds", serviceIds);
noticeDao.delete(params);
}
@Override
public List<NoticePO> listPO(List<String> serviceIds) {
Map<String, Object> params = getHashMap(2);
params.put("serviceIds", serviceIds);
return listPO(params);
}
/**
* 系统列表
*
* @param userId
* @return
*/
private List<String> listSystems(String userId) {
Map<String, Object> params = getHashMap(2);
params.put("userId", userId);
return noticeDao.listSystems(params);
}
/**
* 模块列表
*
* @param userId
* @return
*/
private List<String> listModules(String userId, String noticeSystem) {
Map<String, Object> params = getHashMap(4);
params.put("userId", userId);
params.put("noticeSystem", noticeSystem);
return noticeDao.listModules(params);
}
/**
* 菜单列表
*
* @param userId
* @return
*/
private List<String> listMenus(String userId, String noticeSystem, String noticeModule) {
Map<String, Object> params = getHashMap(6);
params.put("userId", userId);
params.put("noticeSystem", noticeSystem);
params.put("noticeModule", noticeModule);
return noticeDao.listMenus(params);
}
}

View File

@ -8,6 +8,7 @@ import ink.wgink.module.instantmessage.websocket.exception.*;
import ink.wgink.module.instantmessage.websocket.manager.WebSocketChannelManager;
import ink.wgink.module.instantmessage.websocket.pojo.WebSocketClientMessage;
import ink.wgink.module.instantmessage.websocket.pojo.WebSocketSession;
import ink.wgink.module.instantmessage.websocket.pojo.body.IdsBody;
import ink.wgink.module.instantmessage.websocket.pojo.body.RegisterBody;
import ink.wgink.module.instantmessage.websocket.pojo.body.SendStatusBody;
import io.netty.channel.Channel;
@ -17,7 +18,9 @@ import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @ClassName: WebSocketTextHandler
@ -67,6 +70,7 @@ public class WebSocketTextHandler {
} catch (JSONException e) {
clientSocketMessage = new WebSocketClientMessage();
clientSocketMessage.setSystem(true);
clientSocketMessage.setType(ClientSocketTypeEnum.SYSTEM_MESSAGE.getValue());
clientSocketMessage.setFrom(WebSocketChannelManager.FORM_SYSTEM);
sendStatusBody = new SendStatusBody(SendStatusEnum.TO_ERROR.getValue(), SendStatusEnum.MESSAGE_ERROR, e.getMessage());
} finally {
@ -142,8 +146,32 @@ public class WebSocketTextHandler {
}
}
private void listOnlineUser(Channel channel, WebSocketClientMessage clientSocketMessage) {
/**
* 在线用户列表
*
* @param channel 通道
* @param webSocketClientMessage 消息体
* @throws UserSessionException
* @throws UserErrorException
*/
private void listOnlineUser(Channel channel, WebSocketClientMessage webSocketClientMessage) throws UserSessionException, UserErrorException {
webSocketClientMessage.setSystem(true);
webSocketClientMessage.setTo(webSocketClientMessage.getFrom());
IdsBody idsBody = JSONObject.parseObject(webSocketClientMessage.getBody(), IdsBody.class);
if (idsBody.getIds() == null || idsBody.getIds().isEmpty()) {
sendTextFailed(channel, webSocketClientMessage, "用户ID列表为空");
return;
}
List<WebSocketSession> webSocketSessions = WebSocketChannelManager.getInstance().listOnlineUser(idsBody.getIds());
Set<String> idSets = new HashSet<>();
for (WebSocketSession webSocketSession : webSocketSessions) {
idSets.add(webSocketSession.getUserId());
}
idsBody = new IdsBody();
idsBody.setIds(new ArrayList<>(idSets));
webSocketClientMessage.setType(ClientSocketTypeEnum.SEND_STATUS_ONLINE.getValue());
webSocketClientMessage.setBody(JSONObject.toJSONString(idsBody));
sendText(channel, webSocketClientMessage);
}
/**

View File

@ -217,15 +217,41 @@ public class WebSocketChannelManager {
return null;
}
/**
* 全部发
*
* @param tws
*/
public void sendAll(TextWebSocketFrame tws) {
globalGroup.writeAndFlush(tws);
}
/**
* 单发
*
* @param channel
* @param webSocketClientMessage
*/
public void sendText(Channel channel, WebSocketClientMessage webSocketClientMessage) {
if (channel == null || !channel.isOpen() || !channel.isActive()) {
return;
}
TextWebSocketFrame textWebSocketFrame = new TextWebSocketFrame(JSONObject.toJSONString(webSocketClientMessage));
channel.writeAndFlush(textWebSocketFrame);
}
/**
* 群发
*
* @param channels
* @param webSocketClientMessage
*/
public void sendGroupText(List<Channel> channels, WebSocketClientMessage webSocketClientMessage) {
for (Channel channel : channels) {
sendText(channel, webSocketClientMessage);
}
}
private static class WebSocketChannelManagerBuilder {
public static final WebSocketChannelManager webSocketChannelManager = new WebSocketChannelManager();
}

View File

@ -0,0 +1,56 @@
package ink.wgink.module.instantmessage.websocket.pojo.body;
/**
* @ClassName: CountNeedToDealWithBody
* @Description: 待办数量统计
* @Author: wanggeng
* @Date: 2021/9/13 5:39 下午
* @Version: 1.0
*/
public class CountNeedToDealWithBody {
private String system;
private String module;
private String menu;
private String serviceId;
private Integer count;
public String getSystem() {
return system == null ? "" : system.trim();
}
public void setSystem(String system) {
this.system = system;
}
public String getModule() {
return module == null ? "" : module.trim();
}
public void setModule(String module) {
this.module = module;
}
public String getMenu() {
return menu == null ? "" : menu.trim();
}
public void setMenu(String menu) {
this.menu = menu;
}
public String getServiceId() {
return serviceId == null ? "" : serviceId.trim();
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public Integer getCount() {
return count == null ? 0 : count;
}
public void setCount(Integer count) {
this.count = count;
}
}

View File

@ -0,0 +1,23 @@
package ink.wgink.module.instantmessage.websocket.pojo.body;
import java.util.List;
/**
* @ClassName: IdsBody
* @Description: ID列表
* @Author: wanggeng
* @Date: 2021/9/13 9:09 上午
* @Version: 1.0
*/
public class IdsBody {
private List<String> ids;
public List<String> getIds() {
return ids;
}
public void setIds(List<String> ids) {
this.ids = ids;
}
}

View File

@ -0,0 +1,317 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ink.wgink.module.instantmessage.dao.INoticeDao">
<cache flushInterval="3600000"/>
<resultMap id="noticePO" type="ink.wgink.module.instantmessage.pojo.pos.NoticePO">
<id column="id" property="id"/>
<result column="notice_id" property="noticeId"/>
<result column="notice_title" property="noticeTitle"/>
<result column="notice_msg" property="noticeMsg"/>
<result column="notice_target" property="noticeTarget"/>
<result column="notice_system" property="noticeSystem"/>
<result column="notice_module" property="noticeModule"/>
<result column="notice_menu" property="noticeMenu"/>
<result column="notice_service_id" property="noticeServiceId"/>
<result column="user_id" property="userId"/>
<result column="is_handle" property="isHandle"/>
<result column="gmt_create" property="gmtCreate"/>
<result column="creator" property="creator"/>
<result column="gmt_modified" property="gmtModified"/>
<result column="modifier" property="modifier"/>
<result column="is_delete" property="isDelete"/>
</resultMap>
<!-- 建表 -->
<update id="createTable">
CREATE TABLE IF NOT EXISTS `socket_notice` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`notice_id` char(36) DEFAULT NULL COMMENT '主键',
`notice_title` varchar(255) DEFAULT NULL COMMENT '通知标题',
`notice_msg` varchar(255) DEFAULT NULL COMMENT '通知内容',
`notice_target` varchar(255) DEFAULT NULL COMMENT '通知触发目标',
`notice_system` varchar(255) DEFAULT NULL COMMENT '通知业务系统',
`notice_module` varchar(255) DEFAULT NULL COMMENT '通知业务模块',
`notice_service_id` varchar(255) DEFAULT NULL COMMENT '通知业务ID',
`user_id` char(36) DEFAULT NULL COMMENT '通知人',
`is_handle` int(1) DEFAULT '0' COMMENT '是否处理',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`creator` char(36) DEFAULT NULL COMMENT '创建人',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
`modifier` char(36) DEFAULT NULL COMMENT '修改人',
`is_delete` int(1) DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `notice_id` (`notice_id`) USING BTREE,
KEY `notice_title` (`notice_title`) USING BTREE,
KEY `notice_msg` (`notice_msg`) USING BTREE,
KEY `notice_target` (`notice_target`) USING BTREE,
KEY `notice_module` (`notice_module`) USING BTREE,
KEY `notice_service_id` (`notice_service_id`) USING BTREE,
KEY `user_id` (`user_id`) USING BTREE,
KEY `is_handle` (`is_handle`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='小程序用户';
</update>
<!-- 保存 -->
<insert id="save" parameterType="map">
INSERT INTO socket_notice (
notice_id,
notice_title,
notice_msg,
notice_target,
notice_system,
notice_module,
notice_menu,
notice_service_id,
user_id,
is_handle,
gmt_create,
creator,
gmt_modified,
modifier,
is_delete
) VALUES(
#{noticeId},
#{noticeTitle},
#{noticeMsg},
#{noticeTarget},
#{noticeSystem},
#{noticeModule},
#{noticeMenu},
#{noticeServiceId},
#{userId},
#{isHandle},
#{gmtCreate},
#{creator},
#{gmtModified},
#{modifier},
#{isDelete}
)
</insert>
<!-- 更新已办状态 -->
<update id="updateHandle" parameterType="map">
UPDATE
socket_notice
SET
is_handle = #{isHandle},
gmt_modified = #{gmtModified},
modifier = #{modifier}
WHERE
notice_system = #{noticeSystem}
AND
notice_service_id = #{noticeServiceId}
</update>
<!-- 删除 -->
<delete id="delete" parameterType="map">
DELETE FROM
socket_notice
WHERE
<if test="serviceIds != null and serviceIds.size > 0">
notice_service_id IN
<foreach collection="serviceIds" index="index" open="(" separator="," close=")">
#{serviceIds[${index}]}
</foreach>
</if>
</delete>
<!-- 详情 -->
<select id="getPO" parameterType="map" resultMap="noticePO">
SELECT
notice_id,
notice_title,
notice_msg,
notice_target,
notice_system,
notice_module,
notice_menu,
notice_service_id,
user_id,
is_handle,
gmt_create,
creator,
gmt_modified,
modifier,
is_delete
FROM
socket_notice
WHERE
is_delete = 0
<if test="noticeId != null and noticeId != ''">
AND
notice_id = #{noticeId}
</if>
<if test="noticeSystem != null and noticeSystem != ''">
AND
notice_system = #{noticeSystem}
</if>
<if test="noticeModule != null and noticeModule != ''">
AND
notice_module = #{noticeModule}
</if>
<if test="noticeMenu != null and noticeMenu">
AND
notice_menu = #{noticeMenu}
</if>
<if test="noticeServiceId != null and noticeServiceId != ''">
AND
notice_service_id = #{noticeServiceId}
</if>
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
</select>
<!-- 列表 -->
<select id="listPO" parameterType="map" resultMap="noticePO">
SELECT
notice_id,
notice_title,
notice_msg,
notice_target,
notice_system,
notice_module,
notice_menu,
notice_service_id,
user_id,
is_handle,
gmt_create,
creator,
gmt_modified,
modifier,
is_delete
FROM
socket_notice
WHERE
is_delete = 0
<if test="noticeSystem != null and noticeSystem != ''">
AND
notice_system = #{noticeSystem}
</if>
<if test="noticeModule != null and noticeModule != ''">
AND
notice_module = #{noticeModule}
</if>
<if test="noticeMenu != null and noticeMenu">
AND
notice_menu = #{noticeMenu}
</if>
<if test="noticeServiceId != null and noticeServiceId != ''">
AND
notice_service_id = #{noticeServiceId}
</if>
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
<if test="isHandle != null">
AND
is_handle = #{isHandle}
</if>
<if test="serviceId != null and serviceId != ''">
AND
notice_service_id = #{serviceId}
</if>
<if test="serviceIds != null and serviceIds.size > 0">
AND
notice_service_id IN
<foreach collection="serviceIds" index="index" open="(" separator="," close=")">
#{serviceIds[${index}]}
</foreach>
</if>
</select>
<!-- 系统列表 -->
<select id="listSystems" parameterType="map" resultType="java.lang.String">
SELECT
notice_system
FROM
socket_notice
WHERE
is_delete = 0
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
GROUP BY
notice_system
</select>
<!-- 模块列表 -->
<select id="listModules" parameterType="map" resultType="java.lang.String">
SELECT
notice_module
FROM
socket_notice
WHERE
is_delete = 0
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
<if test="noticeSystem != null and noticeSystem != ''">
AND
notice_system = #{noticeSystem}
</if>
GROUP BY
notice_module
</select>
<!-- 菜单列表 -->
<select id="listMenus" parameterType="map" resultType="java.lang.String">
SELECT
notice_menu
FROM
socket_notice
WHERE
is_delete = 0
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
<if test="noticeSystem != null and noticeSystem != ''">
AND
notice_system = #{noticeSystem}
</if>
<if test="noticeModule != null and noticeModule != ''">
AND
notice_module = #{noticeModule}
</if>
GROUP BY
notice_menu
</select>
<!-- 统计 -->
<select id="count" parameterType="map" resultType="java.lang.Integer">
SELECT
COUNT(*)
FROM
socket_notice
WHERE
is_delete = 0
<if test="userId != null and userId != ''">
AND
user_id = #{userId}
</if>
<if test="noticeSystem != null and noticeSystem != ''">
AND
notice_system = #{noticeSystem}
</if>
<if test="noticeModule != null and noticeModule != ''">
AND
notice_module = #{noticeModule}
</if>
<if test="noticeMenu != null and noticeMenu != ''">
AND
notice_menu = #{noticeMenu}
</if>
<if test="isHandle != null">
AND
is_handle = #{isHandle}
</if>
</select>
</mapper>

View File

@ -0,0 +1,207 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="UTF-8">
<title>聊天测试</title>
<style>
.websocket-line {padding: 5px 0;}
.websocket-input {width: 244px; height: 21px; border: 1px solid silver;}
.websocket-container {width: 300px;}
.websocket-history-box {height: 400px; border: 1px solid silver; overflow: auto;}
.websocket-box {padding: 5px 0; text-align: right;}
.message {display: inline-block; max-width: 195px; font-size: 13px; margin: 10px; padding: 5px; border-radius: 5px;}
.receive-msg-box {}
.receive-msg {background-color: #04b304; color: #FFFFFF;}
.send-msg-box {text-align: right;}
.send-msg {text-align: left; background-color: #c5c5c5; color: #000000;}
</style>
</head>
<body>
<div class="websocket-container">
<div class="websocket-line">
<select id="scheme" style="width: 70px; height: 26px; font-size: 18px;">
<option value="ws://" selected>ws://</option>
<option value="wss://">wss://</option>
</select>
<span id="webSocketUrl" th:text="${webSocketUrl}"></span>
</div>
<div class="websocket-line">
当前用户ID <input id="currentUserId" class="websocket-input" type="text" th:value="${currentUserId}" readonly style="width: 208px;"/>
</div>
<div class="websocket-line">
接收用户ID <input id="toUserId" class="websocket-input" type="text" style="width: 208px;"/>
</div>
<div class="websocket-line">
<input id="clientName" class="websocket-input" type="text" placeholder="请输入客户端名称"/>
<button id="loginBtn" onclick="login()">登录</button>
<button id="closeBtn" style="display: none;">关闭</button>
</div>
<div class="websocket-line">
状态:<span id="loginStatus">未登录</span>
</div>
<div id="websocketHistoryBox" class="websocket-history-box">
<!--
<div class="receive-msg-box">
<div class="message receive-msg">收到</div>
</div>
<div class="send-msg-box">
<div class="message send-msg">发送</div>
</div>
-->
</div>
<div class="websocket-box">
<input type="text" id="message" class="websocket-input" placeholder="请输入发送内容"/>
<button id="login" onclick="send()">发送</button>
</div>
</div>
<script type="text/javascript" src="assets/js/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="assets/js/restajax.js"></script>
<script type="text/javascript">
var websocket;
function initWebSocket(sessionId) {
if ('WebSocket' in window) {
websocket = new WebSocket($('#scheme').val() + $('#webSocketUrl').html());
console.log("WebSocket连接成功")
} else {
alert('浏览器不支持WebSocket');
return;
}
//连接发生错误的回调方法
websocket.onerror = function () {
console.log('error')
};
//连接成功建立的回调方法
websocket.onopen = function (event) {
console.log('open', event);
// 打开连接注册WebSocket
register(sessionId);
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
var data = JSON.parse(event.data);
// 注册
if(data.type == 100) {
var body = JSON.parse(data.body);
if(body.code == 200) {
$('#loginStatus').html('已连接');
} else {
$('#loginStatus').html(body.msg);
}
} else if(data.type == 101) {
var body = data.body;
$('#websocketHistoryBox').append('<div class="receive-msg-box"><div class="message receive-msg">'+ body +'</div></div>');
}
}
//连接关闭的回调方法
websocket.onclose = function () {
console.log('close')
}
//监听窗口关闭事件当窗口关闭时主动去关闭websocket连接防止连接还没断开就关闭窗口server端会抛异常。
window.onbeforeunload = function () {
websocket.close();
}
}
function register(sessionId) {
var registBody = {
id: new Date().getTime(),
type: 100,
from: $('#currentUserId').val(),
to: $('#currentUserId').val(),
body: {
sessionId: sessionId
}
}
websocket.send(JSON.stringify(registBody));
}
function login() {
if(!$('#toUserId').val()) {
alert('请输入接收用户ID');
return;
}
if(!$('#clientName').val()) {
alert('请输入客户端名称')
return;
}
restAjax.get(restAjax.path('api/websocket/client/login/{clientName}', [$('#clientName').val()]), {}, null, function(code, data) {
var sessionId = data.data
$('#loginBtn').hide();
$('#closeBtn').show();
$('#clientName').attr('disabled', 'disabled');
$('#toUserId').attr('disabled', 'disabled');
initWebSocket(sessionId);
}, function(code, data) {
alert(data.msg);
})
}
function send() {
if(!websocket) {
alert('请开启WebSocket');
return;
}
if(!$('#message').val()) {
alert('请输入内容');
return;
}
var sendBody = {
id: new Date().getTime(),
type: 101,
from: $('#currentUserId').val(),
to: $('#toUserId').val(),
body: $('#message').val()
}
websocket.send(JSON.stringify(sendBody));
$('#websocketHistoryBox').append('<div class="send-msg-box"><div class="message send-msg">'+ $('#message').val() +'</div></div>');
$('#message').val('')
}
// //判断当前浏览器是否支持WebSocket
//
//
// //将消息显示在网页上
// function setMessageInnerHTML(innerHTML) {
// document.getElementById('message').innerHTML += innerHTML + '<br/>';
// }
//
// //关闭连接
// function closeWebSocket() {
// websocket.close();
// }
//
// var count = 0;
// //发送消息
// function send() {
// var message = document.getElementById('text').value;
// if (count == 0) {
// var registBody = {
// id: new Date().getTime(),
// type: 100,
// from: '1',
// to: '1',
// body: {
// sessionId: message
// }
// }
// websocket.send(JSON.stringify(registBody));
// } else {
// var sendBody = {
// id: new Date().getTime(),
// type: 101,
// from: '1',
// to: '1',
// body: message
// }
// websocket.send(JSON.stringify(sendBody));
// }
// count++;
// }
</script>
</body>
</html>