Commit a677e98de0ca16b7884fd8ecf04a0d0af77cd923

Authored by YunaiV
1 parent f1dd7999

【代码修复】SYSTEM:角色标识的提示不正确问题

yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.exceptions.ExceptionUtil;
4 4 import cn.hutool.core.map.MapUtil;
5 5 import cn.hutool.core.util.ObjUtil;
6 6 import cn.hutool.core.util.StrUtil;
  7 +import cn.hutool.extra.servlet.JakartaServletUtil;
7 8 import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
8 9 import cn.iocoder.yudao.framework.common.exception.ServiceException;
9 10 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
... ... @@ -14,13 +15,14 @@ import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
14 15 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
15 16 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
16 17 import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
  18 +import com.fasterxml.jackson.databind.exc.InvalidFormatException;
17 19 import jakarta.servlet.http.HttpServletRequest;
18 20 import jakarta.validation.ConstraintViolation;
19 21 import jakarta.validation.ConstraintViolationException;
20 22 import jakarta.validation.ValidationException;
21 23 import lombok.AllArgsConstructor;
22 24 import lombok.extern.slf4j.Slf4j;
23   -import org.apache.commons.lang3.exception.ExceptionUtils;
  25 +import org.springframework.http.converter.HttpMessageNotReadableException;
24 26 import org.springframework.security.access.AccessDeniedException;
25 27 import org.springframework.util.Assert;
26 28 import org.springframework.validation.BindException;
... ... @@ -38,7 +40,12 @@ import java.time.LocalDateTime;
38 40 import java.util.Map;
39 41 import java.util.Set;
40 42  
41   -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.*;
  43 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  44 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN;
  45 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
  46 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.METHOD_NOT_ALLOWED;
  47 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_FOUND;
  48 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
