spring实现Validator校验和全局异常处理

简介: spring实现Validator校验和全局异常处理

开整!

首先引入依赖

<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.1.5.Final</version>
        </dependency>
        <!-- FastJson -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

在需要校验的实体类上加注解,这里我们写个接口,给它分个组

package com.ruben.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
/**
 * @ClassName: User
 * @Description:
 * @Date: 2020/8/6 20:22
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @NotBlank(message = "用户名不能为空", groups = {UserCheck.class})
    private String username;
    @NotBlank(message = "密码不能为空", groups = UserCheck.class)
    private String password;
    public interface UserCheck {
    }
}

然后在方法上加上注解,并指定分组

/**
 * 登录
 *
 * @param user 参数为Json格式的User对象{"username":"","password":""}
 * @return 返回json格式的map
 */
@PostMapping("login")
public Map<String, Object> login(@Validated({User.UserCheck.class}) @RequestBody User user) {
    Map<String, Object> map = new HashMap<>(1 << 2);
    String myUsername = "achao";
    String myPassword = "ruben";
    if (myUsername.equals(user.getUsername()) && myPassword.equals(user.getPassword())) {
        map.put("success", true);
        map.put("code", 200);
        map.put("msg", "登录成功!");
    } else {
        map.put("success", false);
        map.put("code", -629);
        map.put("msg", "登录失败,用户名密码错误!");
    }
    return map;
}

这时候,我们发现已经抛出异常了

我们尝试去捕获这个异常MethodArgumentNotValidException

首先写个全局异常处理器

package com.ruben.resolver;
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
 * @ClassName: GlobalExceptionResolver
 * @Description:
 * @Date: 2020/8/17 20:03
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        e.printStackTrace();
        ModelAndView modelAndView = new ModelAndView();
        FastJsonJsonView fastJsonJsonView = new FastJsonJsonView();
        Map<String, Object> map = new HashMap<>(1 << 2);
        map.put("success", false);
        map.put("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
        map.put("msg", "内部错误");
        fastJsonJsonView.setAttributesMap(map);
        modelAndView.setView(fastJsonJsonView);
        return modelAndView;
    }
}

然后在springmvc里一配

1
2
<!-- 全局异常处理 -->
<beanid="handlerExceptionResolver"class="com.ruben.resolver.GlobalExceptionResolver"/>

我们随便写个int i = 2/0;的异常,发现全局异常处理器测试通过

然后精彩部分来了,我们debug发现这个MethodArgumentNotValidException异常全局异常处理器根本没进去!!!

那这样就没办法了吗?No No No!

这里我们采用AOP的方式

首先自定义个注解

package com.ruben.annotation;
import java.lang.annotation.*;
/**
 * @ClassName: Validator
 * @Description: 自定义Validator校验注解,需参数配合BindingResult一起使用
 * @Date: 2020/8/17 20:57
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Validator {
    String value() default "bindingResult";
}

写完,在我们的方法上加上我们的注解和参数

/**
 * 登录
 *
 * @param user 参数为Json格式的User对象{"username":"","password":""}
 * @return 返回json格式的map
 */
@Validator
@PostMapping("login")
public Map<String, Object> login(@Validated({User.UserCheck.class})
                                 @RequestBody User user,
                                 BindingResult bindingResult) {
    Map<String, Object> map = new HashMap<>(1 << 2);
    String myUsername = "achao";
    String myPassword = "ruben";
    if (myUsername.equals(user.getUsername()) && myPassword.equals(user.getPassword())) {
        map.put("success", true);
        map.put("code", 200);
        map.put("msg", "登录成功!");
    } else {
        map.put("success", false);
        map.put("code", -629);
        map.put("msg", "登录失败,用户名密码错误!");
    }
    return map;
}

然后写个简单的AOP来处理

package com.ruben.aop;
import com.ruben.annotation.Validator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @ClassName: ValidatorAop
 * @Description:
 * @Date: 2020/8/17 20:50
 * *
 * @author: achao<achao1441470436 @ gmail.com>
 * @version: 1.0
 * @since: JDK 1.8
 */
