java提供统一接口封装_SpringBoot接口封装统一返回格式

本文介绍了如何在SpringBoot中实现接口的统一返回格式,通过定义`ResultCode`枚举处理状态码,创建`Result`数据传输对象封装返回内容,并利用`ResponseBodyAdvice`接口进行响应拦截和转换,从而简化接口方法的编写,确保返回信息的标准化。
摘要由CSDN通过智能技术生成

springboot技术内幕架构设计与实现

53.1元

包邮

(需用券)

去购买 >

940fafc1c5689762200b13267e0e004b.png

前几天搬砖的时候,发现所有接口方法都定义了一样的返回值,不能真正地将业务逻辑表达出来,没有达到“望文生意”的效果。着手改造一下。

虽然标题是Spring Boot,但是这个接口在包spring-webmvc.jar下(请原谅我这个标题党)。ResponseBodyAdvice接口类路径:

org.springframework.web.servlet.mvc.method.annotation

首先,我们需要定义一个统一的状态码ResultCode,来统一工程中异常情况的描述:

/**

* 统一状态返回码

* 三级状态码不满足时,可返回二级宏观码,依次类推

* 状态码参考 alibaba 《JAVA开发手册-泰山版》

*/

public enum ResultCode {

OK("00000", "成功"),

/** 一级宏观错误码 */

CLIENT_ERROR("A0001", "用户端错误 "),

/** 二级宏观错误码 */

USER_REGISTER_ERROR("A0100", "用户注册错误"),

USER_DISAGREE_PRIVACY_PROTOCOL("A0101", "用户未同意隐私协议"),

REGION_REGISTER_LIMITED("A0102","注册国家或地区受限"),

VALIDATE_USERNAME_FAILED("A0110","用户名校验失败"),

USERNAME_EXISTED("A0111","用户名已存在"),

/* 中间还有好多,鉴于篇幅,就不贴出来了 */

MAIL_NOTICE_FAILED("C0503", "邮件提醒服务失败");

private String status;

private String message;

ResultCode(String status, String message) {

this.status = status;

this.message = message;

}

public String getStatus() {

return status;

}

public void setStatus(String status) {

this.status = status;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

@Override

public String toString() {

return "ResultCode{" +

"status='" + status + '\'' +

", message='" + message + '\'' +

'}';

}

}

枚举的好处我就不多说了,想必大家也经常使用HttpStatus这个枚举。

其次,我们封装一个数据传输对象Result,这个类就用来封装我们统一的返回格式:

import com.jason.enums.ResultCode;

import com.fasterxml.jackson.annotation.JsonView;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

import org.springframework.data.domain.Page;

import java.util.Collection;

import java.util.HashMap;

import java.util.Map;

/**

* 统一返回DTO

* 通过 JsonView 尽可能控制返回格式的精简,酌情使用

*/

@ApiModel

public class Result {

public interface commonResult{};

public interface standardResult extends commonResult{};

@ApiModelProperty(value = "status", name = "响应状态码")

private String status;

@ApiModelProperty(value = "message", name = "响应信息")

private String message;

@ApiModelProperty(value = "body", name = "响应内容")

private Object body;

public Result() {

this.status = ResultCode.OK.getStatus();

this.message = ResultCode.OK.getMessage();

}

public Result(ResultCode resultCode) {

this.status = resultCode.getStatus();

this.message = resultCode.getMessage();

}

public Result(ResultCode resultCode, String message) {

this(resultCode);

this.message = message;

}

public Result(Object body) {

this.status = ResultCode.OK.getStatus();

this.message = ResultCode.OK.getMessage();

this.body = body;

}

public Result(ResultCode resultCode, Object body) {

this(body);

this.status = resultCode.getStatus();

this.message = resultCode.getMessage();

}

public Result(Collection collection) {

this.status = ResultCode.OK.getStatus();

this.message = ResultCode.OK.getMessage();

this.body = collection;

}

public Result(ResultCode resultCode, Collection collection) {

this(collection);

this.status = resultCode.getStatus();

this.message = resultCode.getMessage();

}

public Result(Page page) {

this.status = ResultCode.OK.getStatus();

this.message = ResultCode.OK.getMessage();

Map info = new HashMap<>(8);

info.put("totalItem", page.getTotalElements());

info.put("pageSize", page.getNumber());

info.put("pageNum", page.getSize());

info.put("totalPage", page.getTotalPages());

info.put("item", page.getTotalElements());

this.body = info;

}

public Result(ResultCode resultCode, Page page) {

this(page);

this.status = resultCode.getStatus();

this.message = resultCode.getMessage();

}

@JsonView(commonResult.class)

public String getStatus() {

return status;

}

public void setStatus(String status) {

this.status = status;

}

@JsonView(commonResult.class)

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

@JsonView(standardResult.class)

public Object getBody() {

return body;

}

public void setBody(Object body) {

this.body = body;

}

@Override

public String toString() {

return "Result{" +

"status='" + status + '\'' +

", message='" + message + '\'' +

", body=" + body +

'}';

}

}

这个类每个人定义的方式不一样,包括构造方法或者是否用static修饰,大家都可以根据自身情况实现。

最后,我们再实现接口ResponseBody,可以根据一些条件来控制:

import com.jason.dto.Result;

import com.jason.enums.ResultCode;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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;

/**

* 统一返回对象配置类

* create by Jason

*/

@ControllerAdvice

public class ResultBodyConfig implements ResponseBodyAdvice {

private Logger logger = LoggerFactory.getLogger(this.getClass());

private final static String PACKAGE_PATH = "com.jason.component";

/**

* 针对以下情况 不做 统一包装处理

* 1.返回值为 void 的方法

* 2.返回值为 String 类型的方法

* 3.返回值为 Result 类型的方法

* 4.在包路径 PACKAGE_PATH 以外的方法

* @param methodParameter

* @param aClass

* @return

*/

@Override

public boolean supports(MethodParameter methodParameter, Class extends HttpMessageConverter>> aClass) {

return !methodParameter.getMethod().getReturnType().isAssignableFrom(Void.TYPE)

&& !methodParameter.getMethod().getReturnType().isAssignableFrom(String.class)

&& !methodParameter.getMethod().getReturnType().isAssignableFrom(Result.class)

&& methodParameter.getDeclaringClass().getPackage().getName().contains(PACKAGE_PATH);

}

@Override

public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

if (body instanceof Result) {

return body;

}

return new Result(ResultCode.OK, body);

}

}

方法supports返回true则会执行beforeBodyWrite方法,否则会跳过,继续按照原来接口方法的返回值进行返回。

这里谈一下我过滤这些条件的想法:

返回值为 Void 的方法:返回值为void,嗯。

返回值为 String 的方法: 在SpringMVC中我们会返回字符串来匹配模板,虽然现在都是前后端分离的项目,但是还是按照约定俗成或者是第一反应,将String排除。

返回 Result 的方法:我们已经做了封装,不需要在封装一次了。

不在指定包路径下的方法:用来规避其他组件,比如Swagger。

经过以上这种处理,我们在写接口的时候就可以放心大胆的定义业务需要的返回值了,真正的实现了接口方法就可以描述业务的初衷。

除了这种方式,大家还可以通过过滤器来实现这个功能,这里就不做说明了。

java 11官方入门(第8版)教材

79.84元

包邮

(需用券)

去购买 >

f0f3f55624fb396b1764d42d6df88864.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值