springBoot项目设置统一响应返回

本文探讨了RESTful API的设计原则,重点介绍了JSON作为数据交换格式的优势,并提出了一种统一的响应格式,包括状态码、消息和数据字段。此外,还提供了一个枚举类来管理全局的状态码,以确保API响应的一致性和易于维护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.格式选择
返回格式目前主流的应该只有XML、JSON两种吧,这里我们不做对比,我们使用JSON作为接口的返回格式。

二.数据返回格式
数据的返回格式其实是个比较纠结的问题,在restful风格中很多文章都讲解使用的是http状态码控制请求的结果状态,例如:http状态码为200~300的时候,为正常状态,response响应体即为所需要返回的数据,404时代表没有查询到数据,响应体即为空,500为系统错误,响应体也为空等等,但是这种方式也是存在很大问题的,一是http状态码是有限的,而且每个状态码都已经被赋予特殊的含义,在企业开发中当接口遇到错误的时候,我们可能更希望将结果状态码标记的更为详细,更利于前端开发者使用,毕竟写接口的目的也是方便前端使用,这样也可以降低前后端开发人员沟通成本。
下面给出我们在实际开发中使用的返回值统一格式:

package com.zhuma.demo.comm.result;
import java.io.Serializable;
import com.zhuma.demo.comm.enums.ResultCode;

/**
 * Created by zhumaer on 17/5/24.
 */
 @Data
public class Result implements Serializable {

	private static final long serialVersionUID = -3948389268046368059L;

	private Integer code;

	private String msg;

	private Object data;

	public Result() {}

	public Result(Integer code, String msg) {
		this.code = code;
		this.msg = msg;
	}

	public static Result success() {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		return result;
	}

	public static Result success(Object data) {
		Result result = new Result();
		result.setResultCode(ResultCode.SUCCESS);
		result.setData(data);
		return result;
	}

	public static Result failure(ResultCode resultCode) {
		Result result = new Result();
		result.setResultCode(resultCode);
		return result;
	}

	public static Result failure(ResultCode resultCode, Object data) {
		Result result = new Result();
		result.setResultCode(resultCode);
		result.setData(data);
		return result;
	}

	public void setResultCode(ResultCode code) {
		this.code = code.code();
		this.msg = code.message();
	}
}

备注:
上面代码我们注意到其中引入了一个ResultCode枚举类,该类也是我们后面紧接着要说的,全局统一返回状态码。
这里说明下字段data不是在code=1为成功的时候才会有值哦,比如当code为参数无效错误时,data可以放入更详细的错误描述,用于指明具体是哪个参数为什么导致的无效的。

三.全局状态码
当你发现你的系统中错误码随意定义,没有任何规范的时候,你应该考虑下使用一个枚举全局管理下你的状态码,这对线上环境定位错误问题和后续接口文档的维护都是很有帮助的。
下面我们在给出一个完整版代码示例,用于参考:

package com.zhuma.demo.comm.enums;

import java.util.ArrayList;
import java.util.List;

/**
 * API 统一返回状态码
 * Created by zhumaer on 17/5/24.
 */
public enum ResultCode {

	/* 成功状态码 */
	SUCCESS(1, "成功"),

	/* 参数错误:10001-19999 */
	PARAM_IS_INVALID(10001, "参数无效"),
	PARAM_IS_BLANK(10002, "参数为空"),
	PARAM_TYPE_BIND_ERROR(10003, "参数类型错误"),
	PARAM_NOT_COMPLETE(10004, "参数缺失"),

	/* 用户错误:20001-29999*/
	USER_NOT_LOGGED_IN(20001, "用户未登录"),
	USER_LOGIN_ERROR(20002, "账号不存在或密码错误"),
	USER_ACCOUNT_FORBIDDEN(20003, "账号已被禁用"),
	USER_NOT_EXIST(20004, "用户不存在"),
	USER_HAS_EXISTED(20005, "用户已存在"),

	/* 业务错误:30001-39999 */
	SPECIFIED_QUESTIONED_USER_NOT_EXIST(30001, "某业务出现问题"),

	/* 系统错误:40001-49999 */
	SYSTEM_INNER_ERROR(40001, "系统繁忙,请稍后重试"),

