SoFunction
Updated on 2025-03-08

Spring Internationalization and Validation Detailed explanation

SpringBoot Internationalization and Validation Fusion

Scene

When using the application interaction, it may be necessary to return different language data according to the client's language.

The front-end passes locale-related parameters to the back-end through parameters, request header, etc., and the back-end obtains parameters, and obtains different language-related text information to return to the front-end according to different locale.

Implementation principle

SpringBoot supports internationalization and Validation, mainly through the MessageSource interface and Validator.

International configuration‌

  • Write international configuration files, such asmessages_en_US.propertiesandmessages_zh_CN.properties, juxtaposeresources/i18nIn the directory.
  • Configurationorto specify the location of the internationalization document, e.g.=i18n/messages
  • ConfigurationLocaleResolverTo parse the current requested locale, the commonly used implementation isAcceptHeaderLocaleResolver, it passes the request headeraccept-languageGet the current locale.

‌Validation Configuration‌

Introducedspring-boot-starter-validationReliance to support Validation functionality

		<dependency>
            <groupId></groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

ConfigurationLocalValidatorFactoryBeanTo use international verification messages, it needs to be injectedMessageSource

Example

Introduce dependencies

<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

International configuration files

existsrc/main/resources/i18nCreate two files in the directory:messages_en_US.propertiesandmessages_zh_CN.properties

#messages_en_US.properties
=Welcome to our website!

#messages_zh_CN.properties
=Welcome to our website!

Configure MessageSource‌

In Spring Boot configuration file (or), configurationMessageSourceTo specify the location of the internationalization document.

If you plan to use Validation's default internationalization file, you don't actually need to specify the file separately for Validation, becauseLocalValidatorFactoryBeanWill automatically search

However, you can configure your own internationalization files and letMessageSourceServices both your application messages and Validation messages.

# The internationalization file is placed in the src/main/resources/i18n directory and prefixed with messages=i18n/messages,
=utf-8

Note: The above configuration assumes that your custom message file is located ini18n/, and Validation's default message file is

In fact,The file is located in the jar package of Hibernate Validator, so you don't need to explicitly include it in your resource directory. Spring Boot will automatically load it from the classpath.

Configure LocalValidatorFactoryBean‌

In your configuration class, create aLocalValidatorFactoryBeanthe bean andMessageSourceInject into it.

so,LocalValidatorFactoryBeanWill use SpringMessageSourceto parse the verification message.

import ;
import ;
import ;
import ;
import ;

import ;

@Configuration
public class ValidateConfig {

    @Bean
    public LocalValidatorFactoryBean validatorFactoryBean(MessageSource messageSource) {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        (messageSource);
        // Set up the HibernateValidator checker        ();
// Settings Fast exception return As long as there is a verification error, it will fail immediately, and other parameters are not in verification        Properties properties = new Properties();
        (".fail_fast", "true");
        (properties);
// Load configuration        ();
        return factoryBean;
    }
}

Use verification

import ;

public class MyModel {

    @NotNull(message = "{}")
    private String field;

    // getters and setters
}

In the file, you can add

=This field cannot be null.

And in Hibernate ValidatorThe default verification message is already included in the file, such as{}value.

Custom verification

  • Define constraint annotations: Create an annotation, use@ConstraintTags, and definesmessagegroupsandpayloadproperty
import ;
import ;
import .*;


