`
Inmethetiger
  • 浏览: 111238 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring验证小结和问题

阅读更多

因为从云笔记中粘贴过来的,代码格式就没有了。格式稍好点的地址:Spring验证

目标:

  • Spring自带的验证方式
  • 基于JSR303的验证
  • 国际化显示错误信息

一:使用Spring自带的验证方式

       该种方式相对来说麻烦一点,需要为每个需要验证的实体类编写一个验证类,不过好处是可以处理多字段组合验证以及业务逻辑等复杂验证

 

1.1:定义实体类(User)

public class User {

 

    private String username;

 

    private String nickname;

 

    private String password;

 

   //省略getter /setter

}

 

1.2:定义实体类验证类(UserValidator)

需要继承Validator接口

public class UserValidator implements Validator {

 

    @Override

    public boolean supports(Class<?> clazz) {

        return User.class.equals(clazz); 

    }

 

  public void validate(Object target, Errors errors) {

       User user = (User)target;

        if(StringUtils.isEmpty(user.getUsername())){

            //1:使用这种方式,会报错(No message found under code 'empty.user.username.user.username' for locale 'zh_CN'.),因为rejectValue的第二个参数都是errorcode

            //errors.rejectValue("username","empty.user.username");

            //errors.rejectValue("username","用户名不能为空");

 

            //2:正确用法:rejectValue(String filed,String errorcode,Object[] errorArgs,String defaultMessage)

            errors.rejectValue("username","empty.user.username","用户名不能为空Default");

 

            //使用该种方式,不需要配置ResourceBundleMessageSource

           // ValidationUtils.rejectIfEmpty(errors,"username","empty.user.username","用户名不能为空");

        } else {

           int length =  user.getUsername().length();

            if(length<=3){

                errors.rejectValue("username","min.length.user.username","用户名长度不能小于3Default");

            }else if (length>=6){

                errors.rejectValue("username","max.length.user.username","用户名不能大于6Default");

            }

 

        }

        }

 

}

 

1.3:编写控制器代码:

 @RequestMapping(value = "validatorBySpring", method = RequestMethod.GET)

    public String validatorBySpringForm(@ModelAttribute("user") User user) {

        return "validator/validatorBySpring";

    }

 

    /**

     * 第一种,使用spring自带的validator

     */

 

    @RequestMapping(value = "validatorBySpring", method = RequestMethod.POST)

    public String validatorBySpring(@ModelAttribute("user") User user,

                                    BindingResult result) {

        userValidator.validate(user, result);

        if (result.hasErrors()) {

            return "validator/validatorBySpring";

        }

        return "validator/success";

    }

 

注意:在get方法中,需要加上@ModelAttribute,否则无法访问,或者可以抽出来,写一个以下方法:

@ModelAttribute(“user")

public void getUser(){

     return new User();

},这样的话,访问该控制器的时候都会调用该方法

 

 

1.4:前台

           <form:form action="${ctx}/validator/validatorBySpring" method="post" modelAttribute="user">

               <tr>

                   <td><form:label path="username" >Username</form:label></td>

                   <td><form:input path="username" ></form:input></td>

                   <td><form:errors path="username"></form:errors></td>

               </tr>

 

               <tr>

                   <td> <form:label path="password">password</form:label>  </td>

                   <td> <form:input path="password"></form:input>     </td>

                   <td><form:errors path="password"></form:errors> </td>

               </tr>

 

               <tr>

                   <td> <form:label path="email">email</form:label>  </td>

                   <td> <form:input path="email"></form:input>     </td>

                   <td><form:errors path="email"></form:errors> </td>

               </tr>

               <tr>

                   <td colspan="3">

                       <input type="submit" value="SUBMIT">

                   </td>

               </tr>

 

           </form:form>

       

 

1.5: 在上述代码已经可以完成Spring自带验证了,而且界面能正常显示错误信息,但是在实际过程中,错误信息采用的是硬编码,这是不可取的,所以,接下来需要国际化错误信息

    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">

        <property name="basename">

            <value>messages</value>

        </property>

    </bean>

 

messages_zh_CN.properties 在resources/下

empty.user.username=用户名不能为空

min.length.user.username=用户名长度不能小于3

max.length.user.username=用户名长度不能大于6

 

其中的errorcode可以随便写,只要在messages中对应上即可,在这种情况下,在实体验证类中,就可以使用第一种方式即:errors.rejectValue("username",”empty.user.username)。因为在message文件中有对应的errorcode,所以能正常显示

 

 

 

扩展:

1:不使用rejectValue,而是使用reject,界面该如何显示

eg:errors.reject(“empty.user.username”,”用户名不能为空");

直接在form中写如下:<form:errors />会显示全部错误

 

2:使用ValidationUtils

ValidationUtils.rejectIfEmpty(errors,"username","empty.user.username","用户名不能为空”);

 

 

 

 

 

 Errors主要使用方法:

 reject(String errorcode,Object[] errorArgs,String defaultMessage)

 

rejectValue(String filed,String errorcode,Object[] errorArgs,String defaultMessage)

 

BinderResult接口扩展了Erros接口,以便可以使用Spring的Validator对对象进行校验,同时获取绑定结果对象的信息。

 

二:使用基于jsr303的验证

在Spring3.x企业开发实战里面提到:通过binder.setValidator之后,Spring MVC将使用它对入参对象进行校验,将不再使用Spring框架装配的Validator对入参进行校验。换句话说:即使在入参上标注了@Valid注解,也不会再根据入参对象类中的jsr303注解进行校验了。

 

2.1:

1:使用jsr303注解,可以注解基于javax.validator或者基于hibernated 。之前觉得没有什么不同,但是今天发现还是有不同的

 

2.1.1使用之前的配置,不做任何修改,messages里面没有任何对应的errorcode

 

@NotEmpty

起作用了,提示:may not be empty ,为什么会显示这个会有解释

 

 @NotEmpty(message = "{username.not.empty}")

提示:{username.not.empty}

 

 

不起作用的原因是:NotNull和NotEmpty是不同滴。

 

@NotNull

并没有进行验证,而是直接通过,也就是验证没有起作用

 

@NotNull(message = "{username.not.empty}”)

仍然没有起作用

 

2.1.2:在资源文件中配置如下:

username.not.empty=用户名不能为空1

@NotEmpty

显示  may not be empty

 

 @NotEmpty(message = "{username.not.empty}")

提示:{username.not.empty} 。即,直接显示message里面的内容,而我要的是显示:用户名不能为空1

 

2.1.3:在资源文件配置如下:

username.not.empty=用户名不能为空1

NotNull.user.username=用户名不能为空

NotEmpty.user.username=用户名不能为空

 

 

    @NotEmpty 提示:用户名不能为空

 

    @NotEmpty(message = "{username.not.empty}”)   提示用户名不能为空,即:message里面的没有起作用,

 

去掉NotEmpty.user.username=用户名不能为空,则提示为{username.not.empty}

 

 

 

2.1.4:加上以上配置之后

<!-- 以下 validator  ConversionService 在使用 mvc:annotation-driven 会 自动注册-->

    <bean id="validator"

          class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">

        <property name="providerClass"  value="org.hibernate.validator.HibernateValidator"/>

        <!-- 如果不加默认到 使用classpath下的 ValidationMessages.properties -->

        <property name="validationMessageSource" ref="messageSource"/>

    </bean>

 

资源文件还是如下:

username.not.empty=用户名不能为空1

NotNull.user.username=用户名不能为空

NotEmpty.user.username=用户名不能为空

 

注意,上面的并没有在mvc:annoation-driver中注册

 

 

 @NotEmpty 提示用户名不能为空

 

@NotEmpty(message = "{username.not.empty}")提示用户名不能为空,即messages仍然没有起作用

 

去掉NotEmpty.user.username=用户名不能为空,则提示为{username.not.empty}

 

 

 

将<mvc:annotation-driven validator="validator" />

 

    @NotEmpty 提示用户名不能为空

 

@NotEmpty(message = "{username.not.empty}")提示用户名不能为空,即messages仍然没有起作用

 

去掉NotEmpty.user.username=用户名不能为空,则提示为:用户名不能为空1

 

总结:因为不知道为什么基于javax.validator的注解不起作用,所以字总结基于hibernate的注解。这里一NotEmpty来举例。

首先,如果一旦在实体上标识了该注解,则就已经起作用了。如果不配置错误信息,将使用默认的:在hibernate-validator.jar中的Resource中,有一个ValidatorMessages.properties。里面有错误主力的默认显示:org.hibernate.validator.constraints.NotEmpty.message=may not be empty,这也就是为什么只配置了@NotEmpty之后显示 may not be empty的原因。当配置了自己的资源文件后,因为没有配置validator,所以还是显示之前的错误。那为什么后面没有配置validator。为什么NotEmpty.user.usrname能显示而{username.not.empty}不能正常显示呢?这是因为FileError实现了MessageResourceResolvable接口,里面有自己的一套规则:

Annotation.entity.attribute。所以,我使用NotEmpty.user.username能显示中文,而使用{usrname.not.empty}却显示{username.not.empty}。在配置了validator之后,因为<mvc:annotaitonDriver 中没有指定validator,所以相当于没有配置。即:2.1.3的测试结果和2.1.4的测试结果一样。只有配置了 mvc:annotaiton-driver validator=“validator”之后,才能自定义错误格式,这种情况下才@NotEmpty{message={username.not.empty}}才能显示出来,不过NotEmpty.user.username这样格式的优先级比较高,两者放在一起,还是会显示后者。这就是,为什么在所有的一切都配置好之后,还是会显示“用户名不能为空”,只有在messages里面去掉之后才能显示username.not.empty的信息。

 

 

 

 

 

 

问题:

1:基于spring自带的validator前台不使用Spring form标签如何展示错误? 

2:使用ajax方式,怎样进行验证,和上面是同样的问题,也就是不使用表单

 

其中,基于jsr303的可以实现,可以参考springside里面的代码,但是自带的却不好实现,因为循环FiledError的时候,只能得到errorcode和defultMessage,得不到国际化信息

 

 

资料:

JSR 303 - Bean Validation 介绍及最佳实践

http://www.ibm.com/developerworks/cn/java/j-lo-jsr303/

 

开涛的博客:跟我学Spring mvc 3

http://jinnianshilongnian.iteye.com/blog/1617451

 

spring 3.x 企业开发实战

 

 

 

 

 

1
2
分享到:
评论
4 楼 Inmethetiger 2014-07-28  
yixiandave 写道

能不能在Validation注解的message里面写国际化信息的标识然后在处理过程中转化呢?就是在err.getDefaultMessage()后做一步处理

你的意思是使用errorCode,试了,不行,如果是复杂的处理的话不知道如何做!除非查看源码来看hibernate是如何实现的
3 楼 yixiandave 2014-07-28  
Inmethetiger 写道
yixiandave 写道
如果用JSR303的话,可以引入hibernate-validation包,然后直接在spring mvc的requestMapping方法参数中加入@Valid注解即可实现自动校验,如果要获取验证错误信息可以再注入一个Errors参数。错误信息都在这里面,然后用JSON形式返回前端即可(没用过spring的前端模板,刚接触spring mvc就是前后端分离的开发模式,所以第一个问题帮不了你)。

附上代码案例,因为我这里用了spring4.0的@RestController所以省略了一个@ResponseBody注解。如果是普通的@Controller需要在方法头部或者返回值类型前面加上,另外因为自己的项目图方便用了很多groovy所以可能代码会有点怪异,不过大体上应该能看懂。



我在最后面写了:其中,基于jsr303的可以解决以上两种问题,可以参考springside里面的代码,但是Spring自带的却不好实现,因为循环FiledError的时候,只能得到errorcode和defultMessage,得不到国际化信息

嗯,这种方法我知道,我现在主要的是考虑国际化,你的这个代码,errInfo.put("msg",err.getDefaultMessage())。只是拿到了默认的。

基于Jsr303确实能够得到国际化的信息,之前已经实现了,但是基于spring validator却无法实现,如果没有defaultMessage,则无法显示,如果有,则也只是显示defaultMessage,而不是显示messages属性文件中定义的错误信息,不过还是谢了


能不能在Validation注解的message里面写国际化信息的标识然后在处理过程中转化呢?就是在err.getDefaultMessage()后做一步处理
2 楼 Inmethetiger 2014-07-28  
yixiandave 写道
如果用JSR303的话,可以引入hibernate-validation包,然后直接在spring mvc的requestMapping方法参数中加入@Valid注解即可实现自动校验,如果要获取验证错误信息可以再注入一个Errors参数。错误信息都在这里面,然后用JSON形式返回前端即可(没用过spring的前端模板,刚接触spring mvc就是前后端分离的开发模式,所以第一个问题帮不了你)。

附上代码案例,因为我这里用了spring4.0的@RestController所以省略了一个@ResponseBody注解。如果是普通的@Controller需要在方法头部或者返回值类型前面加上,另外因为自己的项目图方便用了很多groovy所以可能代码会有点怪异,不过大体上应该能看懂。



我在最后面写了:其中,基于jsr303的可以解决以上两种问题,可以参考springside里面的代码,但是Spring自带的却不好实现,因为循环FiledError的时候,只能得到errorcode和defultMessage,得不到国际化信息

嗯,这种方法我知道,我现在主要的是考虑国际化,你的这个代码,errInfo.put("msg",err.getDefaultMessage())。只是拿到了默认的。

基于Jsr303确实能够得到国际化的信息,之前已经实现了,但是基于spring validator却无法实现,如果没有defaultMessage,则无法显示,如果有,则也只是显示defaultMessage,而不是显示messages属性文件中定义的错误信息,不过还是谢了
1 楼 yixiandave 2014-07-27  
如果用JSR303的话,可以引入hibernate-validation包,然后直接在spring mvc的requestMapping方法参数中加入@Valid注解即可实现自动校验,如果要获取验证错误信息可以再注入一个Errors参数。错误信息都在这里面,然后用JSON形式返回前端即可(没用过spring的前端模板,刚接触spring mvc就是前后端分离的开发模式,所以第一个问题帮不了你)。

附上代码案例,因为我这里用了spring4.0的@RestController所以省略了一个@ResponseBody注解。如果是普通的@Controller需要在方法头部或者返回值类型前面加上,另外因为自己的项目图方便用了很多groovy所以可能代码会有点怪异,不过大体上应该能看懂。
    @RequestMapping(value = "login", method = RequestMethod.POST)
    SessAccount doLogin(@Valid @RequestBody LoginInfo loginInfo, Errors errors, HttpServletRequest request) {
        ValidErrorHandleUtils.handleErrors(errors);
        String ip = IpAddressUtils.readRequestIp(request);
        loginInfo.setLoginIp(ip);
        SessAccount account = loginService.checkLogin(loginInfo);
        String key = accountCache.saveUser(account)
        account.setLoginKey(key)
        return account;
    }


errors对象的处理(我这里用了一个通用方法),JSONObject来自阿里的fastjson包
    public static void handleErrors(Errors errors) {
        List<JSONObject> errInfoList = new ArrayList<>();
        if (errors.hasErrors()) {
            for (ObjectError err : errors.getAllErrors()) {
                errInfoList.add(readErrorInfo(err));
            }
            throw new ParamInvalidException(JSON.toJSONString(errInfoList));
        }
    }

    private static JSONObject readErrorInfo(ObjectError err){
        JSONObject errInfo = new JSONObject();
        errInfo.put("field",err.getObjectName());
        errInfo.put("msg",err.getDefaultMessage());
        return errInfo;
    }


需要校验的对象定义
public class LoginInfo {
    @NotNull(message = "用户名不能为空")
    private String loginId;
    @NotNull(message = "密码不能为空")
    private String password;
    private String loginIp;

    public String getLoginId() {
        return loginId;
    }

    public void setLoginId(String loginId) {
        this.loginId = loginId;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPwdHash(IHash hashProvider){
        return hashProvider.hashString(password);
    }

    public String getLoginIp() {
        return loginIp;
    }

    public void setLoginIp(String loginIp) {
        this.loginIp = loginIp;
    }
}

相关推荐

    spring 验证总结

    在Spring框架中,验证是确保数据输入正确性和完整性的关键环节。本文将深入探讨Spring的两种主要验证机制:基于注解的验证和基于Validator接口的验证,并结合JSR303 Bean Validation规范来理解这些机制如何协同工作...

    Spring验证/list配置

    总结起来,`Spring验证/list配置`涉及到如何在Spring Web应用中对集合类型的数据进行验证,这包括使用`@Validated`、`@Valid`注解,以及自定义验证规则和处理验证错误。理解并熟练运用这些知识点,能够提升应用程序...

    spring_validator验证

    Spring Validator验证是Spring MVC框架中的一个关键特性,用于在服务器端对用户输入数据进行校验。在Spring MVC 3.0版本中,引入了注解驱动的验证方式,极大地简化了验证逻辑,使得开发者能够更加方便地处理表单数据...

    Spring框架小结

    - **安全控制**:实现统一的安全策略,如身份验证和授权。 - **性能监控**:监控方法执行的时间,帮助识别性能瓶颈。 #### 实现原理 AOP的核心是动态代理机制。Spring框架支持两种类型的动态代理: - **JDK动态...

    SpringSecurity学习总结源代码

    SpringSecurity是Java开发中用于构建安全Web应用的框架,它提供了强大的身份验证、授权和访问控制功能。在本文中,我们将深入探讨SpringSecurity的核心概念、关键组件以及如何配置和使用这个框架。 首先,Spring...

    spring2.5 的 security 权限验证

    总结,Spring Security 2.5的权限验证机制是其强大功能的体现,通过合理的配置和使用,开发者可以构建出安全、可靠的Web应用。无论是基础的认证授权,还是复杂的会话管理和异常处理,Spring Security都能提供全面的...

    Struts2+Hibernate+Spring项目小结――Struts2部分总结

    Struts2作为MVC框架,提供了丰富的功能和灵活性来处理表单验证、错误处理和服务端校验等问题。理解并熟练运用上述知识点,能够帮助开发者构建出更加健壮、用户体验良好的Web应用。在实际项目中,还需要结合Hibernate...

    Spring框架基础总结

    2. **Spring上下文**:为Spring框架提供上下文信息,是基于核心容器的抽象,提供了更强大的功能,如国际化支持、事件传播、资源加载和验证机制等。 3. **Spring AOP**:将面向切面的编程功能集成到Spring框架中,为...

    Spring_springmvc详细总结

    Spring MVC是Spring框架的一个核心模块,专为构建Web应用程序而设计。它提供了模型-视图-控制器(MVC)架构,使...通过阅读"SpringMVC3深入总结.docx"和"Spring详细总结.docx",你可以获得更深入的理解和实践经验。

    Spring MVC 学习记录总结1

    在这个学习记录总结中,我们将深入理解Spring MVC的核心概念、主要组件以及其工作流程。 1. Spring MVC 概述 Spring MVC 是Spring框架的一部分,它基于Spring IoC(Inversion of Control,控制反转)容器,简化了...

    Spring Security3 安全 个人总结

    在这个总结中,我们将详细介绍 Spring Security3 的安全机制、原理和核心组件。 认证管理器 认证管理器是 Spring Security3 的核心组件之一,负责处理用户的认证请求。认证管理器将用户名和密码与系统中的用户信息...

    Spring Security 学习总结1_3

    Spring Security 是一个强大的且高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序。它提供了全面的安全解决方案,包括Web安全、方法调用安全、API安全等多个方面。Spring Security的核心功能包括...

    spring4.0框架demo

    4. 数据绑定与验证:模型数据可以直接绑定到控制器方法的参数上,同时支持JSR-303/JSR-349验证,确保数据的准确性和完整性。 5. RESTful支持:Spring MVC 4.0加强了对RESTful风格的支持,通过@RequestMapping注解...

    spring-security 官方文档 中文版

    - **小结**:这些组件共同构成了 Spring Security 的核心架构,提供了强大的身份验证和授权能力。 **5.3 验证** - **什么是 Spring Security 的验证呢?** - Spring Security 的验证机制允许开发者自定义认证过程...

    Spring攻略(第二版 中文高清版).part1

    1.15 小结 56 第2章 高级Spring IoC容器 57 2.1 调用静态工厂方法创建Bean 57 2.1.1 问题 57 2.1.2 解决方案 57 2.1.3 工作原理 57 2.2 调用一个实例工厂方法创建Bean 58 2.2.1 问题 58 2.2.2 ...

    Spring web MVC和spring 2.0 form tag解说

    总结,Spring Web MVC和Spring 2.0 Form Tag的结合,使得在Java Web开发中处理表单和模型数据变得更加简洁高效。通过使用Form Tag,开发者可以专注于业务逻辑,而不必过多关注表单的底层细节,提高了开发效率和代码...

    spring boot + 极验滑动验证

    总结,整合Spring Boot 2和极验滑动验证涉及到配置Spring Boot项目、添加极验验证依赖、配置验证参数、编写后端控制器、前端集成以及测试验证流程。这个过程要求对Spring Boot和前端开发有一定的了解,同时熟悉使用...

    Spring+Netty+WebSocket实例

    总结来说,Spring、Netty和WebSocket的结合为构建实时、双向通信的应用提供了强大的基础。通过深入理解这三个组件的工作原理和它们之间的交互,开发者能够创建出满足各种需求的现代Web应用。本实例的实践价值在于它...

Global site tag (gtag.js) - Google Analytics