	/* 数据错误:50001-599999 */
	RESULE_DATA_NONE(50001, "数据未找到"),
	DATA_IS_WRONG(50002, "数据有误"),
	DATA_ALREADY_EXISTED(50003, "数据已存在"),

	/* 接口错误:60001-69999 */
	INTERFACE_INNER_INVOKE_ERROR(60001, "内部系统接口调用异常"),
	INTERFACE_OUTTER_INVOKE_ERROR(60002, "外部系统接口调用异常"),
	INTERFACE_FORBID_VISIT(60003, "该接口禁止访问"),
	INTERFACE_ADDRESS_INVALID(60004, "接口地址无效"),
	INTERFACE_REQUEST_TIMEOUT(60005, "接口请求超时"),
	INTERFACE_EXCEED_LOAD(60006, "接口负载过高"),

	/* 权限错误:70001-79999 */
	PERMISSION_NO_ACCESS(70001, "无访问权限");

	private Integer code;

	private String message;

	ResultCode(Integer code, String message) {
		this.code = code;
		this.message = message;
	}

	public Integer code() {
		return this.code;
	}

	public String message() {
		return this.message;
	}

	public static String getMessage(String name) {
		for (ResultCode item : ResultCode.values()) {
			if (item.name().equals(name)) {
				return item.message;
			}
		}
		return name;
	}

	public static Integer getCode(String name) {
		for (ResultCode item : ResultCode.values()) {
			if (item.name().equals(name)) {
				return item.code;
			}
		}
		return null;
	}

	@Override
	public String toString() {
		return this.name();
	}

	//校验重复的code值
	public static void main(String[] args) {
		ResultCode[] ApiResultCodes = ResultCode.values();
		List<Integer> codeList = new ArrayList<Integer>();
		for (ResultCode ApiResultCode : ApiResultCodes) {
			if (codeList.contains(ApiResultCode.code)) {
				System.out.println(ApiResultCode.code);
			} else {
				codeList.add(ApiResultCode.code());
			}
		}
	}
}

备注:
上述例子中我们对状态码做了一个大的类型上的划分,在实际开发中你可以在后面写你更加详细的错误状态

