first commit

This commit is contained in:
陈现府
2025-11-20 10:45:16 +08:00
commit 8355431361
2643 changed files with 291314 additions and 0 deletions
@@ -0,0 +1,50 @@
//package com.mhd.basic.infrastructure.config;
//
//import org.apache.curator.RetryPolicy;
//import org.apache.curator.framework.CuratorFramework;
//import org.apache.curator.framework.CuratorFrameworkFactory;
//import org.apache.curator.retry.ExponentialBackoffRetry;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
///**
// * curator建立会话
// *
// *使用zk实现分布式锁:
// * 1.定义锁:在通常的Java开发编程中,有两种常⻅的⽅式可以⽤来定义锁,分别是synchronized机制和JDK5提供的
// * ReentrantLock。然⽽,在ZooKeeper中,没有类似于这样的API可以直接使⽤,⽽是通过 ZooKeeper
// * 上的数据节点来表示⼀个锁,例如/base/order_1节点就可以被定义为⼀个锁
// * 2.获取锁:在需要获取排他锁时,所有的客户端都会试图通过调⽤ create()接⼝,在/base节点下创建临时⼦节点/base/order_1。
// * ZooKeeper会保证在所有的客户端中,最终只有⼀个客户端能够创建成功,那么就可以认为该客户端获取了锁。
// * 同时,所有没有获取到锁的客户端就需要到/base 节点上注册⼀个⼦节点/base/order_1变更的Watcher监听,以便实时监听到lock节点的变更情况
// * 3.释放锁:/base/order_1是⼀个临时节点,因此在以下两种情况下,都有可能释放锁。
// * 当前获取锁的客户端机器发⽣宕机,那么ZooKeeper上的这个临时节点就会被移除。正常执⾏完业务逻辑后,客户端就会主动将⾃⼰创建的临时节点删除。
// * ⽆论在什么情况下移除了lock节点,ZooKeeper都会通知所有在/base节点上注册了⼦节点/base/order_1变更Watcher监听的客户端。
// * 这些客户端在接收到通知后,再次重新发起分布式锁获取,即重复获取锁过程。
// *
// *
// * 2023-01-27
// *
// * @author 王子豪
// */
//@Configuration
//public class CuratorConfig {
//
// @Value("${zookeeper.host}")
// private String host;
//
// @Bean(initMethod = "start")
// CuratorFramework curatorFramework(){
// RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// // 使用fluent编程风格
// CuratorFramework client = CuratorFrameworkFactory.builder()
// .connectString(host)
// .sessionTimeoutMs(50000)
// .connectionTimeoutMs(30000)
// .retryPolicy(exponentialBackoffRetry)
// .namespace("base") // 独立的命名空间 /base
// .build();
// return client;
// }
//}
@@ -0,0 +1,74 @@
package com.mhd.basic.infrastructure.config;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 获取spring容器上下文对象
*
* 2022-02-09
*
* @author 王子豪
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
/**
* spring容器上下文对象
*/
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
/**
* 获取上下文对象实例
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通过bean名称获取实例
*
* 该bean一般添加@Component注解就行了
*
* @param name
* bean名称
* @return 实例对象
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过类class获取实例
*
* 该bean一般添加@Component注解就行了
*
* @param clazz
* @return 实例对象
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过类name,class获取指定的实例
*
* 该bean一般添加@Component注解就行了
*
* @param name
* @param clazz
* @return 实例对象
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
@@ -0,0 +1,56 @@
//package com.mhd.basic.infrastructure.config;
//
//import com.alibaba.fastjson.JSONObject;
//import com.alibaba.fastjson2.JSON;
//import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
//import com.mhd.basic.infrastructure.feign.ProductServiceFeign;
//import com.mhd.basic.infrastructure.schedule.ElasticJobConfig;
//import com.mhd.common.core.domain.ElasticJob;
//import com.mhd.common.core.web.domain.AjaxResult;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.CommandLineRunner;
//import org.springframework.core.annotation.Order;
//import org.springframework.stereotype.Component;
//
//import java.util.ArrayList;
//import java.util.List;
//
//@Order(value = 1) // 加载顺序,值越小,优先级越高
//@Slf4j
//@Component
///**
// * 项目启动时执行该方法
// *
// * 2022-05-10
// *
// * @author 王子豪
// */
//public class TaskRun implements CommandLineRunner {
//
// @Value("${zookeeper.host}")
// private String host;
// @Value("${spring.application.name}")
// private String applicationName;
// @Autowired
// private ProductServiceFeign productServiceFeign;
//
// @Override
// public void run(String... args) throws Exception {
// log.info("============================定时任务执行=========================");
// List<ElasticJob> elasticJobs = new ArrayList<>();
// AjaxResult ajaxResult = productServiceFeign.elasticJobList(applicationName);
// if("200".equals(String.valueOf(ajaxResult.get("code")))){
// elasticJobs = JSON.parseArray(JSONObject.toJSONString(ajaxResult.get("data")), ElasticJob.class);
// }
// // 配置分布式协调服务(注册中心)Zookeeper
// ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(host,applicationName+"-job");
// if(elasticJobs != null && elasticJobs.size() > 0){
// for (ElasticJob elasticJob : elasticJobs) {
// //如果不想设置分片,可以将totalCount=1itemParam=“”
// new ElasticJobConfig(applicationName + "-" + elasticJob.getJobName(), elasticJob.getCron(), elasticJob.getTotalCount(), elasticJob.getItemParam(), elasticJob.getClassName(),zookeeperConfiguration).startTask();
// }
// }
// }
//}
@@ -0,0 +1,17 @@
package com.mhd.basic.infrastructure.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@@ -0,0 +1,69 @@
package com.mhd.basic.infrastructure.feign;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.SysTenantsPo;
import com.mhd.common.core.web.domain.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("mhd-product-service")
public interface ProductServiceFeign {
/**
* @Description 获取一级组织
* @Author Alex
* @Date 2022/12/2 13:37
*/
@GetMapping("/organization/selectTopId/{id}")
public AjaxResult selectTopId(@PathVariable("id") Long id);
/**
* 查询当前组织所有的组织id
*/
@GetMapping(value = "/organization/getOrganizationIdsByOrganizationId/{organizationId}")
public AjaxResult getOrganizationIdsByOrganizationId(@PathVariable("organizationId") Long organizationId);
/**
* 查询所有的组织id
*/
@GetMapping(value = "/organization/selectAllOrganizationId")
public AjaxResult selectAllOrganizationId();
/**
* 根据applicationName查询定时任务集合
*/
@GetMapping(value = "/elasticJob/elasticJobList/{applicationName}")
public AjaxResult elasticJobList(@PathVariable("applicationName") String applicationName);
/**
* 根据组织id查询组织信息
* @param id
* @return
*/
@GetMapping("/organization/getInfo/{id}")
public AjaxResult getOrganizationInfo(@PathVariable("id") Long id);
/**
* @Description 根据组织id获取所有的上级组织id
* @Author Alex
* @Date 2022/12/2 13:37
*/
@GetMapping("/organization/selectTopOrganizationList/{id}")
public AjaxResult selectTopOrganizationList(@PathVariable("id") Long id);
@GetMapping("/organization/selectTopIdByTenantsDomainName/{tenantsDomainName}")
public AjaxResult getOrganizationByPath(@PathVariable("tenantsDomainName") String tenantsDomainName);
/**
* 开放接口-获取配置的组织信息
*
* @return
*/
@GetMapping(value = "/tenants/getTenantsInfoByOpen")
public R<SysTenantsPo> getTenantsInfoByOpen();
}
@@ -0,0 +1,24 @@
package com.mhd.basic.infrastructure.feign;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.system.api.domain.SysDictData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient("mhd-system")
public interface SystemServiceFeign {
@GetMapping("/dict/data/{dictCode}")
public AjaxResult getTopOrganization(@PathVariable("dictCode") Long dictCode);
@PostMapping("/dict/data/findDatalist")
public AjaxResult findDatalist(@RequestBody SysDictData sysDictData);
@GetMapping("/dict/data/type/{dictType}")
public AjaxResult selectListByDictType(@PathVariable("dictType") String dictType);
}
@@ -0,0 +1,56 @@
package com.mhd.basic.infrastructure.feign;
import com.mhd.common.core.domain.dto.UserDTO;
import com.mhd.common.core.domain.dto.UserDataPermissionQueryDTO;
import com.mhd.common.core.domain.dto.UserDriverDTO;
import com.mhd.common.core.web.domain.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient("mhd-userCenter-service")
public interface UserServiceFeign {
/**
* @Description 绑定车辆
* @Author Alex
* @Date 2023/1/5 21:24
*/
@PostMapping("/userDriverApi/bindVehicle")
public AjaxResult bindVehicle(@RequestBody UserDriverDTO userDriverDTO);
/**
* 查询用户数据权限-单条
* @param userDataPermissionQueryDTO
* @return
*/
@PostMapping("/userApi/findUserDataPermission")
public AjaxResult findUserDataPermission(@RequestBody UserDataPermissionQueryDTO userDataPermissionQueryDTO);
/**
* 根据用户ID查询用户详细信息
* @param userId
* @return
*/
@GetMapping("/userApi/getInfo/{userId}")
public AjaxResult getInfo(@PathVariable("userId") Long userId);
/**
* 新增用户
* @param userDTO
* @return
*/
@PostMapping("/userApi/add")
public AjaxResult addUser(@RequestBody UserDTO userDTO);
/**
* 根据角色code获取用户ID
*/
@PostMapping("/userApi/getUserIDByRoleCode")
public AjaxResult getUserIdByRoleCode(@RequestBody List<String> code);
}
@@ -0,0 +1,62 @@
package com.mhd.basic.infrastructure.feign.vo;
import com.mhd.common.core.annotation.Excel;
import com.mhd.common.core.annotation.Excel.ColumnType;
import lombok.Data;
import org.apache.ibatis.type.Alias;
/**
* 字典数据表 sys_dict_data
*
* @author mhd
*/
@Data
@Alias("aliasSysDictDataVO")//system包下有重名的类,所以这里使用@Alias命名一个别名
public class SysDictDataVo
{
private static final long serialVersionUID = 1L;
/** 字典编码 */
@Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
private Long dictCode;
/** 字典排序 */
@Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
private Long dictSort;
/** 字典标签 */
@Excel(name = "字典标签")
private String dictLabel;
/** 字典键值 */
@Excel(name = "字典键值")
private String dictValue;
/** 字典类型 */
@Excel(name = "字典类型")
private String dictType;
/** 样式属性(其他样式扩展) */
private String cssClass;
/** 表格字典样式 */
private String listClass;
/** 是否默认(Y是 N否) */
@Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
private String isDefault;
/** 状态(0正常 1停用) */
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
private String status;
/** 组织表ID */
private Long organizationId;
/** 组织名称 */
private String organizationName;
/** 一级组织表ID */
private Long topOrganizationId;
}
@@ -0,0 +1,116 @@
//package com.mhd.basic.infrastructure.schedule;
//
//import com.dangdang.ddframe.job.api.simple.SimpleJob;
//import com.dangdang.ddframe.job.config.JobCoreConfiguration;
//import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
//import com.dangdang.ddframe.job.lite.api.JobScheduler;
//import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
//import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
//import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
//import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
//import com.mhd.basic.infrastructure.config.SpringContextUtils;
//import lombok.extern.slf4j.Slf4j;
//
///**
// * 分布式调度配置
// *
// * 2022-05-10
// *
// * @author 王子豪
// */
//@Slf4j
//public class ElasticJobConfig {
//
// private String jobName;
// private String cron;
// private int totalCount;
// private String itemParam;
// private String className;
// private ZookeeperConfiguration zookeeperConfiguration;
//
// public ElasticJobConfig(String jobName, String cron, int totalCount, String itemParam, String className, ZookeeperConfiguration zookeeperConfiguration) {
// this.jobName = jobName;
// this.cron = cron;
// this.totalCount = totalCount;
// this.itemParam = itemParam;
// this.className = className;
// this.zookeeperConfiguration = zookeeperConfiguration;
// }
//
//
// /**
// * 开始执行
// */
// public void startTask(){
// Class<?> classType = null;
// try {
// classType = getClassType(className);
// } catch (ClassNotFoundException e) {
// throw new RuntimeException(e);
// }
// SimpleJob simpleJob = (SimpleJob) SpringContextUtils.getBean(classType);
// JobScheduler jobScheduler = simpleJobScheduler(simpleJob, jobName, cron, totalCount, itemParam, zookeeperConfiguration);
// jobScheduler.init();
// }
//
// /**
// * 定时任务动态配置
// *
// * @param simpleJob
// * 执行逻辑类
// * @param jobName
// * 任务名称(注册到zk的任务名)
// * @param cron
// * 任务启动时钟配置 "0/20 * * * * ?"
// * @param shardingTotalCount
// * 分片数
// * @param shardingItemParameters
// * 任务参数 例:0=bachelor,1=master,2=doctor
// * @return
// */
// public JobScheduler simpleJobScheduler(SimpleJob simpleJob, String jobName, String cron, int shardingTotalCount,
// String shardingItemParameters,ZookeeperConfiguration zookeeperConfiguration) {
// CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
// coordinatorRegistryCenter.init();
// JobScheduler jobScheduler = new JobScheduler(coordinatorRegistryCenter, getLiteJobConfiguration(simpleJob.getClass(), jobName, cron,
// shardingTotalCount, shardingItemParameters));
// return jobScheduler;
// }
//
// /**
// *
// * @param jobClass
// * 实现SimpleJob接口的实例
// * @param jobName
// * 任务名称(注册到zk的任务名)
// * @param cron
// * 任务启动时间 格式 "0/20 * * * * ?"
// * @param shardingTotalCount
// * 分片数
// * @param shardingItemParameters
// * 任务参数 ,例子:任务参数 例:0=bachelor,1=master,2=doctor
// * @return
// */
// private LiteJobConfiguration getLiteJobConfiguration(Class<? extends SimpleJob> jobClass, String jobName,
// String cron, int shardingTotalCount, String shardingItemParameters) {
//
// return LiteJobConfiguration.newBuilder(new SimpleJobConfiguration(
// JobCoreConfiguration.newBuilder(jobName, cron, shardingTotalCount)
// .shardingItemParameters(shardingItemParameters).jobParameter(shardingItemParameters).build(),
// jobClass.getCanonicalName())).overwrite(true).build();
// }
//
// /**
// * 转换class类
// * @param className
// * @return
// * @throws ClassNotFoundException
// */
// private Class<?> getClassType(String className) throws ClassNotFoundException {
// if(className != null){
// Class<?> aClass = Class.forName(className);
// return aClass;
// }
// return null;
// }
//}
@@ -0,0 +1,105 @@
package com.mhd.basic.infrastructure.util;
import java.util.ArrayList;
import java.util.List;
/**
* @author ZhouGY
* @title StorageLocationCodeUtil
* @description: 库位码生成工具
* @date 2024/4/7 15:51
**/
public class StorageLocationCodeUtil {
public static void main(String[] args) {
String startCode = "1151";
String endCode = "5357";
List<String> result = generateCodes(startCode, endCode);
for (String code : result) {
System.out.println(code);
}
}
public static List<String> generateCodes(String startCode, String endCode) {
// 将起始码和终止码解析成数字形式,以便比较
int[] startValues = parseCode(startCode);
int[] endValues = parseCode(endCode);
// 检查起始码是否大于终止码,如果是则抛出异常
if (compare(startValues, endValues) > 0) {
throw new IllegalArgumentException("起始码不能大于终止码");
}
List<String> codes = new ArrayList<>();
// 递归生成中间码
generateCodesRecursive(startValues, endValues, startValues, codes);
return codes;
}
private static int compare(int[] a, int[] b) {
for (int i = 0; i < a.length; i++) {
if (a[i] > b[i]) {
return 1;
}
}
return 0;
}
public static int[] parseCode(String code) {
int[] values = new int[code.length()];
for (int i = 0; i < code.length(); i++) {
values[i] = Character.getNumericValue(code.charAt(i));
}
return values;
}
private static void generateCodesRecursive(int[] currentValues, int[] endValues, int[] startCode, List<String> result) {
// 生成当前码
result.add(convertCode(currentValues));
// 递增当前码
int[] nextValues = incrementCode(currentValues, endValues, startCode);
// 递归生成下一个码
if (!isEqual(nextValues, startCode)) {
generateCodesRecursive(nextValues, endValues, startCode, result);
}
}
private static boolean isEqual(int[] arr1, int[] arr2) {
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
private static String convertCode(int[] values) {
StringBuilder sb = new StringBuilder();
for (int value : values) {
sb.append(value);
}
return sb.toString();
}
private static int[] incrementCode(int[] currentValues, int[] endValues, int[] startCode) {
int[] nextValues = currentValues.clone();
int index = nextValues.length - 1;
while (index >= 0 && nextValues[index] == endValues[index]) {
nextValues[index] = startCode[index];
index--;
}
if (index >= 0) {
nextValues[index]++;
}
return nextValues;
}
public static String formatCode(int[] values) {
return values[0] + "-" + values[1] + "-" + values[2] + "-" + values[3];
}
}
@@ -0,0 +1,15 @@
package com.mhd.basic.infrastructure.util.annotation;
import java.lang.annotation.*;
/**
* 数据权限注解
* @author zg
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermissions {
String cacheName();//缓存逻辑名称
}
@@ -0,0 +1,80 @@
package com.mhd.basic.infrastructure.util.annotation;
import cn.hutool.core.util.ObjectUtil;
import com.mhd.basic.infrastructure.feign.ProductServiceFeign;
import com.mhd.common.core.domain.entity.R;
import com.mhd.common.core.domain.po.OrganizationPo;
import com.mhd.common.core.enums.RoleEnum;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.model.LoginUser;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.List;
@Component
@Aspect
public class SetDataPermissions {
@Before("@annotation(dst)")
public void dosetFeildValue(JoinPoint pjp, DataPermissions dst) throws Throwable {
Object[] args = pjp.getArgs(); //获取目标对象方法参数
//获取当前登陆人
LoginUser loginUser = SecurityUtils.getLoginUser();
String s = dst.cacheName();
//主要权限
if ("tenant".equals(s)) {
if (loginUser != null) {
objectSetValue(args, "topOrganizationId", loginUser.getUserPo().getTopOrganizationId());
}
} else if ("master".equals(s)) {
if (loginUser != null) {
//判断当前用户是否是超级管理员/租户管理员还是普通用户,如果是超级管理员则返回全部组织,租户管理员则返回租户所属组织的全部组织,普通用户需要判断数据权限
if (RoleEnum.SUPER_ADMIN.getCode().equals(loginUser.getUserPo().getRoleCode())) {
//全部不加限制条件
} else if (loginUser.getUserPo().getRoleCode().contains(RoleEnum.PLAT_ADMIN.getCode())) {
objectSetValue(args, "topOrganizationId", loginUser.getUserPo().getTopOrganizationId());
} else {
objectSetValue(args, "organizationId", loginUser.getUserPo().getOrganizationId());
}
}
}
}
public void objectSetValue(Object[] args, String fieldName, Object value) throws Throwable {
for (Object arg : args) {
Field field = ReflectionUtils.findField(arg.getClass(), fieldName);
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, arg, value);
}
}
public Long getFieldValue(Object[] args, String field) {
Long a = null;
for (Object arg : args) {
try {
Field fieldName = arg.getClass().getDeclaredField(field);
if (fieldName != null) {
fieldName.setAccessible(true);
Object o = fieldName.get(arg);
if (o != null) {
a = Long.valueOf(o.toString());
return a;
}
}
} catch (NoSuchFieldException e) {
continue;
} catch (IllegalAccessException e) {
continue;
}
}
return a;
}
}
@@ -0,0 +1,106 @@
package com.mhd.basic.infrastructure.websocket;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @Author scott
* @Date 2019/11/29 9:41
* @Description: 此注解相当于设置访问URL
*/
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}") //此注解相当于设置访问URL
public class WebSocket {
private Session session;
private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();
/**
* 存放所有在线的客户端
*/
private static Map<String, Session> sessionPool = new HashMap<String, Session>();
@OnOpen
public void onOpen(Session session, @PathParam(value = "userId") String userId) {
try {
this.session = session;
webSockets.add(this);
sessionPool.put(userId, session);
log.info("【websocket消息】有新的连接,用户:{},总数为:{}", userId, webSockets.size());
} catch (Exception e) {
log.error("【websocket消息】连接异常:", e);
}
}
@OnClose
public void onClose(Session session, @PathParam(value = "userId") String userId) {
try {
webSockets.remove(this);
sessionPool.remove(userId);
log.info("【websocket消息】连接断开,用户:{},总数为:{}", userId, webSockets.size());
} catch (Exception e) {
log.error("【websocket消息】连接断开异常:", e);
}
}
@OnMessage
public void onMessage(String message) {
// log.debug("【websocket消息】收到客户端消息:" + message);
// JSONObject obj = new JSONObject();
// obj.put("cmd", "heartcheck");//业务类型
// obj.put("msgTxt", "心跳响应");//消息内容
// session.getAsyncRemote().sendText(obj.toJSONString());
}
// 此为广播消息
public void sendAllMessage(String message) {
log.info("【websocket消息】广播消息:" + message);
for (WebSocket webSocket : webSockets) {
try {
if (webSocket.session.isOpen()) {
webSocket.session.getAsyncRemote().sendText(message);
}
} catch (Exception e) {
log.error("【websocket消息】广播消息异常:", e);
}
}
}
// 此为单点消息
public void sendOneMessage(String userId, String message) {
Session session = sessionPool.get(userId);
if (session != null && session.isOpen()) {
try {
log.info("【websocket消息】 单点消息,消息接收用户:{},消息内容:{}", userId, message);
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
log.error("【websocket消息】 单点消息异常:", e);
}
}
}
// 此为单点消息(多人)
public void sendMoreMessage(List<String> userIds, String message) {
if (CollUtil.isNotEmpty(userIds)) {
userIds.forEach(userId -> {
sendOneMessage(userId, message);
});
}
}
}