Spring MVC Spring 中封装Hibernate Validator,简易使用校验

版权声明:欢迎交流、沟通 QQ:983433479 微信:wj983433479 ;努力学习~赚钱养家不是梦。 https://blog.csdn.net/u012881904/article/details/79538895

Spring MVC Spring 中封装Hibernate Validator,简易使用校验

学习目录回顾

Hibernate Validator简单使用
Hibernate Validator 校验方法的参数,返回值,构造函数
Spring Validator方法级别的参数校验,方法界别参数校验的全局处理,Sping MVC使用Hibernate Validator,自定义校验器
Hibernate Validator 方法界别验证,通过AOP实现,Unable to initialize ‘javax.el.ExpressionFactory’.
以上目录是笔者之前学习的目录,但是想运用在项目中感觉还是有些不是特别的方便,虽然之前也是写了AOP实现,但是实现时候思路不是特别的好!这里重新进行处理简化编码。

统一异常处理(方姐的实现)

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

@Controller
public class ExceptionHandleController {

    Logger logger= LoggerFactory.getLogger(ExceptionHandleController.class);

    /**
     * 统一异常处理,继承这个类的Controller都可进行统一异常处理
     * @param e
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public AjaxResponse handleException(Exception e){
        AjaxResponse response=new AjaxResponse();
        response.setResult(false);
        response.setResultMsg(I18nUtil.getMessage(e.getMessage()));
        if(e instanceof ConstraintViolationException){//获取校验失败的信息
            StringBuilder stringBuilder=new StringBuilder();
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) e).getConstraintViolations();
            for(ConstraintViolation item : constraintViolations){
                logger.info("Item:"+item.getPropertyPath().toString()+"  message:"+item.getMessage());
                stringBuilder.append(item.getMessageTemplate());
            }
            response.setResultMsg(stringBuilder.toString().substring(0,stringBuilder.length()-1));
        }

        return response;
    }
}

统一异常处理(2)


public class ExceptionHandler implements HandlerExceptionResolver {

    private final static Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        AjaxResponse ajaxResponse = new AjaxResponse();
        ajaxResponse.setResult(false);
        String errorMsg = "";
        if (ex instanceof EnergyException || ex instanceof BicRuntimeException) {
            errorMsg = I18nUtil.getMessage(ex.getMessage());
            errorMsg = StringUtils.isEmpty(errorMsg) ? I18nUtil.getMessage(I18nConst.COMMON_SYSTEM_ERROR) : errorMsg;
        } else if (ex instanceof BusinessException) { //已经处理了多语言
            errorMsg = ex.getMessage();
        } else if (ex instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) ex).getConstraintViolations();
            for (ConstraintViolation<?> constraintViolationItem : constraintViolations) {
                errorMsg =  I18nUtil.getMessage(constraintViolationItem.getMessageTemplate());
                errorMsg = StringUtils.isEmpty(errorMsg) ? I18nUtil.getMessage(I18nConst.COMMON_SYSTEM_ERROR) : errorMsg;
                break;
            }
        } else { //其他的异常在这里进行定义拦截
            errorMsg = I18nUtil.getMessage(I18nConst.COMMON_SYSTEM_ERROR);
            logger.error(PrettyLogger.toMessage("expection handler"),ex);
        }
        ajaxResponse.setResultMsg(errorMsg);
        String exceptionStr = JSON.toJSONString(ajaxResponse.getData());
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(exceptionStr);
            response.getWriter().close();
        } catch (IOException e) {
            logger.error(PrettyLogger.toMessage("failed to response error message to front"), e);
        }
        return null;
    }

}

AOP拦截的注解

这里可以自己填写需要校验的时候使用那个分组进行处理

import javax.validation.groups.Default;
import java.lang.annotation.*;

/**
 * Created by wangji on 2018/3/13.
 */
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EgValidate {
    Class<\?> [] groups() default { Default.class };//校验分组信息
}

AOP实现

校验步骤 :
1.首先校验是否含有基本的Hibernate validator 注解(@NotNull ..),有异常抛出
2.校验方法参数中是否含有EgValidate注解,获取分组信息,进行Bean级别的校验,有异常抛出
3.查看当前的方法中(优先级高)(或者父类、父接口)是否含有EgValidate注解,没有获取当前类的中是否是否含有EgValidate注解,获取分组信息,针对每一个非基本类型Bean进行校验,有异常掏出


/ 需要校验的Bean
//public class User implements Serializable {
//
//    @NotBlank(message = "用户名不能为空",groups = {First.class})
//    private String name;
//
//    @NotNull(message="地址不能为空")
//    private String address;
//
//}

// 校验在方法参数中,分组信息以参数中为准
//    @EgValidate
//    public void save(@EgValidate(groups = {First.class}) User user) {
//        userDao.save(user);
//    }

// 先校验基本的Hibernate validator 校验通过后从方法中获取校验的分组进行Bean级别的校验
//    @EgValidate(groups = {First.class})
//    public void save(User user, @NotNull(message="id 不能为空") Integer id) {
//        userDao.save(user);
//    }

// 参数中没有分组、方法上没有分组,那么分组信息以类上的为准
//    @EgValidate(groups = {First.class, Default.class})
//     public class UserInfoService implements IUserInfoService {
//        @Resource
//        private UserDao userDao;
//
//        public void save(User user) {
//            userDao.save(user);
//        }
//    }

/**
 * @descrption: 通过AOP进行拦截方法参数校验
 * @authohr: wangji
 * @date: 2018-03-13 9:51
 */
@Component
@Aspect
public class EgMethodValidationAspect {

    // 获取校验的工厂的信息
    private static final Validator validator = Validation.byProvider(HibernateValidator.class)
            .configure()
            .failFast(true) //快速失败模式开启,当检测到有一项失败立即停止
            .buildValidatorFactory().getValidator();

    /**
     * 注解在方法类上或者方法上有效
     */
    @Pointcut("@within(com.hikvision.energy.validator.EgValidate)||@annotation(com.hikvision.energy.validator.EgValidate) ")
    public void pointcut() {
    }

    /**
     * @param point
     * @desction: 校验步骤
     * 1.首先校验是否含有基本的Hibernate validator 注解,有异常抛出
     * 2.校验方法参数中是否含有EgValidate注解,获取分组信息,进行Bean级别的校验,有异常抛出
     * 3.查看当前的方法中(优先级高)(或者父类、父接口)是否含有EgValidate注解,没有获取当前类的中是否是否含有EgValidate注解,获取分组信息,针对每一个非基本类型Bean进行校验,有异常掏出
     * @author: wangji
     * @date: 2018/3/13 10:16
     */
    @Before("pointcut()")
    public void before(JoinPoint point) throws NoSuchMethodException, SecurityException {

        //  获得切入目标对象
        Object target = point.getThis();
        // 获得切入方法参数
        Object[] args = point.getArgs();
        // 获得切入的方法
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        Annotation[] classAnnotations = target.getClass().getAnnotations();
        Annotation[] methodAnnotations = method.getAnnotations();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        if (parameterAnnotations != null) { //如果方法参数有基本的注解,就进行Hibernate validator 基本的参数校验
            validMethodParams(target, method, args);
        }
        // 判断参数中是否含有EgValidate注解,进行特殊分组,Bean级别的参数校验
        int i = 0;
        Set<Integer> idSet = Sets.newHashSet(3); //排查掉已经在参数中校验过的参数不适用类或者方法上的校验参数在次进行校验
        for (Object arg : args) {
            if (arg != null) {
                for (Annotation parameterAnnotation : parameterAnnotations[i]) {
                    if (parameterAnnotation instanceof EgValidate) {
                        if (arg != null && !ClassUtils.isPrimitiveOrWrapper(arg.getClass())) {
                            validBeanParam(arg, ((EgValidate) parameterAnnotation).groups());
                            idSet.add(i);
                        }
                    }
                }
                i++;
            }
        }
        // 如果没有异常继续校验当前的每一个非基本类型的参数
        EgValidate egValidate = null;
        if (methodAnnotations != null) { //方法上是否有校验参数
            egValidate = AnnotationUtils.findAnnotation(method, EgValidate.class);
        }
        if (egValidate == null && classAnnotations != null) { // 类上是否含有
            egValidate = AnnotationUtils.findAnnotation(target.getClass(), EgValidate.class);
        }
        // 如果在类或者方法上加了验证注解 ,则对所有非基本类型的参数对象进行验证,不管参数对象有没有加注解,使用方法上的分组
        if (egValidate != null && args != null && args.length > 0) {
            i = 0;
            for (Object arg : args) {
                if (arg != null && !ClassUtils.isPrimitiveOrWrapper(arg.getClass()) && !idSet.contains(i)) {
                    validBeanParam(arg, egValidate.groups());
                }
                i++;
            }
        }
    }


