基于SpringBoot 2.0.0开发RestAPI:如何统一自定义接口响应?
嘿,我来帮你搞定Spring Boot 2.0.0里统一自定义API响应的需求!核心思路是定义统一的响应体结构,再通过全局拦截包装实现无侵入式的统一处理,下面一步步来:
1. 定义统一响应实体类
首先创建一个通用的响应体,用来封装所有接口的返回结果,包含状态码、提示消息、业务数据和分页信息(按需):
import lombok.Data; import org.springframework.data.domain.Page; import java.util.List; @Data public class ApiResponse<T> { // 自定义业务状态码(比如200=成功,400=参数错误) private int code; // 响应提示消息 private String message; // 业务数据(支持单个对象/集合) private T data; // 分页信息(仅分页接口返回) private Pagination pagination; // 快速创建成功响应的静态方法 public static <T> ApiResponse<T> success(T data) { ApiResponse<T> response = new ApiResponse<>(); response.setCode(200); response.setMessage("请求成功"); response.setData(data); // 如果返回的是Spring Data的Page对象,自动填充分页信息 if (data instanceof Page) { Page<?> page = (Page<?>) data; Pagination pagination = new Pagination(); pagination.setPageNumber(page.getNumber()); pagination.setPageSize(page.getSize()); pagination.setTotalElements(page.getTotalElements()); pagination.setTotalPages(page.getTotalPages()); pagination.setFirst(page.isFirst()); pagination.setLast(page.isLast()); response.setPagination(pagination); } return response; } // 带自定义消息的成功响应 public static <T> ApiResponse<T> success(String message, T data) { ApiResponse<T> response = success(data); response.setMessage(message); 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); response.setPagination(null); return response; } // 内部类:封装分页详情 @Data public static class Pagination { private int pageNumber; private int pageSize; private long totalElements; private int totalPages; private boolean first; private boolean last; } }
注:如果不用Lombok的
@Data,手动编写getter/setter即可。
2. 全局响应拦截包装(无侵入式)
通过Spring的ResponseBodyAdvice实现全局响应包装,不用修改现有Controller的返回值:
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.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @ControllerAdvice public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // 可以在这里过滤不需要包装的接口(比如静态资源),默认对所有接口生效 return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 已经是ApiResponse类型,直接返回 if (body instanceof ApiResponse) { return body; } // 返回null的情况,包装成空数据的成功响应 if (body == null) { return ApiResponse.success(null); } // 其他类型统一包装成成功响应 return ApiResponse.success(body); } }
3. 全局异常统一处理
为了让异常也返回统一格式,添加全局异常处理器:
import org.springframework.http.HttpStatus; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @RestControllerAdvice public class GlobalExceptionHandler { // 处理自定义业务异常 @ExceptionHandler(CustomException.class) public ApiResponse<Void> handleCustomException(CustomException e) { return ApiResponse.error(e.getCode(), e.getMessage()); } // 处理通用系统异常 @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ApiResponse<Void> handleSystemException(Exception e) { // 生产环境建议隐藏具体异常信息,返回通用提示 return ApiResponse.error(500, "服务器内部错误"); } // 处理参数校验异常 @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public ApiResponse<Void> handleParamException(MethodArgumentNotValidException e) { String errorMsg = e.getBindingResult().getFieldErrors().stream() .map(err -> err.getField() + ": " + err.getDefaultMessage()) .findFirst() .orElse("参数格式错误"); return ApiResponse.error(400, errorMsg); } }
对应的自定义业务异常类:
public class CustomException extends RuntimeException { private int code; public CustomException(int code, String message) { super(message); this.code = code; } public int getCode() { return code; } }
4. 现有Controller无需修改
你的原Controller可以保持不变,比如:
@RestController @RequestMapping("/api/contacts") public class ContactController { @Autowired private ContactRepository contactRepository; @GetMapping public Page<Contact> getContacts(Pageable pageable) { return contactRepository.findAll(pageable); } }
最终效果
请求http://localhost:8080/api/contacts会返回如下统一格式的响应:
{ "code": 200, "message": "请求成功", "data": [ { "id": 10, "name": "raj" } ], "pagination": { "pageNumber": 0, "pageSize": 10, "totalElements": 1, "totalPages": 1, "first": true, "last": true } }
你可以根据业务需求调整ApiResponse的字段(比如添加时间戳、请求ID等),或者优化分页信息的内容。
内容的提问来源于stack exchange,提问作者thirumalairaj
相关产品推荐
相关产品推荐

