问题:
问题描述:从页面上获取用户输入的项目值,登录到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,大功告成!