最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【天天时快讯】springboot统一响应实体封装+统一异常类管理

来源:博客园

前言:

在日常前后端分离的接口开发过程中,需要我们按相应的格式给前端返回响应的数据,常见的方式就是我们后端自己封装一个包装类,每次返回给前端数据的时候都需要我们自己手动构建一。


(相关资料图)

短时间内来看或许并没有什么,但是一旦接口量变大,我们每个接口都去构建返回值的话,那样就会浪费我们很多的开发时间,所以我们就可以对响应的内容进行统一的处理,在写Controller中的方法时我们也可以不用统一返回类型了。例如:

@ApiOperation(value = "分页查询告警信息")    @PostMapping("findAlarmByPage")    public PageInfo selectAll(@RequestBody AlarmReqVo alarmReqVo) {        return towerAlarmInfoService.findByPage(alarmReqVo);    }

这样可以让我们减少很多的工作量。 可能有的朋友就会问:那我们的非空验证可一些异常的处理怎么办呢? 下面介绍的就是统一的异常类型管理。把我们后端所有能发生的异常进行统一的封装(可以自定义一个异常类型),封装之后再返回给前端相应的提示,那么前端就会清晰的知道后端发生了什么错误,是不是前端的锅哈哈哈哈。

响应实体的封装:

首先肯定我们还是需要建一个统一返回的类:

1 package com.dlxx.tower.app.util;  2   3 import com.fasterxml.jackson.annotation.JsonInclude;  4 import lombok.AllArgsConstructor;  5 import lombok.Data;  6 import lombok.NoArgsConstructor;  7   8 @Data  9 @AllArgsConstructor 10 @NoArgsConstructor 11 //这个注解表示变量为空的时候构造json就不带上这个变量 12 @JsonInclude(JsonInclude.Include.NON_NULL) 13 public class FrontResult { 14     /** 15      * 结果状态码 16      */ 17     private Integer code; 18     /** 19      * 响应结果描述 20      */ 21     private String message; 22     /** 23      * 返回数据 24      */ 25     private Object data; 26  27     public FrontResult(Object data) { 28         this.data = data; 29         this.code = ResultEnum.SUCCESS.getCode(); 30         this.message = "操作成功"; 31     } 32  33     /** 34      * 静态方法,返回前端实体结果 35      * 36      * @param code    状态码 37      * @param message 消息 38      * @param data    数据 39      * @return 前端实体结果 40      */ 41     public static FrontResult build(Integer code, String message, Object data) { 42         return new FrontResult(code, message, data); 43     } 44  45     /** 46      * 返回成功的结果实体 47      * 48      * @param message 消息 49      * @param data    数据 50      * @return 实体 51      */ 52     public static FrontResult getSuccessResult(String message, Object data) { 53         FrontResult result = new FrontResult(); 54         result.code = ResultEnum.SUCCESS.getCode(); 55         result.message = message; 56         result.data = data; 57         return result; 58     } 59  60     /** 61      * 返回无需data的成功结果实体 62      * 63      * @param message 消息内容 64      * @return 返回结果 65      */ 66     public static FrontResult getSuccessResultOnlyMessage(String message) { 67         FrontResult result = new FrontResult(); 68         result.code = ResultEnum.SUCCESS.getCode(); 69         result.message = message; 70         result.data = null; 71         return result; 72     } 73  74     /** 75      * 获取一个异常结果 76      * 77      * @param code    错误码 78      * @param message 自定义异常信息 79      * @return FrontResult 80      */ 81     public static FrontResult getExceptionResult(Integer code, String message) { 82         FrontResult result = new FrontResult(); 83         result.code = (code == null) ? ResultEnum.CODE_EXCEPTION.getCode() : code; 84         result.message = message.isEmpty() ? ResultEnum.CODE_EXCEPTION.getMsg() : message; 85         return result; 86     } 87  88     /** 89      * 得到异常结果 90      * 91      * @param resultEnum 枚举结果代码 92      * @return {@link FrontResult} 93      */ 94     public static FrontResult getExceptionResult(ResultEnum resultEnum) { 95         FrontResult result = new FrontResult(); 96         Integer code = resultEnum.getCode(); 97         String msg = resultEnum.getMsg(); 98         result.code = (code == null) ? ResultEnum.CODE_EXCEPTION.getCode() : code; 99         result.message = msg.isEmpty() ? ResultEnum.CODE_EXCEPTION.getMsg() : msg;100         return result;101     }102 }

统一封装一下枚举类型ResultEnum

