Merge remote-tracking branch 'origin/master'
# Conflicts: # src/main/java/com/youlai/boot/config/WebSocketConfig.java # src/main/java/com/youlai/boot/system/controller/DictController.java # src/main/java/com/youlai/boot/system/service/UserOnlineService.java
This commit is contained in:
@@ -138,6 +138,9 @@ public class LogAspect {
|
||||
log.setBrowser(userAgent.getBrowser().getName());
|
||||
log.setBrowserVersion(userAgent.getBrowser().getVersion(userAgentString));
|
||||
}
|
||||
//获取方法名
|
||||
String methodName = joinPoint.getSignature().getName();
|
||||
log.setMethod(methodName);
|
||||
// 保存日志到数据库
|
||||
logService.save(log);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.youlai.boot.system.controller;
|
||||
|
||||
import com.youlai.boot.common.result.Result;
|
||||
import com.youlai.boot.system.service.UserOnlineService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 在线用户控制器
|
||||
*
|
||||
* @author You Lai
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Tag(name = "13.在线用户接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/users/online")
|
||||
@RequiredArgsConstructor
|
||||
public class UserOnlineController {
|
||||
|
||||
private final UserOnlineService userOnlineService;
|
||||
|
||||
/**
|
||||
* 获取在线用户列表
|
||||
*
|
||||
* @return 在线用户列表
|
||||
*/
|
||||
@Operation(summary = "获取在线用户列表")
|
||||
@GetMapping
|
||||
@PreAuthorize("@ss.hasPerm('sys:monitor:online')")
|
||||
public Result<List<UserOnlineService.UserOnlineDTO>> getOnlineUsers() {
|
||||
return Result.success(userOnlineService.getOnlineUsers());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取在线用户统计信息
|
||||
*
|
||||
* @return 在线用户统计
|
||||
*/
|
||||
@Operation(summary = "获取在线用户统计")
|
||||
@GetMapping("/stats")
|
||||
@PreAuthorize("@ss.hasPerm('sys:monitor:online')")
|
||||
public Result<Map<String, Object>> getOnlineStats() {
|
||||
return Result.success(Map.of(
|
||||
"count", userOnlineService.getOnlineUserCount()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.youlai.boot.system.controller;
|
||||
|
||||
import com.youlai.boot.core.security.model.SysUserDetails;
|
||||
import com.youlai.boot.system.service.WebSocketMessageService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.Payload;
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* WebSocket消息控制器
|
||||
* 用于处理WebSocket客户端发送的消息
|
||||
*
|
||||
* @author You Lai
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class WebSocketMessageController {
|
||||
|
||||
private final WebSocketMessageService webSocketMessageService;
|
||||
|
||||
/**
|
||||
* 处理发送到指定用户的消息
|
||||
* 客户端发送消息到 /app/sendToUser/{username}
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @param headerAccessor 消息头访问器
|
||||
* @param username 接收消息的用户名
|
||||
*/
|
||||
@MessageMapping("/sendToUser/{username}")
|
||||
public void sendToUser(@Payload String message, SimpMessageHeaderAccessor headerAccessor, String username) {
|
||||
Authentication authentication = (Authentication) headerAccessor.getUser();
|
||||
if (authentication != null) {
|
||||
SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
|
||||
String sender = userDetails.getUsername();
|
||||
|
||||
// 构建消息
|
||||
Map<String, Object> messageData = Map.of(
|
||||
"sender", sender,
|
||||
"content", message,
|
||||
"timestamp", System.currentTimeMillis()
|
||||
);
|
||||
|
||||
// 发送点对点消息
|
||||
webSocketMessageService.sendPrivateMessage(username, messageData);
|
||||
log.info("用户[{}]向用户[{}]发送消息: {}", sender, username, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理广播消息
|
||||
* 客户端发送消息到 /app/broadcast
|
||||
*
|
||||
* @param message 消息内容
|
||||
* @param headerAccessor 消息头访问器
|
||||
*/
|
||||
@MessageMapping("/broadcast")
|
||||
public void broadcast(@Payload String message, SimpMessageHeaderAccessor headerAccessor) {
|
||||
Authentication authentication = (Authentication) headerAccessor.getUser();
|
||||
if (authentication != null) {
|
||||
SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
|
||||
String sender = userDetails.getUsername();
|
||||
|
||||
// 构建消息
|
||||
Map<String, Object> messageData = Map.of(
|
||||
"sender", sender,
|
||||
"content", message,
|
||||
"timestamp", System.currentTimeMillis()
|
||||
);
|
||||
|
||||
// 发送广播消息
|
||||
webSocketMessageService.broadcastMessage(messageData);
|
||||
log.info("用户[{}]发送广播消息: {}", sender, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.youlai.boot.system.controller;
|
||||
|
||||
import com.youlai.boot.common.result.Result;
|
||||
import com.youlai.boot.system.service.WebSocketMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* WebSocket测试控制器
|
||||
*
|
||||
* @author You Lai
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Tag(name = "12.WebSocket接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/websocket")
|
||||
@RequiredArgsConstructor
|
||||
public class WebSocketTestController {
|
||||
|
||||
private final WebSocketMessageService webSocketMessageService;
|
||||
|
||||
/**
|
||||
* 发送字典更新事件
|
||||
*
|
||||
* @param dictCode 字典编码
|
||||
* @return 操作结果
|
||||
*/
|
||||
@Operation(summary = "发送字典更新事件")
|
||||
@PostMapping("/dict/{dictCode}/updated")
|
||||
public Result<Void> sendDictUpdatedEvent(
|
||||
@Parameter(description = "字典编码") @PathVariable String dictCode
|
||||
) {
|
||||
webSocketMessageService.sendDictUpdatedEvent(dictCode);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送字典删除事件
|
||||
*
|
||||
* @param dictCode 字典编码
|
||||
* @return 操作结果
|
||||
*/
|
||||
@Operation(summary = "发送字典删除事件")
|
||||
@PostMapping("/dict/{dictCode}/deleted")
|
||||
public Result<Void> sendDictDeletedEvent(
|
||||
@Parameter(description = "字典编码") @PathVariable String dictCode
|
||||
) {
|
||||
webSocketMessageService.sendDictDeletedEvent(dictCode);
|
||||
return Result.success();
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,11 @@ public class Log implements Serializable {
|
||||
*/
|
||||
private String requestUri;
|
||||
|
||||
/**
|
||||
* 请求方法
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* IP 地址
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.youlai.boot.system.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* WebSocket消息服务
|
||||
*
|
||||
* @author Ray
|
||||
* @since 3.0.0
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class WebSocketMessageService {
|
||||
|
||||
private final SimpMessagingTemplate messagingTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 字典事件类型
|
||||
*/
|
||||
public enum DictEventType {
|
||||
/**
|
||||
* 字典更新
|
||||
*/
|
||||
DICT_UPDATED,
|
||||
|
||||
/**
|
||||
* 字典删除
|
||||
*/
|
||||
DICT_DELETED
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典事件消息
|
||||
*/
|
||||
public static class DictEvent {
|
||||
/**
|
||||
* 事件类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 字典编码
|
||||
*/
|
||||
private String dictCode;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private long timestamp;
|
||||
|
||||
public DictEvent(DictEventType type, String dictCode) {
|
||||
this.type = type.name();
|
||||
this.dictCode = dictCode;
|
||||
this.timestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDictCode() {
|
||||
return dictCode;
|
||||
}
|
||||
|
||||
public void setDictCode(String dictCode) {
|
||||
this.dictCode = dictCode;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向所有客户端发送字典更新事件
|
||||
*
|
||||
* @param dictCode 字典编码
|
||||
*/
|
||||
public void sendDictUpdatedEvent(String dictCode) {
|
||||
DictEvent event = new DictEvent(DictEventType.DICT_UPDATED, dictCode);
|
||||
sendDictEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向所有客户端发送字典删除事件
|
||||
*
|
||||
* @param dictCode 字典编码
|
||||
*/
|
||||
public void sendDictDeletedEvent(String dictCode) {
|
||||
DictEvent event = new DictEvent(DictEventType.DICT_DELETED, dictCode);
|
||||
sendDictEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送字典事件消息
|
||||
*
|
||||
* @param event 字典事件
|
||||
*/
|
||||
private void sendDictEvent(DictEvent event) {
|
||||
try {
|
||||
String message = objectMapper.writeValueAsString(event);
|
||||
messagingTemplate.convertAndSend("/topic/dict", message);
|
||||
log.info("Sent dict event to clients: {}", message);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to send dict event", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements De
|
||||
.orderByAsc(Dept::getSort)
|
||||
);
|
||||
if (CollectionUtil.isEmpty(deptList)) {
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Set<Long> deptIds = deptList.stream()
|
||||
@@ -238,10 +238,11 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements De
|
||||
if (StrUtil.isNotBlank(ids)) {
|
||||
String[] menuIds = ids.split(",");
|
||||
for (String deptId : menuIds) {
|
||||
String patten = "%," + deptId + ",%";
|
||||
this.update(new LambdaUpdateWrapper<Dept>()
|
||||
.eq(Dept::getId, deptId)
|
||||
.or()
|
||||
.apply("CONCAT (',',tree_path,',') LIKE CONCAT('%,',{0},',%')", deptId)
|
||||
.apply("CONCAT (',',tree_path,',') LIKE {0}", patten)
|
||||
.set(Dept::getIsDeleted, 1)
|
||||
.set(Dept::getUpdateBy, SecurityUtils.getUserId())
|
||||
);
|
||||
|
||||
@@ -116,7 +116,11 @@ public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements Di
|
||||
throw new BusinessException("字典不存在");
|
||||
}
|
||||
// 校验 code 是否唯一
|
||||
<<<<<<< HEAD
|
||||
String dictCode = dictForm.getCode();
|
||||
=======
|
||||
String dictCode = dictForm.getDictCode();
|
||||
>>>>>>> 95412501fc69777ad7db6fef970b479c9651984d
|
||||
if (!entity.getDictCode().equals(dictCode)) {
|
||||
long count = this.count(new LambdaQueryWrapper<Dict>()
|
||||
.eq(Dict::getDictCode, dictCode)
|
||||
@@ -126,6 +130,9 @@ public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements Di
|
||||
// 更新字典
|
||||
Dict dict = dictConverter.toEntity(dictForm);
|
||||
dict.setId(id);
|
||||
<<<<<<< HEAD
|
||||
return this.updateById(dict);
|
||||
=======
|
||||
boolean result = this.updateById(dict);
|
||||
if (result) {
|
||||
// 更新字典数据
|
||||
@@ -145,6 +152,7 @@ public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements Di
|
||||
}
|
||||
}
|
||||
return result;
|
||||
>>>>>>> 95412501fc69777ad7db6fef970b479c9651984d
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user