SpringMVC is used based on annotations: internationalization

Get into the habit of writing together! This is the 10th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .

1. SpringMVC uses internationalization based on annotations

In daily work, if our website needs to be viewed by people in different language regions, we need to use the basic operations of internationalization. The internationalization operation of springmvc is relatively easy.
First, let's create a simple page for internationalization

1-1. Create a login page

First of all, we need to build a springmvc framework. If you have any questions about the construction, you can read the previous article.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% request.setAttribute("basePath",request.getContextPath());%>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.88.1">
    <title>国际化--i18n</title>

    <link rel="canonical" href="https://getbootstrap.com/docs/5.1/examples/sign-in/">


    <!-- Bootstrap core CSS -->
    <link href="${basePath}/assets/dist/css/bootstrap.min.css" rel="stylesheet">

    <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }

        @media (min-width: 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5rem;
            }
        }
    </style>


    <!-- Custom styles for this template -->
    <link href="${basePath}/assets/dist/css/signin.css" rel="stylesheet">
</head>
<body class="text-center">

<main class="form-signin">
    <form>
        <img class="mb-4" src="${basePath}/assets/brand/bootstrap-logo.svg" alt="" width="72" height="57">
        <h1 class="h3 mb-3 fw-normal">Please sign in</h1>

        <div class="form-floating">
            <input type="email" class="form-control" id="floatingInput" placeholder="[email protected]">
            <label for="floatingInput">Email address</label>
        </div>
        <div class="form-floating">
            <input type="password" class="form-control" id="floatingPassword" placeholder="Password">
            <label for="floatingPassword">Password</label>
        </div>

        <div class="checkbox mb-3">
            <label>
                <input type="checkbox" value="remember-me"> Remember me
            </label>
        </div>
        <button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
        <p class="mt-5 mb-3 text-muted">&copy; 2017–2021</p>
    </form>
</main>
</body>
</html>
复制代码

Visit the page as follows:

image.png

1-2. How to achieve internationalization

Think about it, how can we achieve internationalization? Generally, internationalization needs to be compatible with two or more languages. In this case, we have two ways to achieve it:

1. Make N sets of view pages, create corresponding pages for different languages
​​2. Make a page, and then load different language pack files according to the browser language

The first solution is generally not used unless pages in different languages ​​have different requirements for customization. Therefore, the commonly used internationalization uses the second scheme.

1-3. Internationalization is achieved by setting the language in the browser

1-3-1. Create a language pack

1. To create a language pack, you can put the text in all the view pages in the same file, such as: en_US.properties/zn_CH.properties, so there are two language packs.
2. Create different language packages for different views, such as:
login/login_en_US.properties;login/login_zn_CH.properties.

These two schemes can be selected according to the actual situation of the project. This article adopts the second scheme to describe.

In order to facilitate the operation of internationalized language packs, we need to install a plug-in "Resource Bundler Editor" for IDEA

image.png

The final created language pack is as follows:

image.png 创建了中文和英文语言包。为了后期维护及方便,我们文件的命名需要按照i18N方式来命名,具体可以搜一下i18n对照表。

1-3-2、创建对应语言

点击+好,新增一个txt文字key,这个key可以随便写,但是为了语义化建议还是写英文含义。 image.png

之后就挨个语言包创建对应的文字信息

image.png

1-3-3、在spring-mvc文件中进行配置

<!--设置国际化支持,配置国际化属性资源文件-->
<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
    <property name="basenames">
        <array>
            <value>i18N.login</value>
        </array>
    </property>
</bean>
复制代码

如果有很多资源文件,可以在array中再添加即可。

1-3-4、视图层实现国际化

在springMVC中,视图层实现国际化,可以通过两种方案,一种是JSTL标签,另外一种是spring标签库

1-3-4-1、jslt标签实现国际化

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>....<body>
       <!--    <fmt:setLocale value="${param.setLocale}"/>  区域语言的值从传过来的参数中得到 --> 
       <fmt:setLocale value="en_US"/>           <!--指定区域语言-->
       <fmt:bundle basename="login">   <!-- 指定使用basename为login的资源文件,也即资源文件第一个单词为login-->
           <center>
           <table>
               <tr>
                   <td><fmt:message key="email"/></td>
                   <td><input type="text" name="email"></td>   
               </tr> 
           </table>
           </center>   
       </fmt:bundle>
  </body>
复制代码

1-3-4-2、使用spring标签库

1、需要先导入spring的标签库

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
复制代码

