1
This commit is contained in:
@ -0,0 +1,24 @@
|
||||
package com.mosty.websocket;
|
||||
|
||||
import com.mosty.common.base.timeconsume.EnableTimeConsume;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
@EnableTimeConsume
|
||||
@EnableFeignClients(basePackages = "com.mosty.base.feign.service")
|
||||
@EnableDiscoveryClient
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
public class MostyWebSocketApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MostyWebSocketApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.mosty.websocket.config;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Configuration
|
||||
public class FeignConfig implements RequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void apply(RequestTemplate requestTemplate) {
|
||||
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (attr != null) {
|
||||
HttpServletRequest request = attr.getRequest();
|
||||
// 添加token
|
||||
requestTemplate.header("Authorization", request.getHeader("Authorization"));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.mosty.websocket.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 全局配置
|
||||
* @author kevin
|
||||
* @date 2022/5/25 1:56 上午
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties("exclude.path-patterns")
|
||||
public class GlobalYmlConfig {
|
||||
|
||||
/**
|
||||
* swagger 静态文件的放行列表
|
||||
*/
|
||||
private List<String> swagger;
|
||||
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package com.mosty.websocket.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import com.mosty.common.token.SysUserInterceptor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.servlet.config.annotation.*;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 单体服务拦截器
|
||||
* @author kevin
|
||||
* @date 2022/3/21 11:17 PM
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class WebMvcConfig implements WebMvcConfigurer, InitializingBean {
|
||||
|
||||
private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||
private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||
private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
@Value("${server.servlet.context-path:/}")
|
||||
private String contextPath;
|
||||
|
||||
@Autowired
|
||||
private GlobalYmlConfig globalYmlConfig;
|
||||
|
||||
@Override
|
||||
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
ObjectMapper objectMapper = converter.getObjectMapper();
|
||||
// 生成JSON时,将所有Long转换成String
|
||||
SimpleModule simpleModule = new SimpleModule();
|
||||
//日期格式化
|
||||
simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
|
||||
simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
|
||||
simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
|
||||
objectMapper.registerModule(simpleModule);
|
||||
// 时间格式化
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
|
||||
objectMapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
|
||||
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
|
||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
// 设置格式化内容
|
||||
converter.setObjectMapper(objectMapper);
|
||||
converters.add(0, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.info("当前服务的 contextPath={}", contextPath);
|
||||
log.info("当前服务的 swaggerExcludePathPatterns={}", JSON.toJSONString(globalYmlConfig.getSwagger()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
|
||||
configurer.defaultContentType(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(userInfoInterceptor()).addPathPatterns("/**")
|
||||
.excludePathPatterns(globalYmlConfig.getSwagger());
|
||||
log.info("初始化WebMvcConfig 监控拦截器SysUserInterceptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
if (!registry.hasMappingForPattern("/template/**")) {
|
||||
registry.addResourceHandler("/template/**").addResourceLocations("classpath:/template/");
|
||||
}
|
||||
registry.addResourceHandler("swagger-ui.html")
|
||||
.addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("docs.html")
|
||||
.addResourceLocations("classpath:/META-INF/resources/");
|
||||
registry.addResourceHandler("/webjars/**")
|
||||
.addResourceLocations("classpath:/META-INF/resources/webjars/");
|
||||
WebMvcConfigurer.super.addResourceHandlers(registry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SysUserInterceptor userInfoInterceptor() {
|
||||
log.info("初始化WebMvcConfig 拦截器SysUserInterceptor");
|
||||
return new SysUserInterceptor();
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.mosty.websocket.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
@Configuration
|
||||
public class WebSocketConfig implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
package com.mosty.websocket.config;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.mosty.base.model.dto.websocket.WebSocketObject;
|
||||
import com.mosty.websocket.remote.TbBaseAdaptRemoteService;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* sfz为身份证
|
||||
*/
|
||||
@ServerEndpoint("/socket/{sfz}/{uuid}")
|
||||
@Component
|
||||
public class WebSocketServer {
|
||||
|
||||
// 记录当前在线连接数
|
||||
private static int onlineCount = 0;
|
||||
// 存放每个客户端对应WebSocket对象
|
||||
public static Map<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
|
||||
// 与某个客户端的连接会话,需要通过它来给客户端发送数据
|
||||
private Session session;
|
||||
// 身份证号
|
||||
private String sfz = "";
|
||||
// 多浏览器登录的区分UUID,保证session唯一
|
||||
private String uuid = "";
|
||||
@Resource
|
||||
private TbBaseAdaptRemoteService tbBaseAdaptRemoteService;
|
||||
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("sfz") String sfz, @PathParam("uuid") String uuid) {
|
||||
this.session = session;
|
||||
if (!webSocketMap.containsKey(sfz)) {
|
||||
addOnlineCount();
|
||||
}
|
||||
webSocketMap.put(sfz + ":" + uuid, this);
|
||||
System.out.println("有新窗口开始监听:身份证:" + sfz + ",uuid:" + uuid + ",当前人数为" + getOnlineCount());
|
||||
this.sfz = sfz;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose() {
|
||||
webSocketMap.remove(sfz + ":" + uuid);
|
||||
subOnlineCount();
|
||||
System.out.println("连接关闭!,当前人数为" + getOnlineCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
System.out.println("收到来自窗口" + ":" + sfz + ":" + uuid + "的消息:" + message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务器推动消息
|
||||
*/
|
||||
@SneakyThrows
|
||||
public void sendMessage(Map<String, Object> map) throws IOException {
|
||||
this.session.getBasicRemote().sendText(JSON.toJSONString(map));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据身份证号关闭websocket
|
||||
*/
|
||||
public static void closeConn(@PathParam("sfz") String sfz, @PathParam("uuid") String uuid) throws IOException {
|
||||
for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
WebSocketServer item = entry.getValue();
|
||||
if (key.equals(sfz + ":" + uuid)) {
|
||||
webSocketMap.remove(sfz + ":" + uuid);
|
||||
item.onClose();
|
||||
subOnlineCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendBbMessage(WebSocketObject obj) throws IOException {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("type", obj.getType());
|
||||
map.put("data", obj.getObj());
|
||||
for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
|
||||
WebSocketServer webSocketServer = entry.getValue();
|
||||
String sfz = webSocketServer.sfz;
|
||||
LinkedHashMap bb = (LinkedHashMap) obj.getObj();
|
||||
String ssbmdm = bb.get("ssbmdm").toString();
|
||||
// 查询是否拥有数据权限,拥有该数据权限才推送消息
|
||||
boolean flag = this.tbBaseAdaptRemoteService.getDataPermission(sfz, ssbmdm);
|
||||
if (flag) {
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("---------发送给用户:" + sfz + "-------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
System.err.println("--------------------------------------");
|
||||
webSocketServer.sendMessage(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
public static void sendInfo(WebSocketObject obj) throws IOException {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("type", obj.getType());
|
||||
map.put("data", obj.getObj());
|
||||
// 如果是null,推送给所有人
|
||||
if (CollectionUtils.isEmpty(obj.getSfzList())) {
|
||||
for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
|
||||
WebSocketServer webSocketServer = entry.getValue();
|
||||
webSocketServer.sendMessage(map);
|
||||
}
|
||||
} else if (!CollectionUtils.isEmpty(obj.getSfzList())) {
|
||||
// 身份证不为null,推送给个人
|
||||
for (Map.Entry<String, WebSocketServer> entry : webSocketMap.entrySet()) {
|
||||
WebSocketServer webSocketServer = entry.getValue();
|
||||
String key = entry.getKey();
|
||||
key = key.split(":")[1];
|
||||
if (obj.getSfzList().contains(key)) {
|
||||
webSocketServer.sendMessage(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized int getOnlineCount() {
|
||||
return onlineCount;
|
||||
}
|
||||
|
||||
public static synchronized void addOnlineCount() {
|
||||
WebSocketServer.onlineCount++;
|
||||
}
|
||||
|
||||
public static synchronized void subOnlineCount() {
|
||||
WebSocketServer.onlineCount--;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.mosty.websocket.controller;
|
||||
|
||||
import com.mosty.base.model.dto.websocket.WebSocketObject;
|
||||
import com.mosty.common.base.domain.ResponseResult;
|
||||
import com.mosty.websocket.service.WebSocketService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Api(tags = "websocket推送线管")
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/socket")
|
||||
public class WebSocketController {
|
||||
|
||||
private final WebSocketService webSocketService;
|
||||
|
||||
@ApiOperation("向用户发送消息")
|
||||
@PostMapping(value = "sendMessage")
|
||||
public ResponseResult<Void> sendMessage(@RequestBody WebSocketObject obj) {
|
||||
this.webSocketService.sendInfo(obj);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
|
||||
@ApiOperation("向用户发送报备数据")
|
||||
@PostMapping(value = "sendBbMessage")
|
||||
public ResponseResult<Void> sendBbMessage(@RequestBody WebSocketObject obj) {
|
||||
this.webSocketService.sendBbMessage(obj);
|
||||
return ResponseResult.success();
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.mosty.websocket.remote;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.mosty.base.feign.service.MostyBaseFeignService;
|
||||
import com.mosty.base.model.dto.base.SysDeptDTO;
|
||||
import com.mosty.common.base.domain.ResponseResult;
|
||||
import com.mosty.common.base.exception.BusinessException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 调用部门信息远程适配层
|
||||
*
|
||||
* @author kevin
|
||||
* @date 2022/7/6 10:37 上午
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class TbBaseAdaptRemoteService {
|
||||
|
||||
private final MostyBaseFeignService mostyBaseFeignService;
|
||||
|
||||
// 查询用户是否有该部门的数据权限
|
||||
public boolean getDataPermission(String sfz, String deptId) {
|
||||
ResponseResult<Boolean> responseResult = mostyBaseFeignService.getDataPermission(sfz, deptId);
|
||||
if (responseResult == null || !responseResult.isSuccess()) {
|
||||
log.error("查询用户是否有该部门的数据权限异常 responseResult = {},{},{}", JSON.toJSONString(responseResult),sfz,deptId);
|
||||
throw new BusinessException("查询用户是否有该部门的数据权限");
|
||||
}
|
||||
return responseResult.getData();
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.mosty.websocket.service;
|
||||
|
||||
import com.mosty.base.model.dto.websocket.WebSocketObject;
|
||||
|
||||
public interface WebSocketService {
|
||||
|
||||
// 发送websocket消息
|
||||
void sendInfo(WebSocketObject obj);
|
||||
|
||||
// 向用户发送报备数据
|
||||
void sendBbMessage(WebSocketObject obj);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.mosty.websocket.service.impl;
|
||||
|
||||
import com.mosty.base.model.dto.websocket.WebSocketObject;
|
||||
import com.mosty.common.base.exception.BusinessException;
|
||||
import com.mosty.websocket.config.WebSocketServer;
|
||||
import com.mosty.websocket.service.WebSocketService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
|
||||
@Service
|
||||
public class WebSocketServiceImpl implements WebSocketService {
|
||||
|
||||
@Resource
|
||||
private WebSocketServer webSocketServer;
|
||||
|
||||
@Override
|
||||
public void sendInfo(WebSocketObject obj) {
|
||||
try {
|
||||
WebSocketServer.sendInfo(obj);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new BusinessException("消息推送失败!!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendBbMessage(WebSocketObject obj) {
|
||||
try {
|
||||
webSocketServer.sendBbMessage(obj);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new BusinessException("向用户发送报备数据!!");
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user