博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
让Spring Controller 的方法基本数据类型参数支持Bean Validation
阅读量:7154 次
发布时间:2019-06-29

本文共 6415 字,大约阅读时间需要 21 分钟。

  hot3.png

让Spring Controller 的方法基本数据类型参数支持Bean Validation

   

Spring中的Bean Validation

    我们知道Spring MVC层是默认可以支持Bean Validation的,尝试使用了一下感觉很不方便,只支持对Bean的验证,还需要在Bean后面加一个BindingResult作为参数。而在我们的工程中有很多接口都是基本数据类型作为参数的。下面分享怎么来实现MVC层对基本数据类型提供Bean Validation的支持。

  Spring Mvc 层默认的Bean Validation支持配置可以参考这位朋友的博文:

    Spring中对Bean Validation可以支持方法级别的验证的,这块只支持Service层的,可以参考 。我们的实现中的很多代码也是参考了Spring这块的实现。

MVC层Bean Validation的扩展

    我们通过mvc的拦截器配合注解来实现这样的一个扩展。我们拦截Controller方法上带有@Valid注解的方法(这个注解来自Bean Validation规范),然后通过Spring的RequestMappingHandlerAdapter来获取每一个参数的值,然后使用org.hibernate.validator.internal.engine.ValidatorImpl (Hibernate对Bean Validation规范的实现,它额外提供了对方法参数的验证,原本的规范中的api是没有的)来根据每个参数上面的验证注解来验证这些参数是否合法。验证失败的话抛出ConstraintViolationException。

    这样的一个验证过程,下面是这个拦截器的代码:

 

/** * 添加Spring Controller 方法级别的Bean Validation的支持 * @author JiangFeng * */public class ValidationInterceptor implements HandlerInterceptor{	protected final Log logger = LogFactory.getLog(getClass());		private List
 argumentResolvers; @Autowired private Validator validator; @Autowired private RequestMappingHandlerAdapter adapter; private final Map
 argumentResolverCache = new ConcurrentHashMap
(256); private final Map
, Set
> initBinderCache = new ConcurrentHashMap
, Set
>(64); @Autowired public ValidationInterceptor(RequestMappingHandlerAdapter requestMappingHandlerAdapter){ argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers(); } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { LocalValidatorFactoryBean validatorFactoryBean = (LocalValidatorFactoryBean)validator; ValidatorImpl validatorImpl = (ValidatorImpl) validatorFactoryBean.getValidator(); ServletWebRequest webRequest = new ServletWebRequest(request, response); HandlerMethod method = (HandlerMethod)handler; Valid valid = method.getMethodAnnotation(Valid.class); if(valid!=null){ Class
[] groups = new Class
[0]; MethodParameter[] parameters = method.getMethodParameters(); Object[] parameterValues = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter); Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]"); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); WebDataBinderFactory webDataBinderFactory = getDataBinderFactory(method); Object value = resolver.resolveArgument(parameter, mavContainer, webRequest, webDataBinderFactory); parameterValues[i] = value; } Set
> violations = validatorImpl.validateParameters(method.getBean(), method.getMethod(), parameterValues, groups); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } } return true; } private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception { Class
 handlerType = handlerMethod.getBeanType(); Set
 methods = this.initBinderCache.get(handlerType); if (methods == null) { methods = HandlerMethodSelector.selectMethods(handlerType, RequestMappingHandlerAdapter.INIT_BINDER_METHODS); this.initBinderCache.put(handlerType, methods); } List
 initBinderMethods = new ArrayList
(); for (Method method : methods) { Object bean = handlerMethod.getBean(); initBinderMethods.add(new InvocableHandlerMethod(bean, method)); } return new ServletRequestDataBinderFactory(initBinderMethods, adapter.getWebBindingInitializer()); } private HandlerMethodArgumentResolver getArgumentResolver( MethodParameter parameter) { HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter); if (result == null) { for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) { if (logger.isTraceEnabled()) { logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" + parameter.getGenericParameterType() + "]"); } if (methodArgumentResolver.supportsParameter(parameter)) { result = methodArgumentResolver; this.argumentResolverCache.put(parameter, result); break; } } } return result; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }}

我们还需要在spring mvc的配置文件中启用Bean Validation

 

 

具体应用

    Bean Validation配合上统一异常处理,然后再加上前端js里面对json的统一解析。整个开发过程中已经不需要对验证做任何处理了。

    我的框架中的应用场景的代码

@RequestMapping("/handle/addFacilityAdd.action")    @ResponseBody    @Valid    @Workflow    public Result addFacilityAdd(    		 @NotEmpty(message = "设备类型不能为空") @RequestParam(value = "facilityId", required = false) String facilityId,             @Digits(fraction = 6, integer = 3) @RequestParam(value = "longitude", required = false) Double longitude,             @Digits(fraction = 6, integer = 3) @RequestParam(value = "latitude", required = false) Double latitude,             @NotEmpty(message = "地址不能为空") @RequestParam(value = "address", required = false) String address,             @NotEmpty(message = "内容不能为空") @RequestParam(value = "content", required = false) String content)            throws Exception

演示失败返回

{"success":false,"returnTime":"2014-04-18 10:51:50","error":{"errorCode":1002,"errorMessage":"错误的参数","fieldErrors":[{"field":"content","message":"内容不能为空"},{"field":"address","message":"地址不能为空"},{"field":"facilityId","message":"设备类型不能为空"}]},"result":{}}

统一异常拦截后的前端验证js方法

var Valid = {};Valid.valid = function (d) {    if(typeof d !='object'){        d = eval('(' + d + ')');    }    if (!d.success) {        if(d.error.fieldErrors.length>0){            for (var error in d.error.fieldErrors) {                Alert.warning(d.error.fieldErrors[error].message);            }        }else{            Alert.warning(d.error.errorMessage);        }        try {            console.error(d);        } catch (e) {        }        return false;    } else {        return true;    }}

在ajax的回调方法中先调用一验证,就可以直接提示出Bean Validation验证失败的错误信息了。

    

 http://git.oschina.net/for-1988/gbh91frxjy6msalqp28vi.code.git

转载于:https://my.oschina.net/FengJ/blog/223727

你可能感兴趣的文章
反射List<M> To DataTable|反射IList To DataTable|反射 DataTable To List<M>
查看>>
Spark版本定制第4天:Exactly Once的事务处理
查看>>
山地车车架完全手册
查看>>
如何使用SAE的Storage
查看>>
【Todo】InnoDB、MyISAM、数据库引擎
查看>>
iframe通信
查看>>
springboot maven打包一直失败
查看>>
Go:函数、defer
查看>>
js插件---GoJS 如何去水印
查看>>
js防止提交数据之后的按钮连击
查看>>
二年级的30道四则运算题
查看>>
Python 进阶_OOP 面向对象编程_组合与继承
查看>>
用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy
查看>>
使用sql语句修改表的主键和外键
查看>>
5.2二叉搜索树遍历(前序、中序、后序、层次、广度优先遍历)
查看>>
OAuth 2.0文档翻译(第一章)
查看>>
【转】三十分钟掌握STL
查看>>
Android控件在点击、选择时背景变化(button、listview)
查看>>
ubuntu 下载电影问题
查看>>
java aop 日志打印 正则设置
查看>>