网站建设定制开发baseresponse响应类_SpringBoot统一响应体解决方案

前言

网站建设定制开发最近在优化自己之前基于Spring 网站建设定制开发的统一响应体的实现方案。

网站建设定制开发什么是统一响应体呢?网站建设定制开发在目前的架构下,网站建设定制开发后端主要是一个RESTful API网站建设定制开发的数据接口。

但是HTTP网站建设定制开发的数量有限,而随着业务的增长,HTTP状态码无法很好地表示业务中遇到的异常情况。

那么可以通过修改响应返回的JSON数据,让其带上一些固有的字段,例如以下这样的

{

"code": 10000,

"msg": "success",

"data": {

"id": 2,

"name": "test"

}

}

其中关键属性的用途如下:

code为返回结果的状态码

msg为返回结果的消息

data为返回的业务数据

这3个属性为固有属性,每次响应结果都会有带有它们。

需求

希望实现一个能够代替基于AOP的实现方案,需要满足以下几点:

原有的基于AOP的实现方案需要Controller的返回类型为Object,需要新方案不限制返回类型

原有的基于AOP的实现方案需要通过切面表达式+注解控制切点的Controller(注解的包名修改会导致切面表达式的修改,即需要修改两处地方),需要新方案能够基于注解,而不需要修改切面表达式

方案思路

基于上述的需求,选择使用Spring的Controller增强机制,其中关键的类为以下3个:

@ControllerAdvice:类注解,用于指定Controller增强处理器类。

ResponseBodyAdvice:接口,实现后beforeBodyWrite()方法后可以对响应的body进行修改,需要结合@ControllerAdvice使用。

@ExceptionHandler:方法注解,用于指定异常处理方法,需要结合@ControllerAdvice和@ResponseBody使用。

示例关键代码

本示例使用的Spring Boot版本为2.1.6.RELEASE,同时需要开发工具安装lombok插件

引入依赖

org.springframework.boot

spring-boot-starter-web

org.projectlombok

lombok

true

org.springframework.boot

spring-boot-starter-test

test

统一响应体

Controller增强后统一响应体对应的对象

import lombok.AllArgsConstructor;

import lombok.Data;

import java.io.Serializable;

/**

* 统一的公共响应体

* @author NULL

* @date 2019-07-16

*/

@Data

@AllArgsConstructor

public class ResponseResult implements Serializable {

/**

* 返回状态码

*/

private Integer code;

/**

* 返回信息

*/

private String msg;

/**

* 数据

*/

private Object data;

}

统一响应注解

统一响应注解是一个标记是否开启统一响应增强的注解

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 统一响应注解

* 添加注解后,统一响应体才能生效

* @author NULL

* @date 2019-07-16

*/

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD, ElementType.TYPE})

public @interface BaseResponse {

}

状态码枚举

统一响应体中返回的状态码code和状态信息msg对应的枚举类

/**

* 返回状态码

*

* @author NULL

* @date 2019-07-16

*/

public enum ResponseCode {

/**

* 成功返回的状态码

*/

SUCCESS(10000, "success"),

/**

* 资源不存在的状态码

*/

RESOURCES_NOT_EXIST(10001, "资源不存在"),

/**

* 所有无法识别的异常默认的返回状态码

*/

SERVICE_ERROR(50000, "服务器异常");

/**

* 状态码

*/

private int code;

/**

* 返回信息

*/

private String msg;

ResponseCode(int code, String msg) {

this.code = code;

this.msg = msg;

}

public int getCode() {

return code;

}

public String getMsg() {

return msg;

}

}

业务异常类

业务异常类是用于识别业务相关的异常,需要注意这个异常类强制需要以ResponseCode作为构造方法入参,这样可以通过捕获异常获得返回的状态码信息

import com.rjh.web.response.ResponseCode;

import lombok.Data;

import lombok.EqualsAndHashCode;

/**

* 业务异常类,继承运行时异常,确保事务正常回滚

*

* @author NULL

* @since 2019-07-16

*/

@Data

@EqualsAndHashCode(callSuper = false)

public class BaseException extends RuntimeException{

private ResponseCode code;

public BaseException(ResponseCode code) {

this.code = code;

}

public BaseException(Throwable cause, ResponseCode code) {

super(cause);

this.code = code;

}

}

异常处理类

用于处理Controller运行时未捕获的异常的处理类。

import com.rjh.web.exception.BaseException;

