全局统一异常处理, 断言工具-JSR303

一.异常处理

1..定义异常

在开发中,为了保证业务的正确性我们会对业务参数进行校验,不满足要求的参数采用throw new XxxException 来抛出异常,阻止程序继续执行,比如:用户名不可为空,密码错误等。这类异常是需要展示给用户看的,还有一类是程序抛出来的一些未知的异常,如:SQL异常,空指针异常等等,这类异常不能直接抛给用户,而是应该统一捕获后,封装成统一的错误提示返回给用户,如“系统内部异常啦”

为了把我们手动抛出的异常和系统内部出现的异常区分开,我们需要抛出自定义的异常。通过继承RuntimeException自定义异常。

//全局异常
@Data
public class GlobleException extends RuntimeException{

    /**--------------------------------------------------------
     传一个错误信息给异常对象
     --------------------------------------------------------**/
    public GlobleException(String message){
        super(message);
    }
}
1.2.使用异常

在业务中使用自定义的异常来throw异常

1.3.统一捕获异常(异常处理器)

统一捕获异常,使用AOP的思想,解决在controller中大量try-catch重复代码。

通过两个注解来实现异常统一处理:

  • @RestControllerAdvice : 放在类上,是@ControllerAdvice和@ResponseBody注解的组合,它的作用是将controller中抛出的异常进行处理,而处理结果都以JSON格式返回给客户端。

该注解除了搭配@ExceptionHandler注解处理全局异常,还可以搭配其他注解做其他工作!!!

  • @ExceptionHandler(异常类.class) :贴在方法上,可捕获指定类型的异常

    /**--------------------------------------------------------
    全局异常处理
     @RestControllerAdvice :贴在类上,这个类就可以在controller的方法执行前,或者执行后做一些事情
     --------------------------------------------------------**/
    //@ControllerAdvice
    @RestControllerAdvice
    public class GlobleExceptionHandler {
    
        //拦截异常 : 这个注解就可以拦截器 GlobleException 异常
        @ExceptionHandler(GlobleException.class)
        public JSONResult globleException(GlobleException e){
            e.printStackTrace();
            return JSONResult.error(e.getMessage());
        }
    
        //拦截器其他异常
        @ExceptionHandler(Exception.class)
        public JSONResult exception(Exception e){
            e.printStackTrace();
            return JSONResult.error("系统异常,正在殴打程序员...");
        }
    
    }

    该类中处理异常的方法后面会逐渐增加,用于处理不同的业务场景

其中 JSONResult为后端返回前端的格式 error为内部的方法

还可以将返回的消息用枚举类进行统一管理:

定义不同的自定义异常, 所有的异常消息信息都定义在枚举类中, 降低耦合, 修改信息只需要修改枚举类中的信息即可

@AllArgsConstructor
@Getter
public enum GlobalInstances {

    SYSTEM_EXCEPTION("9999","系统异常,正在殴打程序员..."),
    ACCOUNT_PASSWORD_EXCEPTION("1001","账号或密码错误");

    private String code;
    private String message;

/*    GlobalInstances(String code, String message) {
        this.code = code;
        this.message = message;
    }*/
}

那么异常处理器中的方法可变为: (@ExceptionHandler内部可以捕获多个异常)

    @ExceptionHandler({RuntimeException.class, ArrayIndexOutOfBoundsException.class})
    public JSONResult globalExceptionHandler(RuntimeException e){
        e.printStackTrace();

        return JSONResult.error(
                GlobalInstances.SYSTEM_EXCEPTION.getMessage(),
                GlobalInstances.SYSTEM_EXCEPTION.getCode()
        );
    }

二.断言工具

大量的if(条件)throw new Exception("异常") 代码太过冗余,通过断言工具进行抽取,仿照Spring的Assert。

2.1.定义工具

整合到工具包AssertUtil中:

手机号校验断言, 格式不对, 抛出异常:

