09.SpringMVC_处理JSON&国际化&文件上传&拦截器&异常处理
1.处理JSON
- @RequestBody和@ResposeBody
- @RequestBody
- 用来将请求报文转换为方法入参中的某个类型的对象
- 该注解只能添加到方法的入参前面
- 例如:将上传文件的流转换为方法入参中的一个字符串类型
- 表单
- @RequestBody
<formaction="${pageContext.request.contextPath
}/testRequestBody"method="post"enctype="multipart/form-data">
描述:<inputtype="text"name="desp"><br>
文件:<inputtype="file"name="wj"><br>
<inputtype="submit">
</form>
- 测试方法
@RequestMapping("/testRequestBody")
publicString
testRequestBody(@RequestBodyStringbody){
System.out.println("请求报文中的信息是:"+body);
return"success";
}
这里如果是要显示保文信息就不用写
<beanid="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
设置字符集
<propertyname="defaultEncoding"value="UTF-8"></property>
设置文件的大小
<propertyname="maxUploadSize"value="102400"></property>
</bean>
- 也可以通过在方法的入参中传入HttpEntity<T>对象来实现类似的功能
- @ResposeBody
- 用来将Handler的方法的返回值以某种格式响应给前端
-
该注解可以添加到类上,也可以添加到方法上
- 如果添加到类上,Handler中的所有方法的返回值将直接响应给页面
@ResponseBody//如果该注解添加到类上,类中所有的方法的返回值将直接响应给浏览器
@Controller
publicclass
SpringMVCHandler {
- 如果添加到方法上,只有添加了该注解的方法的返回值会直接响应給页面
@ResponseBody
@RequestMapping("/testResponseBody")
publicString
testResponseBody(){
System.out.println("测试ResponseBody");
return"success";//当Handler的方法上添加了@ResponseBody注解之后返回值将直接响应给浏览器
JSP页面显示的是success
}
@ResponseBody
@RequestMapping("/testResponseBody2")
publicString
testResponseBody2(){
System.out.println("测试ResponseBody2");
return"page";//当Handler的方法上添加了@ResponseBody注解之后返回值将直接响应给浏览器
}
- 也可以通过将方法的返回值设置为ResponseEntity<T>来实现类似的功能
- 实现文件下载的功能
//实现文件下载的效果
@RequestMapping("/testResponseEntity")
publicResponseEntity<byte[]>
testResponseEntity(HttpSession
session)throws
IOException{
//获取ServletContext对象
ServletContextservletContext
=
session.getServletContext();
//获取输入流
InputStreamis
=
servletContext.getResourceAsStream("/download/meinv.jpg");
//创建byte数组
byte[]body
=
new
byte[is.available()];
//将流读到数组中
is.read(body);
//设置响应头
HttpHeadersheaders
=
new
HttpHeaders();
//告诉浏览器如果处理文件
headers.add("Content-Disposition","attachment;
filename=mn.jpg");
//设置Http的状态码为OK
HttpStatusstatusCode
= HttpStatus.OK;
//创建ResponseEntity
ResponseEntity<byte[]>responseBody
=
new
ResponseEntity<byte[]>(body,headers,statusCode);
returnresponseBody;
}
- 实现文件上传功能
//文件上传
@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desp") String desp ,
@RequestParam("wj") MultipartFile file , HttpSession session) throws IllegalStateException, IOException{
System.out.println("文件的描述性信息是:"+desp);
//获取文件名
String fileName = file.getOriginalFilename();
//获取文件的类型
String contentType = file.getContentType();
//获取文件的大小
long size = file.getSize();
System.out.println("文件名是:"+fileName);
System.out.println("文件的类型是:"+contentType);
System.out.println("文件的大小是:"+size+"字节");
//获取ServletContext对象
ServletContext servletContext = session.getServletContext();
//获取upload目录在服务器端的真实路径
String realPath = servletContext.getRealPath("/upload");
//判断服务端是否有upload目录,如果没人,让它自动创建
File upload = new File(realPath);
if(!upload.exists()){
//创建该目录
upload.mkdirs();
}
//将文件上传到upload目录中
file.transferTo(new File(realPath+"/"+fileName));
return "success";
}
在springmvc.xml中需要配置以下
<beanid="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- //设置字符集 -->
<propertyname="defaultEncoding"value="UTF-8"></property>
<!-- 设置文件的大小 -->
<propertyname="maxUploadSize"value="102400"></property>
</bean>
- 处理JSON
- 导入以下jar包
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
- 发送一个Ajax请求并在处理请求的方法上添加@RequestBody注解
- 发送Ajax请求
<buttonid="btn">Test
JSON</button><br>
$(function(){
//给按钮绑定单击事件
$("#btn").click(function(){
//发送Ajax请求
//设置请求地址
varurl
="${pageContext.request.contextPath }/testJSON"
$.post(url,function(data){
for(vari
= 0; i < data.length; i++){
alert(data[i].id+"-"+data[i].username);
}
});
});
});
- 处理请求
@ResponseBody
@RequestMapping("/testJSON")
publicList<User>
testJSON(){
System.out.println("通过发送Ajax请求处理JSON数据");
//创建一个List<User>
List<User>list
=
new
ArrayList<>();
//向list中添加User对象
returnlist;
}
- 能实现上述功能是通过HttpMessageConverter<T>接口的具体实现类来实现的
2.国际化
- SpringMVC通过LocaleResolver解析器获取本地化信息,默认使用的解析器是AcceptHeaderLocaleResolver,这时发请求时会自动获取浏览器中的Accept-Language的属性值来实现国际化
- 实现国际化需要在SpringMVC的配置文件中配置国际化资源文件
<!-- 设置国际化资源文件 -->
<beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 设置国际化资源文件的基础名 -->
<propertyname="basename"value="i18n"></property>
</bean>
- 我们可以通过超链接的形式来实现中英文的切换
- 1)在SPringMVC的配置文件中配置SessionLocaleResolver解析器和LocaleChangeInterceptor拦截器
<!-- 配置SessionLocaleResolver -->
<beanid="localeResolver"class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
<!-- 配置LocaleChangeInterceptor -->
<!-- 拦截器额执行顺序由配置的先后顺序决定 -->
<mvc:interceptors>
<beanclass="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<!-- 通过paramName属性设置超链接中传入的语言及国家信息的请求参数
-->
<propertyname="paramName"value="language"></property>
</bean>
</mvc:interceptors>
- 2)前端的超链接发送请求时需要携带一个请求参数,参数的默认的名字是locale,我们可以在LocaleChangeIntercepto中设置这个参数名
<ahref="${pageContext.request.contextPath
}/testCutomerI18N?language=zh_CN">中文</a>|
<ahref="${pageContext.request.contextPath
}/testCutomerI18N?language=en_US">ENGLISH</a>
<!-- 设置不经过Handler的方法直接响应的页面 -->
<mvc:view-controller path="/testCutomerI18N" view-name="success"/>
- 通过1)和2)的设置之后,当我们点击超链接时,会将语言及国家的信息设置到session域中,以后在发送请求会直接从session域中获取语言及国家的信息,以此来实现国际化的操作
3.文件的上传
- 1)需要导入以下jar包
commons-fileupload-1.3.1.jar
commons-io-2.5.jar
- 2)在SpringMVC的配置文件中配置CommonsMultipartResovler解析器
<!-- 配置CommonsMultipartResovler -->
<beanid="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置字符集 -->
<propertyname="defaultEncoding"value="UTF-8"></property>
<!-- 设置文件的大小 -->
<propertyname="maxUploadSize"value="102400"></property>
</bean>
- 3)上传文件的表单
<formaction="${pageContext.request.contextPath
}/testFileUpload"method="post"enctype="multipart/form-data">
描述:<inputtype="text"name="desp"><br>
文件:<inputtype="file"name="wj"><br>
<inputtype="submit">
</form>
- 4)处理文件上传的方法,该方法中需要传入一个MultipartFile类型的一个参数
@RequestMapping("/testFileUpload")
publicString
testFileUpload(@RequestParam("desp")
String
desp
,
@RequestParam("wj")MultipartFile
file
, HttpSession
session)throws
IllegalStateException, IOException{
System.out.println("文件的描述性信息是:"+desp);
//获取文件名
StringfileName
=
file.getOriginalFilename();
//获取文件的类型
StringcontentType
=
file.getContentType();
//获取文件的大小
longsize
=
file.getSize();
System.out.println("文件名是:"+fileName);
System.out.println("文件的类型是:"+contentType);
System.out.println("文件的大小是:"+size+"字节");
//获取ServletContext对象
ServletContextservletContext
=
session.getServletContext();
//获取upload目录在服务器端的真实路径
StringrealPath
=
servletContext.getRealPath("/upload");
//判断服务端是否有upload目录,如果没人,让它自动创建
Fileupload
=
new
File(realPath);
if(!upload.exists()){
//创建该目录
upload.mkdirs();
}
//将文件上传到upload目录中
file.transferTo(newFile(realPath+"/"+fileName));
return"success";
}
4.拦截器
- 自定义拦截器需要实现HandlerInterceptor接口
publicclass
FirstInterceptor
implements
HandlerInterceptor {
/**
* 在调用目标方法之前执行
*
* 可以用来设置权限、日志、事务
*/
@Override
publicboolean
preHandle(HttpServletRequest
request, HttpServletResponseresponse,
Objecthandler)
throwsException
{
System.out.println("FirstInterceptor的preHandle方法被调用");
returntrue;
}
/**
* 调用目标之后渲染视图之前执行
*
* 可以修改ModelAndView中模型数据及视图
*/
@Override
publicvoid
postHandle(HttpServletRequest
request, HttpServletResponseresponse,
Objecthandler,
ModelAndViewmodelAndView)throws
Exception {
System.out.println("FirstInterceptor的postHandle方法被调用");
}
/**
* 渲染视图之后执行
*
* 可以用来释放资源
*/
@Override
publicvoid
afterCompletion(HttpServletRequest
request, HttpServletResponseresponse,
Objecthandler, Exceptionex)
throwsException
{
System.out.println("FirstInterceptor的afterCompletion方法被调用");
}
}
- 在SpringMVC中配置拦截器
<!-- 配置LocaleChangeInterceptor -->
<!-- 拦截器额执行顺序由配置的先后顺序决定 -->
<mvc:interceptors>
<beanclass="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<!-- 通过paramName属性设置超链接中传入的语言及国家信息的请求参数
-->
<propertyname="paramName"value="language"></property>
</bean>
<!--
通过以下这种方式配置的拦截器会拦截所有的请求 -->
<beanclass="com.atguigu.springmvc.interceptor.FirstInterceptor"></bean>
<!-- 也可以通过以下方式配置拦截器,通过这种方式可以配置拦截和不拦截那些请求 -->
<mvc:interceptor>
<!-- 设置拦截的请求 -->
<mvc:mappingpath="/testInterceptor"/>
<!-- 设置不拦截那些请求 -->
<!-- <mvc:exclude-mapping path=""/> -->
<beanclass="com.atguigu.springmvc.interceptor.SecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
- 具体多个拦截器的执行顺序请参照源码
-
-
5.异常处理
- Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常
- Spring MVC 提供的 HandlerExceptionResolver的实现类(打红色方框的)
- @ExceptionHandler注解
- 通过该注解标识一个处理异常的方法
@ExceptionHandler(value=ArithmeticException.class)
//定义一个处理异常的方法
publicString
resoveException(Exceptione){
System.out.println("异常信息是:"+e);
return"error";
}
//异常匹配的优先级:根据继承关系优先匹配
@ExceptionHandler(value=RuntimeException.class)
//定义一个处理异常的方法
publicString
resoveException2(Exceptione){
System.out.println("[异常信息是]:"+e);
return"error";
}
@ExceptionHandler(value=Exception.class)
//定义一个处理异常的方法
publicString
resoveException3(Exceptione){
System.out.println("【异常信息是】:"+e);
return"error";
}
- 在方法上添加了@ExceptionHandler注解之后,该方法只能处理当前Handler的方法执行时出现的异常,如果想定义一个全局的处理异常的方法,我们可以使用@ControllerAdvice注解标识一个处理异常的类
@ControllerAdvice
//如果当前Handler中没有处理异常的方法,会去标识了@ControllerAdvice注解的类中去寻找处理异常的方法
publicclass
ResolveExceptionClass {
//定义一个处理异常的方法
@ExceptionHandler(value=Exception.class)
publicString
resoveException3(Exceptione){
System.out.println("{异常信息是}:"+e);
return"error";
}
}
实例:
JSP:
<h2>出错信息</h2>${requestScope.exception
}
类中:
packageexception;
importorg.springframework.web.bind.annotation.ControllerAdvice;
importorg.springframework.web.bind.annotation.ExceptionHandler;
importorg.springframework.web.servlet.ModelAndView;
@ControllerAdvice
publicclass
ResolveExceptionClass {
//定义一个处理异常的方法
@ExceptionHandler(value=Exception.class)
public
ModelAndView
resoveException3(Exception
e){
System.out.println("{异常信息是}:"+e);
ModelAndViewmv
=
new
ModelAndView("error");
mv.addObject("exception",e);
mv.setViewName("error");
return
mv;
}
}
异常对象不能通过Map集合方式传递给成功页面,可以通过ModelAndView将异常对象传递给成功页面上
- @ResponseStatus
- 通过该注解可以标识一个异常类,当出现该异常时会去指定的异常页面
@ResponseStatus(value=HttpStatus.UNAUTHORIZED,reason="滚犊子!你没有此权限!!!")
publicclass
UnAuthorizedException
extends
RuntimeException {
/**
*
*/
privatestatic
final
long
serialVersionUID
= 1L;
}
- 测试方法
@RequestMapping("/testResponseStatus")
publicString
testResponseStatus(@RequestParam("username")
String
username){
if(!"superAdmin".equals(username)){
//抛出没有权限的异常
thrownew
UnAuthorizedException();
}
return"success";
}