2、使用spring:message 标签替换文字,如下替换原文密码

<spring:message code="txt_password">
复制代码

3、最终替换完之后,我们的login.jsp页面为:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<% request.setAttribute("basePath",request.getContextPath());%>

<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
    <meta name="generator" content="Hugo 0.88.1">
    <title>国际化--i18n</title>

    <link rel="canonical" href="https://getbootstrap.com/docs/5.1/examples/sign-in/">


    <!-- Bootstrap core CSS -->
    <link href="${basePath}/assets/dist/css/bootstrap.min.css" rel="stylesheet">

    <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }

        @media (min-width: 768px) {
            .bd-placeholder-img-lg {
                font-size: 3.5rem;
            }
        }
    </style>


    <!-- Custom styles for this template -->
    <link href="${basePath}/assets/dist/css/signin.css" rel="stylesheet">
</head>
<body class="text-center">

<main class="form-signin">
    <form>
        <img class="mb-4" src="${basePath}/assets/brand/bootstrap-logo.svg" alt="" width="72" height="57">
        <h1 class="h3 mb-3 fw-normal"><spring:message code="txt_plase_login"/></h1>

        <div class="form-floating">
            <input type="email" class="form-control" id="floatingInput" placeholder="[email protected]">
            <label for="floatingInput"><spring:message code="txt_email"></label>
        </div>
        <div class="form-floating">
            <input type="password" class="form-control" id="floatingPassword" placeholder="Password">
            <label for="floatingPassword"><spring:message code="txt_password"></label>
        </div>

        <div class="checkbox mb-3">
            <label>
                <input type="checkbox" value="remember-me"> <spring:message code="txt_remember_me">
            </label>
        </div>
        <button class="w-100 btn btn-lg btn-primary" type="submit"><spring:message code="txt_login"></button>
        <p class="mt-5 mb-3 text-muted">&copy; 2017–2021</p>
    </form>
</main>
</body>
</html>
复制代码

1-3-4-3、测试

image.png 最终访问控制器发现这个错误、看错误是没找到key,最后发现使用idea在添加资源文件之后,并没有实时编译,删除历史编译文件,重新编译再次访问

image.png 这次出现了中文乱码的问题,接着处理,如下

image.png 重启服务再次访问

image.png 设置浏览器语言为英文、再次访问如下:

image.png

1-3-5、实现原理

其实SpringMVC中国际化的处理非常简单,就是按照浏览器所带来的语言信息决定的。默认情况下,SpringMVC 根据Accept-Language参数判断客户端的本地化类型。

当接受到请求时,SpringMVC 会在上下文中查找-一个本地化解析器(LocalResolver) ,找到后使用它获取请求所对应的本地化类型信息:Locale locale =request.getLocale();//获取浏览器的区域信息

1-4、通过自定义解析器,设置国际化

上面案例主要通过修改浏览器的语言,然后在请求的时候,通过request请求头中携带语言设置,让springmvc通过使用AcceptHandlerLocaleResolver来进行解析。

我们自己实现实际也是通过覆盖AcceptHandlerLocaleResolver来实现,然后在请求中携带语言标记

1-4-1、将SessionLocaleResolver注入到spring

这么做的目的是,页面在切换的时候,我们就语言保存到SessionLocaleResolver中,这样后面的页面再次访问就可以按照设置的语言显示了

<!--使用SessionLocaleResolver保持Local状态,会存session中获取Local对象-->
<bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver" id="localeResolver"></bean>
复制代码

1-4-2、编写控制器保存语言设置

/**
 * 保持语言设置
 * @param local  页面传过来的语言
 * @param localeResolver 将SessionLocaleResolver 注入到方法中
 * @param request
 * @param response
 * @return
 */
@RequestMapping("/i18n/{local}")
public String changeLocal(@PathVariable String local, @Autowired SessionLocaleResolver localeResolver,
                          HttpServletRequest request, HttpServletResponse response){
    Locale locale=new Locale(local.split("_")[0],local.split("_")[1]);
    localeResolver.setLocale(request,response,locale);
    return  "login";
}
复制代码

1-4-3、修改login页面添加中英文切换

<div class="row">
    <a class="col-6" href="${basePath}/i18n/zh_CN">中文</a>
    <a class="col-6" href="${basePath}/i18n/en_US">Englis h</a>
</div>
复制代码

image.png 这样就可以完成语言切换了

1-5、使用springmvc拦截器设置国际化