import lombok.AllArgsConstructor;/** * 结果枚举 * * @author longjun * @date 2023/04/11 */@AllArgsConstructorpublic enum ResultEnum {    /**     * 成功     */    SUCCESS(200, "操作成功"),    /**     * 代码异常     */    CODE_EXCEPTION(500, "后端代码内部异常"),    /**     * 参数错误     */    PARAMETER_ERROR(999, "前端入参异常"),    /**     * 失败     */    FAIL(1111, "后端代码异常异常"),    /**     * 空点     */    NULL_POINT(1000, "空指针异常"),    /**     * 指数误差     */    OUT_OF_INDEX_ERROR(1001, "索引越界异常"),    /**     * 模型零     */    MODEL_NULL(1002, "前端入参实体的实体为空"),    /**     * 数据库错误     */    DATABASE_ERROR(1003, "数据库异常"),    /**     * 身份验证错误     */    AUTHENTICATION_ERROR(1004, "身份验证异常"),    /**     * 逻辑错误     */    LOGIC_ERROR(1005, "业务逻辑异常"),    /**     * 类没有找到     */    CLASS_NOT_FOUND(1006, "类未找到异常"),    /**     * sql异常     */    SQL_EXCEPTION(1007, "sql语句异常"),    /**     * io例外     */    IO_EXCEPTION(1008, "io异常"),    /**     * json解析错误     */    JSON_PARSE_ERROR(1009, "json转换异常"),    NUMBER_FORMAT_ERROR(1010, "String转换为数字错误"),    /**     * 更新失败     */    UPDATE_FAIL(1011, "更新失败"),    /**     * 发送POST错误     */    SEND_POST_ERROR(1012, "发送POST请求异常"),    /**     * 短信发送错误     */    SMS_SEND_ERROR(1013, "短信发送失败");    /**     * 状态码     */    private Integer code;    public Integer getCode() {        return code;    }    ResultEnum(Integer code) {        this.code = code;    }    private String msg;    public String getMsg() {        return msg;    }}  

基本的类型封装好了,接下来就是重头戏,关键代码也在这里。主要就是实现了ResponseBodyAdvice接口,其实是对加了@RestController(也就是@Controller+@ResponseBody)注解的处理器将要返回的值进行增强处理。

其实也就是采用了AOP的思想,对返回值进行一次修改。

该接口一共有两个方法:

(1)supports ——判断是否要执行beforeBodyWrite方法,true为执行,false不执行 —— 通过supports方法,我们可以选择哪些类或哪些方法要对response进行处理,其余的则不处理。

(2)beforeBodyWrite —— 对 response 处理的具体执行方法。

