自定义参数校验以及统一处理结果集(代码片段)

野生java研究僧 野生java研究僧     2023-02-19     587

关键词:

自定义参数校验以及统一处理结果集

1.引入校验组件

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

更多校验使用方法请参考:java后端参数校验validaction(用法详解)

2.定义统一返回结果

统一返回值类型无论项目前后端是否分离都是非常必要的,方便对接接口的开发人员更加清晰地知道这个接口的调用是否成功(不能仅仅简单地看返回值是否为 null 就判断成功与否,因为有些接口的设计就是如此),使用一个状态码、状态信息就能清楚地了解接口调用情况

@Data
public class ResponseResult<T>  
    private static final long serialVersionUID = 5337617615451873318L;
    /**
     * code 200 表示业务处理成功,-200表示业务处理失败
     *
     * @since 1.0
     **/
    private String code;
    /**
     * 存放业务提示信息
     *
     * @since 1.0
     **/
    private String message;
    /**
     * subCode 10000 表示10000请求成功 -10000表示请求处理失败
     *
     * @since 1.0
     **/

    private String subCode;
    /**
     * 存放系统异常消息
     *
     * @since 1.0
     **/
    private String subMessage;
    /**
     * 存放系统异常具体错误详情
     *
     * @since 1.0
     **/
    private String errorDetails;
    /**
     * 响应时间
     *
     * @since 1.0
     **/
    private String responseTime;
    /**
     * 出错的服务mac地址
     *
     * @since 1.0
     **/
    private String mac;
    /**
     * 预留处理字段
     *
     * @since 1.0
     **/
    private Object option;
    /**
     * 执行时间
     *
     * @since 1.0
     **/
    private Long executeTime;

    /**
     * 响应数据
     *
     * @since 1.0
     **/
    private T data;

    private static final String UNKNOWN_ERROR_CODE = "9999";

    private static final String SUCCESS_CODE = "10000";
    private static final String ERROR_CODE = "0";

    private static final String BUSINESS_SUCCESS = "200";
    private static final String BUSINESS_ERROR = "500";

    private static final String SYSTEM_ERROR_MESSAGE = "系统异常,请联系管理员处理";
    private static final String SYSTEM_SUCCESS_MESSAGE = "服务调用成功";
    private static final String UNKNOWN_ERROR_MESSAGE = "未知异常";


    private ResponseResult() 
    

    private ResponseResult(String code, String message, String subMessage, String subCode, T data, String errorDetails,Long executeTime) 
        this.code = code;
        this.message = message;
        this.subMessage = subMessage;
        this.subCode = subCode;
        this.data = data;
        this.errorDetails = errorDetails;
        // 将日期格式化为:yyyy-MM-dd HH:mm:ss
        this.responseTime = DateTools.format(new Date(), DateTools.DEFAULT_DATETIME_FORMAT);
        String mac = SysTemUtil.getLocalMacAddress(null);
        this.mac = StringUtils.hasLength(mac) ? mac.replaceAll("-", "") : "";
        this.executeTime = executeTime;
    

    private ResponseResult(String code, String message, String subMessage, String subCode, T data, String errorDetails ) 
        this.code = code;
        this.message = message;
        this.subMessage = subMessage;
        this.subCode = subCode;
        this.data = data;
        this.errorDetails = errorDetails;
        // 将日期格式化为:yyyy-MM-dd HH:mm:ss
        this.responseTime = DateTools.format(new Date(), DateTools.DEFAULT_DATETIME_FORMAT);
        String mac = SysTemUtil.getLocalMacAddress(null);
        this.mac = StringUtils.hasLength(mac) ? mac.replaceAll("-", "") : "";
    
    // 构造一个响应结果对象
    public static <E> ResponseResult<E> build(String code, String message, String subMessage, String subCode, E data, String errorDetails) 
        return new ResponseResult<>(code, message, subMessage, subCode, data, errorDetails);

    
    // 简单的成功响应不带返回值
    public static <E> ResponseResult<E> success() 
        return build(BUSINESS_SUCCESS, "", SYSTEM_SUCCESS_MESSAGE, SUCCESS_CODE, null, "");
    
    // 简单的成功响应
    public static <E> ResponseResult<E> success(E data) 
        return build(BUSINESS_SUCCESS, "", SYSTEM_SUCCESS_MESSAGE, SUCCESS_CODE, data, "");
    

    // 简单的成功响应,携带提示信息
    public static <E> ResponseResult<E> success(String message, E data) 
        return build(BUSINESS_SUCCESS, message, SYSTEM_SUCCESS_MESSAGE, SUCCESS_CODE, data, "");
    

    // 简单的失败响应
    public static <E> ResponseResult<E> error(String subMessage) 
        return build(BUSINESS_ERROR, subMessage, SYSTEM_SUCCESS_MESSAGE, SUCCESS_CODE, null, "");
    

    // 系统异常的失败响应
    public static <E> ResponseResult<E> systemError(String errorDetails) 
        return build(BUSINESS_ERROR, SYSTEM_SUCCESS_MESSAGE, SYSTEM_ERROR_MESSAGE, SUCCESS_CODE, null, errorDetails);
    

    // 失败响应写的异常原因
    public static <E> ResponseResult<E> error(String message, String subMessage) 
        return build(BUSINESS_ERROR, message, subMessage, ERROR_CODE, null, "");
    

    // 响应失败,携带数据和提示信息
    public static <E> ResponseResult<E> error(String message, E data) 
        return build(BUSINESS_ERROR, message, SYSTEM_SUCCESS_MESSAGE, ERROR_CODE, data, "");
    