@Aspect
@Component
public class ValidatorAop {
    /**
     * 参数校验AOP
     *
     * @param joinPoint 织入点为这个注解
     * @param validator 自定义的注解
     * @return
     */
    @Around("@annotation(validator)")
    public Object validateParam(ProceedingJoinPoint joinPoint, Validator validator) {
        //获取错误参数(也就是我们注解里面的bindingResult)
        String value = validator.value();
        //获取所有参数名
        String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
        BindingResult bindingResult = null;
        //遍历所有参数名,如果参数名相同,则根据当前i作为下标去获取参数
        for (int i = 0; i < parameterNames.length; i++) {
            if (value.equals(parameterNames[i])) {
                bindingResult = (BindingResult) joinPoint.getArgs()[i];
            }
        }
        //返回一个map
        Map<String, Object> map = new HashMap<>(1 << 2);
        //如果bindingResult不为空并且bindingResult数组不为空(hasErrors是调用List的isEmpty取反)
        if (bindingResult != null && bindingResult.hasErrors()) {
            map.put("success", false);
            map.put("code", HttpStatus.BAD_REQUEST);
            //拼接结果(个人喜欢把所有错误信息返回,也可以只返回第一个提升效率)
            map.put("msg", bindingResult.getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(" ")));
            return map;
        }
        try {
            //方法执行
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            //方法执行必须抛出一个Throwable异常
            throwable.printStackTrace();
        }
        return null;
    }
}

顺便放上一张我们的参数和提示截图

大功告成!

相关文章
|
Java 开发者 UED
Spring Boot的全局异常处理机制
【2月更文挑战第13天】
1051 0
|
4月前
|
JSON Java 数据库
第08课:Spring Boot中的全局异常处理
第08课:Spring Boot中的全局异常处理
660 0
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——处理系统异常
本文介绍了在Spring Boot项目中如何通过创建`GlobalExceptionHandler`类来全局处理系统异常。通过使用`@ControllerAdvice`注解,可以拦截项目中的各种异常,并结合`@ExceptionHandler`注解针对特定异常(如参数缺失、空指针等)进行定制化处理。文中详细展示了处理参数缺失异常和空指针异常的示例代码,并说明了通过拦截`Exception`父类实现统一异常处理的方法。虽然拦截`Exception`可一劳永逸,但为便于问题排查,建议优先处理常见异常,最后再兜底处理未知异常,确保返回给调用方的信息友好且明确。
1169 0
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——处理系统异常
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——拦截自定义异常
本文介绍了在实际项目中如何拦截自定义异常。首先,通过定义异常信息枚举类 `BusinessMsgEnum`,统一管理业务异常的代码和消息。接着,创建自定义业务异常类 `BusinessErrorException`,并在其构造方法中传入枚举类以实现异常信息的封装。最后,利用 `GlobalExceptionHandler` 拦截并处理自定义异常,返回标准的 JSON 响应格式。文章还提供了示例代码和测试方法,展示了全局异常处理在 Spring Boot 项目中的应用价值。
417 0
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——定义返回的统一 json 结构
本课主要讲解Spring Boot中的全局异常处理方法。在项目开发中,各层操作难免会遇到各种异常,若逐一处理将导致代码耦合度高、维护困难。因此,需将异常处理从业务逻辑中分离,实现统一管理与友好反馈。本文通过定义一个简化的JsonResult类(含状态码code和消息msg),结合全局异常拦截器,展示如何封装并返回标准化的JSON响应,从而提升代码质量和用户体验。
226 0
|
12月前
|
开发框架 Java UED
如何使用 Spring Boot 实现异常处理
如何使用 Spring Boot 实现异常处理
506 2
|
Java Spring UED
Spring框架的异常处理秘籍:打造不败之身的应用!
【8月更文挑战第31天】在软件开发中,异常处理对应用的稳定性和健壮性至关重要。Spring框架提供了一套完善的异常处理机制,包括使用`@ExceptionHandler`注解和配置`@ControllerAdvice`。本文将详细介绍这两种方式,并通过示例代码展示其具体应用。`@ExceptionHandler`可用于控制器类中的方法,处理特定异常;而`@ControllerAdvice`则允许定义全局异常处理器,捕获多个控制器中的异常。
181 0
|
Java API 开发者
【开发者福音】Spring Boot 异常处理:优雅应对错误,提升应用健壮性,让调试不再是噩梦!
【8月更文挑战第29天】本文通过对比传统错误处理方式与Spring Boot推荐的最佳实践,展示了如何在Spring Boot应用中实现统一且优雅的异常处理。传统方法需在每个可能出错的地方显式处理异常,导致代码冗余且不一致。而Spring Boot的全局异常处理机制则能集中处理所有异常,简化代码并确保错误响应格式统一,提高应用程序的健壮性和可维护性。文中提供了具体的示例代码以帮助读者更好地理解和应用这一机制。
503 0
|
运维 Java 关系型数据库
Spring运维之boot项目bean属性的绑定读取与校验
Spring运维之boot项目bean属性的绑定读取与校验
176 2
|
JSON Java 数据库
Spring Boot中的全局异常处理
主要讲解了Spring Boot 的全局异常处理,包括异常信息的封装、异常信息的捕获和处理,以及在实际项目中,我们用到的自定义异常枚举类和业务异常的捕获与处理,在项目中运用的非常广泛,基本上每个项目中都需要做全局异常处理。

热门文章

最新文章

下一篇
oss云网关配置