//手机的正则表达式    
private static final Pattern CHINA_PATTERN_PHONE = Pattern.compile("^((13[0-9])|(14[0,1,4-9])|(15[0-3,5-9])|(16[2,5,6,7])|(17[0-8])|(18[0-9])|(19[0-3,5-9]))\\d{8}$");
 
/**--------------------------------------------------------
    手机号断言
    --------------------------------------------------------**/
    public static void isPhone(String phone,String message){
        Matcher m = CHINA_PATTERN_PHONE.matcher(phone); //将手机号放入匹配器对象
        if(!m.matches()){ //进行正则匹配,返回boolean值
            throw new RuntimeException(message);
        }
    }

不为空断言, 为空抛异常:

    /**--------------------------------------------------------
    断言 不为空,如果为空,抛异常
    --------------------------------------------------------**/
    public static void isNotEmpty(String text, String message) {
        if (text == null || text.trim().length() == 0) {
            throw new RuntimeException(message);
        }
    }


    /**--------------------------------------------------------
    断言对象为空
    --------------------------------------------------------**/
    public static void isNull(Object obj , String message){
        if(obj != null){
            throw new RuntimeException(message);
        }
    }
    public static void isNotNull(Object obj , String message){
        if(obj == null){
            throw new RuntimeException(message);
        }
    }

判断false和true断言:

    /**--------------------------------------------------------
     断言false,如果为true,我报错
     --------------------------------------------------------**/
    public static void isFalse(boolean isFalse , String message){
        if(isFalse){
            throw new RuntimeException(message);
        }
    }
    public static void isTrue(boolean isTrue , String message){
        if(!isTrue){
            throw new RuntimeException(message);
        }
    }

比较字符串断言:

    /**--------------------------------------------------------
     断言两个字符串一致
     --------------------------------------------------------**/
    public static void isEquals(String s1,String s2 , String message){
        isNotEmpty(s1, "不可为空");
        isNotEmpty(s2, "不可为空");
        if(!s1.equals(s2)){
            throw new RuntimeException(message);
        }
    }
    public static void isEqualsTrim(String s1,String s2 , String message){
        isNotEmpty(s1, "不可为空");
        isNotEmpty(s2, "不可为空");
        if(!s1.trim().equals(s2.trim())){
            throw new RuntimeException(message);
        }
    }

    public static void isEqualsIgnoreCase(String s1,String s2 , String message){
        isNotEmpty(s1, "不可为空");
        isNotEmpty(s2, "不可为空");
        if(!s1.trim().equalsIgnoreCase(s2.trim())){
            throw new RuntimeException(message);
        }
    }
2.2.使用断言工具
AssertUtil.isNotEmpty(username,"用户名不能为空")

三.参数校验Validation --> (JSR303)

参数校验是我们程序开发中必不可少的过程。用户在前端页面上填写表单时,前端js程序会校验参数的合法性,当数据到了后端,为了防止恶意操作,保持程序的健壮性,后端同样需要对数据进行校验。后端参数校验最简单的做法是直接在业务方法里面进行判断,当判断成功之后再继续往下执行。但这样带给我们的是代码的耦合,冗余。当我们多个地方需要校验时,我们就需要在每一个地方调用校验程序,导致代码很冗余,且不美观。

那么如何优雅的对参数进行校验呢?JSR303就是为了解决这个问题出现的,本篇文章主要是介绍 JSR303,Hibernate Validator 等校验工具的使用,以及自定义校验注解的使用。

3.1.相关注解

Bean Validation 中内置的 constraint (限制,约束)

Constraint详细信息
@Null被注释的元素必须为 null
@NotNull被注释的元素必须不为 null
@AssertTrue被注释的元素必须为 true
@AssertFalse被注释的元素必须为 false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式

Hibernate Validator 附加的 constraint

Constraint详细信息
@Email被注释的元素必须是电子邮箱地址
@Length被注释的字符串的大小必须在指定的范围内
@NotEmpty被注释的字符串的必须非空
@Range被注释的元素必须在合适的范围内
3.2.对象校验
1.在参数实体类的字段上注解

在实体类上, 用约束注解标注需要校验的字段