42 49  
43 50 /**
44 51 * 全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号
... ... @@ -88,7 +95,7 @@ public class GlobalExceptionHandler {
88 95 return validationException((ValidationException) ex);
89 96 }
90 97 if (ex instanceof NoHandlerFoundException) {
91   - return noHandlerFoundExceptionHandler(request, (NoHandlerFoundException) ex);
  98 + return noHandlerFoundExceptionHandler((NoHandlerFoundException) ex);
92 99 }
93 100 if (ex instanceof NoResourceFoundException) {
94 101 return noResourceFoundExceptionHandler(request, (NoResourceFoundException) ex);
... ... @@ -123,7 +130,7 @@ public class GlobalExceptionHandler {
123 130 */
124 131 @ExceptionHandler(MethodArgumentTypeMismatchException.class)
125 132 public CommonResult<?> methodArgumentTypeMismatchExceptionHandler(MethodArgumentTypeMismatchException ex) {
126   - log.warn("[missingServletRequestParameterExceptionHandler]", ex);
  133 + log.warn("[methodArgumentTypeMismatchExceptionHandler]", ex);
127 134 return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", ex.getMessage()));
128 135 }
129 136  
... ... @@ -150,6 +157,22 @@ public class GlobalExceptionHandler {
150 157 }
151 158  
152 159 /**
  160 + * 处理 SpringMVC 请求参数类型错误
  161 + *
  162 + * 例如说,接口上设置了 @RequestBody实体中 xx 属性类型为 Integer,结果传递 xx 参数类型为 String
  163 + */
  164 + @ExceptionHandler(HttpMessageNotReadableException.class)
  165 + public CommonResult<?> methodArgumentTypeInvalidFormatExceptionHandler(HttpMessageNotReadableException ex) {
  166 + log.warn("[methodArgumentTypeInvalidFormatExceptionHandler]", ex);
  167 + if(ex.getCause() instanceof InvalidFormatException) {
  168 + InvalidFormatException invalidFormatException = (InvalidFormatException) ex.getCause();
  169 + return CommonResult.error(BAD_REQUEST.getCode(), String.format("请求参数类型错误:%s", invalidFormatException.getValue()));
  170 + }else {
  171 + return defaultExceptionHandler(ServletUtils.getRequest(), ex);
  172 + }
  173 + }
  174 +
  175 + /**
153 176 * 处理 Validator 校验不通过产生的异常
154 177 */
155 178 @ExceptionHandler(value = ConstraintViolationException.class)
... ... @@ -177,7 +200,7 @@ public class GlobalExceptionHandler {
177 200 * 2. spring.mvc.static-path-pattern 为 /statics/**
178 201 */
179 202 @ExceptionHandler(NoHandlerFoundException.class)
180   - public CommonResult<?> noHandlerFoundExceptionHandler(HttpServletRequest req, NoHandlerFoundException ex) {
  203 + public CommonResult<?> noHandlerFoundExceptionHandler(NoHandlerFoundException ex) {
181 204 log.warn("[noHandlerFoundExceptionHandler]", ex);
182 205 return CommonResult.error(NOT_FOUND.getCode(), String.format("请求地址不存在:%s", ex.getRequestURL()));
183 206 }
... ... @@ -253,7 +276,7 @@ public class GlobalExceptionHandler {
253 276 // 情况二:处理异常
254 277 log.error("[defaultExceptionHandler]", ex);
255 278 // 插入异常日志
256   - this.createExceptionLog(req, ex);
  279 + createExceptionLog(req, ex);
257 280 // 返回 ERROR CommonResult
258 281 return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
259 282 }
... ... @@ -279,7 +302,7 @@ public class GlobalExceptionHandler {
279 302 errorLog.setExceptionName(e.getClass().getName());
280 303 errorLog.setExceptionMessage(ExceptionUtil.getMessage(e));
281 304 errorLog.setExceptionRootCauseMessage(ExceptionUtil.getRootCauseMessage(e));
282   - errorLog.setExceptionStackTrace(ExceptionUtils.getStackTrace(e));
  305 + errorLog.setExceptionStackTrace(ExceptionUtil.stacktraceToString(e));
283 306 StackTraceElement[] stackTraceElements = e.getStackTrace();
284 307 Assert.notEmpty(stackTraceElements, "异常 stackTraceElements 不能为空");
285 308 StackTraceElement stackTraceElement = stackTraceElements[0];
... ... @@ -292,12 +315,12 @@ public class GlobalExceptionHandler {
292 315 errorLog.setApplicationName(applicationName);
293 316 errorLog.setRequestUrl(request.getRequestURI());
294 317 Map<String, Object> requestParams = MapUtil.<String, Object>builder()
295   - .put("query", ServletUtils.getParamMap(request))
296   - .put("body", ServletUtils.getBody(request)).build();
  318 + .put("query", JakartaServletUtil.getParamMap(request))
  319 + .put("body", JakartaServletUtil.getBody(request)).build();
297 320 errorLog.setRequestParams(JsonUtils.toJsonString(requestParams));
298 321 errorLog.setRequestMethod(request.getMethod());
299 322 errorLog.setUserAgent(ServletUtils.getUserAgent(request));
300   - errorLog.setUserIp(ServletUtils.getClientIP(request));
  323 + errorLog.setUserIp(JakartaServletUtil.getClientIP(request));
301 324 errorLog.setExceptionTime(LocalDateTime.now());
302 325 }
303 326  
... ... @@ -314,51 +337,51 @@ public class GlobalExceptionHandler {
314 337 }
315 338 // 1. 数据报表
316 339 if (message.contains("report_")) {
317   - log.error("[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
  340 + log.error("[报表模块 yudao-module-report - 表结构未导入][参考 https://cloud.iocoder.cn/report/ 开启]");
318 341 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
319   - "[报表模块 yudao-module-report - 表结构未导入][参考 https://doc.iocoder.cn/report/ 开启]");
  342 + "[报表模块 yudao-module-report - 表结构未导入][参考 https://cloud.iocoder.cn/report/ 开启]");
320 343 }
321 344 // 2. 工作流
322 345 if (message.contains("bpm_")) {
323   - log.error("[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
  346 + log.error("[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://cloud.iocoder.cn/bpm/ 开启]");
324 347 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
325   - "[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://doc.iocoder.cn/bpm/ 开启]");
  348 + "[工作流模块 yudao-module-bpm - 表结构未导入][参考 https://cloud.iocoder.cn/bpm/ 开启]");
326 349 }
327 350 // 3. 微信公众号
328 351 if (message.contains("mp_")) {
329   - log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
  352 + log.error("[微信公众号 yudao-module-mp - 表结构未导入][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
330 353 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
331   - "[微信公众号 yudao-module-mp - 表结构未导入][参考 https://doc.iocoder.cn/mp/build/ 开启]");
  354 + "[微信公众号 yudao-module-mp - 表结构未导入][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
332 355 }
333 356 // 4. 商城系统
334 357 if (StrUtil.containsAny(message, "product_", "promotion_", "trade_")) {
335   - log.error("[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
  358 + log.error("[商城系统 yudao-module-mall - 已禁用][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
336 359 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
337   - "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
  360 + "[商城系统 yudao-module-mall - 已禁用][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
338 361 }
339 362 // 5. ERP 系统
340 363 if (message.contains("erp_")) {
341   - log.error("[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]");
  364 + log.error("[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
342 365 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
343   - "[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://doc.iocoder.cn/erp/build/ 开启]");
  366 + "[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
344 367 }
345 368 // 6. CRM 系统
346 369 if (message.contains("crm_")) {
347   - log.error("[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://doc.iocoder.cn/crm/build/ 开启]");
  370 + log.error("[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
348 371 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
349   - "[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://doc.iocoder.cn/crm/build/ 开启]");
  372 + "[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
350 373 }
351 374 // 7. 支付平台
352 375 if (message.contains("pay_")) {
353   - log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
  376 + log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
354 377 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
355   - "[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
  378 + "[支付模块 yudao-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
356 379 }
357 380 // 8. AI 大模型
358 381 if (message.contains("ai_")) {
359   - log.error("[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://doc.iocoder.cn/ai/build/ 开启]");
  382 + log.error("[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
360 383 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
361   - "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://doc.iocoder.cn/ai/build/ 开启]");
  384 + "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
362 385 }
363 386 return null;
364 387 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/DictTypeConstants.java
... ... @@ -13,12 +13,11 @@ public interface DictTypeConstants {
13 13 // ========== SYSTEM 模块 ==========
14 14  
15 15 String USER_SEX = "system_user_sex"; // 用户性别
  16 + String DATA_SCOPE = "system_data_scope"; // 数据范围
16 17  
17 18 String LOGIN_TYPE = "system_login_type"; // 登录日志的类型
18 19 String LOGIN_RESULT = "system_login_result"; // 登录结果
19 20  
20   - String ERROR_CODE_TYPE = "system_error_code_type"; // 错误码的类型枚举
21   -
22 21 String SMS_CHANNEL_CODE = "system_sms_channel_code"; // 短信渠道编码
23 22 String SMS_TEMPLATE_TYPE = "system_sms_template_type"; // 短信模板类型
24 23 String SMS_SEND_STATUS = "system_sms_send_status"; // 短信发送状态
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
... ... @@ -27,10 +27,10 @@ public interface ErrorCodeConstants {
27 27 // ========== 角色模块 1-002-002-000 ==========
28 28 ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1_002_002_000, "角色不存在");
29 29 ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1_002_002_001, "已经存在名为【{}】的角色");
30   - ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在编码为【{}】的角色");
  30 + ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1_002_002_002, "已经存在标识为【{}】的角色");
31 31 ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1_002_002_003, "不能操作类型为系统内置的角色");
32 32 ErrorCode ROLE_IS_DISABLE = new ErrorCode(1_002_002_004, "名字为【{}】的角色已被禁用");
33   - ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用");
  33 + ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "标识【{}】不能使用");
