Spring MVC的国际化
意思就是当一个软件需要在全球范围内使用时,就必须考虑在不同地域和语言环境下的使用情况,最简单的要求就是在用户界面上显示的信息可以使用本地化语言来表示。
Spring MVC国际化概述
国际化是指程序在不做任何修改的情况下,就可以在不同的国家,不同的语言环境下,按照当地的语言和格式习惯显示字符
本地化:国际化的程序运行在本地机器上时,能根据本地机器的语言和地区设置显示相应的字符。
Spring MVC的国际化结构:DispatcherServlet会解析一个LocaleResolver接口对象,通过它来决定用户区域,读出对应用户系统设定的语言或者用户选择的语言,确定其国际化
LocaleResolver接口包括如下几个实现类:
- AcceptLanguageLocaleResolver
- SessionLocaleResolver
- CookieLocaleResolver
这三个实现类应该是对应下面的三种实现方式。
基于浏览器请求的国际化实现
例子:
先写个user实体类(我真的是要被拼写错误搞死。。耐人寻味)

创建国际化配置文件

中文的这个,比如你在loginName=这里输入中文“名称”他会自动把名称两个字转化为\u540D\u79F0(emmm…这里的title拼写错了,debug的时候发现的,图片就不改了)

在springmvc.xml文件中加载
<mvc:default-servlet-handler/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize" value="1048576"></property>
<!--字符编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
<!--国际化配置 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<!--国际化资源文件名 -->
<property name="basename" value="message"></property>
</bean>
<!--AcceptHeaderLocaleResolver因为是默认的区域语言解析器,可不配置 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"></bean>
写注册页面

写控制器类
不需要作图的还是复制代码好一点,以后万一用到可以过来直接复制
package com.springmvc.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.support.RequestContext;
import com.springmvc.entity.User;
@Controller
public class UserController {
@RequestMapping(value = "/{formName}")
public String registerForm(@PathVariable String formName,Model model) {
User user = new User();
model.addAttribute("user",user);
return "formName";//动态跳转页面
}
@RequestMapping(value = "/register",method = RequestMethod.POST)
public String register(@ModelAttribute @Validated User user,Model model,HttpServletRequest request) {
//从后台代码获取国际化资源文件中的userName
RequestContext requestContext = new RequestContext(request);
String userName=requestContext.getMessage("userName");
System.out.println(userName);
model.addAttribute("user",user);
return "success";
}
}
写成功页面

我检查完拼写错误后,终于,运行成功了

填写相应信息点击提交后

再测试下英文的
因为我是用火狐和chrome两个浏览器,现在几乎一直用chrome,所以索性把火狐设成英文界面,方便以后项目测试国际化。


我总觉得事情没有这么简单。这种配置方法说简单,挺简单,毕竟就两个文件,很好理解,但是我觉得之后应该不会用这种方法来国际化,难道真就每一个内容都要输到文件里?然后再在页面上用标签,还要一一去对应code别填错了?只是个登录界面还好,真要门户网站,感觉写标签都要写的头皮发麻。
基于HttpSession的国际化实现
使用的是LocalResolver接口的SessionLocaleResolver实现类,使用它时,Spring MVC会对HttpSession作用域中获取用户所设置的语言区域,来确定使用哪个语言区域。通过请求参数改变国际化的值时,可使用Spring 提供的国际化拦截器LocaleChangeInterceptor。(?前半段我听懂了,后半段??)
工作流程:

修改springmvc.xml,把上面AcceotLanguageLocaleResolver类型的Bean localeResolver,添加SessionLocaleResolver类型的Bean,添加国际化操作拦截器
<!--SessionLocaleResolver配置 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
<mvc:interceptors>
<!--如果采用基于session/cookie的国际化,必须配置国际化操作的拦截器 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>
为了方便切换,在registerForm.jsp的注册页面上,添加中文和英文的超链接,用于切换语言环境,当然,做测试的时候我还是会chrome上测中文,火狐上测英文

在UserController中更改registerForm方法

