一、拦截器
1.简介
使用拦截器Interceptor对请求进行拦截,类似于过滤器Filter
2.用法
步骤:
- 定义一个类,实现HandlerInterceptor
package interceptor;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Description TODO
* @Author Matthew
* @Date 2019/3/30 15:54
* @Version 1.0
*/
public class HelloInterceptor implements HandlerInterceptor {
//调用目标处理方法之前执行,可以作权限,日志等处理
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod)handler;//参数handler本质上就是HandlerMethod实例
Object bean = handlerMethod.getBean();
Method method = handlerMethod.getMethod();
System.out.println("HelloInterceptor.preHandle,bean:" + bean.getClass() + ",method:" + method.getName()
+ ",args:" + Arrays.toString(method.getParameterTypes()));
}
return true;//true表示继续调用后续的拦截器或目标处理方法,false表示不再调用
}
//调用目标处理方法之后处理,渲染视图之前,可以对数据模型或视图进行修改
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HelloInterceptor,postHandle");
}
//渲染视图之后,,可以用来释放资源
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("HelloInterceptor.afterCompletion");
}
}
package interceptor;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description TODO
* @Author Matthew
* @Date 2019/3/30 16:41
* @Version 1.0
*/
public class TimeInterceptor implements HandlerInterceptor {
private long startTime,endTime;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
startTime = System.currentTimeMillis();
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
endTime = System.currentTimeMillis();
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
System.out.println("执行目标方法" + handlerMethod.getMethod().getName() + "花费时间:" + (endTime-startTime) + "ms");
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
- 配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--默认拦截所有请求-->
<bean class="interceptor.HelloInterceptor"/>
<!--拦截指定请求-->
<mvc:interceptor>
<mvc:mapping path="/user/regist"/>
<mvc:mapping path="login"/>
<mvc:mapping path="/path/*"/>
<mvc:exclude-mapping path="/path/test7"/>
<bean class="interceptor.TimeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
HelloInterceptor,postHandle
HelloInterceptor.afterCompletion
HelloInterceptor,postHandle
HelloInterceptor,postHandle
HelloInterceptor.afterCompletion
HelloInterceptor.afterCompletion
登录之后
HelloInterceptor.preHandle,bean:class controller.ParamController,method:test9,args:[class java.lang.String]
RequestBody = username=%E7%8B%AC%E5%AD%A4%E6%B1%82%E8%B4%A5&password=123
HelloInterceptor,postHandle
HelloInterceptor.afterCompletion
二、处理AJAX
- @ResponseBody
为方法添加该注解后,将返回值写到响应体中
package controller;
/**
* @Description TODO
* @Author Matthew
* @Date 2019/3/30 17:46
* @Version 1.0
*/
@Controller
@RequestMapping("/ajax")
public class AjaxController {
@RequestMapping("/test1")
public void test1(HttpServletResponse response) throws IOException {
response.getWriter().write("success");
}
@RequestMapping("/test2")
@ResponseBody //将返回值写到响应体中,并不是跳转视图
public String test2(){
return "success2";
}
@RequestMapping("/getUser")
@ResponseBody
public User getUser(){
User user = new User(1001, "唐闪", "123", 18);
return user;
}
}
- 返回JSON
三种方式:
jackson,SpringMVC默认支持
gson,SpringMVC默认支持,google开发
fastjson,SpringMVC默认不支持,alibaba开发
2.1 使用jackson
步骤: - 添加jar包
<!--jackson-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
- 配置消息转换器(省略)
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器,jackson和gson可以省略,fastjson不可以-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
2.2 使用gson
步骤:
- 添加jar包
<!--gson-->
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
- 配置消息转换器(省略)
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器,jackson和gson可以省略,fastjson不可以-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
2.3 使用fastjson
步骤:
- 添加jar包
<!-- fastjson -->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
- 配置消息转换器
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器,jackson和gson可以省略,fastjson不可以-->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
三、文件上传和下载
文件上传
1.1 简介
SpringMVC对文件上传提供了支持,基于commons-fileupload
1.2 用法
步骤:
- 添加jar包
<!-- commons-fileupload -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
- 编写jsp页面
<%--
Created by IntelliJ IDEA.
User: Matthew
Date: 2019/3/30
Time: 17:41
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
<script>
$(function () {
$('#btn').on('click',function () {
$.post('${pageContext.request.contextPath}/ajax/getUsers', function (data) {
console.log(data);
});
});
});
</script>
</head>
<body>
<button id="btn">发送AJAX请求</button>
</body>
</html>
- 配置文件解析器
<!--配置文件解析器 id必须为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSizePerFile" value="5000000"/>
</bean>
- 通过CommonsMultipartFile来接收文件
package controller;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import util.StringUtils;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Description TODO
* @Author Matthew
* @Date 2019/3/30 20:18
* @Version 1.0
*/
@Controller
@RequestMapping("/file")
public class FileController {
//文件上传只能以post方式
@PostMapping("/upload")//文件上传CommonsMultipartFile前必须加RequestParam注解
public String upload(String username, @RequestParam CommonsMultipartFile file, HttpSession session) {
System.out.println("用户名:" + username);
System.out.println("表单名称:" + file.getName());
System.out.println("文件名:" + file.getOriginalFilename());
System.out.println("文件大小:" + file.getSize());
//获取上传目录的物理路径
String path = session.getServletContext().getRealPath("\\WEB-INF\\upload\\");
System.out.println(path);
try {
file.transferTo(new File(path, StringUtils.renameFileName(file.getOriginalFilename())));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
@PostMapping("/uploads")//文件上传CommonsMultipartFile前必须加RequestParam注解
public String uploads(String username, @RequestParam CommonsMultipartFile[] files, HttpSession session) {
//获取上传目录的物理路径
String path = session.getServletContext().getRealPath("\\WEB-INF\\upload\\");
for (CommonsMultipartFile file : files) {
try {
file.transferTo(new File(path, StringUtils.renameFileName(file.getOriginalFilename())));
} catch (IOException e) {
e.printStackTrace();
}
}
return "success";
}
}
文件下载
两种方式:
使用OutputStream
使用ResponseEntity
使用OutputStream
传递文件名的两种方式:
使用请求参数传递文件名
使用rest风格传递文件名
默认情况下如果url结尾有后缀,会被自动截取掉,解决方式:
1. 将文件名放到url中间
2. 配置不自动截取后缀(使用较少)
// @RequestMapping("/download")
// public void download(String filename, HttpSession session, HttpServletResponse response) {
@RequestMapping("/{filename}/download")
public void download(@PathVariable String filename, HttpSession session, HttpServletResponse response) throws IOException {
String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
File file = new File(path, filename);
try {
response.setHeader("content-disposition", "attachment;filename=" + filename);
StreamUtils.copy(new FileInputStream(file), response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
// @RequestMapping("/download")
// public void download(String filename, HttpSession session, HttpServletResponse response) {
@RequestMapping("/{filename}/download")
public void download(@PathVariable String filename, HttpSession session, HttpServletResponse response) throws IOException {
String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
File file = new File(path, filename);
try {
response.setHeader("content-disposition", "attachment;filename=" + filename);
StreamUtils.copy(new FileInputStream(file), response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
2.2 使用ResponseEntity
@RequestMapping("/download2")
public ResponseEntity<byte[]> download2(String filename, HttpSession session) throws IOException {
String path = session.getServletContext().getRealPath("/WEB-INF/upload/");
File file = new File(path, filename);
byte[] bytes = FileUtils.readFileToByteArray(file);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("content-disposition","attachment;filename=" + filename);
return new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.OK);//包含:文件数据,响应头,状态码
}