@Documented
@Target({, , })
@Retention()
@Constraint(validatedBy = )
public @interface MyValidate {
    String message() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  • Implementing Constraint Verifier**: Create an implementationConstraintValidatorInterface class and rewriteisValidmethod
  • existisValidUse in the methodConstraintValidatorContext**‌: If verification fails, useConstraintValidatorContextofbuildConstraintViolationWithTemplateMethod to buildConstraintViolation
import ;

import ;
import ;


public class MyValidateContent implements ConstraintValidator&lt;MyValidate, ParamVo&gt; {
    @Override
    public void initialize(MyConstraint constraintAnnotation) {
        // Initialize the code (if needed)    }
    @Override
    public boolean isValid(ParamVo paramVo, ConstraintValidatorContext constraintValidatorContext) {
        if ("N".equals(())) {
            if (() &lt; 18) {
                buildMessage(constraintValidatorContext, "template1");
                return false;
            }
        } else {
            if (() &lt;  20) {
                buildMessage(constraintValidatorContext, "template2");
                return false;
            }
        }
        return true;
    }

    private void buildMessage(ConstraintValidatorContext context, String key) {
        String template = ('{'+key+'}').intern();
        (template)
                .addConstraintViolation();
    }
}

In this example, ifsexyesNandageLess than18, the validator will useConstraintValidatorContextTo build aConstraintViolation

Message template"{template1}"Will be parsed when verification fails and replaced with youMyValidateThe default message defined in the annotation or you are inInternationalized messages defined in the file.

Make sure yoursMyValidateAnnotation defines amessageAttributes, and you are inThere is a corresponding entry in the file, for example:

template1=Men should be greater than18
template2=Women should be greater than20
import ;
import ;
import ;
import ;

import ;
import ;

@Getter
@Setter
@MyValidate
public class ParamVo {
    @NotBlank(message = "{}")
    private String sex;
    @NotNull(message = "age cannot be empty")
    private Integer age;
    @NotBlank(message = "{}")
    @Length(max = 3,message = "{}")
    private String name;
}

Controller layer exception handling

import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;


@RestControllerAdvice
public class GlobalException {
    @ExceptionHandler()
    public ResponseEntity&lt;Object&gt; handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map&lt;String, String&gt; errors = new HashMap&lt;&gt;();
        BindingResult result = ();
        for (FieldError error : ()) {
            ((), ());
        }
        // Here you can customize the returned error message structure according to actual needs        Map&lt;String, Object&gt; response = new HashMap&lt;&gt;();
        ("status", HttpStatus.BAD_REQUEST.value());
        ("errors", errors);
        return new ResponseEntity&lt;&gt;(response, HttpStatus.BAD_REQUEST);
    }
}

Internal method verification

import ;
import ;
import ;
//@Validated 
@Validated
public interface ServiceIntface {
    //Check the return value, check the parameter    @NotNull Object hello(@NotNull @Min(10) Integer id, @NotNull String name);
}
import .slf4j.Slf4j;
import ;

@Slf4j
@Service
public class ServiceImpl implements ServiceIntface {
    @Override
    public Object hello(Integer id, String name) {
        return null;
    }
}
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;


@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler()
    public ResponseEntity&lt;Object&gt; handleValidationExceptions(ConstraintViolationException ex) {
        Map&lt;String, String&gt; errors = new HashMap&lt;&gt;();
        Set&lt;ConstraintViolation&lt;?&gt;&gt; constraintViolations = ();
        for (ConstraintViolation&lt;?&gt; constraintViolation : constraintViolations) {
            String key = ().toString();
            String message = ();
            (key, message);
        }

        // Here you can customize the returned error message structure according to actual needs        Map&lt;String, Object&gt; response = new HashMap&lt;&gt;();
        ("status", HttpStatus.BAD_REQUEST.value());
        ("errors", errors);
        return new ResponseEntity&lt;&gt;(response, HttpStatus.BAD_REQUEST);
    }
}
  • Verify that written on the interface and throw an exception
  • Verification is written in specific implementation and throws exceptions

Note

International use in code

Response in the code, manually get the getMessage method using MessageSource, that is, getMessage() in the spring container

# messages_en_US.properties
=Welcome to our website!

# messages_zh_CN.properties
=Welcome to our website!

#Define the message and use placeholders {0}, {1}, etc. to indicate the parameter position#=Welcome {0} to {1}
//Create a configuration class to configure LocaleResolver to resolve the current locale environment according to the request:import ;
import ;
import ;
import ;
import .;

import ;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
        (); // Set the default language        return sessionLocaleResolver;
    }
}
//Create a controller to use international messagesimport ;
import ;
import ;
import ;
import ;

import ;
import ;

@RestController
@RequestMapping("/hello")
public class HelloController {

    @Autowired
    private MessageSource messageSource;

    @GetMapping
    public String hello(HttpServletRequest request) {
        Locale locale = (Locale) (.LOCALE_RESOLVER_ATTRIBUTE);
         //("", new Object[]{"Zhang San", "China"}, ).        return ("", null, locale);
    }
}

Locale Getting

By default, the messageSource object registered by spring is ResourceBundleMessageSource, which will be read.Configuration.

The locale is obtained in the request throughLocaleResolverProcessing, defaultAcceptHeaderLocaleResolver,passWebMvcAutoConfigurationInject, fromAccept-LanguageGet locale information in the request header.

At this time, the front-end can pass different request headers in different locales to achieve the effect of switching languages

Accept-Language: en-Us
Accept-Language: zh-CN

By default, the front-end requests do not need to be processed. If you agree to pass other information Local, use the custom I18nLocaleResolver to replace the defaultAcceptHeaderLocaleResolver, rewriteresolveLocaleMethods can customize Locale's parsing logic.

import ;
import ;
import ;
import ;

import ;
import ;
import ;

/**
 *
 */
@Configuration
public class I18nConfig {
    @Bean
    public LocaleResolver localeResolver() {
        return new I18nLocaleResolver();
    }

    /**
      * Get international information of request header
      * Use customI18nLocaleResolverReplace the defaultAcceptHeaderLocaleResolver,RewriteresolveLocaleMethods can be customizedLocaleAnalytical logic。
      *
      * Use after customizationcontent-languagepassLocaleinformation,use_Divide languages ​​and regions。
      * content-language: en_US
      * content-language: zh_CN
      */
    static class I18nLocaleResolver implements LocaleResolver {

        @Override
        public Locale resolveLocale(HttpServletRequest httpServletRequest) {
            String language = ("content-language");
            Locale locale = ();
            if ((language)) {
                String[] split = ("_");
                locale = new Locale(split[0], split[1]);
            }
            return locale;
        }

        @Override
        public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

        }
    }
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.