国际化
国际化概述
国际化并不是对内容进行国际化,而是对本身要显示的文字进行国际化,需要在SpringIOC容器中配置国际化资源文件的bean,国际化是具体通过Locale完成。SpringMVC为国际化提供了本地化拦截器和本地化解析器,以便完成通过超链接切换方式完成国际化。
- 本地化解析器:SessionLocaleResovler
- 本地化拦截器:LocaleChangeInterceptor
通过超链接切换国际化
配置国际化资源文件:
基础文件,i18n.properties
username=mapengpeng
usergender=male
国际化中文文件,i18n_zh_CN.properties
username=\u9A6C\u9E4F\u9E4F
usergender=\u7537
国际化英文文件,i18n_en_US.properties
username=pengpengma
usergender=Man
配置国际化资源文件的bean
<!-- 配置国际化资源文件的bean -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
配置本地化解析器和本地化拦截器
<!-- 本地化解析器 -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
</bean>
<!-- 本地化拦截器,这个bean被mvc标签包起来了,外部bean不能引用它,即就是内部bean不用bean id -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
编写index.jsp
<a href=""${pageContext.request.contextPath}/testChangeLanguage?locale=zh_CN">中文</a>
<br>
<a href=""${pageContext.request.contextPath}/testChangeLanguage?locale=en_US">English</a>
<br>
编写请求处理器:
package com.wanbangee.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LocaleController {
@RequestMapping("testChangeLanguage")
public String testChangeLanguage() {
return "success";
}
}
编写success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<fmt:message key="username"></fmt:message>
<fmt:message key="usergender"></fmt:message>
</body>
</html>
总结
掌握通过切换超链接完成国际化操作:
·在之前的国际化基础上配置SessionLocaleResolver的bean
·配置 Interceptor:LocaleChangeInterceptor
·需要添加请求参数,参数名称为locale,值为本地化语言,比如zh_CN,表示简体中文,en_US,表示美式英文
文件上传
掌握在SpringMVC中使用FileUpload上传组件
SpringMVC中,为文件的上传提供了直接的支持,这种支持是使用可插拔的组件MultipartResolver实现的,
SPring使用FileUpload实现了MultipartResolver接口,实现类名称叫做CommonsMultipartResolver,SpringMVC上下文中并没有默认装配MultipartResolver,因此默认情况是进行不了文件上传的,
需要我们在SpringMVC上下文中配置MultipartResolver这个bean。
1.配置文件上传的解析器:在springmvc-servlet.xml配置文件中配置。
<!-- 配置文件上传的解析器MultipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<!-- 文件上传的最大字节数"#{5*1024*1024}"使用SpringMVC的EL表达式 -->
<property name="maxUploadSize" value="#{5*1024*1024}"></property>
</bean>
2.添加jar包
commons-fileupload-1.2.1.jar
commons-io-2.0.jar
3.编写文件上传的表单
<form action="testFileUpLoad" method="post" enctype="multipart/form-data">
empName:<input type="text" name="empName">
empMail:<input type="text" name="empMail">
empPic:<input type="file" name="empPic1">
empPic:<input type="file" name="empPic2">
empPic:<input type="file" name="empPic3">
<input type="submit" value="Submit">
</form>
编写请求处理器
package com.wanbangee.controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.wanbangee.util.NewFileName;
@Controller
public class FileUploadConttroller {
@RequestMapping("testFileUpLoad")
public String testFileUpLoad(String empName,String empMail,MultipartFile empPic1,MultipartFile empPic2,MultipartFile empPic3,HttpServletRequest request) throws Exception {
System.out.println(empName);
System.out.println(empMail);
System.out.println(empPic1.getName()); //获得请求参数名(就是文本框名称)
System.out.println(empPic2.getOriginalFilename());//获得文件名称(文件名加文件的后缀名)
System.out.println(empPic3.getSize());//获得文件的大小
//获得上传文件的后缀名
String names1[] = empPic1.getOriginalFilename().split("\\.");
String name1 = names1[names1.length-1];//取得数组中最后一位元素
String names2[] = empPic2.getOriginalFilename().split("\\.");
String name2 = names2[names2.length-1];
String names3[] = empPic3.getOriginalFilename().split("\\.");
String name3 = names3[names3.length-1];
String path = request.getServletContext().getRealPath("/file");
//获得file文件夹的真实路径,就是在硬盘中位置,如D:\Tomcat\apache-tomcat-8.5.55\wtpwebapps\SpringMVC02\file
File file1 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name1);
File file2 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name2);
File file3 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name3);
empPic1.transferTo(file1);//将上传文件另存为一个新的文件
empPic2.transferTo(file2);//将上传文件另存为一个新的文件
empPic3.transferTo(file3);//将上传文件另存为一个新的文件
return "success";
}
}
在util包下写个工具类NewFileName用来获取新的文件名
package com.wanbangee.util;
import javax.servlet.http.HttpServletRequest;
public class NewFileName {
public static String getNewFileName(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
// IPV6 地址是以冒号分割,IPV4以.分割
String localAddr = request.getLocalAddr().replaceAll(":", "").replaceAll("\\.", "");
sb.append(localAddr);
Long currentTime = System.currentTimeMillis();//取得时间戳
sb.append(currentTime);
//三位随机数
for(int i = 0;i<3;i++) {
int random = (int) Math.round(Math.random()*9);
sb.append(random);
}
return sb.toString();
}
}
使用字节输出流方式,
package com.wanbangee.controller;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.wanbangee.util.NewFileName;
@Controller
public class FileUploadConttroller {
@RequestMapping("testFileUpLoad")
public String testFileUpLoad(String empName,String empMail,MultipartFile empPic1,MultipartFile empPic2,MultipartFile empPic3,HttpServletRequest request) throws Exception {
System.out.println(empName);
System.out.println(empMail);
System.out.println(empPic1.getName()); //获得请求参数名(就是文本框名称)
System.out.println(empPic2.getOriginalFilename());//获得文件名称(文件名加文件的后缀名)
System.out.println(empPic3.getSize());//获得文件的大小
//获得上传文件的后缀名
String names1[] = empPic1.getOriginalFilename().split("\\.");
String name1 = names1[names1.length-1];//取得数组中最后一位元素
String names2[] = empPic2.getOriginalFilename().split("\\.");
String name2 = names2[names2.length-1];
String names3[] = empPic3.getOriginalFilename().split("\\.");
String name3 = names3[names3.length-1];
String path = request.getServletContext().getRealPath("/file");
//获得file文件夹的真实路径,就是在硬盘中位置,如D:\Tomcat\apache-tomcat-8.5.55\wtpwebapps\SpringMVC02\file
File file1 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name1);
File file2 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name2);
File file3 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name3);
InputStream in1 = empPic1.getInputStream();
// byte b1[] = new byte[(int)empPic1.getSize()];
// byte b1[] = empPic1.getBytes();
// in1.read(b1);
OutputStream ps1 = new FileOutputStream(file1,true);
int temp = 0;
while((temp = in1.read()) != -1) {
ps1.write(temp);
}
InputStream in2 = empPic2.getInputStream();
// byte b2[] = new byte[(int)empPic2.getSize()];
// byte b2[] = empPic2.getBytes();
// in2.read(b2);
OutputStream ps2 = new FileOutputStream(file2,true);
temp = 0;
while((temp = in2.read()) != -1) {
ps2.write(temp);
}
InputStream in3 = empPic3.getInputStream();
// byte b3[] = new byte[(int)empPic3.getSize()];
// byte b3[] = empPic3.getBytes();
// in3.read(b3);
OutputStream ps3 = new FileOutputStream(file3,true);
temp = 0;
while((temp = in3.read()) != -1) {
ps3.write(temp);
}
return "success";
}
}
总结
对于文件上传来说,主要的就是要懂得如何配置,及之前的IO的操作需要熟悉。
拦截器
最擅长使用拦截器框架就是Struts2,因为Struts2的几乎所有的功能都是靠Struts2的拦截器完成的。
SpringMVC里面也有定义一些拦截器,完成一些功能,比如国际化定义的本地化拦截器。
SPringMVC的拦截器会对请求进行拦截,用户也可以自定义拦截器来实现特定的功能,
SpringMVC中提供了一个拦截器的接口:HandlerInterceptor,所有的拦截器都必须实现这个接口:
- preHandle():在执行处理器的目标方法之前执行,可以对用户的请求进行处理。
- postHandle() : 这个方法在执行处理器的目标方法之后,渲染视图之前执行,可以对请求的响应进行处理。
- afterCompletion():这个方法是在执行目标方法和渲染视图之后执行,这个方法可以进行请求资源的清理。
1.拦截器配置,在springmvc-servlet.xml配置文件中配置。
<!-- 本地化拦截器 -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!-- 自定义拦截器配置,放在mvc:interceptors里面的拦截器,会拦截所有的请求 -->
<bean class="com.wanbangee.interceptor.Interceptor01"></bean>
</mvc:interceptors>
2.编写拦截器(注意过滤器和拦截器的比较)
package com.wanbangee.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 Interceptor01 implements HandlerInterceptor {
//preHandle : 在执行处理器的目标方法之前执行,可以对用户的请求进行处理
//该方法的返回值如果为false,表示请求不再向下执行。return true;请求继续向下执行
//这里有request对象和response对象,可以在这里做一些验证,非法参数,统一编码....
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle---------------------Interceptor01");
return true;
}
//postHandle 这个方法在执行处理器的目标方法之后,渲染视图之前执行,可以对请求的响应进行处理。
//可以对数据模型或视图信息进行一些业务上的处理。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle------------Interceptor01");
}
//afterCompletion 这个方法是在执行目标方法和渲染视图之后执行,可以进行请求资源的清理,释放一些资源。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion---------------Interceptor01");
}
}
3.为了便于测试三个方法之间的关系,在文件上传类FileUploadConttroller中加上两行输出语句。
package com.wanbangee.controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.wanbangee.util.NewFileName;
@Controller
public class FileUploadConttroller {
@RequestMapping("testFileUpLoad")
public String testFileUpLoad(String empName,String empMail,MultipartFile empPic1,MultipartFile empPic2,MultipartFile empPic3,HttpServletRequest request) throws Exception {
System.out.println("FileUpLoadController..... start");
//获得上传文件的后缀名
String names1[] = empPic1.getOriginalFilename().split("\\.");
String name1 = names1[names1.length-1];
String names2[] = empPic2.getOriginalFilename().split("\\.");
String name2 = names2[names2.length-1];
String names3[] = empPic3.getOriginalFilename().split("\\.");
String name3 = names3[names3.length-1];
String path = request.getServletContext().getRealPath("/file");
File file1 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name1);
File file2 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name2);
File file3 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name3);
empPic1.transferTo(file1);//另存为
empPic2.transferTo(file2);//另存为
empPic3.transferTo(file3);//另存为
System.out.println("FileUpLoadController..... end");
return "success";
}
}
运行结果发现:
//preHandle : 在执行处理器的目标方法之前执行,可以对用户的请求进行处理
//该方法的返回值如果为false,表示请求不再向下执行。return true;请求继续向下执行
//postHandle() : 这个方法在执行处理器的目标方法之后,渲染视图之前执行,可以对请求的响应进行处理。
//afterCompletion():这个方法是在执行目标方法和渲染视图之后执行,这个方法可以进行请求资源的清理。
一个拦截器的执行顺序:
多个拦截器执行顺序
如果有两个拦截器呢,而且preHandler都返回true?
第一个拦截器的代码,Interceptor01
package com.wanbangee.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 Interceptor01 implements HandlerInterceptor {
//preHandle : 在执行处理器的目标方法之前执行,可以对用户的请求进行处理
//该方法的返回值如果为false,表示请求不再向下执行。return true;请求继续向下执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle1---------------------Interceptor01");
return true;
}
//postHandle 这个方法在执行处理器的目标方法之后,渲染视图之前执行,可以对请求的响应进行处理。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle1------------Interceptor01");
}
//afterCompletion 这个方法是在执行目标方法和渲染视图之后执行,这个方法可以进行请求资源的清理。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion1---------------Interceptor01");
}
}
第二个拦截器的代码,Interceptor02
package com.wanbangee.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 Interceptor02 implements HandlerInterceptor {
//preHandle : 在执行处理器的目标方法之前执行,可以对用户的请求进行处理
//该方法的返回值如果为false,表示请求不再向下执行。return true;请求继续向下执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle2---------------------Interceptor02");
return true;
}
//postHandle 这个方法在执行处理器的目标方法之后,渲染视图之前执行,可以对请求的响应进行处理。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle2------------Interceptor02");
}
//afterCompletion 这个方法是在执行目标方法和渲染视图之后执行,这个方法可以进行请求资源的清理。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion2---------------Interceptor02");
}
}
//将这两个自定义拦截器放到本地化拦截器中
<!-- 本地化拦截器 -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!-- 自定义拦截器配置 -->
<bean class="com.wanbangee.interceptor.Interceptor01"></bean>
<bean class="com.wanbangee.interceptor.Interceptor02"></bean>
</mvc:interceptors>
3.为了便于测试三个方法之间的关系,在文件上传类FileUploadConttroller中加上两行输出语句。
package com.wanbangee.controller;
import java.io.File;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import com.wanbangee.util.NewFileName;
@Controller
public class FileUploadConttroller {
@RequestMapping("testFileUpLoad")
public String testFileUpLoad(String empName,String empMail,MultipartFile empPic1,MultipartFile empPic2,MultipartFile empPic3,HttpServletRequest request) throws Exception {
System.out.println("FileUpLoadController..... start");
//获得上传文件的后缀名
String names1[] = empPic1.getOriginalFilename().split("\\.");
String name1 = names1[names1.length-1];
String names2[] = empPic2.getOriginalFilename().split("\\.");
String name2 = names2[names2.length-1];
String names3[] = empPic3.getOriginalFilename().split("\\.");
String name3 = names3[names3.length-1];
String path = request.getServletContext().getRealPath("/file");
File file1 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name1);
File file2 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name2);
File file3 = new File(path + File.separator + NewFileName.getNewFileName(request) + "." + name3);
empPic1.transferTo(file1);//另存为
empPic2.transferTo(file2);//另存为
empPic3.transferTo(file3);//另存为
System.out.println("FileUpLoadController..... end");
return "success";
}
}
如果有两个拦截器呢,而且第一个拦截器的preHandle方法返回false?
如果有两个拦截器呢,而且第一个拦截器的preHandle方法返回true,第二个拦截器的preHandler返回false?
由此得出结论:preHandle方法执行,并且返回true,则一定会执行对象拦截器的afterCompletion方法。
拦截器配置细节
<!-- 本地化拦截器 -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!-- 自定义拦截器配置 -->
<bean class="com.wanbangee.interceptor.Interceptor01"></bean>
<bean class="com.wanbangee.interceptor.Interceptor02"></bean>
</mvc:interceptors>
以上的配置,表示所有经过DispatcherServlet的请求都会执行配置的三个拦截器,
但是实际情况可能是,这个拦截器只对特定的请求才进行拦截。
<!-- 拦截器的配置:mvc:interceptors : 配置一组拦截器,此组拦截器会拦截所有的请求-->
<mvc:interceptors>
<!-- 本地化拦截器 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
<!-- 自定义拦截器配置
- 定义内部bean
- 引用外部bean
-->
<!-- 配置单个拦截器的细节,拦截器只会拦截符合配置规范的请求
- mvc:mapping 表示拦截器会拦截的请求
- 可以是具体的请求地址
- 可以是/* 表示所有请求
- mvc:exclude-mapping 表示不拦截的请求
- bean 表示配置一个内部bean ,必须是一个拦截器,但是不能和 ref 同时配置
- 配置顺序
mvc:mapping 前
mvc:exclude-mapping 中
bean/ref 后
-->
<mvc:interceptor>
<mvc:mapping path="/*"/>
<mvc:exclude-mapping path="/testFileUpLoad"/>
<bean class="com.wanbangee.interceptor.FirstInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/testFileUpLoad"/>
<bean class="com.wanbangee.interceptor.FirstInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
异常处理
ExceptionHandler注解(重要)
在程序开发的时候,控制层难免会出现异常,出现异常之后直接在页面显示500肯定不合适,如果显示的内容不是500,
而是一些友好的提示性信息,比较合适。SpringMVC上下文中,已经装备好了异常解析器对象:ExceptionHandlerExceptionResolver,所有的其他装配的异常解析器都是ExceptionHandlerExceptionResolver的子类。
异常处理步骤:
1.在欢迎界面index.jsp
<a href="testExceptionHandler">test ExceptionHandler</a>
2.控制器中
@Controller
public class FileUploadConttroller {
@RequestMapping("testExceptionHandler")
public String testExceptionHandler() {
System.out.println("testExceptionHandler");
System.out.println(1/1);
int arr[] = {1,2,3};
System.out.println(arr[1]);
Emp emp = new Emp();
System.out.println(emp.getEmpName().length());
return "success";
}
3.编写异常处理器MyExceptionHandler,来处理指定异常类型
package com.wanbangee.exception;
import java.sql.SQLException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice//此注解用来专门处理后端异常的程序
public class MyExceptionHandler {
//表示这个异常处理的方法能够处理 算术异常和sql异常
@ExceptionHandler({ArithmeticException.class,SQLException.class})
public String handlerArithmeticException() {
System.out.println("后端出现了算术异常");
return "error";
}
//表示这个异常处理的方法能够处理 数组下标越界异常
@ExceptionHandler(ArrayIndexOutOfBoundsException.class)
public String handlerArrayIndexOutOfBoundsException() {
System.out.println("后端出现了数组下标越界异常");
return "error";
}
//表示这个异常处理的方法能够处理所有异常,没有出现上述单独标出的异常就会执行这个总异常
//和所放前后顺序无关,就算这个总异常放在最前面,要是出现单独标出的异常如数组下标越界异常,也是先执行单独标出的数组下标越界异常
@ExceptionHandler(Exception.class)
public String handlerException() {
System.out.println("后端出现了异常");
return "error";
}
}
4.编写视图解析器error.jsp
<h1>网站正在建设中!!!</h1>
总结
对于ExceptionHandler注解的使用要非常熟悉