SpringBoot项目中实现返回结果和枚举类的国际化

前言

什么是国际化呢?国际惯例,来时来一段官方介绍:

  1. 国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。
  2. 它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素。
  3. 换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。
  4. 开发这样的程序的过程,就称为国际化。
SpringBoot项目中实现返回结果和枚举类的国际化

在我们实际开发中,一个web应用可能要在多个地区使用,面对不同地区的不同语言,为了适应不同的用户,我们可以尝试在前端页面实现多语言的支持,那么同样对于后端返回的一些提示信息,异常信息等,我们后端也可以根据不同的语言环境来进行国际化处理,返回相应的信息。

开发工具

IDEA、Maven、SpringBoot2.0.5、Jdk1.8、google浏览器

SpringBoot中的国际化

原理:

想要使应用支持国际化,首先需要知道用户的语言环境,即用户想要看到的语言,我们设想在用户每次请求时告诉服务器自己的语言环境,服务器收到请求后,根据不同的语言环境返回不同的信息来实现国际化。在spring应用中,用户的语言环境是通过区域解析器来识别的,而区域解析器有分为好几种(后面详细说),在我们不做配置修改时,spring使用AcceptHeaderLocaleResolver作为默认的区域解析器,它是根据HTTP请求 Header中的Accept-language的值来解析,当然区域解析器我们也可以自定义配置。

springboot默认就支持国际化。我们只需要只需要作相应的配置即可。

1.首先你需要一个springboot项目。IDEA中分分钟创建好一个项目。

2.在resources下定义国际化配置文件,注意名称必须以messages开始。(在springboot中,当我们不修改配置时默认去解析名称以message开始的properties文件)

messages.properties (默认环境,无法确定语言环境时,解析该文件中的相应信息)

messages_zh_CN.properties(中文语言环境时,解析该文件中的相应信息)

messages_en_US.properties(英文语言环境时,解析该文件中的相应信息)

在三个配置文件中分别以Key = Value形式存储如下三条信息,如下:

welcome = 这是一个支持国际化的项目。

