Article directory
1. Internationalization: i18n
1.1, i18n overview
Internationalization is also called i18n, which comes from the first and last characters i and n of the English word internationalization, and 18 is the number of characters in the middle. Since software may be released to multiple countries, the process of displaying software in different languages for users in different countries is internationalization. Generally speaking, internationalization in software is achieved through configuration files. If you want to support two languages, you need two versions of configuration files.
1.2. Java internationalization
(1) Java itself supports internationalization. java.util.Locale is used to specify the locale and other information of the current user, and java.util.ResourceBundle is used to find the resource file corresponding to the binding. Locale contains language information and country information. The static method used by Locale when creating the default locale object:
/**
* This method must be called only for creating the Locale.*
* constants due to making shortcuts.
*/
private static Locale createConstant(String lang, String country) {
BaseLocale base = BaseLocale.createInstance(lang, country);
return getInstance(base, null);
}
(2) Configuration file naming rules:
basename_language_country.properties
The above naming rules must be followed before java can recognize it. Among them, basename is required, language and country are optional. There is a priority concept here. If both messages.properties and messages_zh_CN.propertes are provided at the same time, and if the locale provided conforms to en_CN, then the messages_en_CN.propertes configuration file will be searched first. If not found, the messages.properties configuration will be searched. document. Finally, as prompted, all configuration files must be placed in the classpath, usually in the resources directory
(3) Experiment: Demonstrate Java internationalization
The first step is to create the sub-module spring6-i18n and introduce spring dependencies.
Step 2 Create two configuration files in the resource directory: messages_zh_CN.propertes and messages_en_GB.propertes
Step 3 Test
package com.atguigu.spring6.javai18n;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.ResourceBundle;
public class Demo1 {
public static void main(String[] args) {
System.out.println(ResourceBundle.getBundle("messages",
new Locale("en","GB")).getString("test"));
System.out.println(ResourceBundle.getBundle("messages",
new Locale("zh","CN")).getString("test"));
}
}
1.3. Spring6 internationalization
1.3.1. MessageSource interface
Internationalization in spring is supported through the MessageSource interface.
Common implementation classes
ResourceBundleMessageSource
This is based on Java's ResourceBundle basic class implementation, allowing internationalized resources to be loaded only through resource names.
ReloadableResourceBundleMessageSource
This function is similar to the function of the first class, with the addition of a scheduled refresh function, which allows updating resource information without restarting the system.
StaticMessageSource
It allows to provide internationalized information programmatically. Later we can use this to implement the function of storing internationalized information in the db.
1.3.2. Use Spring6 internationalization
Step 1: Create resource files
Internationalized file naming format: basename_language_country.properties
Contents like {0},{1} are dynamic parameters.
(1) Create atguigu_en_US.properties
www.atguigu.com=welcome {0},时间:{1}
(2) Create atguigu_zh_CN.properties
www.atguigu.com=欢迎 {0},时间:{1}
Step 2: Create spring configuration file and configure MessageSource
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>atguigu</value>
</list>
</property>
<property name="defaultEncoding">
<value>utf-8</value>
</property>
</bean>
</beans>
Step 3 Create test class
package com.atguigu.spring6.javai18n;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.Locale;
public class Demo2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//传递动态参数,使用数组形式对应{0} {1}顺序
Object[] objs = new Object[]{
"atguigu",new Date().toString()};
//www.atguigu.com为资源文件的key值,
//objs为资源文件value值所需要的参数,Local.CHINA为国际化为语言
String str=context.getMessage("www.atguigu.com", objs, Locale.CHINA);
System.out.println(str);
}
}
2. Data verification: Validation
2.1. Overview of Spring Validation
During development, we often encounter the need for parameter verification. For example, when a user registers, it is necessary to verify that the user name cannot be empty, the length of the user name does not exceed 20 characters, the mobile phone number is in a legal mobile phone number format, etc. If we use the ordinary method, we will couple the verification code with the real business processing logic, and if we want to add a new verification logic in the future, we will need to modify multiple places. Spring validation allows object verification rules to be defined through annotations, which separates verification from business logic, making code writing more convenient. Spring Validation is actually a further encapsulation of Hibernate Validator to facilitate use in Spring.
There are many verification methods in Spring
The first is to implement the org.springframework.validation.Validator interface and then call this class in the code
The second is to perform verification according to the Bean Validation method, that is, through annotations.
The third method is to implement verification based on methods
In addition, custom verification can also be implemented
2.2. Experiment 1: Implementation through Validator interface
The first step is to create the submodule spring6-validator
Step 2: Introduce relevant dependencies
<dependencies>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.5.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
Step 3: Create entity classes and define properties and methods
package com.atguigu.spring6.validation.method1;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Step 4: Create a class to implement the Validator interface and implement the interface method to specify the verification rules.
package com.atguigu.spring6.validation.method1;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class PersonValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Person.class.equals(clazz);
}
@Override
public void validate(Object object, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
Person p = (Person) object;
if (p.getAge() < 0) {
errors.rejectValue("age", "error value < 0");
} else if (p.getAge() > 110) {
errors.rejectValue("age", "error value too old");
}
}
}
The class defined above actually implements the corresponding method in the interface.
The supports method is used to indicate which type this check is used on.
Validate is the place where validation logic is set. ValidationUtils is a validation tool class encapsulated by Spring to help quickly implement validation.
Step 5: Use the above Validator to test
package com.atguigu.spring6.validation.method1;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
public class TestMethod1 {
public static void main(String[] args) {
//创建person对象
Person person = new Person();
person.setName("lucy");
person.setAge(-1);
// 创建Person对应的DataBinder
DataBinder binder = new DataBinder(person);
// 设置校验
binder.setValidator(new PersonValidator());
// 由于Person对象中的属性为空,所以校验不通过
binder.validate();
//输出结果
BindingResult results = binder.getBindingResult();
System.out.println(results.getAllErrors());
}
}
2.3. Experiment 2: Bean Validation annotation implementation
Using the Bean Validation verification method is how to inject the javax.validation.ValidatorFactory and javax.validation.Validator required for Bean Validation into the container. Spring has an implementation class by default, LocalValidatorFactoryBean, which implements the interface in Bean Validation above, and also implements the org.springframework.validation.Validator interface.
The first step is to create a configuration class and configure LocalValidatorFactoryBean
@Configuration
@ComponentScan("com.atguigu.spring6.validation.method2")
public class ValidationConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
Step 2: Create an entity class and use annotations to define verification rules
package com.atguigu.spring6.validation.method2;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
public class User {
@NotNull
private String name;
@Min(0)
@Max(120)
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Common annotations
@NotNull restriction must not be null
@NotEmpty only applies to string type, the string is not empty, and the length Not 0
@NotBlank only applies to string types, the string is not empty, and the string after trim() is not an empty string
@DecimalMax(value) The limit must be a number not greater than the specified value
@DecimalMin(value) The limit must be a number not less than the specified value
@Max(value) The limit must be Is a number that is not greater than the specified value
@Min(value) The limit must be a number that is not less than the specified value
@Pattern(value) The limit must comply with the specified Regular expression
@Size(max,min) The limit character length must be between min and max
@Email Verify that the element value of the annotation is Email, also Custom email formats can be specified through regular expressions and flags
The third step is to use two different validators to implement
(1) Use jakarta.validation.Validator to verify
package com.atguigu.spring6.validation.method2;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
@Service
public class MyService1 {
@Autowired
private Validator validator;
public boolean validator(User user){
Set<ConstraintViolation<User>> sets = validator.validate(user);
return sets.isEmpty();
}
}
(2) Use org.springframework.validation.Validator to verify
package com.atguigu.spring6.validation.method2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindException;
import org.springframework.validation.Validator;
@Service
public class MyService2 {
@Autowired
private Validator validator;
public boolean validaPersonByValidator(User user) {
BindException bindException = new BindException(user, user.getName());
validator.validate(user, bindException);
return bindException.hasErrors();
}
}
Step 4 Test
package com.atguigu.spring6.validation.method2;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestMethod2 {
@Test
public void testMyService1() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService1 myService = context.getBean(MyService1.class);
User user = new User();
user.setAge(-1);
boolean validator = myService.validator(user);
System.out.println(validator);
}
@Test
public void testMyService2() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService2 myService = context.getBean(MyService2.class);
User user = new User();
user.setName("lucy");
user.setAge(130);
user.setAge(-1);
boolean validator = myService.validaPersonByValidator(user);
System.out.println(validator);
}
}
2.4. Experiment 3: Method-based verification
The first step is to create a configuration class and configure MethodValidationPostProcessor
package com.atguigu.spring6.validation.method3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
@Configuration
@ComponentScan("com.atguigu.spring6.validation.method3")
public class ValidationConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
Step 2: Create an entity class and use annotations to set verification rules
package com.atguigu.spring6.validation.method3;
import jakarta.validation.constraints.*;
public class User {
@NotNull
private String name;
@Min(0)
@Max(120)
private int age;
@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误")
@NotBlank(message = "手机号码不能为空")
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
Step 3 Define the Service class and operate the object through annotations
package com.atguigu.spring6.validation.method3;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@Service
@Validated
public class MyService {
public String testParams(@NotNull @Valid User user) {
return user.toString();
}
}
Step 4 Test
package com.atguigu.spring6.validation.method3;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestMethod3 {
@Test
public void testMyService1() {
ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
MyService myService = context.getBean(MyService.class);
User user = new User();
user.setAge(-1);
myService.testParams(user);
}
}
2.5. Experiment 4: Implement custom verification
Step 1: Customize verification annotations
package com.atguigu.spring6.validation.method4;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {
CannotBlankValidator.class})
public @interface CannotBlank {
//默认错误消息
String message() default "不能包含空格";
//分组
Class<?>[] groups() default {
};
//负载
Class<? extends Payload>[] payload() default {
};
//指定多个时使用
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List {
CannotBlank[] value();
}
}
Step 2: Write the real verification class
package com.atguigu.spring6.validation.method4;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class CannotBlankValidator implements ConstraintValidator<CannotBlank, String> {
@Override
public void initialize(CannotBlank constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//null时不进行校验
if (value != null && value.contains(" ")) {
//获取默认提示信息
String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
System.out.println("default message :" + defaultConstraintMessageTemplate);
//禁用默认提示信息
context.disableDefaultConstraintViolation();
//设置提示语
context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
return false;
}
return true;
}
}