代码也放这了
@RequestMapping(value = "/{formName}")
public String registerForm(@PathVariable String formName,Model model,
String request_locale,HttpServletRequest request) {
System.out.println("request_locale="+request_locale);
if (request_locale!=null) {
if (request_locale.equals("zh_CN")) {
//设置中文环境
Locale locale = new Locale("zh","CN");
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}else if (request_locale.equals("en_US")) {
//设置英文环境
Locale locale = new Locale("en","US");
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}else {
//使用之前的语言环境
request.getSession().setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, LocaleContextHolder.getLocale());
}
}
User user = new User();
model.addAttribute("user",user);
return formName;
}
然后重启tomcat运行就好了
registerForm根据提交的request_locale参数值,获取session对象,并调用setAttribute()方法进行语言切换

就反正点击英文就会切换到之前演示的英文版,自己脑补下效果。
基于Cookie的国际化实现
把springmvc.xml之前配置的换成(其实只换了一句话)
<!--CookieLocaleResolver配置 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"></bean>
<mvc:interceptors>
<!--如果采用基于session/cookie的国际化,必须配置国际化操作的拦截器 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>
修改registerForm方法

代码:
@RequestMapping(value = "/{formName}")
public String registerForm(@PathVariable String formName,Model model,
String request_locale,HttpServletRequest request,HttpServletResponse response) {
System.out.println("request_locale="+request_locale);
if (request_locale!=null) {
if (request_locale.equals("zh_CN")) {
//设置中文环境
Locale locale = new Locale("zh","CN");
(new CookieLocaleResolver()).setLocale(request, response, locale);
}else if (request_locale.equals("en_US")) {
//设置英文环境
Locale locale = new Locale("en","US");
(new CookieLocaleResolver()).setLocale(request, response, locale);
}else {
//使用之前的语言环境
(new CookieLocaleResolver()).setLocale(request, response,LocaleContextHolder.getLocale());
}
}
User user = new User();
model.addAttribute("user",user);
return formName;
}
然后运行,和之前的效果一样
按f12发现请求头是en_US,响应头是zh_CN

Spring MVC的拦截器
拦截器是Spring MVC中强大的控件,他可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,也可以在渲染视图后进行操作
拦截器概述
有点类似于Servlet中的Filter拦截器,用于拦截用户的请求并作出相应的处理。比如通过拦截器来进行用户权限验证,或者用来判断用户是否已经登录。
在Spring MVC中定义一个拦截器有两种方法:实现HandlerInterceptor接口,实现WebRequestInterceptor接口
实现HandlerInterceptor接口
要实现这个接口,就要实现其三个方法
- preHandle方法:该方法在执行控制器方法之前执行,返回值为布尔类型,如果返回false,表示拦截请求,不再向下执行;如果返回true表示放行,程序继续向下执行。
- postHandle方法:在执行控制器方法调用过后,且在返回ModelAndView之前执行。由于该方法会在DispatcherServlet进行返回视图渲染之前被调用,所以此方法多被用于处理返回的视图,可通过此方法对请求语中的模型和视图做进一步的修改
- afterCompletion方法:该方法在执行完控制器之后执行,该方法适合进行一些资源清理,记录日志信息等处理工作
实现了HandlerInterceptor接口之后,需要在Spring的类加载配置文件中配置拦截器实现类,才能使拦截器起到拦截的效果,加载配置有两种方式
后续有代码演示的话我再把代码粘过来
- 针对HandlerInterceptor配置
- 针对全局配置
实现WebRequestInterceptor接口
也是那三个方法,只不过参数不一样
- preHandle(WebRequest request):在Controller方法调用之前调用,但返回值使void,所以我们一般用它来进行资源的准备工作。
- postHandle(WebRequset request,ModelMap model):也是在Controller方法调用之后,视图返回渲染之前调用,所以可以在这个方法里面通过改变模型数据ModelMap来改变数据的展示。WebRequset 对象是用于传递整个请求数据的,比如在preHandle中准备的数据都可以通过它来传递和访问。
- afterCompletion(WebRequset request,Exception ex):WebRequset参数就可以把我们在preHandle中准备的资源传递到这里进行释放。Exception参数表示当前请求的异常对象,如果在Controller中抛出的异常已经被Spring的异常处理器给处理了,那么这个异常对象就是null。
拦截器执行流程
单个拦截器的执行流程

修改UserController控制器类
注释掉之前动态跳转的方法,新增hello方法