welcome = 这是一个支持国际化的项目。


  • welcome = This is a project supporting internationalization.
  • SpringBoot项目中实现返回结果和枚举类的国际化

    3.创建thymeleaf页面

    加入thymeleaf依赖

    1. org.springframework.boot
    2. spring-boot-starter-thymeleaf

    在resources/templates目录下创建hello.html页面:

    尝试在不同的语言环境下,通过#{welcome}获取信息

    1. demo

    4.创建访问页面的controller

    注意这里controller的注解时@Controller

    1. import org.springframework.stereotype.Controller;
    2. import org.springframework.web.bind.annotation.RequestMapping;
    3. /**
    4. * 描述:
    5. *
    6. * @author zhengql
    7. * @date 2018/9/25 19:28
    8. */
    9. @Controller
    10. public class BaseController {
    11. @RequestMapping("/hi")
    12. public String hello() {
    13. return "/hello";
    14. }
    15. }

    测试国际化效果

    这里使用google浏览器进行测试,测试之前需要安装插件Language Switcher

    Language Switcher : 可以改变当前请求的语言环境(根据自己的选择)

    启动我们的springboot项目,google浏览器访问 http://127.0.0.1:8080/hi ,可以看到如下页面:

    通过Language Switcher切换语言环境为English - United States,重新访问 http://127.0.0.1:8080/hi ,可以看到如下页面:

    ok,大功告成,到此一个简单的国际化项目就完成了。

    扩展国际化

    通过上面的小栗子,我们可以看到一个简单的国际化使用,但是在开发中中还需要我们进行一定的配置,来满足我们不同情况下的使用。

    在返回结果中获取国际化信息

    很多时候,后端接收到一个请求后,需要返回一个提示信息,而此时我们可以使这个返回信息支持国际化

    这里就用到了org.springframework.context.MessageSource接口,MessageSource提供了三个方法

    @Nullable//参数字段可为空

    1. String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4);
    2. String getMessage(String var1, @Nullable Object[] var2, Locale var3) throws NoSuchMessageException;
    3. String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;

    String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。var2中的参数将使用标准类库中的MessageFormat来作消息中替换值。

    String getMessage(String code, Object[] args, Locale loc):本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个NoSuchMessageException异常。

    String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的属性都封装到一个MessageSourceResolvable实现中,而本方法可以指定MessageSourceResolvable实现。

    下面我们实践一下:

    1.创建一个以json返回格式的controller,注入MessageSource,注意controller的注解为@RestController

    在这里首先我们需要获取到当前请求的Locale,有两种方法:

    1. Locale locale = LocaleContextHolder.getLocale();
    2. Locale locale = RequestContextUtils.getLocale(request);

    两种方式根据情况选择使用,下面是controller代码

    1. package com.example.i18n.controller;
    2. import org.springframework.beans.factory.annotation.Autowired;
    3. import org.springframework.context.MessageSource;
    4. import org.springframework.context.i18n.LocaleContextHolder;
    5. import org.springframework.web.bind.annotation.RequestMapping;
    6. import org.springframework.web.bind.annotation.RestController;
    7. /**
    8. * 描述:
    9. *
    10. * @author zhengql
    11. * @date 2018/9/21 10:54
    12. */
    13. @RestController
    14. public class JsonController {
    15. @Autowired
    16. private MessageSource messageSource;
    17. @RequestMapping("/ha")
    18. public String ha() {
    19. return messageSource.getMessage("welcome", null, LocaleContextHolder.getLocale());
    20. }
    21. }

    2.启动项目访问 http://127.0.0.1:8080/ha ,可以看到相应语言环境的返回信息

    通过Language Switcher切换语言环境为English - United States,重新访问http://127.0.0.1:8080/ha,可以看到如下页面:

    支持占位符国际化信息返回

    我们经常会遇到这样一个场景,登录账号需要验证码,填写完手机号获取验证码后会收到一条类似于尊敬的用户13099999999您好,您的验证码是6666,这种信息,其实就是一个模板,通过改变参数,重复使用。我们通过国际化资源文件中的占位符,配合MessageSource提供的api也可以实现。

    资源文件中加入如下属性:

    messages.properties,messages_zh_CN.properties

    1. hello=你好:{0} , 你的验证码为 :{1}

    messages_en_US.properties

    1. hello=Hello: {0}, your verification code is: {1}

    我们在JsonController中,创建一个测试接口

    1. @RequestMapping("/haha")
    2. public String haha() {
    3. return messageSource.getMessage("hello", new Object[]{"zhangsan","123456"}, LocaleContextHolder.getLocale());
    4. }

    启动项目直接,访问 http://127.0.0.1:8080/haha 可以看到相应语言环境的返回信息

    通过Language Switcher切换语言环境为English - United States,重新访问 http://127.0.0.1:8080/haha ,可以看到如下页面:

    支持国际化的枚举类

    既然返回信息可以实现国际化,那我们的枚举类同样也可以实现国际化咯

    创建一个枚举类EnumSuccessOrError.java

    1. /**
    2. * 描述:枚举类举例
    3. *
    4. * @author zhengql
    5. * @date 2018/9/26 20:52
    6. */
    7. public enum EnumSuccessOrError {
    8. SUCCESS(0, "操作成功"),
    9. ERROR(1, "操作失败");
    10. /**
    11. * 返回状态码
    12. */
    13. private int statusCode;
    14. /**
    15. * 返回状态信息
    16. */
    17. private String statusMsg;
    18. EnumSuccessOrError(int statusCode, String statusMsg) {
    19. this.statusCode = statusCode;
    20. this.statusMsg = statusMsg;
    21. }
    22. /**
    23. * @return the statusCode
    24. */
    25. public int getStatusCode() {
    26. return statusCode;
    27. }
    28. /**
    29. * @return the statusMsg
    30. */
    31. public String getStatusMsg() {
    32. return statusMsg;
    33. }
    34. }

    如上,刚刚创建的枚举类是不支持国际化的,我们呢需要改造他,当调用getStatusMsg方法时根据语言环境返回相应的国际化字符串。可以从如下两个点着手:

    getStatusMsg方法改造

    资源文件中添加不同语言环境对应的返回值

    先在三个资源文件中加入不同环境的返回值:

    messages.properties,messages_zh_CN.properties

    1. SUCCESS = 操作成功
    2. ERROR = 操作失败

    messages_en_US.properties

    1. SUCCESS=success
    2. ERROR=error

    改造后的枚举如下:

    1. public enum EnumSuccessOrError {
    2. SUCCESS(0, "SUCCESS"),
    3. ERROR(1, "ERROR");
    4. /**
    5. * 返回状态码
    6. */
    7. private int statusCode;
    8. /**
    9. * 返回状态信息
    10. */
    11. private String statusMsg;
    12. EnumSuccessOrError(int statusCode, String statusMsg) {
    13. this.statusCode = statusCode;
    14. this.statusMsg = statusMsg;
    15. }
    16. private MessageSource messageSource;
    17. public EnumSuccessOrError setMessageSource(MessageSource messageSource) {
    18. this.messageSource = messageSource;
    19. return this;
    20. }
    21. //通过静态内部类的方式注入bean,并赋值到枚举中
    22. @Component
    23. public static class ReportTypeServiceInjector {
    24. @Autowired
    25. private MessageSource messageSource;
    26. @PostConstruct
    27. public void postConstruct() {
    28. for (EnumSuccessOrError rt : EnumSet.allOf(EnumSuccessOrError.class))
    29. rt.setMessageSource(messageSource);
    30. }
    31. }
    32. /**
    33. * @return the statusCode
    34. */
    35. public int getStatusCode() {
    36. return statusCode;
    37. }
    38. /**
    39. * @return the statusMsg,根据语言环境返回国际化字符串
    40. */
    41. public String getStatusMsg() {
    42. return messageSource.getMessage(statusMsg,null,statusMsg, LocaleContextHolder.getLocale());
    43. }
    SpringBoot项目中实现返回结果和枚举类的国际化

    此时我们在JsonController中,再创建一个测试接口

    1. @RequestMapping("/enumDemo")
    2. public String enumDemo() {
    3. return EnumSuccessOrError.SUCCESS.getStatusMsg();
    4. }

    启动项目直接,访问 http://127.0.0.1:8080/enumDemo 可以看到相应语言环境的返回信息。


    分享到:


    相關文章: