diff --git a/pom.xml b/pom.xml index ca6f200..7ee20d3 100644 --- a/pom.xml +++ b/pom.xml @@ -173,13 +173,11 @@ easyexcel 3.1.1 - - - - - - - + + + org.springframework.boot + spring-boot-starter-websocket + diff --git a/src/main/java/com/example/venue_reservation_service/config/CacheInitializer.java b/src/main/java/com/example/venue_reservation_service/config/CacheInitializer.java index 1f68683..215042e 100644 --- a/src/main/java/com/example/venue_reservation_service/config/CacheInitializer.java +++ b/src/main/java/com/example/venue_reservation_service/config/CacheInitializer.java @@ -1,16 +1,38 @@ package com.example.venue_reservation_service.config; +import cn.hutool.json.JSON; +import com.example.venue_reservation_service.converter.ListConverter; +import com.example.venue_reservation_service.mapper.SensitiveWordMapper; +import com.example.venue_reservation_service.service.SensitiveWordService; +import com.example.venue_reservation_service.utils.RedisUtil; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.util.List; + @Component @Slf4j public class CacheInitializer { + @Resource + private SensitiveWordMapper sensitiveWordMapper; + + @Resource + private RedisUtil redisUtil; + + private final static String REDIS_KEY = "sensitive-word"; + @PostConstruct // 在Bean初始化后执行[5](@ref) public void init() { - log.info("敏感词库已加载到Redis"); + List list = sensitiveWordMapper.selectWordsOrderedByPriority(); + try { + redisUtil.set(REDIS_KEY, ListConverter.listToString(list)); + log.info("敏感词库已加载到Redis"); + } catch (Exception e) { + e.printStackTrace(); + log.error("服务异常,"+e.getMessage()); + } } } \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java b/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java index c015572..a10b86e 100644 --- a/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java +++ b/src/main/java/com/example/venue_reservation_service/config/InterceptorConfig.java @@ -11,9 +11,9 @@ public class InterceptorConfig implements WebMvcConfigurer { registry.addInterceptor(new JWTInterceptor()) .addPathPatterns("/user/**") .addPathPatterns("/reservation/**") - .addPathPatterns("/information/**") +// .addPathPatterns("/information/**") .addPathPatterns("/hot/**") - .addPathPatterns("/type/**") +// .addPathPatterns("/type/**") .addPathPatterns("/slot/**") .addPathPatterns("/admin/**") .addPathPatterns("/school/**") diff --git a/src/main/java/com/example/venue_reservation_service/config/WebSocketConfig.java b/src/main/java/com/example/venue_reservation_service/config/WebSocketConfig.java new file mode 100644 index 0000000..163b794 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/config/WebSocketConfig.java @@ -0,0 +1,25 @@ +package com.example.venue_reservation_service.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.enableSimpleBroker("/topic", "/queue"); + config.setApplicationDestinationPrefixes("/app"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/ws") + .setAllowedOriginPatterns("*") + .withSockJS(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/controller/CommentController.java b/src/main/java/com/example/venue_reservation_service/controller/CommentController.java index ac22a4e..731b90f 100644 --- a/src/main/java/com/example/venue_reservation_service/controller/CommentController.java +++ b/src/main/java/com/example/venue_reservation_service/controller/CommentController.java @@ -1,6 +1,8 @@ package com.example.venue_reservation_service.controller; import com.example.venue_reservation_service.domain.Comment; +import com.example.venue_reservation_service.dto.PageDTO; +import com.example.venue_reservation_service.dto.SearchDTO; import com.example.venue_reservation_service.service.CommentService; import com.example.venue_reservation_service.vo.Result; import io.swagger.annotations.Api; @@ -20,6 +22,31 @@ public class CommentController { @ApiOperation("发布评论") @PostMapping("/create") public Result create(@RequestBody Comment comment){ - return null; + return commentService.createComment(comment); + } + + @ApiOperation("超级管理员查看评论信息") + @PostMapping("/admin") + public Result admin(@RequestBody PageDTO dto){ + return commentService.queryComment(dto); + } + + @ApiOperation("超级管理员撤回评论") + @GetMapping("/withdraw/{id}") + public Result withdraw(@PathVariable("id") Integer id){ + return commentService.withdrawComment(id); + } + + @ApiOperation("用户查看评论信息") + @PostMapping("/user") + public Result user(@RequestBody SearchDTO dto){ + return commentService.queryByUser(dto); + } + + @ApiOperation("点赞/取消点赞") + @GetMapping("like") + public Result like(@RequestParam("userId") Integer userId, + @RequestParam("commentId") Integer commentId){ + return commentService.like(userId, commentId); } } diff --git a/src/main/java/com/example/venue_reservation_service/controller/MessageController.java b/src/main/java/com/example/venue_reservation_service/controller/MessageController.java new file mode 100644 index 0000000..d262196 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/controller/MessageController.java @@ -0,0 +1,35 @@ +package com.example.venue_reservation_service.controller; + +import com.example.venue_reservation_service.dto.MessageDTO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; + +@RestController +@RequestMapping("/message") +@Api("预约通知管理") +@CrossOrigin +public class MessageController { + + private final SimpMessagingTemplate messagingTemplate; + + public MessageController(SimpMessagingTemplate messagingTemplate) { + this.messagingTemplate = messagingTemplate; + } + + // 发送消息到指定用户 + @GetMapping("/send") + public String sendMessageToUser(@RequestParam("userId") Integer userId) { + MessageDTO message = new MessageDTO(); + message.setUserId(userId); + message.setContent("测试"); + String destination = "/queue/messages/" + userId; + messagingTemplate.convertAndSend(destination, message); + return "消息已发送给用户ID: " + userId; + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/controller/SensitiveWordController.java b/src/main/java/com/example/venue_reservation_service/controller/SensitiveWordController.java index 4520af9..b756e13 100644 --- a/src/main/java/com/example/venue_reservation_service/controller/SensitiveWordController.java +++ b/src/main/java/com/example/venue_reservation_service/controller/SensitiveWordController.java @@ -42,7 +42,6 @@ public class SensitiveWordController { log.info("添加敏感词{}", dto); return sensitiveWordService.addSensitiveWord(dto); } - /** * 修改敏感词信息 */ diff --git a/src/main/java/com/example/venue_reservation_service/converter/ListConverter.java b/src/main/java/com/example/venue_reservation_service/converter/ListConverter.java new file mode 100644 index 0000000..1727681 --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/converter/ListConverter.java @@ -0,0 +1,19 @@ +package com.example.venue_reservation_service.converter; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; + +public class ListConverter { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + // List 转 String + public static String listToString(List list) throws Exception { + return objectMapper.writeValueAsString(list); + } + + // String 转回 List + public static List stringToList(String str) throws Exception { + return objectMapper.readValue(str, objectMapper.getTypeFactory() + .constructCollectionType(List.class, String.class)); + } +} diff --git a/src/main/java/com/example/venue_reservation_service/domain/Comment.java b/src/main/java/com/example/venue_reservation_service/domain/Comment.java index 0295f8c..6b08f6d 100644 --- a/src/main/java/com/example/venue_reservation_service/domain/Comment.java +++ b/src/main/java/com/example/venue_reservation_service/domain/Comment.java @@ -36,9 +36,9 @@ public class Comment implements Serializable { private String content; /** - * 审核状态(0:待审核;1:审核通过;2:审核不通过) + * 审核状态(1:审核通过;2:审核不通过) */ - private String status; + private Integer status; /** * 创建时间 diff --git a/src/main/java/com/example/venue_reservation_service/domain/UserLike.java b/src/main/java/com/example/venue_reservation_service/domain/UserLike.java index 065f71c..f7585bc 100644 --- a/src/main/java/com/example/venue_reservation_service/domain/UserLike.java +++ b/src/main/java/com/example/venue_reservation_service/domain/UserLike.java @@ -45,6 +45,7 @@ public class UserLike implements Serializable { /** * 逻辑删除 */ + private Integer isDelete; @TableField(exist = false) private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/example/venue_reservation_service/dto/MessageDTO.java b/src/main/java/com/example/venue_reservation_service/dto/MessageDTO.java new file mode 100644 index 0000000..47a5dba --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/dto/MessageDTO.java @@ -0,0 +1,15 @@ +package com.example.venue_reservation_service.dto; + +import lombok.Data; + +// 消息数据模型 +@Data +public class MessageDTO { + + private Integer userId; + + private String content; + + private String sender = "系统通知"; + +} \ No newline at end of file diff --git a/src/main/java/com/example/venue_reservation_service/dto/SearchDTO.java b/src/main/java/com/example/venue_reservation_service/dto/SearchDTO.java new file mode 100644 index 0000000..30918cb --- /dev/null +++ b/src/main/java/com/example/venue_reservation_service/dto/SearchDTO.java @@ -0,0 +1,11 @@ +package com.example.venue_reservation_service.dto; + +import lombok.Data; + +@Data +public class SearchDTO extends PageDTO{ + + private Integer userId; + + private Integer onlyOne; +} diff --git a/src/main/java/com/example/venue_reservation_service/mapper/SensitiveWordMapper.java b/src/main/java/com/example/venue_reservation_service/mapper/SensitiveWordMapper.java index ce3704f..0661488 100644 --- a/src/main/java/com/example/venue_reservation_service/mapper/SensitiveWordMapper.java +++ b/src/main/java/com/example/venue_reservation_service/mapper/SensitiveWordMapper.java @@ -4,6 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.venue_reservation_service.domain.SensitiveWord; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + @Mapper public interface SensitiveWordMapper extends BaseMapper { + + List selectWordsOrderedByPriority(); + } diff --git a/src/main/java/com/example/venue_reservation_service/service/CommentService.java b/src/main/java/com/example/venue_reservation_service/service/CommentService.java index 9c64e6c..8d70436 100644 --- a/src/main/java/com/example/venue_reservation_service/service/CommentService.java +++ b/src/main/java/com/example/venue_reservation_service/service/CommentService.java @@ -2,6 +2,8 @@ package com.example.venue_reservation_service.service; import com.example.venue_reservation_service.domain.Comment; import com.baomidou.mybatisplus.extension.service.IService; +import com.example.venue_reservation_service.dto.PageDTO; +import com.example.venue_reservation_service.dto.SearchDTO; import com.example.venue_reservation_service.vo.Result; /** @@ -11,6 +13,13 @@ import com.example.venue_reservation_service.vo.Result; */ public interface CommentService extends IService { + Result queryComment(PageDTO dto); + + Result queryByUser(SearchDTO dto); + Result createComment(Comment comment); + Result withdrawComment(Integer id); + + Result like(Integer userId, Integer commentId); } diff --git a/src/main/java/com/example/venue_reservation_service/service/SensitiveWordService.java b/src/main/java/com/example/venue_reservation_service/service/SensitiveWordService.java index 159858b..04a2820 100644 --- a/src/main/java/com/example/venue_reservation_service/service/SensitiveWordService.java +++ b/src/main/java/com/example/venue_reservation_service/service/SensitiveWordService.java @@ -1,12 +1,13 @@ package com.example.venue_reservation_service.service; +import com.baomidou.mybatisplus.extension.service.IService; import com.example.venue_reservation_service.domain.SensitiveWord; import com.example.venue_reservation_service.dto.PageDTO; import com.example.venue_reservation_service.dto.SensitiveWordDTO; import com.example.venue_reservation_service.dto.WordDTO; import com.example.venue_reservation_service.vo.Result; -public interface SensitiveWordService { +public interface SensitiveWordService extends IService { // 获取敏感词数据 Result getSensitiveWords(WordDTO dto); diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/CommentServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/CommentServiceImpl.java index b6c3a9a..c42437c 100644 --- a/src/main/java/com/example/venue_reservation_service/service/impl/CommentServiceImpl.java +++ b/src/main/java/com/example/venue_reservation_service/service/impl/CommentServiceImpl.java @@ -1,13 +1,34 @@ package com.example.venue_reservation_service.service.impl; +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.venue_reservation_service.converter.ListConverter; import com.example.venue_reservation_service.domain.Comment; +import com.example.venue_reservation_service.domain.User; +import com.example.venue_reservation_service.domain.UserLike; +import com.example.venue_reservation_service.dto.PageDTO; +import com.example.venue_reservation_service.dto.SearchDTO; +import com.example.venue_reservation_service.filter.SensitiveFilter; import com.example.venue_reservation_service.mapper.CommentMapper; +import com.example.venue_reservation_service.mapper.UserMapper; import com.example.venue_reservation_service.service.CommentService; +import com.example.venue_reservation_service.service.UserLikeService; +import com.example.venue_reservation_service.utils.RedisUtil; +import com.example.venue_reservation_service.vo.AvatarVO; +import com.example.venue_reservation_service.vo.QueryVO; import com.example.venue_reservation_service.vo.Result; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; /** * @author 31586 @@ -18,14 +39,115 @@ import java.time.LocalDateTime; public class CommentServiceImpl extends ServiceImpl implements CommentService{ + @Resource + private RedisUtil redisUtil; + + private final static String REDIS_KEY = "sensitive-word"; + + @Resource + private UserLikeService userLikeService; + + @Resource + private UserMapper userMapper; + + @Value("${access.url}") + private String accessUrl; + + @Override + public Result queryComment(PageDTO dto) { + Page page = new Page(dto.getCurrent(), dto.getSize()); + page = page(page, null); + QueryVO vo = new QueryVO<>(); + vo.setTotal(page.getTotal()); + vo.setList(page.getRecords()); + return Result.ok(vo).message("数据加载完成"); + } + + @Override + public Result queryByUser(SearchDTO dto) { + Page page = new Page<>(dto.getCurrent(), dto.getSize()); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + if (dto.getOnlyOne() == 1) { + wrapper.eq(Comment::getUserId, dto.getUserId()); + } + wrapper.eq(Comment::getStatus, 2); + page = page(page, wrapper); + QueryVO vo = new QueryVO<>(); + vo.setTotal(page.getTotal()); + List list = new ArrayList<>(); + page.getRecords().forEach(item -> { + User user = userMapper.selectById(item.getUserId()); + if(user.getIsUpload() == 1){ + user.setAvatar(accessUrl + user.getAvatar()); + } + AvatarVO ele = BeanUtil.copyProperties(user, AvatarVO.class); + UserLike like = userLikeService.getOne(Wrappers.lambdaQuery() + .eq(UserLike::getUserId, dto.getUserId()) + .eq(UserLike::getCommentId, item.getId())); + if (Optional.ofNullable(like).isEmpty() || like.getIsDelete() == 1) { + ele.setIsLike(0); + }else{ + ele.setIsLike(1); + } + BeanUtil.copyProperties(item, ele); + list.add(ele); + }); + vo.setList(list); + return Result.ok(vo).message("数据加载完成"); + } + @Override public Result createComment(Comment comment) { - // TODO 对敏感词进行脱敏处理 -- + List list; + try { + list = ListConverter.stringToList((String) redisUtil.get(REDIS_KEY)); + } catch (Exception e) { + e.printStackTrace(); + return Result.fail().message("服务异常"); + } + SensitiveFilter filter = new SensitiveFilter(); + filter.buildTrie(list); + String content = filter.filter(comment.getContent()); + comment.setContent(content); + comment.setStatus(2); // 过滤完成后默认为发布状态 comment.setCreateTime(LocalDateTime.now()); comment.setUpdateTime(LocalDateTime.now()); - // TODO 保存评论记录 - return null; + save(comment); + return Result.ok().message("评论发布成功"); } + + @Override + public Result withdrawComment(Integer id) { + Comment comment = getById(id); + if (Optional.ofNullable(comment).isEmpty()) { + return Result.fail().message("未查询到评论信息"); + } + comment.setStatus(comment.getStatus() == 1 ? 2 : 1); + updateById(comment); + return Result.ok().message(comment.getStatus() == 1 ? "撤回成功" : "恢复成功"); + } + + @Override + public Result like(Integer userId, Integer commentId) { + UserLike like = userLikeService.getOne(Wrappers.lambdaQuery() + .eq(UserLike::getUserId, userId) + .eq(UserLike::getCommentId, commentId)); + if (Optional.ofNullable(like).isEmpty()) { + // 用户之前未点赞过该条评论 + like = new UserLike(); + like.setCommentId(commentId); + like.setUserId(userId); + like.setCreateTime(LocalDateTime.now()); + like.setIsDelete(0); + userLikeService.save(like); + }else{ + like.setIsDelete(like.getIsDelete() == 1 ? 0 : 1); + userLikeService.updateById(like); + } + return Result.ok().message(like.getIsDelete() == 1 ? "取消点赞" : "点赞成功"); + } + + } diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/SensitiveWordServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/SensitiveWordServiceImpl.java index 8b195b9..8cf3fb7 100644 --- a/src/main/java/com/example/venue_reservation_service/service/impl/SensitiveWordServiceImpl.java +++ b/src/main/java/com/example/venue_reservation_service/service/impl/SensitiveWordServiceImpl.java @@ -4,11 +4,13 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.example.venue_reservation_service.converter.ListConverter; import com.example.venue_reservation_service.domain.SensitiveWord; import com.example.venue_reservation_service.dto.SensitiveWordDTO; import com.example.venue_reservation_service.dto.WordDTO; import com.example.venue_reservation_service.mapper.SensitiveWordMapper; import com.example.venue_reservation_service.service.SensitiveWordService; +import com.example.venue_reservation_service.utils.RedisUtil; import com.example.venue_reservation_service.vo.QueryVO; import com.example.venue_reservation_service.vo.Result; import jakarta.annotation.Resource; @@ -26,6 +28,12 @@ public class SensitiveWordServiceImpl extends ServiceImpl + + diff --git a/src/test/java/com/example/venue_reservation_service/VenueReservationServiceApplicationTests.java b/src/test/java/com/example/venue_reservation_service/VenueReservationServiceApplicationTests.java index cdb54b7..2db5851 100644 --- a/src/test/java/com/example/venue_reservation_service/VenueReservationServiceApplicationTests.java +++ b/src/test/java/com/example/venue_reservation_service/VenueReservationServiceApplicationTests.java @@ -27,6 +27,7 @@ class VenueReservationServiceApplicationTests { @Test void contextLoads() throws Exception { + System.out.println(MD5Util.generateRandomString(10)); } public static void main(String[] args) {