Java响应返回流程如何统一

wen java案例 27

本文目录导读:

Java响应返回流程如何统一

  1. 通用响应体封装(最常用)
  2. 使用全局异常处理器(更优雅)
  3. 使用 ResponseBodyAdvice 自动包装(最自动化)
  4. 最佳实践建议
  5. 推荐方案

在Java后端开发中,统一响应返回流程是提升代码可维护性、规范前后端交互的核心手段,通常有两种主流实现方式,下面分别说明:

通用响应体封装(最常用)

1 定义统一响应类

import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
    private String timestamp;
    // 私有构造器
    private ApiResponse() {
        this.timestamp = LocalDateTime.now().toString();
    }
    // 成功响应
    public static <T> ApiResponse<T> success(T data) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(200);
        response.setMessage("success");
        response.setData(data);
        return response;
    }
    // 成功响应(带自定义消息)
    public static <T> ApiResponse<T> success(String message, T data) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(200);
        response.setMessage(message);
        response.setData(data);
        return response;
    }
    // 失败响应
    public static <T> ApiResponse<T> error(int code, String message) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(code);
        response.setMessage(message);
        response.setData(null);
        return response;
    }
    // 失败响应(带自定义数据)
    public static <T> ApiResponse<T> error(int code, String message, T data) {
        ApiResponse<T> response = new ApiResponse<>();
        response.setCode(code);
        response.setMessage(message);
        response.setData(data);
        return response;
    }
}

2 使用方式

@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public ApiResponse<User> getUser(@PathVariable Long id) {
        try {
            User user = userService.findById(id);
            return ApiResponse.success(user);
        } catch (Exception e) {
            return ApiResponse.error(500, "查询用户失败: " + e.getMessage());
        }
    }
}

使用全局异常处理器(更优雅)

1 自定义业务异常

import lombok.Getter;
@Getter
public class BusinessException extends RuntimeException {
    private int code;
    private String message;
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
    // 预定义错误码
    public static class ErrorCode {
        public static final int PARAM_ERROR = 400;
        public static final int UNAUTHORIZED = 401;
        public static final int FORBIDDEN = 403;
        public static final int NOT_FOUND = 404;
        public static final int SERVER_ERROR = 500;
    }
}

2 全局异常处理器

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
    // 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ApiResponse<Void> handleBusinessException(BusinessException e) {
        return ApiResponse.error(e.getCode(), e.getMessage());
    }
    // 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<Void> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.joining(", "));
        return ApiResponse.error(400, message);
    }
    // 处理其他未捕获异常
    @ExceptionHandler(Exception.class)
    public ApiResponse<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return ApiResponse.error(500, "服务器内部错误");
    }
}

3 控制器直接返回数据

@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        if (user == null) {
            throw new BusinessException(404, "用户不存在");
        }
        return user;  // 直接返回数据,由全局异常处理器统一包装
    }
}

使用 ResponseBodyAdvice 自动包装(最自动化)

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class ResponseWrapperAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 排除已经包装的响应和特定类型
        return !returnType.getParameterType().equals(ApiResponse.class)
                && !returnType.getParameterType().equals(ResponseEntity.class);
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        // 对 String 类型特殊处理(避免类型转换错误)
        if (body instanceof String) {
            return ApiResponse.success((String) body);
        }
        return ApiResponse.success(body);
    }
}

最佳实践建议

1 定义枚举响应码

public enum ResponseCode {
    SUCCESS(200, "成功"),
    BAD_REQUEST(400, "请求参数错误"),
    UNAUTHORIZED(401, "未授权"),
    FORBIDDEN(403, "禁止访问"),
    NOT_FOUND(404, "资源不存在"),
    METHOD_NOT_ALLOWED(405, "请求方法不允许"),
    INTERNAL_ERROR(500, "服务器内部错误"),
    BUSINESS_ERROR(1001, "业务逻辑错误");
    private final int code;
    private final String message;
    ResponseCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
    // getter ...
}

2 完整示例

// 使用总结
@RestController
@RequestMapping("/api")
public class DemoController {
    @GetMapping("/example")
    public ApiResponse<String> example() {
        // 方式1:直接返回包装对象
        return ApiResponse.success("Hello World");
    }
    @GetMapping("/auto-wrap")
    public String autoWrap() {
        // 方式2:配合 ResponseBodyAdvice 自动包装
        return "自动包装";
    }
    @GetMapping("/error")
    public void throwError() {
        // 方式3:抛出异常由全局异常处理器处理
        throw new BusinessException(1001, "自定义业务错误");
    }
}

推荐方案

生产中推荐使用:全局异常处理器 + ResponseBodyAdvice 组合

  • GlobalExceptionHandler:统一处理异常
  • ResponseWrapperAdvice:自动包装成功响应
  • BusinessException:自定义业务异常

这样控制器只需关注业务逻辑,返回纯数据对象即可,所有响应(成功/失败)都会统一封装成 ApiResponse 格式。

抱歉,评论功能暂时关闭!