34 34  
35 35 // ========== 用户模块 1-002-003-000 ==========
36 36 ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "用户账号已经存在");
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleRespVO.java
... ... @@ -6,9 +6,9 @@ import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
6 6 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
7 7 import com.alibaba.excel.annotation.ExcelProperty;
8 8 import io.swagger.v3.oas.annotations.media.Schema;
  9 +import jakarta.validation.constraints.NotBlank;
9 10 import lombok.Data;
10 11  
11   -import jakarta.validation.constraints.NotBlank;
12 12 import java.time.LocalDateTime;
13 13 import java.util.Set;
14 14  
... ... @@ -46,7 +46,8 @@ public class RoleRespVO {
46 46 private String remark;
47 47  
48 48 @Schema(description = "数据范围,参见 DataScopeEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
49   - @ExcelProperty("数据范围")
  49 + @ExcelProperty(value = "数据范围", converter = DictConvert.class)
  50 + @DictFormat(DictTypeConstants.DATA_SCOPE)
50 51 private Integer dataScope;
51 52  
52 53 @Schema(description = "数据范围(指定部门数组)", example = "1")
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleSaveReqVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
3 5 import com.mzt.logapi.starter.annotation.DiffLogField;
4 6 import io.swagger.v3.oas.annotations.media.Schema;
5   -import lombok.Data;
6   -
7 7 import jakarta.validation.constraints.NotBlank;
8 8 import jakarta.validation.constraints.NotNull;
9 9 import jakarta.validation.constraints.Size;
  10 +import lombok.Data;
10 11  
11 12 @Schema(description = "管理后台 - 角色创建/更新 Request VO")
12 13 @Data
... ... @@ -23,7 +24,7 @@ public class RoleSaveReqVO {
23 24  
24 25 @NotBlank(message = "角色标志不能为空")
25 26 @Size(max = 100, message = "角色标志长度不能超过 100 个字符")
26   - @Schema(description = "角色编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN")
  27 + @Schema(description = "角色标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ADMIN")
27 28 @DiffLogField(name = "角色标志")
28 29 private String code;
29 30  
... ... @@ -32,7 +33,14 @@ public class RoleSaveReqVO {
32 33 @DiffLogField(name = "显示顺序")
33 34 private Integer sort;
34 35  
  36 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  37 + @DiffLogField(name = "状态")
  38 + @NotNull(message = "状态不能为空")
  39 + @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
  40 + private Integer status;
  41 +
35 42 @Schema(description = "备注", example = "我是一个角色")
  43 + @Size(max = 500, message = "备注长度不能超过 500 个字符")
36 44 @DiffLogField(name = "备注")
37 45 private String remark;
38 46  
... ...