获取本机物理地址的工具方法:

   /**
     * 获取本地mac地址
     * 注意:物理地址是48位,别和ipv6搞错了
     * @param inetAddress
     * @return 本地mac地址
     */
    public static   String getLocalMacAddress(InetAddress inetAddress) 
        if (inetAddress==null)
            try 
                inetAddress = InetAddress.getLocalHost();
             catch (UnknownHostException e) 
                e.printStackTrace();
                throw new RuntimeException("获取主机mac地址失败");
            
        
        try 
            //获取网卡,获取地址
            byte[] mac = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < mac.length; i++) 
                if (i != 0) 
                    sb.append("-");
                
                //字节转换为整数
                int temp = mac[i] & 0xff;
                String str = Integer.toHexString(temp);
                if (str.length() == 1) 
                    sb.append("0").append(str);
                 else 
                    sb.append(str);
                
            
            return sb.toString();
         catch (Exception exception) 
            exception.getMessage();
        
        return "";
    

3.返回值统一包装处理

Spring 中提供了一个类 ResponseBodyAdvice ,能帮助我们实现上述需求

ResponseBodyAdvice 是对 Controller 返回的内容在 HttpMessageConverter 进行类型转换之前拦截,进行相应的处理操作后,再将结果返回给客户端。那这样就可以把统一包装的工作放到这个类里面。

public interface ResponseBodyAdvice<T> 
    boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);

    @Nullable
    T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class<? extends 		HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);

4.@RestControllerAdvice+ResponseBodyAdvice统一处理

import com.springboot.example.bean.ResponseResult;
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.validation.FieldError;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @RestControllerAdvice+@ExceptionHandler 异常处理器的优先级要高,如果那边处理过了是ResponseResult,直接返回
 * 所以建议在 @RestControllerAdvice+@ExceptionHandler进行处理可以获取到完整的错误信息,                 			
 * @RestControllerAdvice+ResponseBodyAdvice适合对所有返回值进行第二次处理,不适合异常消息捕获
 * @author compass
 * @date 2023-02-05
 * @since 1.0
 **/
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> 
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) 
        return true;
    

    @Override
    public Object beforeBodyWrite(Object result, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) 
       try 
           if (result instanceof ResponseResult) 
               return result;
            else if ("error".equals(Objects.requireNonNull(methodParameter.getMethod()).getName())) 
               Map map = (Map) result;
               String path = map.get("path") == null ? "" : map.get("path").toString();
               Object errors = map.get("errors");
               if (errors instanceof List) 
                   List errorList = (List) errors;
                   StringBuilder subMessageBuffer = new StringBuilder();
                   StringBuilder messageBuffer = new StringBuilder();
                   for (Object item : errorList) 
                       if (item instanceof FieldError) 
                           FieldError error = (FieldError) item;
                           String rejectedValue = error.getRejectedValue() + "";
                           String field = error.getField();
                           String message = error.getDefaultMessage();
                           messageBuffer.append("请求路径:").append(path).append(";");
                           messageBuffer.append("校验不通过的字段名:").append(field).append(",")
                                   .append("被拒绝的值:").append(rejectedValue).append(",")
                                   .append("提示信息:").append(message).append(";");
                           subMessageBuffer.append(message).append(",");
                       
                       String message = messageBuffer.toString();
                       String subMessage = subMessageBuffer.toString();
                       subMessage = subMessage.substring(0, subMessage.lastIndexOf(','));
                       return ResponseResult.build("10000", message, subMessage, "500", null, null);
                   
               
               // 处理是 @PathVariable 和 @RequestParam 参数校验
               Object stats = map.get("status");
               if (Integer.valueOf(500).equals(stats)) 
                   String message = "请求路径:"+map.get("path")+";"+map.get("message");
                   String subMessage = map.get("message")+"";
                   return ResponseResult.build("10000", message, subMessage, "500", null, null);
               
           
           return result;
       catch (Exception e)
           e.printStackTrace();
           return ResponseResult.error("系统异常","统一返回值处理失败");
       
    

5.@RestControllerAdvice+@ExceptionHandler处理

