From 9e465b1ebc84d518e39ca982489d35066c9dc05d Mon Sep 17 00:00:00 2001
From: chenyuepan <3158614516@qq.com>
Date: Thu, 19 Jun 2025 08:44:55 +0800
Subject: [PATCH] =?UTF-8?q?netty=E5=AE=9E=E7=8E=B0=E8=81=8A=E5=A4=A9?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 21 +++
.../VenueReservationServiceApplication.java | 9 +-
.../domain/VeException.java | 67 +++++++
.../exception/GlobalExceptionHandler.java | 90 +++++++++
.../exception/ImageValidateException.java | 16 ++
.../exception/MinioRemoveException.java | 8 +
.../exception/MinioUploadException.java | 8 +
.../mapper/VeExceptionMapper.java | 18 ++
.../netty/ChatServerHandler.java | 177 ++++++++++++++++++
.../netty/NettyChatServer.java | 67 +++++++
.../service/VeExceptionService.java | 13 ++
.../service/impl/UserServiceImpl.java | 58 +++---
.../service/impl/VeExceptionServiceImpl.java | 22 +++
.../utils/ImageValidator.java | 34 ++++
src/main/resources/application.yml | 2 +
.../resources/mapper/VeExceptionMapper.xml | 23 +++
.../dcpint/icdcshare/IfsDcpIcdcShareTest.java | 21 ++-
17 files changed, 613 insertions(+), 41 deletions(-)
create mode 100644 src/main/java/com/example/venue_reservation_service/domain/VeException.java
create mode 100644 src/main/java/com/example/venue_reservation_service/exception/GlobalExceptionHandler.java
create mode 100644 src/main/java/com/example/venue_reservation_service/exception/ImageValidateException.java
create mode 100644 src/main/java/com/example/venue_reservation_service/exception/MinioRemoveException.java
create mode 100644 src/main/java/com/example/venue_reservation_service/exception/MinioUploadException.java
create mode 100644 src/main/java/com/example/venue_reservation_service/mapper/VeExceptionMapper.java
create mode 100644 src/main/java/com/example/venue_reservation_service/netty/ChatServerHandler.java
create mode 100644 src/main/java/com/example/venue_reservation_service/netty/NettyChatServer.java
create mode 100644 src/main/java/com/example/venue_reservation_service/service/VeExceptionService.java
create mode 100644 src/main/java/com/example/venue_reservation_service/service/impl/VeExceptionServiceImpl.java
create mode 100644 src/main/resources/mapper/VeExceptionMapper.xml
diff --git a/pom.xml b/pom.xml
index 2e63fcd..9ebbc55 100644
--- a/pom.xml
+++ b/pom.xml
@@ -181,6 +181,27 @@
org.springframework.boot
spring-boot-starter-webflux
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ com.github.ben-manes.caffeine
+ caffeine
+ 3.1.8
+
+
+
+ io.netty
+ netty-all
+ 4.1.86.Final
+
+
+
+ com.alibaba
+ fastjson
+ 2.0.34
+
diff --git a/src/main/java/com/example/venue_reservation_service/VenueReservationServiceApplication.java b/src/main/java/com/example/venue_reservation_service/VenueReservationServiceApplication.java
index 24db822..16ff701 100644
--- a/src/main/java/com/example/venue_reservation_service/VenueReservationServiceApplication.java
+++ b/src/main/java/com/example/venue_reservation_service/VenueReservationServiceApplication.java
@@ -1,24 +1,19 @@
package com.example.venue_reservation_service;
-import com.example.venue_reservation_service.utils.ScheduleUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import jakarta.annotation.Resource;
import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.client.RestTemplate;
-
-import java.time.LocalDate;
-import java.time.LocalTime;
import java.util.Arrays;
import java.util.TimeZone;
@@ -30,7 +25,7 @@ public class VenueReservationServiceApplication {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+08:00"));
- SpringApplication.run(VenueReservationServiceApplication.class, args);
+ ConfigurableApplicationContext context = SpringApplication.run(VenueReservationServiceApplication.class, args);
System.out.println("(*^▽^*)启动成功!!!(〃'▽'〃)");
}
diff --git a/src/main/java/com/example/venue_reservation_service/domain/VeException.java b/src/main/java/com/example/venue_reservation_service/domain/VeException.java
new file mode 100644
index 0000000..93a2f1d
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/domain/VeException.java
@@ -0,0 +1,67 @@
+package com.example.venue_reservation_service.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * 系统异常日志表
+ * @TableName venue_exception
+ */
+@TableName(value ="venue_exception")
+@Data
+public class VeException implements Serializable {
+ /**
+ * 主键ID
+ */
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /**
+ * 异常类型
+ */
+ private String exceptionType;
+
+ /**
+ * 异常信息
+ */
+ private String exceptionMessage;
+
+ /**
+ * 异常堆栈
+ */
+ private String exceptionStack;
+
+ /**
+ * 方法名称
+ */
+ private String methodName;
+
+ /**
+ * 参数数据
+ */
+ private String parameterData;
+
+ /**
+ * 用户ID
+ */
+ private Integer userId;
+
+ /**
+ * 操作时间
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime operationTime;
+
+ @TableField(exist = false)
+ private static final long serialVersionUID = 1L;
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/venue_reservation_service/exception/GlobalExceptionHandler.java b/src/main/java/com/example/venue_reservation_service/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..e1e156a
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/exception/GlobalExceptionHandler.java
@@ -0,0 +1,90 @@
+package com.example.venue_reservation_service.exception;
+
+import com.example.venue_reservation_service.domain.VeException;
+import com.example.venue_reservation_service.service.VeExceptionService;
+import com.example.venue_reservation_service.vo.Result;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerMapping;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.time.LocalDateTime;
+import java.util.Map;
+
+@RestControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler {
+
+ @Autowired
+ private VeExceptionService exceptionService;
+
+ // 文件移除异常处理
+ @ExceptionHandler(MinioRemoveException.class)
+ public Result handleMinioRemoveException(MinioRemoveException e) {
+ log.error("文件移除失败: {}", e.getMessage());
+ recordException(e, "MinioRemoveException");
+ return Result.fail().message("旧头像删除失败,请重试");
+ }
+
+ // 文件校验异常处理
+ @ExceptionHandler(ImageValidateException.class)
+ public Result handleImageValidateException(ImageValidateException e) {
+ String errorMsg = "FILE_SIZE".equals(e.getErrorType())
+ ? "文件大小超过250MB限制" : "不支持的文件类型";
+ log.error("文件校验失败: {} - {}", e.getErrorType(), e.getMessage());
+ recordException(e, "ImageValidateException");
+ return Result.fail().message(errorMsg);
+ }
+
+ // 文件上传异常处理
+ @ExceptionHandler(MinioUploadException.class)
+ public Result handleMinioUploadException(MinioUploadException e) {
+ log.error("文件上传失败: {}", e.getMessage());
+ recordException(e, "MinioUploadException");
+ return Result.fail().message("头像上传失败,请稍后重试");
+ }
+
+ // 记录异常到数据库
+ private void recordException(Exception e, String exceptionType) {
+ try {
+ HttpServletRequest request = ((ServletRequestAttributes)
+ RequestContextHolder.currentRequestAttributes()).getRequest();
+
+ HandlerMethod handlerMethod = (HandlerMethod) request.getAttribute(
+ HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
+
+ VeException logEntity = new VeException();
+ logEntity.setExceptionType(exceptionType);
+ logEntity.setExceptionMessage(e.getMessage());
+
+ // 获取堆栈信息
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ logEntity.setExceptionStack(sw.toString());
+
+ logEntity.setMethodName(handlerMethod.getMethod().getName());
+
+ // 获取参数数据
+ Map params = request.getParameterMap();
+ logEntity.setParameterData(params.toString());
+
+ // 从请求中获取用户ID
+ String userId = request.getParameter("userId");
+ if (userId != null) {
+ logEntity.setUserId(Integer.parseInt(userId));
+ }
+
+ logEntity.setOperationTime(LocalDateTime.now());
+
+ exceptionService.save(logEntity);
+ } catch (Exception ex) {
+ log.error("记录异常日志失败: {}", ex.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/venue_reservation_service/exception/ImageValidateException.java b/src/main/java/com/example/venue_reservation_service/exception/ImageValidateException.java
new file mode 100644
index 0000000..a92e02d
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/exception/ImageValidateException.java
@@ -0,0 +1,16 @@
+package com.example.venue_reservation_service.exception;
+
+// 文件校验异常(包含文件过大和非图片文件)
+public class ImageValidateException extends RuntimeException {
+ private final String errorType;
+
+ public ImageValidateException(String message, String errorType) {
+ super(message);
+ this.errorType = errorType;
+ }
+
+ public String getErrorType() {
+ return errorType;
+ }
+}
+
diff --git a/src/main/java/com/example/venue_reservation_service/exception/MinioRemoveException.java b/src/main/java/com/example/venue_reservation_service/exception/MinioRemoveException.java
new file mode 100644
index 0000000..6e407d4
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/exception/MinioRemoveException.java
@@ -0,0 +1,8 @@
+package com.example.venue_reservation_service.exception;
+
+// 文件移除异常
+public class MinioRemoveException extends RuntimeException {
+ public MinioRemoveException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/example/venue_reservation_service/exception/MinioUploadException.java b/src/main/java/com/example/venue_reservation_service/exception/MinioUploadException.java
new file mode 100644
index 0000000..41af926
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/exception/MinioUploadException.java
@@ -0,0 +1,8 @@
+package com.example.venue_reservation_service.exception;
+
+// 文件上传异常
+public class MinioUploadException extends RuntimeException {
+ public MinioUploadException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/venue_reservation_service/mapper/VeExceptionMapper.java b/src/main/java/com/example/venue_reservation_service/mapper/VeExceptionMapper.java
new file mode 100644
index 0000000..8a70108
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/mapper/VeExceptionMapper.java
@@ -0,0 +1,18 @@
+package com.example.venue_reservation_service.mapper;
+
+import com.example.venue_reservation_service.domain.VeException;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+* @author 31586
+* @description 针对表【venue_exception(系统异常日志表)】的数据库操作Mapper
+* @createDate 2025-06-18 09:39:17
+* @Entity generator.domain.VeException
+*/
+public interface VeExceptionMapper extends BaseMapper {
+
+}
+
+
+
+
diff --git a/src/main/java/com/example/venue_reservation_service/netty/ChatServerHandler.java b/src/main/java/com/example/venue_reservation_service/netty/ChatServerHandler.java
new file mode 100644
index 0000000..dbf2ac2
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/netty/ChatServerHandler.java
@@ -0,0 +1,177 @@
+package com.example.venue_reservation_service.netty;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ChatServerHandler extends SimpleChannelInboundHandler {
+
+ private static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
+ private static final Map userChannelMap = new HashMap<>();
+ private static final Map roleMap = new HashMap<>();
+
+ static {
+ roleMap.put(0, "普通用户");
+ roleMap.put(1, "普通用户");
+ roleMap.put(2, "普通用户");
+ roleMap.put(3, "系统管理员");
+ roleMap.put(4, "超级管理员");
+ }
+
+ @Override
+ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
+ Channel incoming = ctx.channel();
+ channels.add(incoming);
+ System.out.println("New client connected: " + incoming.remoteAddress());
+ }
+
+ @Override
+ public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+ Channel incoming = ctx.channel();
+ String username = null;
+
+ // 查找并移除用户
+ for (Map.Entry entry : userChannelMap.entrySet()) {
+ if (entry.getValue().equals(incoming)) {
+ username = entry.getKey();
+ break;
+ }
+ }
+
+ if (username != null) {
+ userChannelMap.remove(username);
+ broadcastMessage("系统通知", username + " 已退出聊天", 3);
+ }
+
+ channels.remove(incoming);
+ System.out.println("Client disconnected: " + incoming.remoteAddress());
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
+ String request = frame.text();
+ Channel incoming = ctx.channel();
+
+ try {
+ JSONObject jsonObject = JSON.parseObject(request);
+ String type = jsonObject.getString("type");
+
+ if ("login".equals(type)) {
+ handleLogin(incoming, jsonObject);
+ } else if ("message".equals(type)) {
+ handleMessage(incoming, jsonObject);
+ } else {
+ sendErrorMessage(incoming, "未知消息类型: " + type);
+ }
+ } catch (Exception e) {
+ System.err.println("Error processing message: " + e.getMessage());
+ e.printStackTrace();
+ sendErrorMessage(incoming, "消息格式错误");
+ }
+ }
+
+ private void handleLogin(Channel incoming, JSONObject jsonObject) {
+ String username = jsonObject.getString("username");
+ int userRole = jsonObject.getIntValue("userRole");
+
+ if (username == null || username.isEmpty()) {
+ sendErrorMessage(incoming, "用户名不能为空");
+ return;
+ }
+
+ if (userChannelMap.containsKey(username)) {
+ sendErrorMessage(incoming, "用户名已被使用");
+ return;
+ }
+
+ userChannelMap.put(username, incoming);
+ String roleName = roleMap.getOrDefault(userRole, "未知角色");
+ broadcastMessage("系统通知", username + " (" + roleName + ") 加入了聊天", 3);
+ System.out.println(username + " logged in with role: " + roleName);
+ }
+
+ private void handleMessage(Channel incoming, JSONObject jsonObject) {
+ String username = jsonObject.getString("username");
+ int userRole = jsonObject.getIntValue("userRole");
+ String content = jsonObject.getString("content");
+
+ if (content == null || content.isEmpty()) {
+ return;
+ }
+
+ if (!userChannelMap.containsKey(username) || !userChannelMap.get(username).equals(incoming)) {
+ sendErrorMessage(incoming, "用户未登录");
+ return;
+ }
+
+ String roleName = roleMap.getOrDefault(userRole, "未知角色");
+ String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+ JSONObject messageJson = new JSONObject();
+ messageJson.put("type", "message");
+ messageJson.put("sender", username);
+ messageJson.put("senderRole", userRole);
+ messageJson.put("roleName", roleName);
+ messageJson.put("content", content);
+ messageJson.put("timestamp", timestamp);
+
+ broadcastMessage(messageJson.toJSONString());
+ }
+
+ private void broadcastMessage(String message) {
+ for (Channel channel : channels) {
+ channel.writeAndFlush(new TextWebSocketFrame(message));
+ }
+ }
+
+ private void broadcastMessage(String from, String content, int role) {
+ JSONObject messageJson = new JSONObject();
+ messageJson.put("type", "system");
+ messageJson.put("sender", from);
+ messageJson.put("senderRole", role);
+ messageJson.put("message", content);
+ messageJson.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+
+ broadcastMessage(messageJson.toJSONString());
+ }
+
+ private void sendErrorMessage(Channel channel, String message) {
+ JSONObject errorJson = new JSONObject();
+ errorJson.put("type", "error");
+ errorJson.put("message", message);
+ channel.writeAndFlush(new TextWebSocketFrame(errorJson.toJSONString()));
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ Channel channel = ctx.channel();
+ String username = null;
+
+ // 查找并移除用户
+ for (Map.Entry entry : userChannelMap.entrySet()) {
+ if (entry.getValue().equals(channel)) {
+ username = entry.getKey();
+ break;
+ }
+ }
+
+ if (username != null) {
+ userChannelMap.remove(username);
+ broadcastMessage("系统通知", username + " 连接异常断开", 3);
+ }
+
+ cause.printStackTrace();
+ ctx.close();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/venue_reservation_service/netty/NettyChatServer.java b/src/main/java/com/example/venue_reservation_service/netty/NettyChatServer.java
new file mode 100644
index 0000000..9aa17af
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/netty/NettyChatServer.java
@@ -0,0 +1,67 @@
+package com.example.venue_reservation_service.netty;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
+import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
+import io.netty.handler.stream.ChunkedWriteHandler;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NettyChatServer {
+
+ @Value("${server.netty.port}")
+ private int port;
+
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+ @PostConstruct
+ public void start() throws Exception {
+ bossGroup = new NioEventLoopGroup();
+ workerGroup = new NioEventLoopGroup();
+
+ ServerBootstrap b = new ServerBootstrap();
+ b.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .option(ChannelOption.SO_BACKLOG, 100)
+ .childOption(ChannelOption.SO_KEEPALIVE, true)
+ .childHandler(new ChannelInitializer() {
+ @Override
+ public void initChannel(SocketChannel ch) throws Exception {
+ ch.pipeline().addLast(
+ new HttpServerCodec(),
+ new HttpObjectAggregator(65536),
+ new ChunkedWriteHandler(),
+ new WebSocketServerCompressionHandler(),
+ new WebSocketServerProtocolHandler("/ws", null, true),
+ new ChatServerHandler()
+ );
+ }
+ });
+
+ ChannelFuture f = b.bind(port).sync();
+ System.out.println("Netty Chat Server started and listen on port " + port);
+ }
+
+ @PreDestroy
+ public void stop() {
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ }
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/venue_reservation_service/service/VeExceptionService.java b/src/main/java/com/example/venue_reservation_service/service/VeExceptionService.java
new file mode 100644
index 0000000..96ee9a2
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/service/VeExceptionService.java
@@ -0,0 +1,13 @@
+package com.example.venue_reservation_service.service;
+
+import com.example.venue_reservation_service.domain.VeException;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+* @author 31586
+* @description 针对表【venue_exception(系统异常日志表)】的数据库操作Service
+* @createDate 2025-06-18 09:39:17
+*/
+public interface VeExceptionService extends IService {
+
+}
diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/UserServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/UserServiceImpl.java
index 34bc38b..8efdef6 100644
--- a/src/main/java/com/example/venue_reservation_service/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/example/venue_reservation_service/service/impl/UserServiceImpl.java
@@ -1,16 +1,16 @@
package com.example.venue_reservation_service.service.impl;
import cn.hutool.core.lang.UUID;
-import cn.hutool.jwt.JWTUtil;
-import com.auth0.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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.domain.*;
import com.example.venue_reservation_service.dto.*;
+import com.example.venue_reservation_service.exception.ImageValidateException;
+import com.example.venue_reservation_service.exception.MinioRemoveException;
+import com.example.venue_reservation_service.exception.MinioUploadException;
import com.example.venue_reservation_service.mapper.AdminMapper;
import com.example.venue_reservation_service.service.*;
import com.example.venue_reservation_service.mapper.UserMapper;
@@ -21,20 +21,15 @@ import com.example.venue_reservation_service.vo.Result;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import jakarta.annotation.Resource;
import org.apache.commons.io.FilenameUtils;
-import org.checkerframework.checker.units.qual.A;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
-
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-
/**
* @author 31586
* @description 针对表【venue_user】的数据库操作Service实现
@@ -353,34 +348,47 @@ public class UserServiceImpl extends ServiceImpl
if (Optional.ofNullable(user).isEmpty()) {
return Result.fail().message("用户信息不存在");
}
- // 检查是否上传头像
- if(user.getIsUpload() == 1){
- // 删除原来的图片
- try {
- minioUtil.removeFile(user.getAvatar());
- }catch (Exception e){
- e.printStackTrace();
- return Result.fail().message("服务错误,请稍后重试");
+
+ try {
+ // 检查是否上传过头像
+ if(user.getIsUpload() == 1) {
+ try {
+ minioUtil.removeFile(user.getAvatar());
+ } catch (Exception e) {
+ throw new MinioRemoveException("删除旧文件失败: " + e.getMessage());
+ }
}
- }
- if (ImageValidator.validateImageFile(file)) {
- // 生成新的名称
- String extension = FilenameUtils.getExtension(file.getOriginalFilename()); // 获取文件扩展名
+
+ // 文件校验(修改为抛出异常)
+ ImageValidator.validateImageFileWithException(file);
+
+ String extension = FilenameUtils.getExtension(file.getOriginalFilename());
String filename = UUID.randomUUID().toString().replaceAll("-", "") + "." + extension;
+
try {
minioUtil.uploadFile(file, filename, file.getContentType());
- }catch (Exception e){
- e.printStackTrace();
- return Result.fail().message("服务错误,图片上传失败,请稍后重试");
+ } catch (Exception e) {
+ // 上传失败时重置用户状态
+ user.setIsUpload(0);
+ updateById(user);
+ throw new MinioUploadException("文件上传失败: " + e.getMessage());
}
+
+ // 更新用户信息
user.setIsUpload(1);
user.setAvatar(filename);
updateById(user);
- return Result.ok(imgUrl + user.getAvatar()).message("头像图片上传成功");
+ return Result.ok(imgUrl + user.getAvatar()).message("头像上传成功");
+
+ } catch (MinioRemoveException | ImageValidateException | MinioUploadException e) {
+ throw e; // 抛出给全局异常处理器
+ } catch (Exception e) {
+ log.error("系统未知错误: {}" + e.getMessage());
+ return Result.fail().message("系统错误,请稍后重试");
}
- return Result.fail().message("非图片文件或文件过大");
}
+
@Override
public Result getUserInfo(Integer userId) {
User user = getById(userId);
diff --git a/src/main/java/com/example/venue_reservation_service/service/impl/VeExceptionServiceImpl.java b/src/main/java/com/example/venue_reservation_service/service/impl/VeExceptionServiceImpl.java
new file mode 100644
index 0000000..dbf0521
--- /dev/null
+++ b/src/main/java/com/example/venue_reservation_service/service/impl/VeExceptionServiceImpl.java
@@ -0,0 +1,22 @@
+package com.example.venue_reservation_service.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.example.venue_reservation_service.mapper.VeExceptionMapper;
+import com.example.venue_reservation_service.service.VeExceptionService;
+import com.example.venue_reservation_service.domain.VeException;
+import org.springframework.stereotype.Service;
+
+/**
+* @author 31586
+* @description 针对表【venue_exception(系统异常日志表)】的数据库操作Service实现
+* @createDate 2025-06-18 09:39:17
+*/
+@Service
+public class VeExceptionServiceImpl extends ServiceImpl
+ implements VeExceptionService {
+
+}
+
+
+
+
diff --git a/src/main/java/com/example/venue_reservation_service/utils/ImageValidator.java b/src/main/java/com/example/venue_reservation_service/utils/ImageValidator.java
index 4c8d148..c507f38 100644
--- a/src/main/java/com/example/venue_reservation_service/utils/ImageValidator.java
+++ b/src/main/java/com/example/venue_reservation_service/utils/ImageValidator.java
@@ -1,5 +1,6 @@
package com.example.venue_reservation_service.utils;
+import com.example.venue_reservation_service.exception.ImageValidateException;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
@@ -15,6 +16,39 @@ public class ImageValidator {
// 250MB 字节限制 (250 * 1024 * 1024)
private static final long MAX_SIZE_BYTES = 262144000L;
+ // 修改后的文件校验方法(抛出异常)
+ public static void validateImageFileWithException(MultipartFile file) {
+ if (file == null || file.isEmpty()) {
+ throw new ImageValidateException("文件为空", "FILE_EMPTY");
+ }
+
+ if (file.getSize() > ImageValidator.MAX_SIZE_BYTES) {
+ throw new ImageValidateException("文件大小超过限制", "FILE_SIZE");
+ }
+
+ String originalName = file.getOriginalFilename();
+ if (originalName == null || originalName.lastIndexOf(".") == -1) {
+ throw new ImageValidateException("文件无扩展名", "FILE_EXT");
+ }
+
+ String extension = originalName.substring(originalName.lastIndexOf(".") + 1).toLowerCase();
+ if (!ImageValidator.ALLOWED_EXTENSIONS.contains(extension)) {
+ throw new ImageValidateException("不支持的文件类型", "FILE_TYPE");
+ }
+
+ try (ImageInputStream iis = ImageIO.createImageInputStream(file.getInputStream())) {
+ if (iis == null) {
+ throw new ImageValidateException("无法读取文件内容", "FILE_READ");
+ }
+ Iterator readers = ImageIO.getImageReaders(iis);
+ if (!readers.hasNext()) {
+ throw new ImageValidateException("不是有效的图片文件", "FILE_FORMAT");
+ }
+ } catch (IOException e) {
+ throw new ImageValidateException("文件读取失败: " + e.getMessage(), "FILE_IO");
+ }
+ }
+
/**
* 验证是否为图片文件且大小<250MB
* @param file MultipartFile对象
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index c43b36f..683f9ec 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -2,6 +2,8 @@ server:
port: 9020
# servlet:
# context-path: /api
+ netty:
+ port: 9030
#localhosturl: 172.16.6.53 # 学校服务器
localhosturl: 119.29.191.232 # 双创服务器
diff --git a/src/main/resources/mapper/VeExceptionMapper.xml b/src/main/resources/mapper/VeExceptionMapper.xml
new file mode 100644
index 0000000..9304ec2
--- /dev/null
+++ b/src/main/resources/mapper/VeExceptionMapper.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id,exception_type,exception_message,
+ exception_stack,method_name,parameter_data,
+ user_id,operation_time
+
+
diff --git a/src/test/java/com/example/venue_reservation_service/dcpint/icdcshare/IfsDcpIcdcShareTest.java b/src/test/java/com/example/venue_reservation_service/dcpint/icdcshare/IfsDcpIcdcShareTest.java
index 11ed60a..29b1a8b 100644
--- a/src/test/java/com/example/venue_reservation_service/dcpint/icdcshare/IfsDcpIcdcShareTest.java
+++ b/src/test/java/com/example/venue_reservation_service/dcpint/icdcshare/IfsDcpIcdcShareTest.java
@@ -22,16 +22,19 @@ public class IfsDcpIcdcShareTest {
String param=""
+ "IcdcShare"
//+ "getUnit"
- + "08192ec57d80193b9fa4b9a0"
+ + "cgyy_dcpint_getJbxx"
+// + "getJzgjcxx2"
+ +"08192ec57d80193b9fa4b9a0"
//+"pageSize=8&pageNo=1"
- +"STUDENTID=1966&pageSize=5&pageNo=1"
+// +"GH=1966&pageSize=5&pageNo=1"
//+"STUDENTID=2017"
+ "";
param= IfsDcpIntUtils.desEncode(param);
Map params = new HashMap();
//注意:参数名"clienttype","name"和"param"不能变
params.put("clienttype", "java");
- params.put("name", "thirdpartytest");
+// params.put("name", "thirdpartytest");
+ params.put("name", "getJzgjcxx2");
params.put("param", param);
/*返回值说明
(1)正确的返回为:{"success":true,"message":true}
@@ -40,13 +43,13 @@ public class IfsDcpIcdcShareTest {
具体判断可以简单以返回串不包含false字符串为成功标志。
*/
String result = IfsDcpIntUtils.httpPostRequest(params);
+ System.out.println(result);
// System.out.println("result:" + result);
- ObjectMapper mapper = new ObjectMapper();
- ResponseResult responseResult = mapper.readValue(result, ResponseResult.class);
- for (Unit unit : responseResult.getMessage()) {
- System.out.println(unit);
- }
- System.out.println(responseResult.getPage());
+// ResponseResult responseResult = mapper.readValue(result, ResponseResult.class);
+// for (Unit unit : responseResult.getMessage()) {
+// System.out.println(unit);
+// }
+// System.out.println(responseResult.getPage());
// result
}