1-5-1、在spring-mvc中添加拦截器

<!--使用springmvc提供的拦截器,接收locale参数,设置到session中-->
<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
复制代码

查看LocaleChangeinterceptor源码中的preHandle方法如下:

image.png 可以发现第一步通过locale获得页面传的参数,然后将此参数设置到LocaleResolver中,实际处理方式和上面,自己实现的方式基本一致。

1-5-2、login.jsp修改国际化支持

<div class="row">
    使用拦截器设置locale<p></p>
    <a class="col-6" href="?locale=zh_CN">中文</a>
    <a class="col-6" href="?locale=en_US">English</a>
</div>
复制代码

二、小结

2-1、基于浏览器设置的语言切换国际化

1.新建jsp对应的国际化属性资源文件:
login.properties
login_en_US.properties
login_zh_CN.properties
2.配置springmvc, 将国际化资源文件注入到springmvc中

<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
        <property name="basenames">
             <array>
                 <value>i18n/login</value>
             </array>
         </property>

</bean>
复制代码

3. 在页面来调用属性资源文件

< spring:message> </spring:message>

2-2、使用超链接的方式切换语言

1.更改默认本地化语言解析器LocaleResolver 改成SessionLocaleResolver

方式1:  创建一个请求方法,接收local参数(en_US、zh_CN)   设置session中去
方式2:  使用springmvc提供的拦截器,接收local参数(en_US、zh_CN)   设置session中去
复制代码

三、java中错误信息国际化处理。

3-1、spring form标签使用JSR303返回错误信息

3-1-1、修改跳转login页面的控制器方法

使用spring formb标签显示错误信息,必须从控制器进行跳转,因为需要加一个Model,图中加了User,会自动添加到Model中,主要为了给jsp页面form标签中的modelAttribute赋值。这个是必须步骤 image.png

3-1-2、修改登录页面

1、添加spring form标签

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
复制代码

2、将form标签改为spring form标签 下面代码中的modelAttribute="user",即为上面跳转页面控制器中的变量名

<form:form action="${basePath}/login" method="post" modelAttribute="user">
复制代码

3、添加错误信息显示标签 错误信息同样使用spring form标签,path的值,需要和user bean中的属性保持一致。

<form:errors path="email"></form:errors>
复制代码
<form:errors path="password"></form:errors>
复制代码

3-2-3、使用maven添加validator包

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.3.Final</version>
</dependency>
复制代码

3-2-4、添加User Bean,并设置JSR303注解

分别给email和password设置了相关验证注解 image.png

3-2-5、添加登录提交方法

使用JSR303,在方法参数中一定要添加BindingResult image.png

3-2-6、测试

image.png 这样虽然错误信息显示出来了,但是如果页面切换到英文,错误信息依然是中文,这样就有问题了。因此我们还需要给后台相关信息做国际化操作。

3-2、国际化代码中的的内容

3-2-1、使用MessageSource设置国际化

3-2-1-1、在控制器中注入MessageSource

使用MessageSource获得属性key的值,因为已经通过过滤器/SessionLocaleResolver设置了国际化的语言,因此这边通过MessageSource.getMessage(),传入对应的错误信息key 以及Locale就可以自动获取资源文件中配置的信息了。 image.png 可以看到在getMessage方法中第二个参数,目前传null,这个地方是一个object[] 可以传递相关参数,如我们修改资源文件login_err:

image.png

Then modify the controller as follows:

image.pngThe test is as follows:

image.png

3-2-2-2. Test

You can see the following, the email or password error has been displayed in Englishimage.png

The following is in Chineseimage.png

3-3. Internationalized JSR303 annotation error message

3-3-1, methodInvocation: Spring MVC error when calling the processing method

The format of the JSR303 error message when configuring the resource file is as follows:
The prefix of the key is: annotation.object.attribute. For example:
NotEmpty.user.email= Email cannot be empty

3-3-1-1, process the verification annotation information in the user

image.pngThe authentication information can be removed from the user

image.png

3-3-1-2. Test verification

3-3-2, typeMismatch: data type mismatch occurs during data binding

This is the format for data type verification, such as our birthday

Key prefix: typeMismatch.object.property
typeMismatch.user.birthday=Birthday date format error

3-3-2-1, add attribute error information

image.png

3-3-2-2, modify the jsp page

image.png

3-3-2-3. Test verification

image.png

At this point, the internationalization process is completed!

Guess you like

Origin juejin.im/post/7084799580478373902