目录
3.1:ConversionService组件:负责数据类型的转换以及格式化功能;
3.3:bindingResult负责保存以及解析数据绑定期间数据校验产生的错误;
2.1:实现Converter接口,做一个自定义类型的转换器
2.2:将这个Converter配置在ConversionService中
2.3:告诉SpringNMVC使用这个ConversionService
2.4:源码上WebDataBinder上的ConversionService组件就替换了;并且还自动添加了默认的转换器
1:《mvc:annotation-driven/》在那配置
2.1:《mvc:default-servlet-handler/》 《mvc:annotation-driven/》都不配置
2.2:只配置《mvc:default-servlet-handler/》
2.3:加上《mvc:default-servlet-handler/》,加上《mvc:annotation-driven/》
4.3:如果使用springmvc的表单标签,springmvc会自动提该配置信息
一:分析springmvc绑定数据类型源码
1:问题:
- 页面提交的所有数据都是字符串
- Integer age,Date birth ; employName=zhangsan&age=18&gender=1;String age = request.getParameter("age");
2:数据转换牵扯到以下操作;
3:分析源码
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer"); Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory"); String name = ModelFactory.getNameForParameter(parameter); ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null) { mavContainer.setBinding(name, ann.binding()); } Object attribute = null; BindingResult bindingResult = null; if (mavContainer.containsAttribute(name)) { attribute = mavContainer.getModel().get(name); } else { try { attribute = this.createAttribute(name, parameter, binderFactory, webRequest); } catch (BindException var10) { if (this.isBindExceptionRequired(parameter)) { throw var10; } if (parameter.getParameterType() == Optional.class) { attribute = Optional.empty(); } bindingResult = var10.getBindingResult(); } } if (bindingResult == null) { //将页面提交过来的数据封装到javaBean的属性中 WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { if (!mavContainer.isBindingDisabled(name)) { this.bindRequestParameters(binder, webRequest); } this.validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } if (!parameter.getParameterType().isInstance(attribute)) { attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); } bindingResult = binder.getBindingResult(); } Map<String, Object> bindingResultModel = bindingResult.getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return attribute; }
3.1:ConversionService组件:负责数据类型的转换以及格式化功能;
ConversionService中有非常多的converter;不同类型的转换和格式化用它自己的converter
ConversionService converters =
@org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.LocalDate -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@edd23ab
@org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.LocalDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@4f10103d
@org.springframework.format.annotation.DateTimeFormat java.time.LocalTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.LocalTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@2b482406
@org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.OffsetDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@5bff2a4e
@org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.OffsetTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@220f2940
@org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime -> java.lang.String: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.time.ZonedDateTime -> java.lang.String : org.springframework.format.datetime.standard.TemporalAccessorPrinter@174673c
@org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654
@org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654
@org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
@org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@67fe49bf
java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@5184d61b
java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@6a45e172
java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@64048fc3
java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@37cbfe30
java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@79fc7df4
java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@6d7337c1
java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@6e0b7bd8
java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@1135afc3
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDate: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.LocalDate: org.springframework.format.datetime.standard.TemporalAccessorParser@6228dd42
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.LocalDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@6bf61650
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.LocalTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.LocalTime: org.springframework.format.datetime.standard.TemporalAccessorParser@2837beeb
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.OffsetDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@60f3f7
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.OffsetTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.OffsetTime: org.springframework.format.datetime.standard.TemporalAccessorParser@3cb8bdb7
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime: org.springframework.format.datetime.standard.Jsr310DateTimeFormatAnnotationFormatterFactory@39274b77,java.lang.String -> java.time.ZonedDateTime: org.springframework.format.datetime.standard.TemporalAccessorParser@14a1511f
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654
java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@32abc654
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@140bb45d
java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@22f562e2
java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@5f2594f5
java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@1347a7be
【java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@28a5e291】
java.lang.String -> java.time.Instant: org.springframework.format.datetime.standard.InstantFormatter@1eb74d34
java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@6def03d3
java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@569d2e80
java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@343b18b
java.time.Instant -> java.lang.String : org.springframework.format.datetime.standard.InstantFormatter@1eb74d34
java.time.ZoneId -> java.util.TimeZone : org.springframework.core.convert.support.ZoneIdToTimeZoneConverter@63b3b722
java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@1f07f950
java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@3bfdcdf6
java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@19cfea5e
java...
3.2:validators负责数据校验工作;
3.3:bindingResult负责保存以及解析数据绑定期间数据校验产生的错误;
4:图解数据绑定流程
二:自定义类型转换;
1:原理步骤
- ConversionService::是一个接口; 它里面有Converter(转换器)进行工作:
- Converter是ConversionService中的组件;
2:实际操作步骤
2.1:实现Converter接口,做一个自定义类型的转换器
Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到 ConversionServiceFactoryBean 中:
- Converter<S,T>:将 S 类型对象转为 T 类型对象
- ConverterFactory:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类
- GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换
自定义装换器
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import com.atguigu.springmvc.crud.entities.Department;
import com.atguigu.springmvc.crud.entities.Employee;
/**
* 将字符串转换为Employee对象类型
*/
@Component
public class StringToEmployeeConverter implements Converter<String, Employee> {
@Override
public Employee convert(String source) {
if(source!=null){
String[] strs = source.split("-");
if(strs!=null && strs.length == 4){
String lastName = strs[0];
String email = strs[1];
Integer gender = Integer.parseInt(strs[2]);
Integer deptId = Integer.parseInt(strs[3]);
Department dept = new Department();
dept.setId(deptId);
Employee employee = new Employee(null,lastName,email,gender,dept);
System.out.println(source+"--converter--"+employee);
return employee ;
}
}
return null;
}
}
2.2:将这个Converter配置在ConversionService中
<!-- 告诉SpringMVC别用默认的ConversionService,
而用我自定义的ConversionService、可能有我们自定义的Converter; -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--converters转换器中添加我们自定义的类型转换器 -->
<property name="converters">
<set>
<bean class="com.atguigu.component.MyStringToEmployeeConverter"></bean>
</set>
</property>
</bean>
2.3:告诉SpringNMVC使用这个ConversionService
<!-- conversion-service="conversionService":使用我们自己配置的类型转换组件 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
2.4:源码上WebDataBinder上的ConversionService组件就替换了;并且还自动添加了默认的转换器
ConversionService converters =
java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@47d21368
java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@3cdad94b
java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@2a65d058
java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@5b63b99f
java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@1fee86c
java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@281e80cc
java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@7cd83820
java.lang.String -> com.atguigu.bean.Employee : com.atguigu.component.MyStringToEmployeeConverter@3dc22c7a
java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@4331ec46
java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@76a136a0
java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@31192e76
java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@761ba575
java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@17fc3d69
java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@38f0c949
java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@8784d56
java.time.ZoneId -> java.util.TimeZone : org.springframework.core.convert.support.ZoneIdToTimeZoneConverter@c0a6ab8
java.util.Locale -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@406235ad
java.util.Properties -> java.lang.String : org.springframework.core.convert.support.PropertiesToStringConverter@7e193089
java.util.TimeZone -> java.time.ZoneId : org.springframework.core.convert.support.TimeZoneToZoneIdConverter@463abd52
java.util.UUID -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@59e6cea9
org.springframework.core.convert.support.ArrayToArrayConverter@1a90e2f2
org.springframework.core.convert.support.ArrayToCollectionConverter@6762ee5d
org.springframework.core.convert.support.ArrayToObjectConverter@1aae2bbf
org.springframework.core.convert.support.ArrayToStringConverter@15ee899f
org.springframework.core.convert.support.ByteBufferConverter@2609c195
org.springframework.core.convert.support.ByteBufferConverter@2609c195
org.springframework.core.convert.support.CollectionToArrayConverter@50c81740
org.springframework.core.convert.support.CollectionToCollectionConverter@75ece48f
org.springframework.core.convert.support.CollectionToObjectConverter@59d26508
org.springframework.core.convert.support.CollectionToStringConverter@1960bfcd
org.springframework.core.convert.support.FallbackObjectToStringConverter@1137fd96
org.springframework.core.convert.support.IdToEntityConverter@6a196118,org.springframework.core.convert.support.ObjectToObjectConverter@27400a7
org.springframework.core.convert.support.MapToMapConverter@50cfc69
org.springframework.core.convert.support.ObjectToArrayConverter@78a37337
org.springframework.core.convert.support.ObjectToCollectionConverter@3a0b9fce
org.springframework.core.convert.support.StringToArrayConverter@8747ea2
org.springframework.core.convert.support.StringToCollectionConverter@324a432d
三:《mvc:annotation-driven》
1:《mvc:annotation-driven/》在那配置
- 直接配置响应的页面:无需经过控制 器来执行结果 ;但会导致其他请求路径失效,需要配置mvc:annotation-driven标签
<mvc:view-controller path="/success" view-name="success"/> |
- RESTful-CRUD操作,删除时,通过jQuery执行delete请求时,找不到静态资源,需要配置mvc:annotation-driven标签
<mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理。 |
- 配置类型转换器服务时,需要指定转换器服务引用
<mvc:annotation-driven conversion-service=“conversionService”/> 会将自定义的
ConversionService 注册到 Spring MVC 的上下文中
- 后面完成JSR 303数据验证,也需要配置
2:《mvc:annotation-driven》的作用
通过<mvc:default-servlet-handler/> <mvc:annotation-driven/>的配置来解析<mvc:annotation-driven/>的作用
2.1:《mvc:default-servlet-handler/》 《mvc:annotation-driven/》都不配置
动态资源(@RequestMapping映射的资源能访问),静态资源(js,html,img)不可访问
2.2:只配置《mvc:default-servlet-handler/》
2.3:加上《mvc:default-servlet-handler/》,加上《mvc:annotation-driven/》
SimpleUrlHandlerMapping:将请求直接交给tomcat;有他,静态资源就没问题
四:数据格式化
1:数据格式化概述
- 对属性对象的输入/输出进行格式化,从其本质上讲依然属于 “类型转换” 的范畴
- 在自定义装换器中创建的ConversionService组件是没有格式化器存在的;因为他实现的是ConversionServiceFactoryBean;只有装换器;
- 解决办法是实现FormattingConversionServiceFactroyBean 这个工厂,不仅拥有转换器,还拥有格式化器
2:日期格式化
在对应的属性上加上@DateTimeFormat注解,可以改变前台提交的时候该字段的格式
3:数字格式化
五:数据校验-JSR303校验
1:如何校验
①使用JSR 303验证标准
Java Specification Requests的缩写,意思是Java 规范提案
②加入hibernate validator验证框架-导包
第三方校验框架,导包:
<!--jsr303校验--> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>7.0.0.Alpha6</version> </dependency>
③在SpringMVC配置文件中增加<mvc:annotation-driven/>
④需要在bean的属性上增加对应验证的注解
⑤在目标方法bean类型的前面增加@Valid注解
2:检验错误信息展示
给需要校验的javaBean后面紧跟一个BindingResult。这个BindingResult就是封装前一个bean的校验结果;
没有错误正常流转业务,有错误就继续返回原页面,然后使用springmvc标签展示错误信息
3:使用原生表单提示数据校验错误信息
如果使用原生的表单,那么提取BindingResult中的错误信息,放在请求域中带到表单;
4:提示检验错误信息的国际化配置
- 每个属性在数据绑定和数据校验发生错误时,都会生成一个对应的 FieldError 对象。
- 当一个属性校验失败后,校验框架会为该属性生成 4 个消息代码,这些代码以校验注解类名为前缀,结合 modleAttribute、属性名及属性类型名生成多个对应的消息代码:例如 User 类中的 password 属性标注了一个 @Pattern 注解,当该属性值不满足 @Pattern 所定义的规则时, 就会产生以下 4 个错误代码:
codes(优先级从高到底,精确优先)
[
Email.employee.email, 校验规则.隐含模型中这个对象的key.对象的属性
Email.email, 校验规则.属性名
Email.java.lang.String, 校验规则.属性类型
];
1、如果是隐含模型中employee对象的email属性字段发生了@Email校验错误,就会生成 Email.employee.email;
2、 Email.email:所有的email属性只要发生了@Email错误;
3、 Email.java.lang.String,:只要是String类型发生了@Email错误
4、Email:只要发生了@Email校验错误;
- 当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看 WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认的错误消息,否则使用国际化消息。
- 若数据类型转换或数据格式转换时发生错误,或该有的参数不存在,或调用处理方法时发生错误,都会在隐含模型中创建错误消息。其错误代码前缀说明如下:
- required:必要的参数不存在。如 @RequiredParam(“param1”) 标注了一个入参,但是该参数不存在
- typeMismatch:在数据绑定时,发生数据类型不匹配的问题
- methodInvocation:Spring MVC 在调用处理方法时发生了错误
4.1:先编写国际化配置文件
4.2:注册配置国际化文件
4.3:如果使用springmvc的表单标签,springmvc会自动提该配置信息
4.4:高级国际化,动态的传入消息参数
在中英文配置文件中这么写:
{0}:永远都是当前属性名;
{1}、{2}:如果属性配置有参数,那么这些就是参数,不过参数的顺序为英文大小写排序
5:通过注解属性,确定错误提示信息