国际化(i18n)是针对不同国家不同区域,同样的程序会有不同的表现形式;
在日常使用的开源框架中,都会有不同程度的国际化在里面; 刚好现在需要让程序中搞一下国际化,那么就跟踪一下如何在SpringBoot中使用国际化
使用基本就两个地方:
代码提交至: https://github.com/eeaters/spring-cloud-demo/tree/master/spring-boot-demo/i18n
为了测试方便,这里将地区的传递放在了requestParam中
@Configuration
public class I18nConfig {
@Bean
public LocaleResolver localeResolver() {
return new I18nLocaleResolver();
}
/**
* @see RequestContextFilter
*/
static class I18nLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String language = request.getParameter("language");
Locale locale ;
if (StringUtils.hasText(language)) {
String[] split = language.split("_"); //国家-地区-方言
if (split.length == 1) {
locale = new Locale(split[0]);
} else {
locale = new Locale(split[0], split[1]);
}
}else{
locale = Locale.getDefault();
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
}
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ExtendWith(SpringExtension.class)
public class ApplicationTest {
@Autowired
TestRestTemplate restTemplate;
@Test
public void test() {
//里面只有一个message参数
EchoEntity echoEntity = new EchoEntity();
ResponseEntity<String> entity = restTemplate.postForEntity("/echo", echoEntity, String.class);
System.out.println("entity.getBody() = " + entity.getBody());
ResponseEntity<String> entity2 = restTemplate.postForEntity("/echo?language=en", echoEntity, String.class);
System.out.println("entity.getBody() = " + entity2.getBody());
}
}
如果不做任何处理;入参校验失败时错误信息不会返回,不便于查看,简单加一个异常处理
@RestControllerAdvice
public class GlobalControllerAdvice {
@ExceptionHandler
public ResponseEntity handleValidException(MethodArgumentNotValidException e) {
StringBuilder sb = new StringBuilder();
for (ObjectError error : e.getBindingResult().getAllErrors()) {
if (error instanceof FieldError) {
String field = ((FieldError) error).getField();
Object rejectedValue = ((FieldError) error).getRejectedValue();
String errorMessage = error.getDefaultMessage();
sb.append(field)
.append(" : ")
.append(rejectedValue)
.append(" -> ")
.append(errorMessage);
}else{
sb.append(error.getDefaultMessage());
}
}
return ResponseEntity.badRequest().body(sb.toString());
}
}
entity.getBody() = message : null -> 不能为空
entity.getBody() = message : null -> must not be blank
Demo中国际化实现的底层依赖于 hibernate-validator 的校验功能 而 hibernate-validator 依赖于Java的国际化 ResourceBundle
来一段ResourceBundle的实例代码:
public class ResourceBundleExample {
@Test
public void load() {
//在resources下创建example.properties
ResourceBundle bundle = ResourceBundle.getBundle("example", Locale.US);
String name = bundle.getString("name");
System.out.println("name = " + name);
}
}
Idea环境下resources目录下右键会有ResourceBundle的选项 ,
创建时会提示一个basename并提示选择en和zh_CN两个Project Locale;
这个就是国际化对应的不同地域的展示文案;
上面代码中 ResourceBundle.getBundle("example", Locale.US); 这段代码可以获取到resources目录下example*.properties的配置文件,那么以这里为debug的目标
得到以下结论:
以Post请求, method(@ResponseBody @Valid Object obj) 为例跨越式跟踪
对于简单的校验流程就跑通了
当使用@Min等需要返回预定好的数据时,那么就需要使用到占位符,那Min举例 : javax.validation.constraints.Min.message = must be greater than or equal to {value} 这时候在第6步插入的时候会判断是否存在 {
符号; 如果存在就使用el表达式的规则进行占位符的替换
SpringBoot中需要使用国际化需要在resource目录下创建messages.properties文件;
原因: MessageSourceAutoConfiguration 是SpringBoot国际化的一个自动装配类, 生效的条件为:
@ConditionalOnMissingBean(
name = {"messageSource"},
search = SearchStrategy.CURRENT
)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
配置文件中增加简单的额配置
# messages.properties中
name=eeaters
notFound = not found
# messages_zh_CN.properties中
name=\u98df\u6b7b\u5f92
notFound = \u4e0d\u5b58\u5728\u7684\u503c
@Component
public class MessageAdapter implements ApplicationContextAware {
static MessageSource messageSource;
public static String getMessage(String code) {
return messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
messageSource = applicationContext.getBean(MessageSource.class);
}
}
@GetMapping("echo")
public ResponseEntity<String> echoGet(@RequestParam String message) {
try {
return ResponseEntity.ok(MessageAdapter.getMessage(message));
} catch (NoSuchMessageException e) {
return ResponseEntity.ok(MessageAdapter.getMessage("notFound"));
}
}
localhost:8080/echo?language=en&message=name → eeaters
localhost:8080/echo?message=name → 食死徒
localhost:8080/echo?language=en&message=abc → not found
localhost:8080/echo?message=abc → 不存在的值
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。