package com.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyInterceptor拦截器执行preHandle()方法");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor拦截器执行postHandle()方法");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("MyInterceptor拦截器执行afterCompletion()方法");
}
}
修改springmvc.xml配置文件
注释掉之前国际化拦截器的配置
添加如下配置
<mvc:interceptors>
<!--使用bean直接定义在<mvc:interceptors>下面的拦截器将拦截所有请求 -->
<bean class="com.springmvc.interceptor.MyInterceptor"></bean>
</mvc:interceptors>
写hello.jsp页面,随便写一句话,这个程序主要是看拦截器执行顺序

启动tomcat运行,访问localhost:8080/springmvc-6/hello
然后观察控制台

具体的应用实例我看后面好像有
多个拦截器执行流程

这里还是写了个实例用来证明执行流程,顺便掩饰了下操作
把之前自定义的拦截器复制两份,命名MyInterceptor 1,MyInterceptor 2,然后把里面的输出语句也都整成1,2的

修改springmvc.xml文件,注释掉指点单拦截器的配置,增加如下配置
<mvc:interceptors>
<!--定义多个拦截器 -->
<mvc:interceptor><!--拦截器1 -->
<mvc:mapping path="/**"></mvc:mapping><!--配置拦截器所作用的路径 -->
<!--定义在mvc:interceptor下面的拦截器,表示对匹配路径请求才进行拦截 -->
<bean class="com.springmvc.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor><!--拦截器2 -->
<mvc:mapping path="/hello"></mvc:mapping><!--配置拦截器所作用的路径 -->
<!--定义在mvc:interceptor下面的拦截器,表示对匹配路径请求才进行拦截 -->
<bean class="com.springmvc.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
然后运行,访问,观察控制台

通过结果确定,执行顺序并不完全是线性的,而是根据不同的方法功能穿插运行。
使用拦截器实现用户登录权限验证
先画出流程图,搞明白程序运行流程

这么一看,有点像我之前PHP项目里做登录,然后登录成功后主界面显示用户名的流程,只不过当时使用的好像是session。。。
回头问问老师拦截器实现有什么区别,或者好处,然后补充
先写Controller控制器类
//向用户登录页面的跳转方法
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String loginPage() {
System.out.println("用户从login的请求到登录跳转login.jsp页面");
return "login";
}
//用户实现登录的方法
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(User user,Model model,HttpSession session) {
String loginName=user.getLoginName();
String password=user.getPassword();
if (loginName!=null&&loginName.equals("fzj")&&password!=null&&password.equals("123456")) {
System.out.println("用户登录成功");
//将用户添加至session中保存
session.setAttribute("CURRENT_USER", user);
return "redirect:index";//重新定向到主页的index跳转方法
}
model.addAttribute("message","账号或密码错误,请重新登录!");
return "login";//跳转到登录页面
}
//向主页跳转的方法
@RequestMapping(value = "/index")
public String indexPage() {
System.out.println("用户从index请求到主页跳转");
return "index";
}
//用户退出登录的方法
@RequestMapping(value = "/logout")
public String logout(HttpSession session) {
session.invalidate();//清除session
System.out.println("控制器方法退出功能实现,清除session,重定向到login的请求");
return "redirect:login";//重定向到登录界面
}
写拦截器类
package com.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 登录的拦截器类
* @author Mike-laptop
*
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("测试拦截器方法是否执行");
// 获取请求的URI
String url = request.getRequestURI();
if (!(url.contains("Login")||url.contains("login"))) {
//非登录请求,获取session,判断是否有用户数据
if (request.getSession().getAttribute("CURRENT_USER")!=null) {
return true;//说明已经登录,放行
}else {//没有登录则跳转到登录页面
request.setAttribute("message", "您还没有登录,请先登录");
request.getRequestDispatcher("/ch11/login.jsp").forward(request, response);
}
}else {
//登录请求,放行
return true;
}
return false; //默认拦截
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
在springmvc.xml文件中配置该拦截器
<!--登录拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"></mvc:mapping>
<bean class="com.springmvc.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
写登录和主页


运行,加入想直接访问index会被拦截器拦截,然后跳转到登录页面,并设置提示信息为没登陆的提示信息

其他的就不演示了,还是正常登录登出老一套
这个我感觉吧,其实就是把session判断换了个地方。。我当时写PHP课设的时候,有个购物车功能,只有登录才能看购物车里,我会在点击购物车按钮时看session是否为空,为空就不给看,让登录。不为空就显示该session记录的用户的购物车。
应该是一个道理。
407

被折叠的 条评论
为什么被折叠?



