Administrator
发布于 2022-10-22 / 47 阅读
0
0

SpringMVC国际化、异常处理

国际化

写在前面:你被哪些傻逼bug困扰过?

前面有一篇博客中,写有我实现国际化,但失败的问题,原因是读取不到需要的国际化配置文件
今天机缘巧合之下解决了。解决方法是:将浏览器默认添加的语言删掉,手动添加

 
image-1666430634418

若使用默认的第四个英语来,读取不到配置文件,因为程序获取的locale信息是en,而不是你配置的en_US,
使用美国的那个英语获取的locale信息才会是en_US

 
image-1666430737218

为什么会发现这样子,是因为复习到国际化的时候,写了一个controller

@Autowired
    private MessageSource messageSource;
    
    @RequestMapping("/locales")
    public String getLocale(Locale locale) {
    --
    如果使用浏览器本身带的那个英语,得到的是en。
    --
        System.out.println(locale);
        String wel = messageSource.getMessage("welcomeinfo",null,locale);
        System.out.println(wel);
        return "locale";
    }

国际化的实现方式

1、根据浏览器语言设置的情况对文本, 时间, 数值进行本地化处理

	使用 JSTL 的 fmt 标签
    
    在 bean 中注入 ResourceBundleMessageSource 的实例, 使用其对应的getMessage 方法
    可以在 bean 中获取国际化资源文件 Locale 对应的消息
      String wel = messageSource.getMessage("welcomeinfo",null,locale);
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>success</h1>
<fmt:message key="welcomeinfo"/>
</h1>
<form action="" method="post">
    <fmt:message key="username"/>:<input /><br/>
    <fmt:message key="password"/>:<input /><br/>
    <input type="submit" value='<fmt:message key="loginBtn"/>'/>
</form>
</body>

控制层代码如上个controller代码所示

 

2、通过超链接切换 Locale

2.1自定义LocalResolver

MyLocaleResolver

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        Locale l = null;
        String locale = request.getParameter("locale");
        if (locale != null && !"".equals(locale)) {
            //带了,就用你带了的区域信息
          l = new Locale(locale.split("_")[0], locale.split("_")[1]);
        }else {
            //没带,用默认的
            l = request.getLocale();
        }
        return l;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        //不会写,就直接抄源码的实现
        throw new UnsupportedOperationException(
                "Cannot change HTTP accept header - use a different locale resolution strategy");
    }

controller

    @RequestMapping("/login")
    public String indexlocale(Locale locale, HttpServletRequest request) {
        System.out.println(locale);
        String s = request.getParameter("locale");
        System.out.println(s);
        return "login";
    }

jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<fmt:message key="welcomeinfo"/>
</h1>
<form action="" method="post">
    <fmt:message key="username"/>:<input /><br/>
    <fmt:message key="password"/>:<input /><br/>
    <input type="submit" value='<fmt:message key="loginBtn"/>'/>
    <!-- 切换语言 -->
</form>
<a href="/login?locale=zh_CN">中文</a> | <a href="login?locale=en_US">英语</a>
</body>
</html>

web.xml

<bean id="localeResolver" class="com.lly.LocaleReslover.MyLocaleResolver"></bean>

总结:其实就是替代了默认的AcceptHeaderLocaleResolver,根据你超链接携带的区域化信息新建一个Locale

 

2.2SessionLocaleResolver & LocaleChangeInterceptor

在以上代码的基础上,将自己写的自定义区域信息解析器注释掉,加入SessionLocaleResolver配合拦截器LocaleChangeInterceptor使用

<!--    <bean id="localeResolver" class="com.lly.LocaleReslover.MyLocaleResolver"></bean>-->
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
    </mvc:interceptors>

LocaleChangeInterceptor原理–preHandle

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
          throws ServletException {
--
//获取参数--locale的值
--
      String newLocale = request.getParameter(getParamName());
      if (newLocale != null) {
          if (checkHttpMethod(request.getMethod())) {
          --
          //获取请求的区域信息解析器
          --
              LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
              if (localeResolver == null) {
                  throw new IllegalStateException(
                          "No LocaleResolver found: not in a DispatcherServlet request?");
              }
              try {
              --
              //将区域信息设置进解析器
              --
              
                  localeResolver.setLocale(request, response, parseLocaleValue(newLocale));
              }
              catch (IllegalArgumentException ex) {
                  if (isIgnoreInvalidLocale()) {
                      logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage());
                  }
                  else {
                      throw ex;
                  }
              }
          }
      }
      // Proceed in any case.
      return true;
  }

ps:你也可以在方法内将locale的信息设置进session中,如此只需配SessionLocaleResolver就行

四种区域信息解析器

AcceptHeaderLocaleResolver:根据 HTTP 请求头的 Accept-Language 参数确定本地化类型,
如果没有显式定义本地化解析器, SpringMVC 使用该解析器。

CookieLocaleResolver:根据指定的 Cookie 值确定本地化类型

SessionLocaleResolver:根据 Session 中特定的属性确定本地化类型

LocaleChangeInterceptor:从请求参数中获取本次请求对应的本地化类型。

评论