<think>嗯,用户问的是在Spring Boot项目中如何设计统一响应体类。这个问题应该是关于后端开发的,特别是RESTful API的设计。我需要先回想一下常见的做法。 首先,统一响应体的目的是为了让前端或其他客户端接收到结构一致的响应,方便处理。通常包含状态码、消息、数据这几个部分。可能需要考虑成功和失败的情况,所以状态码应该有成功和错误的区分。 那怎么开始设计这个类呢?可能需要一个泛型类,因为返回的数据类型可能不同。比如,有的接口返回用户信息,有的返回列表,泛型可以灵活处理。然后,状态码可以用枚举来定义,这样更规范。比如,定义一个ResultCode枚举,包含code和message字段。 接下来,响应体类可能包含code、message、data这三个字段。然后提供一些静态方法方便创建成功或失败的响应对象。比如success(data)返回code 200,message“成功”,以及data。而fail的话,可能传入错误码和错误信息,或者直接使用预定义的枚举。 另外,可能还需要考虑分页的情况,如果有分页数据,可以在data里包含列表和总条数等信息。这时候可以再设计一个分页响应类,包含items和total,然后作为data的一部分。 还有,是否要处理异常情况?比如全局异常处理,捕获异常后返回统一的错误格式。这时候响应体类可能需要支持传入异常信息,并转换为对应的错误码和消息。 可能用户还希望知道如何在实际Controller中使用这个响应体。比如,原本返回User对象的方法,现在应该返回ResponseResult<User>,或者通过注解自动包装。不过Spring Boot中更常见的做法是使用@RestControllerAdvice配合ResponseBodyAdvice接口来自动包装返回值,这样Controller可以直接返回数据对象,由全局处理类封装成统一响应体。 但用户的问题可能更偏向于响应体类的结构设计,而不是自动包装的实现。所以重点还是放在类的定义上,包括字段、构造方法、静态工厂方法等。 需要考虑是否提供链式调用的方法,比如builder模式,但静态方法可能更简洁。比如ResponseResult.success().code(200).message("成功").data(user).build(),但使用静态方法如ResponseResult.ok(data)可能更方便。 另外,是否需要序列化的问题,比如字段命名用下划线还是驼峰,可能用@JsonInclude来忽略null值,避免返回空字段。 总结一下步骤:定义枚举类管理状态码,设计泛型响应体类包含code、message、data,提供静态方法创建成功和失败对象,处理分页情况,可能配合全局异常处理返回错误信息。 可能用户还不太清楚如何具体编码,所以需要给出示例代码,包括类定义、枚举、以及使用示例。比如: public class ResponseResult<T> { private int code; private String message; private T data; // 构造方法、getter/setter public static <T> ResponseResult<T> success(T data) { return new ResponseResult<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); } // 其他静态方法 } 然后枚举类定义SUCCESS和ERROR等状态。同时,可以提到分页的情况,比如PageResult类包含数据和总数。 最后,在Controller中的使用示例,返回ResponseResult.success(userService.getUserById(id))。 可能还需要提到和Swagger等文档工具的整合,确保生成的文档显示正确的响应模型。 另外,是否需要考虑国际化?可能消息字段需要根据语言环境变化,但统一响应体可能暂时不需要处理,除非用户特别要求。 总之,关键点包括:使用泛型、状态码枚举、静态工厂方法、分页处理,以及可能的全局异常处理配合。</think>在Spring Boot项目中设计统一响应体类时,可通过以下步骤实现标准化响应结构: --- ### 一、基础响应体设计(核心三要素) ```java public class R<T> { private Integer code; // 状态码 private String msg; // 描述信息 private T data; // 业务数据(泛型) // 成功响应(无数据) public static <T> R<T> ok() { return new R<>(200, "操作成功", null); } // 成功响应(带数据) public static <T> R<T> ok(T data) { return new R<>(200, "操作成功", data); } // 失败响应 public static <T> R<T> fail(int code, String msg) { return new R<>(code, msg, null); } // 构造器(建议保留全参构造) public R(int code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } // getters/setters省略(需补充完整) } ``` --- ### 二、状态码枚举管理(规范错误码) ```java public enum ResultCode { SUCCESS(200, "成功"), BAD_REQUEST(400, "参数错误"), UNAUTHORIZED(401, "未授权"), FORBIDDEN(403, "禁止访问"), NOT_FOUND(404, "资源不存在"), INTERNAL_ERROR(500, "服务器内部错误"); private final int code; private final String message; // 构造器 + getters } ``` --- ### 三、分页数据扩展设计 ```java public class PageResult<T> { private List<T> list; // 当前页数据 private Long total; // 总记录数 private Integer pageNum; // 当前页码 private Integer pageSize; // 每页数量 // 构造器 + getters/setters } // 使用示例 R<PageResult<User>> pageResult = R.ok(new PageResult<>(userList, total)); ``` --- ### 四、全局异常处理(统一错误响应) ```java @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public R<Void> handleException(Exception e) { return R.fail(ResultCode.INTERNAL_ERROR.getCode(), e.getMessage()); } @ExceptionHandler(MethodArgumentNotValidException.class) public R<Void> handleValidationException(MethodArgumentNotValidException ex) { String errorMsg = ex.getBindingResult() .getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(", ")); return R.fail(ResultCode.BAD_REQUEST.getCode(), errorMsg); } } ``` --- ### 五、实际使用示例 ```java @GetMapping("/users/{id}") public R<User> getUser(@PathVariable Long id) { User user = userService.getById(id); return user != null ? R.ok(user) : R.fail(ResultCode.NOT_FOUND); } @PostMapping("/users") public R<Void> createUser(@Valid @RequestBody UserDTO dto) { userService.create(dto); return R.ok(); } ``` --- ### 六、Swagger集成展示 ```java @Schema(description = "统一响应实体") public class R<T> { @Schema(description = "状态码", example = "200") private Integer code; @Schema(description = "提示信息", example = "操作成功") private String msg; @Schema(description = "业务数据") private T data; } ``` --- ### 设计要点总结 1. **标准化结构**:固定`code-msg-data`三要素,前端无需处理不同格式 2. **类型安全**:使用泛型保持数据类型一致性 3. **错误码统一管理**:通过枚举避免硬编码 4. **异常处理**:全局捕获异常生成标准错误响应 5. **扩展性**:支持分页等复杂数据结构 6. **文档友好**:结合Swagger生成清晰API文档 建议通过`ResponseBodyAdvice`实现自动包装响应,避免每个Controller方法手动返回`R<T>`对象,保持代码简洁性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值