SpringMVC 基于注解使用:国际化

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

一、SpringMVC基于注解使用国际化

在日常工作中,如果我们的网站需要给不同语言地区的人进行查看,此时就需要使用国际化的基本操作,springmvc的国际化操作比较容易。
首先我们先来创建一个简单的页面,用于国际化操作

1-1、创建login页面

首先我们需要先搭建一个springmvc的框架,如果搭建还有疑问,可以看下之前的文章。

<%@ 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>
复制代码

访问页面如下:

image.png

1-2、如何实现国际化

思考一下,我们该如何实现国际呢?一般国际化需要兼容两种及以上的语言才行,这种情况下,我们有两种方式来实现:

1、制作N套视图页面,为不同的语言创建对应的页面
2、制作一个页面,然后根据浏览器语言,加载不同的语言包文件

第一种方案一般情况下不使用,除非需要不同语言的页面有不同的需求定制。因此常用的国际化使用第二种方案。

1-3、通过浏览器设置语言实现国际化

1-3-1、创建语言包

1、创建语言包可以将所有的视图页面中的文字放在同一个文件中,如: en_US.properties/zn_CH.properties,这样就是两个语言包。
2、给不同的视图创建不同的语言包,如:
login/login_en_US.properties;login/login_zn_CH.properties。

这两种方案,可以根据项目实际情况自行选择,本文采用第二种方案进行叙述。

为了方便国际化语言包的操作,我们需要给IDEA安装一个插件“Resource Bunlder Editor”

扫描二维码关注公众号,回复: 13779873 查看本文章

image.png

最终创建的语言包如下:

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

然后控制器中修改如下:

image.png 测试如下:

image.png

3-2-2-2、测试

可以看到如下,邮箱或密码错误已经显示为英文 image.png

以下为中文 image.png

3-3、国际化JSR303注解错误信息

3-3-1、methodInvocation:Spring MVC 在调用处理方法时发生的错误

JSR303错误信息在配置资源文件的时候格式如下:
key的前缀为:注解.对象.属性 。如:
NotEmpty.user.email= 邮箱不能为空

3-3-1-1、处理user中的验证注解信息

image.png user中就可以把验证信息去掉了

image.png

3-3-1-2、测试验证

3-3-2、typeMismatch:在数据绑定时,发生数据类型不匹配

这个是进行数据类型校验的如我们一个生日的格式

key的前缀:typeMismatch.对象.属性
typeMismatch.user.birthday= 生日日期格式错误

3-3-2-1、添加属性错误信息

image.png

3-3-2-2、修改jsp页面

image.png

3-3-2-3、测试验证

image.png

到此国际化处理完毕!

猜你喜欢

转载自juejin.im/post/7084799580478373902