    /**
     * @param obj    参数中的Bean类型参数
     * @param groups 分组信息
     * @desction: 进行参数中的Bean校验
     * @author: wangji
     * @date: 2018/3/13 10:10
     */
    private void validBeanParam(Object obj, Class<?>... groups) {
        Set<ConstraintViolation<Object>> validResult = validator.validate(obj, groups);
        throwConstraintViolationException(validResult);
    }


    /**
     * @param obj    当前的实例
     * @param method 实例的方法
     * @param params 参数
     * @desction: 对于Hibernate 基本校验Bean放在参数中的情况的校验 【例如 User getUserInfoById(@NotNull(message = "不能为空") Integer id);】
     * @author: wangji
     * @date: 2018/3/13 10:11
     */
    private void validMethodParams(Object obj, Method method, Object[] params) {
        ExecutableValidator validatorParam = validator.forExecutables();
        Set<ConstraintViolation<Object>> validResult = validatorParam.validateParameters(obj, method, params);
        throwConstraintViolationException(validResult);
    }

    /**
     * @param validResult
     * @desction: 判断校验的结果是否存在异常
     * @author: wangji
     * @date: 2018/3/13 10:09
     */
    private void throwConstraintViolationException(Set<ConstraintViolation<Object>> validResult) {
        if (!validResult.isEmpty()) {
            throw new ConstraintViolationException(validResult);
        }
    }
}

使用

1.需要将EgValidate放置在class类中或者当前方法上让其被拦截

@Controller
@RequestMapping("/")
public class DoorPersonInfoController extends ExceptionHandleController {

 //    public class User implements Serializable {
//
//        @NotBlank(message = "用户名不能为空",groups = {ValidationDP1.class})
//        private String name;
//
//        @NotNull(message="地址不能为空")
//        private String address;
//    }

    /**
     * 不使用校验分组,使用默认的分组Default.class(Bean中没有编写校验分组的信息)
     *
     * @param user
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/test0")
    @EgValidate
    public AjaxResponse testValidator0(User user) throws Exception {
        AjaxResponse response = new AjaxResponse();
        response.setResult(true);
        response.setResultMsg("校验通过");
        return response;
    }

    /**
     * 使用方法上的分组校验
     *
     * @param user
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/test1")
    @EgValidate(groups = {ValidationDP1.class})
    public AjaxResponse testValidator1(User user) throws Exception {
        AjaxResponse response = new AjaxResponse();
        response.setResult(true);
        response.setResultMsg("校验通过");
        return response;
    }

    /**
     * 使用参数上的分组校验
     *
     * @param user
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/test2")
    @EgValidate
    public AjaxResponse testValidator2(@EgValidate(groups = {ValidationDP1.class, Default.class}) User user) throws Exception {
        AjaxResponse response = new AjaxResponse();
        response.setResult(true);
        response.setResultMsg("校验通过");
        return response;
    }


    /**
     * 先校验基本的Hibernate validator 注解,通过后使用参数上的分组校验Bean
     *
     * @param user
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping(value = "/test3")
    @EgValidate
    public AjaxResponse testValidator3(@EgValidate(groups = {ValidationDP1.class, Default.class}) User user, @NotNull(message = "不能为空") Integer id) throws Exception {
        AjaxResponse response = new AjaxResponse();
        response.setResult(true);
        response.setResultMsg("校验通过");
        return response;
    }


}

总结

之前考虑不够充分,经过多次的沟通和参考别人的实现,处理成现在的这个demo!多学习多思考多交流。

猜你喜欢

转载自blog.csdn.net/u012881904/article/details/79538895
今日推荐