文档首页> Linux命令> SpringMVC之JSON返回及异常处理机制

SpringMVC之JSON返回及异常处理机制

发布时间:2025-06-26 00:04       

🌟 Spring MVC JSON返回与异常处理全解析

(基于Spring Framework 5.3.x+最佳实践)


一、JSON返回核心机制

1. 基础配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new MappingJackson2HttpMessageConverter()); // JSON序列化核心
    }
}
​

依赖要求:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version> <!-- 最新稳定版 -->
</dependency>
​
2. 控制器实现
@RestController // 等效于@Controller + @ResponseBody
@RequestMapping("/api")
public class UserController {
  
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id); // 自动转JSON
    }
  
    @PostMapping("/create")
    public ResponseEntity<ApiResponse> createUser(@Valid @RequestBody UserDTO dto) {
        User savedUser = userService.save(dto);
        return ResponseEntity.status(HttpStatus.CREATED)
                             .body(ApiResponse.success(savedUser));
    }
}
​

关键注解:

  • @RestController:自动序列化返回值
  • @ResponseBody:方法级JSON响应
  • ResponseEntity:精确控制HTTP状态码/头信息
3. 高级序列化控制
public class ApiResponse<T> {
    @JsonInclude(JsonInclude.Include.NON_NULL) // 忽略null字段
    private T data;
  
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss") // 日期格式化
    private LocalDateTime timestamp;
  
    // 枚举序列化为描述文字
    @JsonValue
    public String getCodeDesc() {
        return code.getDescription();
    }
}
​

🔥 二、全局异常处理(工业级方案)

1. 统一异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {
  
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ErrorResponse handleBizEx(BusinessException ex) {
        return new ErrorResponse(ex.getCode(), ex.getMessage());
    }
  
    // 处理校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    public ErrorResponse handleValidEx(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.toList());
        return new ErrorResponse("VALID_FAIL", errors);
    }
  
    // 兜底异常处理
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ErrorResponse handleUnknownEx(Exception ex) {
        log.error("System Error: ", ex); // 记录完整堆栈
        return new ErrorResponse("SYSTEM_ERROR", "服务暂不可用");
    }
}
​
2. 自定义异常体系
public class BusinessException extends RuntimeException {
    private final String errorCode;
  
    public BusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
  
    // 带根本原因构造器
    public BusinessException(String errorCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }
}
​
3. 错误响应标准化
public class ErrorResponse {
    private final String code;
    private final Object detail; // 支持String/List/Map
  
    public ErrorResponse(String code, Object detail) {
        this.code = code;
        this.detail = detail;
    }
  
    // 生成样例:
    // { "code": "AUTH_FAIL", "detail": "Token已过期" }
    // { "code": "VALID_FAIL", "detail": ["邮箱格式错误", "密码强度不足"] }
}
​

🛡️ 三、生产环境增强策略

1. 安全敏感数据处理
@JsonFilter("sensitiveFilter")
public class UserDTO {
    private String name;
  
    @JsonIgnore // 完全排除字段
    private String password;
  
    @JsonProperty(access = Access.WRITE_ONLY) // 仅允许写入
    private String authToken;
}

// 控制器动态过滤
@GetMapping("/safe-info")
public MappingJacksonValue getSafeInfo() {
    User user = userService.getCurrentUser();
    SimpleFilterProvider filters = new SimpleFilterProvider()
            .addFilter("sensitiveFilter", 
                SimpleBeanPropertyFilter.serializeAllExcept("authToken"));
    return new MappingJacksonValue(user).setFilters(filters);
}
​
2. 国际化错误消息
# errors.properties
user.not_found=用户ID {0} 不存在
email.invalid=邮箱格式不合法
​
@ExceptionHandler(ResourceNotFoundException.class)
public ErrorResponse handleNotFoundEx(ResourceNotFoundException ex, 
                                     Locale locale) {
    String message = messageSource.getMessage(
        "user.not_found", 
        new Object[]{ex.getResourceId()}, 
        locale
    );
    return new ErrorResponse("NOT_FOUND", message);
}
​
3. 链路追踪集成
@ExceptionHandler(Exception.class)
public ErrorResponse handleGlobalEx(Exception ex, WebRequest request) {
    String traceId = MDC.get("traceId"); // 从SLF4J MDC获取
    return new ErrorResponse("SYSTEM_ERROR", traceId);
}
​

⚠️ 四、避坑指南

  1. 日期序列化问题
    # application.yml
    spring:
      jackson:
        time-zone: GMT+8
        date-format: yyyy-MM-dd HH:mm:ss
    ​
  2. 循环引用解决
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, 
                      property = "id")
    public class Department {
        private List<Employee> employees;
    }
    ​
  3. 空集合处理