• 实战分析:SpringBoot项目 JSR303校验、Hutool工具类的具体使用


    我是 ABin-阿斌:写一生代码,创一世佳话,筑一览芳华。 如果小伙伴们觉得文章有点 feel ,那就点个赞再走哦。
    在这里插入图片描述

    声明:

    • 原文地址:https://blog.csdn.net/weixin_51216079/article/details/120413239

    • 原文作者:CSDN:Coder-CT

    一、前言

    • 在日常开发当中我们会做很多的业务校验,那么我们如果将这些异常有效的返回到页面去跟用户做交互呢?下面我们可以具体卡看看比较常用的几个校验工具。

    二、正文

    Hutool 相关

    • 引入 Hutool 依赖
       
          <dependency>
            <groupId>cn.hutoolgroupId>
            <artifactId>hutool-allartifactId>
           <version>5.8.4version>
         dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    代码举例

    • 具体我们可以直接点击到:Assert 断言内部看源码,都是中文注释。基本上看一眼就会了,还是比较简单的。

    在这里插入图片描述

    • 当然 Hutool 不单单是用来做断言校验,这个工具类的功能是非常丰富的。 更加详细用法可看官网:Hutool官网
     PsMessageRelease messageFloodControl = this.getById(messageId);
     Assert.isTrue(ObjectUtils.isNotEmpty(messageFloodControl), "ID为:{},的详情信息不存在!", messageId);
     
      PsMessageRelease one = this.getOne(Wrappers.lambdaQuery(PsMessageRelease.class)
                    .eq(PsMessageRelease::getTitle, query.getTitle())
                    .eq(PsMessageRelease::getDeleteStatus, DeleteConstant.NOT_DEL)
                    .last(MybatisPlusConst.LIMIT_1));
     Assert.isNull(one, "信息主题不可重复!");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    JSR303 相关

    • JSR303 校验不用导入依赖,web 依赖集成了,JSR303 我们一般用来做一些入参的校验。

    代码举例


    @validated 和 @valid 的区别

    • 在检验 Controller 的入参是否符合规范时,使用 @Validated 或 者@Valid 在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同。

    嵌套:

    public class Song {
    
        @NotNull(message = "id不能为空")
        @Min(value = 1, message = "id必须为正整数")
        private Long id;
    
        @NotNull(message = "singers不能为空")
        @Size(min = 1, message = "至少要有一个属性")
        private List<Singer> singers;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意: Singer 有自己的校验规则 如果 Song 只有 @NotNull 和 @Size 那么 Singer 里面的属性就没法校验

    public class Singer{
    
        @NotNull(message = "id不能为空")
        @Min(value = 1, message = "id必须为正整数")
        private Long id;
    
        @NotNull(message = "vid不能为空")
        @Min(value = 1, message = "vid必须为正整数")
        private Long vid;
    
        @NotBlank(message = "pidName不能为空")
        private String pidName;
    
        @NotBlank(message = "vidName不能为空")
        private String vidName;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    @RestController
    public class ItemController {
    
        @RequestMapping("/song /add")
        public void addSong(@RequestBody @Validated Song song) {
            System.out.println(song);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 这里只会校验 singer 里面的字段数量和非空校验,不会对 singer 字段里的 Singer 实体进行字段验证,也就是 @Validated 和@Valid 加在方法参数前,都不会对参数进行嵌套验证。

    • Song 更新一下代码

    public class Song {
    
        @NotNull(message = "id不能为空")
        @Min(value = 1, message = "id必须为正整数")
        private Long id;
        
        @Valid // 嵌套验证必须用@Valid
        @NotNull(message = "singers不能为空")
        @Size(min = 1, message = "至少要有一个属性")
        private List<Singer> singers;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    细节点注意:

    • @Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
    • @Validated:只能用在类、方法和方法参数上 ,不能用在字段上!
    • @Valid:作为标准JSR-303规范,不会进行分组校验,直接校验字段
    • 新增或修改的时候就需要进行分组校验
    @Data
    @TableName("hss_equipment")
    public class Equipment implements Serializable {
    	private static final long serialVersionUID = 1L;
    
    	/**
    	 * id
    	 */
    	@NotNull(message = "修改必须指定id",groups = {UpdateGroup.class})//只有在修改的时候才会触发
    	@Null(message = "新增不能指定id",groups = {AddGroup.class})//只有在新增的时候才会触发
    	@TableId
    	private Long Id;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    指定两个分组接口 ,不需要实现,这两个接口需要打在接口上面,用于区分

    // 添加的分组校验接口
    public interface AddGroup {
    }
    
    // 修改的分组校验接口
    public interface UpdateGroup {
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用@Validated指定分组 只有指定了分组的字段才会生效

    
      /**
         * 保存
         */
        @RequestMapping("/save")
        public R save(@Validated({AddGroup.class}) @RequestBody Equipment equipment) {
            brandService.save(brand);
            return R.ok();
        }
    
        /**
         * 修改
         */
        @RequestMapping("/update")
        public R update(@Validated({UpdateGroup.class})@RequestBody Equipment equipment) {
            brandService.updateById(brand);
    
            return R.ok();
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    全局异常类

    import com.molomessage.message.sys.service.EmailService;
    import com.molomessage.message.sys.utils.R;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.BindException;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.*;
    import java.text.SimpleDateFormat;
    
    /**
     * chen
     * 2021-
     * 全局异常
     * 该注解会 适用所有的@RequestMapper() 结合@ExceptionHander 实现全局异常处理
     */
    @RestControllerAdvice
    @ResponseBody
    public class GlobalExceptionHandler {
        @Autowired
        private EmailService emailService;
        private final static Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
        //jsr303校验全局异常
        @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class}) /*定义拦截*/
        public R exceptionHandler(HttpServletRequest request, Exception e) {
            BindingResult bindingResult = null;
            if (e instanceof MethodArgumentNotValidException) {
                bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            } else if (e instanceof BindException) {
                bindingResult = ((BindException) e).getBindingResult();
            }
            StringBuffer buffer = new StringBuffer();
            //获取全部异常信息
            bindingResult.getFieldErrors().forEach(fieldError ->
                    buffer.append(fieldError.getDefaultMessage() + ","));
    
            return R.error(buffer.toString());
        }
    
        //hutool断言全局异常处理
        @ExceptionHandler(value = {IllegalArgumentException.class}) /*定义拦截*/
        public R hutoolHandler(HttpServletRequest request, Exception e) {
            return R.error(e.getMessage());
        }
    
        //其它异常信息
        @ExceptionHandler(value = Exception.class)
        public R exception(Exception e) {
            e.printStackTrace();
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            final String format = sf.format(new java.util.Date());
            StackTraceElement[] stackTrace = e.getStackTrace();
            //发送邮件内容
            StringBuffer buffer = new StringBuffer();
            buffer.append("异常类型:" + e + ",\n");
            if (e.getMessage() != null) buffer.append("异常原因:" + e.getMessage() + ",\n");
            //类名
            buffer.append("类名:" + stackTrace[0].getClassName() + ",\n");
            //文件名
            buffer.append("文件名:" + stackTrace[0].getFileName() + ",\n");
            //方法名
            buffer.append("方法名:" + stackTrace[0].getMethodName() + ",\n");
            //具体哪一行报的错
            buffer.append("报错行数:" + stackTrace[0].getLineNumber() + ",\n");
            buffer.append(format + "\n");//当前系统时间
            buffer.append(" \n");//换行
            //发送邮件给管理员
            //emailService.emailSend("8048984@qq.com", "业务异常", buffer.toString());
            //异常信息写出到文件中
            try {
                //以追加的形式写入文件中
                FileOutputStream stream = new FileOutputStream("F:/logs/java全局异常信息.txt", true);
                try {
                    stream.write(buffer.toString().getBytes());
                    stream.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            }
            return R.error("服务器异常").put("异常类型", e.toString())
                    .put("异常原因",e.getMessage())
                    .put("异常文件名", stackTrace[0].getFileName())
                    .put("异常方法名", stackTrace[0].getMethodName())
                    .put("异常行数", stackTrace[0].getLineNumber());
        }
    
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    自定义返回类

    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 返回数据
     * 
     * @author chen
     * @date 2021年
     */
    public class R extends HashMap<String, Object> {
    	private static final long serialVersionUID = 1L;
    	public R() {
    		put("success",true);
    		put("code", 0);
    		put("msg","操作成功");
    	}
    	
    	public static R error() {
    		return error(500, "未知异常,请联系管理员");
    	}
    	public static R error(String msg) {
    	    return error(500, msg);
    	}
    	
    	public static R error(int code, String msg) {
    		R r = new R();
    		r.put("code", code);
    		r.put("msg", msg);
    		r.put("success",false);
    
    		return r;
    	}
    
    	public static R ok(String msg, Object obj) {
    		R r = new R();
    		r.put("success",true);
    		r.put("msg", msg);
    		r.put("data", obj);
    		return r;
    	}
    	public static R ok(String msg) {
    		R r = new R();
    		r.put("success",true);
    		r.put("msg", msg);
    		return r;
    	}
    	
    	public static R ok(Map<String, Object> map) {
    		R r = new R();
    		r.putAll(map);
    		return r;
    	}
    	
    	public static R ok() {
    		return new R();
    	}
    
    	public R put(String key, Object value) {
    		super.put(key, value);
    		return this;
    	}
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
  • 相关阅读:
    mindspore将parameter转为tensor时报错
    Java基础,transient关键字
    2022-08-06 第四小组 修身课 学习笔记(every day)
    验证C++中 cout 输出情况的小程序
    [单片机框架][bsp层][N32G4FR][bsp_i2c] i2c配置和使用
    【pen200-lab】10.11.1.39
    Verilog语法之条件编译`ifdef, `ifndef,`else, `elsif, `endif
    linux 离线安装软件
    第二章:ShardingSphere简介
    Spring Data JPA渐进式学习--如何自定义查询方法呢?
  • 原文地址:https://blog.csdn.net/Mango_Bin/article/details/126207186