1 package com.dlxx.tower.app.config; 2  3 import com.dlxx.tower.app.exception.BizException; 4 import com.dlxx.tower.app.util.FrontResult; 5 import com.fasterxml.jackson.core.JsonProcessingException; 6 import com.fasterxml.jackson.databind.ObjectMapper; 7 import org.springframework.core.MethodParameter; 8 import org.springframework.http.MediaType; 9 import org.springframework.http.converter.HttpMessageConverter;10 import org.springframework.http.server.ServerHttpRequest;11 import org.springframework.http.server.ServerHttpResponse;12 import org.springframework.web.bind.annotation.RestControllerAdvice;13 import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;14 15 /**16  * 响应控制器建议17  *18  * @author longjun19  * @description: 全局处理增强版Controller,避免Controller里返回数据每次都要用响应体来包装20  *21  * @date 2023/04/0422  */23 @RestControllerAdvice(basePackages = {"com.dlxx.tower.app.controller"})24 public class ResponseControllerAdvice implements ResponseBodyAdvice {25     @Override26     public boolean supports(MethodParameter returnType, Class> aClass) {27         // 如果接口返回的类型本身就是ResultVO那就没有必要进行额外的操作,返回false28         return !returnType.getGenericParameterType().equals(FrontResult.class);29     }30 31     @Override32     public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {33         // String类型不能直接包装,所以要进行些特别的处理34         if (returnType.getGenericParameterType().equals(String.class)) {35             ObjectMapper objectMapper = new ObjectMapper();36             try {37                 // 将数据包装在ResultVO里后,再转换为json字符串响应给前端38                 return objectMapper.writeValueAsString(new FrontResult(data));39             } catch (JsonProcessingException e) {40                 throw new BizException();41             }42         }43         // 将原本的数据包装在ResultVO里44         return new FrontResult(data);45     }46 }View Code

这样基本上就可以对返回值进行统一封装了,下面就开始介绍全局异常;

统一异常处理:

首先自定义一个异常类型

1 package com.dlxx.tower.app.exception; 2  3 import com.dlxx.tower.app.util.FrontResult; 4 import com.dlxx.tower.app.util.ResultEnum; 5  6 /** 7  * 业务异常 8  * 自定义一个异常类,用于处理我们发生的业务异常 9  *10  * @author longjun11  * @version 1.0.012  * @date 2023/04/0413  */14 public class BizException extends RuntimeException {15 16     private static final long serialVersionUID = 1L;17 18     /**19      * 错误码20      */21     protected Integer errorCode;22     /**23      * 错误信息24      */25     protected String errorMsg;26 27     public BizException() {28         super();29     }30 31     public BizException(FrontResult errorInfoInterface) {32         super(errorInfoInterface.getCode().toString());33         this.errorCode = errorInfoInterface.getCode();34         this.errorMsg = errorInfoInterface.getMessage();35     }36 37     public BizException(FrontResult errorInfoInterface, Throwable cause) {38         super(errorInfoInterface.getCode().toString(), cause);39         this.errorCode = errorInfoInterface.getCode();40         this.errorMsg = errorInfoInterface.getMessage();41     }42 43     public BizException(String errorMsg) {44         super(errorMsg);45         this.errorMsg = errorMsg;46     }47 48     public BizException(Integer errorCode, String errorMsg) {49         super(String.valueOf(errorCode));50         this.errorCode = errorCode;51         this.errorMsg = errorMsg;52     }53 54     public BizException(ResultEnum resultEnum) {55         super(String.valueOf(resultEnum.getCode()));56         this.errorCode = resultEnum.getCode();57         this.errorMsg = resultEnum.getMsg();58     }59 60     public BizException(Integer errorCode, String errorMsg, Throwable cause) {61         super(String.valueOf(errorCode), cause);62         this.errorCode = errorCode;63         this.errorMsg = errorMsg;64     }65 66 67     public Integer getErrorCode() {68         return errorCode;69     }70 71     public void setErrorCode(Integer errorCode) {72         this.errorCode = errorCode;73     }74 75     public String getErrorMsg() {76         return errorMsg;77     }78 79     public void setErrorMsg(String errorMsg) {80         this.errorMsg = errorMsg;81     }82 83     @Override84     public String getMessage() {85         return errorMsg;86     }87 88     @Override89     public Throwable fillInStackTrace() {90         return this;91     }92 93 }
View Code

然后就是异常处理类

1 package com.dlxx.tower.app.config;  2   3 import com.dlxx.tower.app.exception.BizException;  4 import com.dlxx.tower.app.util.FrontResult;  5 import com.dlxx.tower.app.util.ResultEnum;  6 import com.fasterxml.jackson.core.JsonParseException;  7 import lombok.extern.slf4j.Slf4j;  8 import org.springframework.http.converter.HttpMessageNotReadableException;  9 import org.springframework.web.bind.annotation.ExceptionHandler; 10 import org.springframework.web.bind.annotation.ResponseBody; 11 import org.springframework.web.bind.annotation.RestControllerAdvice; 12  13 import javax.servlet.http.HttpServletRequest; 14 import java.io.IOException; 15 import java.sql.SQLException; 16  17 /** 18  * 全局异常处理程序 19  * 

20 * 统一异常处理 21 * 使用该注解表示开启了全局异常的捕获 22 * 23 * @author longjun 24 * @version 1.0.0 25 * @date 2023/04/04 26 */ 27 @RestControllerAdvice 28 @Slf4j 29 public class GlobalExceptionHandler { 30 31 /** 32 * 处理自定义的业务异常 33 * 34 * @param req 35 * @param e 36 * @return 37 */ 38 @ExceptionHandler(value = BizException.class) 39 @ResponseBody 40 public FrontResult bizExceptionHandler(HttpServletRequest req, BizException e) { 41 log.error("URL : " + req.getRequestURL().toString()); 42 log.error("HTTP_METHOD : " + req.getMethod()); 43 log.error("发生业务异常!原因是:{}", e.getErrorMsg()); 44 return FrontResult.getExceptionResult(e.getErrorCode(), e.getErrorMsg()); 45 } 46 47 /** 48 * 处理空指针的异常 49 * 50 * @param req 51 * @param e 52 * @return 53 */ 54 @ExceptionHandler(value = NullPointerException.class) 55 @ResponseBody 56 public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e) { 57 log.error("URL : " + req.getRequestURL().toString()); 58 log.error("HTTP_METHOD : " + req.getMethod()); 59 log.error("发生空指针异常!原因是:", e); 60 return FrontResult.getExceptionResult(ResultEnum.NULL_POINT); 61 } 62 63 64 /** 65 * 处理索引越界异常 66 * 67 * @param req 68 * @param e 69 * @return 70 */ 71 @ExceptionHandler(value = IndexOutOfBoundsException.class) 72 @ResponseBody 73 public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e) { 74 log.error("URL : " + req.getRequestURL().toString()); 75 log.error("HTTP_METHOD : " + req.getMethod()); 76 log.error("索引越界异常!原因是:", e); 77 return FrontResult.getExceptionResult(ResultEnum.OUT_OF_INDEX_ERROR); 78 } 79 80 /** 81 * 处理类未找到异常 82 * 83 * @param req 84 * @param e 85 * @return 86 */ 87 @ExceptionHandler(value = ClassNotFoundException.class) 88 @ResponseBody 89 public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e) { 90 log.error("URL : " + req.getRequestURL().toString()); 91 log.error("HTTP_METHOD : " + req.getMethod()); 92 log.error("发生类未找到异常!原因是:", e); 93 return FrontResult.getExceptionResult(ResultEnum.CLASS_NOT_FOUND); 94 } 95 96 97 /** 98 * 处理SQL异常 99 *100 * @param req101 * @param e102 * @return103 */104 @ExceptionHandler(value = SQLException.class)105 @ResponseBody106 public FrontResult exceptionHandler(HttpServletRequest req, SQLException e) {107 log.error("URL : " + req.getRequestURL().toString());108 log.error("HTTP_METHOD : " + req.getMethod());109 log.error("发生SQL异常!原因是:", e);110 return FrontResult.getExceptionResult(ResultEnum.SQL_EXCEPTION);111 }112 113 /**114 * 处理IO异常115 *116 * @param req117 * @param e118 * @return119 */120 @ExceptionHandler(value = IOException.class)121 @ResponseBody122 public FrontResult exceptionHandler(HttpServletRequest req, IOException e) {123 log.error("URL : " + req.getRequestURL().toString());124 log.error("HTTP_METHOD : " + req.getMethod());125 log.error("发生IO异常!原因是:", e);126 return FrontResult.getExceptionResult(ResultEnum.IO_EXCEPTION);127 }128 129 130 /**131 * json转换异常处理程序132 *133 * @param req 要求事情134 * @param e e135 * @return {@link FrontResult}136 */137 @ExceptionHandler(value = JsonParseException.class)138 @ResponseBody139 public FrontResult exceptionHandler(HttpServletRequest req, JsonParseException e) {140 log.error("URL : " + req.getRequestURL().toString());141 log.error("HTTP_METHOD : " + req.getMethod());142 log.error("发生JSON转换异常!原因是:", e);143 return FrontResult.getExceptionResult(ResultEnum.JSON_PARSE_ERROR);144 }145 146 /**147 * String转数字异常处理程序148 *149 * @param req 要求事情150 * @param e e151 * @return {@link FrontResult}152 */153 @ExceptionHandler(value = NumberFormatException.class)154 @ResponseBody155 public FrontResult exceptionsHandler(HttpServletRequest req, NumberFormatException e) {156 log.error("URL : " + req.getRequestURL().toString());157 log.error("HTTP_METHOD : " + req.getMethod());158 log.error("发生String转数字异常!原因是:", e);159 return FrontResult.getExceptionResult(ResultEnum.NUMBER_FORMAT_ERROR);160 }161 162 /**163 * 前端参数不匹配异常处理程序164 *165 * @param req 要求事情166 * @param e e167 * @return {@link FrontResult}168 */169 @ExceptionHandler(value = HttpMessageNotReadableException.class)170 @ResponseBody171 public FrontResult exceptionsHandler(HttpServletRequest req, HttpMessageNotReadableException e) {172 log.error("URL : " + req.getRequestURL().toString());173 log.error("HTTP_METHOD : " + req.getMethod());174 log.error("发生前端参数不匹配异常!原因是:", e);175 return FrontResult.getExceptionResult(ResultEnum.PARAMETER_ERROR);176 }177 178 /**179 * 处理其他异常180 *181 * @param req182 * @param e183 * @return184 */185 @ExceptionHandler(value = Exception.class)186 @ResponseBody187 public FrontResult exceptionHandler(HttpServletRequest req, Exception e) {188 log.error("URL : " + req.getRequestURL().toString());189 log.error("HTTP_METHOD : " + req.getMethod());190 log.error("未知异常!原因是:", e);191 return FrontResult.getExceptionResult(ResultEnum.FAIL);192 }193 194 195 }

View Code

这里就已经可以实现这两个功能了

需要我们触发异常的时候就可以直接这样用

throw new BizException(ResultEnum.AUTHENTICATION_ERROR.getCode(), "验证码校验失败。");

第一个参数就是我们封装的枚举,第二个就是自定义的信息,当然也可以直接用枚举,这些都可以自己修改的。

关键词: