问题:
问题描述:从页面上获取用户输入的项目值,登录到DB中的某个Table表里,出现登录异常。
问题原因:Table里的属性有最大长度check,输入的项目长度大于表中属性最大长度。
但实际上在登录操作之前,已经对属性最大长度进行了check。
Form里对属性做了如下操作:例如DB可登录最大长度20
@Size(min = 1, max = 20) public String name;
根本原因:DB中属性的最大长度单位是字节,但@Size做的check是字符串的长度check,单位是字符。
通俗的理解就是,两边的check单位不一致。
例如 String a = "汉字"; 此时 字符串a的字符长度为2,但一个汉字等于2个字节,也就是说
字符串a的字节长度是4。
解决方法:
spring框架自带的@size已经不能满足我们此时的需求,打算自己实装一个check类来替代@size的作用。
实现步骤:
要完成一个自定义的注解,需要下面三个步骤。
第一步:首先定义一个validation check 注解
第二步:写个类来实现第一步定义的注解,即实现验证器
第三步:添加一个默认的错误信息
下面我们就开始吧。
引入validation包。因为我的是maven工程。pom.xml里添加下面配置
<dependency> <groupid>javax.validation</groupid> <artifactid>validation-api</artifactid> <version>1.1.0.Final</version> </dependency>
如果是普通java工程,直接导入validation-api-1.1.0.Final.jar即可。
这个包提供的常用注解及说明。
下面写一个注解类,CharSize.java
import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Documented @Constraint(validatedBy = CharSizeValidator.class) @Target({ METHOD, FIELD, ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface CharSize { String message() default "{javax.validation.constraints.Size.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; /** * @return size the element must be higher or equal to */ int min() default 0; /** * @return size the element must be lower or equal to */ int max() default Integer.MAX_VALUE; }
详细说明:
@Target表示该注解可以用在什么地方,比如可以出现在field属性定义上,method上,或者是另一个annotation注解上。
这里限定只能出现在方法,属性和另一个注解上。
@Constraint表示该注解的实现类,表示哪个验证器提供验证,这里是CharSizeValidator.class这个类来实现check功能。
@Retention表示该注解的保存范围。RUNTIME表示在源码,编译好的class文件中保存信息,执行的时候加载到JVM中去。
@interface表明这是一个注解,关键字。message(),groups(),payload()这个三个方法一般约束接口都具备,其中message()是必须的。
default表示默认初期值,"{javax.validation.constraints.Size.message}";这里我没有自己定义新的默认message,而且沿用@size的
默认message,(改善要,理应新建一个message管理的属性资源文件),这里{}表示引用资源文件,{}内是文件信息的可以,如果
不加{},表示引号内的内容就是消息本身。
groups()表示该约束属于哪个验证组,分组check。
min和max是我自己添加进去的属性。
下面就来实现这个约束,CharSizeValidator.java
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class CharSizeValidator implements ConstraintValidator<CharSize,String> { public int maxCharSize; public void initialize(CharSize charSize) { this.maxCharSize = charSize.max(); } @Override public boolean isValid(String StringValue, ConstraintValidatorContext context) { if(StringValue == null){ return true; } int f = StringValue.getBytes().length; if(f > maxCharSize){ return false; }else{ return true; } } }
Form里添加我们自定义的注解吧。EchoForm.java(其他代码这里就省略了)
@NotNull // (1) @CharSize(max = 20, message = "name 不能长于20位字节!") public String name;
这里对name属性 进行charSize 检证,长度设置20字节,提供出错时抛出的提示信息。
测试:在controller.java里如下方法
@RequestMapping(value = "hello", method = {RequestMethod.GET, RequestMethod.POST}) public String hello(@Validated EchoForm form, BindingResult result, Model model) { if (result.hasErrors()) { return "home2"; } return "home2"; }
这里注意@Validated check对象的后面需要紧跟 BindingResult 对象
测试时输入了16个汉字,共32个字节,大于20个字节,成功捕获,满足我们的需求。
OK,大功告成!