import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

/**

* 异常处理器

*

* @author NULL

* @since 2019-07-16

*/

@ControllerAdvice(annotations = BaseResponse.class)

@ResponseBody

@Slf4j

public class ExceptionHandlerAdvice {

/**

* 处理未捕获的Exception

* @param e 异常

* @return 统一响应体

*/

@ExceptionHandler(Exception.class)

public ResponseResult handleException(Exception e){

log.error(e.getMessage(),e);

return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null);

}

/**

* 处理未捕获的RuntimeException

* @param e 运行时异常

* @return 统一响应体

*/

@ExceptionHandler(RuntimeException.class)

public ResponseResult handleRuntimeException(RuntimeException e){

log.error(e.getMessage(),e);

return new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(),ResponseCode.SERVICE_ERROR.getMsg(),null);

}

/**

* 处理业务异常BaseException

* @param e 业务异常

* @return 统一响应体

*/

@ExceptionHandler(BaseException.class)

public ResponseResult handleBaseException(BaseException e){

log.error(e.getMessage(),e);

ResponseCode code=e.getCode();

return new ResponseResult(code.getCode(),code.getMsg(),null);

}

}

响应增强类

Conrtoller增强的统一响应体处理类,需要注意异常处理类已经进行了增强,所以需要判断一下返回的对象是否为统一响应体对象。

import lombok.extern.slf4j.Slf4j;

import org.springframework.core.MethodParameter;

import org.springframework.http.MediaType;

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;

/**

* 统一响应体处理器

* @author NULL

* @date 2019-07-16

*/

@ControllerAdvice(annotations = BaseResponse.class)

@Slf4j

public class ResponseResultHandlerAdvice implements ResponseBodyAdvice {

@Override

public boolean supports(MethodParameter returnType, Class converterType) {

log.info("returnType:"+returnType);

log.info("converterType:"+converterType);

return true;

}

@Override

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

if(MediaType.APPLICATION_JSON.equals(selectedContentType) || MediaType.APPLICATION_JSON_UTF8.equals(selectedContentType)){ // 判断响应的Content-Type为JSON格式的body

if(body instanceof ResponseResult){ // 如果响应返回的对象为统一响应体,则直接返回body

return body;

}else{

// 只有正常返回的结果才会进入这个判断流程,所以返回正常成功的状态码

ResponseResult responseResult =new ResponseResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),body);

return responseResult;

}

}

// 非JSON格式body直接返回即可

return body;

}

}

使用示例

首先准备一个User对象

import lombok.Data;

import lombok.EqualsAndHashCode;

import java.io.Serializable;

/**

* 用户类

* @author NULL

* @date 2019-07-16

*/

@Data

@EqualsAndHashCode

public class User implements Serializable {

private Integer id;

private String name;

}

然后是准备一个简单的UserController即可

import com.rjh.web.entity.User;

import com.rjh.web.exception.BaseException;

import com.rjh.web.response.BaseResponse;

import com.rjh.web.response.ResponseCode;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

/**

* 测试用的Controller

*

* @author NULL

* @date 2019-07-16

*/

@BaseResponse

@RestController

@RequestMapping("users")

public class UserController {

@GetMapping("/{userId}")

public User getUserById(@PathVariable Integer userId){

if(userId.equals(0)){

throw new BaseException(ResponseCode.RESOURCES_NOT_EXIST);

}

if(userId.equals(1)){

throw new RuntimeException();

}

User user=new User();

user.setId(userId);

user.setName("test");

return user;

}

}

运行结果

在浏览器直接访问http://127.0.0.1:8080/users/0,则返回结果如下(结果经过格式化处理):

{

"code": 10001,

"msg": "资源不存在",

"data": null

}

在浏览器直接访问http://127.0.0.1:8080/users/1,则返回结果如下(结果经过格式化处理):

{

"code": 50000,

"msg": "服务器异常",

"data": null

}

在浏览器直接访问http://127.0.0.1:8080/users/2,则返回结果如下(结果经过格式化处理):

{

"code": 10000,

"msg": "success",

"data": {

"id": 2,

"name": "test"

}

}

由运行结果可以得知统一响应增强其实已经生效了,而且能够很好的处理异常。

示例代码地址

下面是这个示例的代码地址,如果觉得不错或者帮助到你,希望大家给个Star:

https://github.com/spring-bas...

参考资料

相关资源:
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发