@NotEmpty(message = "手机不可为空")
private String phone;
2.在参数实体类前注解

开启校验: 使用@Valid开启校验功能

校验功能需要开启, 因为防止不不要的校验

只在需要校验的方法形参前 添加该注解

public JSONResult register(@RequestBody @Valid RegisterParamDto dto)

@Valid 或者 @Validated都可以标识该类需要进行校验,在类上也可以加该注解。

3.3.参数校验

单个参数也可以直接在参数前加上限制注解:

@Valid
@RestController
public class UserController{
    
    @RequestMapping("/user/add")
    public JSONResult add(@NotEmpty(message = "不可为空") String username, String password){
        ...省略...
    }
}
  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "b'jackson-datatype-jsr310'" 是一个Java库的名称,它是用于处理日期时间格式的 Jackson 库的一个扩展。这个库可以让开发者更容易地在 Java 应用程序中使用与ISO-8601标准相兼容的日期和时间格式。 ### 回答2: Jackson-datatype-jsr310是指Jackson的扩展库,用于支持Java 8新的日期和时间API(JSR-310)与Java对象之间的序列化和反序列化。JSR-310是Java 8发布的一项新的标准,它提供了一组强类型的日期和时间API,解决了Java标准库中日期处理的不足和问题。 在Java中,日期和时间相关的类在处理时常常出现各种问题。Java标准库的日期和时间类大多是基于旧的Calendar和Date类而来,设计较为复杂,使用不够友好,特别是在进行格式化和解析时,容易出现错误。JSR-310重新定义了新的日期和时间API,提供了更多更好用的方法和类,比旧的日期和时间API更加强大和易用。 使用Jackson-datatype-jsr310,我们可以将Java对象中的日期和时间类型数据序列化到JSON或其他数据格式中,并在反序列化时还原成对应的Java对象。这样就可以方便地在Java和其他语言之间进行数据的交换了。Jackson-datatype-jsr310支持Java 8 API中的LocalDate,LocalDateTime,ZonedDateTime等类型。 例如,在将Java对象转换为JSON字符串的过程中,我们可以使用ObjectMapper的registerModule方法,注册一个JavaTimeModule,它便会将Java 8日期和时间类自动序列化成JSON字符串。反序列化时,我们同样可以使用registerModule方法注册JavaTimeModule,并在将JSON字符串转化成Java对象时,自动将日期和时间类型还原成对应的Java对象。 总而言之,Jackson-datatype-jsr310是一个非常实用的工具,它可以使得Java程序更加简洁和易维护,尤其是在处理日期和时间相关的操作时,更加高效和准确。 ### 回答3: Jackson-datatype-jsr310是一个Java库,用于将Java 8中的JSR310日期和时间API(也称为Java时间API)与Jackson JSON处理库集成。这个库的主要目的是提供一种简单的方法将Java时间对象序列化和反序列化为JSON格式。 Java时间API是Java 8中引入的新的日期和时间功能,用于替代旧的Date和Calendar类。Java时间API使用不同的类表示日期,时间和时间段,并提供了一系列强大的方法来进行日期计算和格式化。 Jackson是一个用于处理JSON数据的流行Java库。Jackson提供了强大和高效的序列化和反序列化JSON的功能,由于其高性能和灵活性,成为Java编程中常用的JSON库。 Jackson-datatype-jsr310将Java时间API与Jackson集成的过程变得非常容易。使用这个库,您可以轻松地在Java对象和JSON之间转换日期,时间和时间段。这个库扩展了Jackson的ObjectMapper类,为JSR310类提供了序列化和反序列化的支持。 除了简化Java时间API和Jackson之间的集成之外,Jackson-datatype-jsr310还提供了许多其他功能,例如格式化日期和时间的方式完全可以按照自己的意愿来进行自定义配置。 总体来说,Jackson-datatype-jsr310是一个非常有用的Java库,使得Java时间API和Jackson的集成变得非常容易。它提供了灵活、高效、可靠的JSON序列化和反序列化,为Java程序员提供了一种简单而强大的方法来处理日期、时间和时间段的处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值