From ecba46e02002b844cd8257c5fb3af70b6a46f9bc Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Tue, 22 Apr 2025 20:49:49 +0800 Subject: [PATCH] =?UTF-8?q?wip:=20=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../youlai/boot/config/WebSocketConfig.java | 35 ++--- .../system/controller/DictController.java | 41 ++++- .../controller/UserOnlineController.java | 55 +++++++ .../WebSocketMessageController.java | 83 +++++++++++ .../controller/WebSocketTestController.java | 54 +++++++ .../boot/system/service/DictService.java | 9 +- .../system/service/UserOnlineService.java | 140 ++++++++++++++++++ .../service/WebSocketMessageService.java | 123 +++++++++++++++ .../system/service/impl/DictServiceImpl.java | 65 ++++---- 9 files changed, 554 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/youlai/boot/system/controller/UserOnlineController.java create mode 100644 src/main/java/com/youlai/boot/system/controller/WebSocketMessageController.java create mode 100644 src/main/java/com/youlai/boot/system/controller/WebSocketTestController.java create mode 100644 src/main/java/com/youlai/boot/system/service/UserOnlineService.java create mode 100644 src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java diff --git a/src/main/java/com/youlai/boot/config/WebSocketConfig.java b/src/main/java/com/youlai/boot/config/WebSocketConfig.java index 2d9bbf48..aee90d81 100644 --- a/src/main/java/com/youlai/boot/config/WebSocketConfig.java +++ b/src/main/java/com/youlai/boot/config/WebSocketConfig.java @@ -3,10 +3,10 @@ package com.youlai.boot.config; import cn.hutool.core.util.StrUtil; import com.youlai.boot.core.security.model.SysUserDetails; import com.youlai.boot.core.security.token.TokenManager; -import com.youlai.boot.system.event.UserConnectionEvent; +import com.youlai.boot.system.service.UserOnlineService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.messaging.Message; @@ -27,25 +27,19 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; /** - * WebSocket 配置 + * WebSocket配置 * - * @author Ray.Hao - * @since 2.4.0 + * @author You Lai + * @since 3.0.0 */ -// 启用WebSocket消息代理功能和配置STOMP协议,实现实时双向通信和消息传递 @EnableWebSocketMessageBroker @Configuration @Slf4j +@RequiredArgsConstructor public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - private final ApplicationEventPublisher eventPublisher; - private final TokenManager tokenManager; - - public WebSocketConfig(ApplicationEventPublisher eventPublisher, TokenManager tokenManager) { - this.eventPublisher = eventPublisher; - this.tokenManager = tokenManager; - } + private final UserOnlineService userOnlineService; /** * 注册一个端点,客户端通过这个端点进行连接 @@ -56,7 +50,9 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { // 注册 /ws 的端点 .addEndpoint("/ws") // 允许跨域 - .setAllowedOriginPatterns("*"); + .setAllowedOriginPatterns("*") + // 开启SockJS支持,用于不支持WebSocket的浏览器 + .withSockJS(); } @@ -70,7 +66,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { // 客户端订阅消息的请求前缀,topic一般用于广播推送,queue用于点对点推送 registry.enableSimpleBroker("/topic", "/queue"); - + // 服务端通知客户端的前缀,可以不设置,默认为user registry.setUserDestinationPrefix("/user"); } @@ -135,8 +131,8 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { // 绑定用户身份到当前会话(重要:用于@SendToUser等注解) accessor.setUser(authentication); - // 发布用户上线事件(示例:可用于更新在线用户列表) - eventPublisher.publishEvent(new UserConnectionEvent(this, username, true)); + // 记录用户上线状态 + userOnlineService.userConnected(username, accessor.getSessionId()); } // 处理客户端断开请求 @@ -149,7 +145,9 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { if (authentication != null && authentication.isAuthenticated()) { String username = ((SysUserDetails) authentication.getPrincipal()).getUsername(); log.info("WebSocket连接关闭:用户[{}]", username); - eventPublisher.publishEvent(new UserConnectionEvent(this, username, false)); + + // 记录用户下线状态 + userOnlineService.userDisconnected(username); } } } catch (AuthenticationException ex) { @@ -166,5 +164,4 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { } }); } - } diff --git a/src/main/java/com/youlai/boot/system/controller/DictController.java b/src/main/java/com/youlai/boot/system/controller/DictController.java index 3ec31b3b..0e47bb54 100644 --- a/src/main/java/com/youlai/boot/system/controller/DictController.java +++ b/src/main/java/com/youlai/boot/system/controller/DictController.java @@ -16,6 +16,7 @@ import com.youlai.boot.system.model.form.DictForm; import com.youlai.boot.common.annotation.Log; import com.youlai.boot.system.service.DictItemService; import com.youlai.boot.system.service.DictService; +import com.youlai.boot.system.service.WebSocketMessageService; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; @@ -42,7 +43,7 @@ public class DictController { private final DictService dictService; private final DictItemService dictItemService; - + private final WebSocketMessageService webSocketMessageService; //--------------------------------------------------- // 字典相关接口 @@ -80,6 +81,10 @@ public class DictController { @RepeatSubmit public Result saveDict(@Valid @RequestBody DictForm formData) { boolean result = dictService.saveDict(formData); + // 发送字典更新通知 + if (result && formData.getCode() != null) { + webSocketMessageService.sendDictUpdatedEvent(formData.getCode()); + } return Result.judge(result); } @@ -88,9 +93,13 @@ public class DictController { @PreAuthorize("@ss.hasPerm('sys:dict:edit')") public Result updateDict( @PathVariable Long id, - @RequestBody DictForm DictForm + @RequestBody DictForm dictForm ) { - boolean status = dictService.updateDict(id, DictForm); + boolean status = dictService.updateDict(id, dictForm); + // 发送字典更新通知 + if (status && dictForm.getCode() != null) { + webSocketMessageService.sendDictUpdatedEvent(dictForm.getCode()); + } return Result.judge(status); } @@ -100,7 +109,16 @@ public class DictController { public Result deleteDictionaries( @Parameter(description = "字典ID,多个以英文逗号(,)拼接") @PathVariable String ids ) { + // 获取字典编码列表,用于发送删除通知 + List dictCodes = dictService.getDictCodesByIds(Arrays.stream(ids.split(",")).toList()); + dictService.deleteDictByIds(Arrays.stream(ids.split(",")).toList()); + + // 发送字典删除通知 + for (String dictCode : dictCodes) { + webSocketMessageService.sendDictDeletedEvent(dictCode); + } + return Result.success(); } @@ -138,6 +156,12 @@ public class DictController { ) { formData.setDictCode(dictCode); boolean result = dictItemService.saveDictItem(formData); + + // 发送字典更新通知 + if (result) { + webSocketMessageService.sendDictUpdatedEvent(dictCode); + } + return Result.judge(result); } @@ -163,6 +187,12 @@ public class DictController { formData.setId(itemId); formData.setDictCode(dictCode); boolean status = dictItemService.updateDictItem(formData); + + // 发送字典更新通知 + if (status) { + webSocketMessageService.sendDictUpdatedEvent(dictCode); + } + return Result.judge(status); } @@ -170,9 +200,14 @@ public class DictController { @DeleteMapping("/{dictCode}/items/{itemIds}") @PreAuthorize("@ss.hasPerm('sys:dict-item:delete')") public Result deleteDictItems( + @PathVariable String dictCode, @Parameter(description = "字典ID,多个以英文逗号(,)拼接") @PathVariable String itemIds ) { dictItemService.deleteDictItemByIds(itemIds); + + // 发送字典更新通知 + webSocketMessageService.sendDictUpdatedEvent(dictCode); + return Result.success(); } diff --git a/src/main/java/com/youlai/boot/system/controller/UserOnlineController.java b/src/main/java/com/youlai/boot/system/controller/UserOnlineController.java new file mode 100644 index 00000000..d0333150 --- /dev/null +++ b/src/main/java/com/youlai/boot/system/controller/UserOnlineController.java @@ -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> getOnlineUsers() { + return Result.success(userOnlineService.getOnlineUsers()); + } + + /** + * 获取在线用户统计信息 + * + * @return 在线用户统计 + */ + @Operation(summary = "获取在线用户统计") + @GetMapping("/stats") + @PreAuthorize("@ss.hasPerm('sys:monitor:online')") + public Result> getOnlineStats() { + return Result.success(Map.of( + "count", userOnlineService.getOnlineUserCount() + )); + } +} \ No newline at end of file diff --git a/src/main/java/com/youlai/boot/system/controller/WebSocketMessageController.java b/src/main/java/com/youlai/boot/system/controller/WebSocketMessageController.java new file mode 100644 index 00000000..46a6f212 --- /dev/null +++ b/src/main/java/com/youlai/boot/system/controller/WebSocketMessageController.java @@ -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 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 messageData = Map.of( + "sender", sender, + "content", message, + "timestamp", System.currentTimeMillis() + ); + + // 发送广播消息 + webSocketMessageService.broadcastMessage(messageData); + log.info("用户[{}]发送广播消息: {}", sender, message); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/youlai/boot/system/controller/WebSocketTestController.java b/src/main/java/com/youlai/boot/system/controller/WebSocketTestController.java new file mode 100644 index 00000000..d857b6ae --- /dev/null +++ b/src/main/java/com/youlai/boot/system/controller/WebSocketTestController.java @@ -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 sendDictUpdatedEvent( + @Parameter(description = "字典编码") @PathVariable String dictCode + ) { + webSocketMessageService.sendDictUpdatedEvent(dictCode); + return Result.success(); + } + + /** + * 发送字典删除事件 + * + * @param dictCode 字典编码 + * @return 操作结果 + */ + @Operation(summary = "发送字典删除事件") + @PostMapping("/dict/{dictCode}/deleted") + public Result sendDictDeletedEvent( + @Parameter(description = "字典编码") @PathVariable String dictCode + ) { + webSocketMessageService.sendDictDeletedEvent(dictCode); + return Result.success(); + } +} \ No newline at end of file diff --git a/src/main/java/com/youlai/boot/system/service/DictService.java b/src/main/java/com/youlai/boot/system/service/DictService.java index 6c9b9b68..5ab06ab7 100644 --- a/src/main/java/com/youlai/boot/system/service/DictService.java +++ b/src/main/java/com/youlai/boot/system/service/DictService.java @@ -66,6 +66,11 @@ public interface DictService extends IService { */ void deleteDictByIds(List ids); - - + /** + * 根据字典ID列表获取字典编码列表 + * + * @param ids 字典ID列表 + * @return 字典编码列表 + */ + List getDictCodesByIds(List ids); } diff --git a/src/main/java/com/youlai/boot/system/service/UserOnlineService.java b/src/main/java/com/youlai/boot/system/service/UserOnlineService.java new file mode 100644 index 00000000..2bab17a0 --- /dev/null +++ b/src/main/java/com/youlai/boot/system/service/UserOnlineService.java @@ -0,0 +1,140 @@ +package com.youlai.boot.system.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.youlai.boot.core.security.model.SysUserDetails; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 用户在线状态服务 + * 负责维护用户的在线状态和相关统计 + * + * @author You Lai + * @since 3.0.0 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class UserOnlineService { + + // 在线用户映射表,key为用户名,value为用户在线信息 + private final Map onlineUsers = new ConcurrentHashMap<>(); + + private final SimpMessagingTemplate messagingTemplate; + private final ObjectMapper objectMapper; + + /** + * 用户上线 + * + * @param username 用户名 + * @param sessionId WebSocket会话ID + */ + public void userConnected(String username, String sessionId) { + UserOnlineInfo info = new UserOnlineInfo(username, sessionId, System.currentTimeMillis()); + onlineUsers.put(username, info); + log.info("用户[{}]上线,当前在线用户数:{}", username, onlineUsers.size()); + + // 通知在线用户状态变更 + notifyOnlineUsersChange(); + } + + /** + * 用户下线 + * + * @param username 用户名 + */ + public void userDisconnected(String username) { + onlineUsers.remove(username); + log.info("用户[{}]下线,当前在线用户数:{}", username, onlineUsers.size()); + + // 通知在线用户状态变更 + notifyOnlineUsersChange(); + } + + /** + * 获取在线用户列表 + * + * @return 在线用户名列表 + */ + public List getOnlineUsers() { + return onlineUsers.values().stream() + .map(info -> new UserOnlineDTO(info.getUsername(), info.getLoginTime())) + .collect(Collectors.toList()); + } + + /** + * 获取在线用户数量 + * + * @return 在线用户数 + */ + public int getOnlineUserCount() { + return onlineUsers.size(); + } + + /** + * 检查用户是否在线 + * + * @param username 用户名 + * @return 是否在线 + */ + public boolean isUserOnline(String username) { + return onlineUsers.containsKey(username); + } + + /** + * 通知所有客户端在线用户变更 + */ + private void notifyOnlineUsersChange() { + try { + OnlineUsersChangeEvent event = new OnlineUsersChangeEvent(); + event.setType("ONLINE_USERS_CHANGE"); + event.setCount(onlineUsers.size()); + event.setUsers(getOnlineUsers()); + event.setTimestamp(System.currentTimeMillis()); + + String message = objectMapper.writeValueAsString(event); + messagingTemplate.convertAndSend("/topic/online-users", message); + } catch (JsonProcessingException e) { + log.error("Failed to send online users change event", e); + } + } + + /** + * 用户在线信息 + */ + @Data + private static class UserOnlineInfo { + private final String username; + private final String sessionId; + private final long loginTime; + } + + /** + * 用户在线DTO(用于返回给前端) + */ + @Data + public static class UserOnlineDTO { + private final String username; + private final long loginTime; + } + + /** + * 在线用户变更事件 + */ + @Data + private static class OnlineUsersChangeEvent { + private String type; + private int count; + private List users; + private long timestamp; + } +} diff --git a/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java b/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java new file mode 100644 index 00000000..e183d7af --- /dev/null +++ b/src/main/java/com/youlai/boot/system/service/WebSocketMessageService.java @@ -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); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java index 8bd1d11f..4dfb2a2d 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/DictServiceImpl.java @@ -12,7 +12,6 @@ import com.youlai.boot.system.model.entity.Dict; import com.youlai.boot.system.model.entity.DictItem; import com.youlai.boot.system.model.form.DictForm; import com.youlai.boot.system.model.query.DictPageQuery; -import com.youlai.boot.system.model.vo.DictItemOptionVO; import com.youlai.boot.system.model.vo.DictPageVO; import com.youlai.boot.system.service.DictItemService; import com.youlai.boot.system.service.DictService; @@ -110,20 +109,23 @@ public class DictServiceImpl extends ServiceImpl implements Di */ @Override public boolean updateDict(Long id, DictForm dictForm) { - // 更新字典 - Dict entity = dictConverter.toEntity(dictForm); - - // 校验 code 是否唯一 - String dictCode = entity.getDictCode(); - long count = this.count(new LambdaQueryWrapper() - .eq(Dict::getDictCode, dictCode) - .ne(Dict::getId, id) - ); - if (count > 0) { - throw new BusinessException("字典编码已存在"); + // 获取字典 + Dict entity = this.getById(id); + if (entity == null) { + throw new BusinessException("字典不存在"); } - - return this.updateById(entity); + // 校验 code 是否唯一 + String dictCode = dictForm.getCode(); + if (!entity.getDictCode().equals(dictCode)) { + long count = this.count(new LambdaQueryWrapper() + .eq(Dict::getDictCode, dictCode) + ); + Assert.isTrue(count == 0, "字典编码已存在"); + } + // 更新字典 + Dict dict = dictConverter.toEntity(dictForm); + dict.setId(id); + return this.updateById(dict); } /** @@ -131,25 +133,34 @@ public class DictServiceImpl extends ServiceImpl implements Di * * @param ids 字典ID,多个以英文逗号(,)分割 */ - @Override @Transactional + @Override public void deleteDictByIds(List ids) { - for (String id : ids) { - Dict dict = this.getById(id); - if (dict != null) { - boolean removeResult = this.removeById(id); - // 删除字典下的字典项 - if (removeResult) { - dictItemService.remove( - new LambdaQueryWrapper() - .eq(DictItem::getDictCode, dict.getDictCode()) - ); - } + // 删除字典 + this.removeByIds(ids); - } + // 删除字典项 + List list = this.listByIds(ids); + if (!list.isEmpty()) { + List dictCodes = list.stream().map(Dict::getDictCode).toList(); + dictItemService.remove(new LambdaQueryWrapper() + .in(DictItem::getDictCode, dictCodes) + ); } } + /** + * 根据字典ID列表获取字典编码列表 + * + * @param ids 字典ID列表 + * @return 字典编码列表 + */ + @Override + public List getDictCodesByIds(List ids) { + List dictList = this.listByIds(ids); + return dictList.stream().map(Dict::getDictCode).toList(); + } + }