在 SpringMVC 中,有一个类是 RequestResponseBodyMethodProcessor,这个类有两个作用

  1. 用于解析 @RequestBody 标注的参数
  2. 处理 @ResponseBody 标注方法的返回值

解析 @RequestBoyd 标注参数的方法是 resolveArgument

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor 
      /**
     * Throws MethodArgument

.netcore统一参数校验异常处理结果返回功能实现(代码片段)

我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的话,代码就不优雅,也不容易维护。所以,我们需要... 查看详情

.netcore统一参数校验异常处理结果返回功能实现(代码片段)

我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的话,代码就不优雅,也不容易维护。所以,我们需要... 查看详情

统一异常处理(代码片段)

...能返回固定的结果,不能说明错误信息。此时可以通过自定义异常,然后统一处理来解决。对于统一异常,通常有四种解决方法,推荐使用第一种或者第四种,分别如下(推荐)方法一:通过配置文件设置异常处理自定义异常/***统... 查看详情

springmvc,springboot统一校验自定义异常全局异常处理(代码片段)

引入jar包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>写一个DTO用来接收客户端传送的参数@Datapubliccl 查看详情

springmvc,springboot统一校验自定义异常全局异常处理(代码片段)

引入jar包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>写一个DTO用来接收客户端传送的参数@Datapubliccl 查看详情

.netcore统一参数校验异常处理结果返回功能实现(代码片段)

我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的话,代码就不优雅,也不容易维护。所以,我们需要... 查看详情

商城项目10_jsr303常用注解在项目中如何使用统一处理异常分组校验功能自定义校验注解(代码片段)

...dler④.处理错误状态码⑤.分组校验功能(多场景校验)⑥.自定义校验注解①.JSR303校验概述、注解①.JSR是JavaSpecificationRequests的缩写,意思是Java规范提案,JSR-303是JAVAEE6中的一项子规范,叫做BeanValidation即,J 查看详情

springboot中集成参数校验(代码片段)

SpringBoot中集成参数校验引入依赖自定义参数校验创建自定义注解自定义校验逻辑在校验对象的属性上加上注解分组校验定义分组接口在UserVO对象参数分配分组在需要参数校验的方法指定分组SprinBoot集成参数校验Validator,以及... 查看详情

es实战自定义处理es的cat命令结果集示例(代码片段)

处理ES的Cat命令结果集示例以_cat/health为例一般的返回结果为healthstatusindexuuidprirepdocs.countdocs.deletedstore.sizepri.store.sizegreenopen.kibanai2DCHBCIQpmNv844IfH86w10206.9kb6.9kbgreenopen.monitoring-alerts-2Qd_LW97SQ 查看详情

springboot统一参数校验统一异常统一响应,这才是优雅的处理方式!(代码片段)

...以下3个问题:当接收到请求时,如何优雅的校验参数返回 查看详情

javaspringboot中自定义参数校验(代码片段)

查看详情

瞧瞧人家用springboot写的后端api接口,那叫一个优雅

...一下controller层的代码啦:日常开发中,我们一般都是自定义统一的异常类,如下:在controller层 查看详情

阿昌教你自定义注解验证bean对象(代码片段)

...置返回值】的文章,讲了常见的一些注解,和自定义的报错返回处理器,没看过的可以去看一下。在Springboot中本身就可以通过大量的注解来实现对一些请求参数的校验。这里在做一点的补充,关于自定义注解࿰... 查看详情

springboot参数校验(代码片段)

...参数为例实体参数校验分组校验嵌套校验常用校验注解自定义校验下一节Springboot异常配置Springboot参数校验上一节Springbootcrud和swagger使 查看详情

flask学习-45.flask-restx自定义参数校验和自定义错误内容error_msg使用(代码片段)

...验,比如是否为空,字符串长度,以及一些自定义的参数规则。add_argument参数classArgument(object):""":paramname:Eitheranameoral 查看详情

flask学习-34.restful-full请求参数自定义参数校验类型(reqparse.requestparser())(代码片段)

...验,比如是否为空,字符串长度,以及一些自定义的参数规则。add_argument参数下面是add_argument可以使用的参数,部分源码如下:classArgument(objec 查看详情

后端开发总结:代码健壮性:容错处理+测试(代码片段)

...状态码,比如500请求通了,但是结果有问题。自定义的返回response中的code信息,比如5000response,err:=http请求iferr!=nil||response.StatusCode()!=http.StatusOK//打印日志信息log.Log().Errorf("servicereturnconfigureerror:%v",err)//... 查看详情

重学springboot系列之统一全局异常处理(代码片段)

...机制异常处理的乱象例举该如何设计异常处理开发规范自定义异常和相关数据结构该如何设计数据结构枚举异常的类型自定义异常请求接口统一响应数据结构使用示例如下通用全局异常处理逻辑通用异常处理逻辑全局异常处理器... 查看详情