SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
- servlet规范中的一部分,任何java web工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
-
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
2、自定义拦截器
那如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持
2、配置web.xml 和 springmvc-servlet.xml 文件
3、编写一个拦截器
package com.kuang.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}
//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}
//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}
4、在springmvc的配置文件中配置拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="com.kuang.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5、编写一个Controller,接收请求
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//测试拦截器的控制器
@Controller
public class InterceptorController {
@RequestMapping("/interceptor")
@ResponseBody
public String testFunction() {
System.out.println("控制器中的方法执行了");
return "hello";
}
}
6、前端 index.jsp
<a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
7、启动tomcat 测试一下!
3、验证用户是否登录 (认证用户)
实现思路
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
测试:
1、编写一个登陆页面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<h1>登录页面</h1>
<hr>
<body>
<form action="${pageContext.request.contextPath}/user/login">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="pwd"> <br>
<input type="submit" value="提交">
</form>
</body>
</html>
2、编写一个Controller处理请求
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
@Controller
@RequestMapping("/user")
public class UserController {
//跳转到登陆页面
@RequestMapping("/jumplogin")
public String jumpLogin() throws Exception {
return "login";
}
//跳转到成功页面
@RequestMapping("/jumpSuccess")
public String jumpSuccess() throws Exception {
return "success";
}
//登陆提交
@RequestMapping("/login")
public String login(HttpSession session, String username, String pwd) throws Exception {
// 向session记录用户身份信息
System.out.println("接收前端==="+username);
session.setAttribute("user", username);
return "success";
}
//退出登陆
@RequestMapping("logout")
public String logout(HttpSession session) throws Exception {
// session 过期
session.invalidate();
return "login";
}
}
3、编写一个登陆成功的页面 success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录成功页面</h1>
<hr>
${user}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>
4、在 index 页面上测试跳转!启动Tomcat 测试,未登录也可以进入主页!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h1>首页</h1>
<hr>
<%--登录--%>
<a href="${pageContext.request.contextPath}/user/jumplogin">登录</a>
<a href="${pageContext.request.contextPath}/user/jumpSuccess">成功页面</a>
</body>
</html>
5、编写用户登录拦截器
package com.kuang.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
// 如果是登陆页面则放行
System.out.println("uri: " + request.getRequestURI());
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
// 如果用户已登陆也放行
if(session.getAttribute("user") != null) {
return true;
}
// 用户没有登陆跳转到登陆页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
6、在Springmvc的配置文件中注册拦截器
<!--关于拦截器的配置-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
7、再次重启Tomcat测试!
OK,测试登录拦截功能无误.
4、文件上传和下载
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
目录
一:搭建SpringMvc开发环境
二:实现文件上传的功能
三:将上传文件绑定到具体的对象上
四 : 实现用户下载的功能
五:总结
一:搭建Springmvc开发环境
首先我们在myeclipse中,新建一个web项目,名为:SpringMvcFileUpload.然后导入必要的jar包,这里的jar包主要是Spring的jar包还有另外一个很重要的jar包,名称为:commons-fileupload-1.3.1.jar,这个是apache开发的一个专门用来上传文件的工具包,其中预置了很多的文件上传的api供我们使用,、
1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
然后在src目录下新建一个包,名为com.wyq.Controller和com.wyq.domain。两个包分别用来存放控制器和领域模型。然后在webRoot目录下新建Folder,取名jsp,主要用来存放我们的jsp页面,接下来配置web.xml文件,在其中配置上我们的Springmv的控制分发器Servlet用于处理客户端请求的链接,然后新建一个Springmvc-config文件,主要是配置Springmvc的bean,这里除了需要配置视图解析器用来解析视图资源和基本的扫描包之外,还需要配置一个很重要的bean,该bean的名字是“multiPartResolver”,主要是用来处理文件的,其中可以配置的属性为上传文件的大小和编码,我们来具体看一下配置文件的代码:
web.xml文件:
springDispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:springmvc-config.xml 1 springDispatcherServlet /springmvc-config.xml:
<context:component-scan base-package="com.wyq" />
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
【注意!!!这个bena的id必须为:multipartResolver ,
’否则上传文件会报400的错误!在这里栽过坑,教训!】
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
CommonsMultipartFile 的 常用方法:
String getOriginalFilename():获取上传文件的原名
InputStream getInputStream():获取文件流
void transferTo(File dest):将上传文件保存到一个目录文件中
二:实现文件上传的功能
2.1:首先我们来新建一个jsp页面,命名为:uploadform.jsp写一个上传的页面form表单,其中一定要注意的是在表单的属性中添加entcypt=“multipart/form-data”,这表示上传的将会是二进制流的格式,以规定的二进制进行上传,便于服务器处理,使用post请求:
<body>
<form action="gotoAction" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td>开始上传</td>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
</body>
2.2:再写一个上传成功的jsp页面,主要是用来当上传成功时候跳转的页面,命名为:success.jsp
<body>
<h2>文件上传成功!</h2>
</body>
2.3:然后再写一个上传失败的页面,主要是用来当上传失败的时候跳转的页面,命名为:error.jsp
<body>
<h2>文件上传失败!请检查文件是否存在</h2>
</body>
2.4:写好了jsp页面,接下来就是写我们的控制器了,Springmvc控制器,在我们的com.wyq.Controller中写一个FileUploadController类,然后写上具体的代码,如下所示,注意其中使用MultipartFile来接受form表单传过来的file文件,MultipartFile有几个核心的api,可以供我们使用,比如 boolean isEmpty(),用来判断文件是否为空。void transferTo( File file),把文件写入目标路径地址.
@Controller
public class FileUploadController {
@RequestMapping(value="/{formName}")
public String loginForm(@PathVariable String formName){
return formName;
}
@RequestMapping(value="/gotoAction",method=RequestMethod.POST)
public String upload(@RequestParam("file") MultipartFile file,
HttpServletRequest request){
if (!file.isEmpty()) {
String contextPath = request.getContextPath();//"/SpringMvcFileUpload"
String servletPath = request.getServletPath();//"/gotoAction"
String scheme = request.getScheme();//"http"
String storePath= "E:\\project\\SpringMvcFileUpload\\WebRoot\\images";//存放我们上传的文件路径
String fileName = file.getOriginalFilename();
File filepath = new File(storePath, fileName);
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();//如果目录不存在,创建目录
}
try {
file.transferTo(new File(storePath+File.separator+fileName));//把文件写入目标文件地址
} catch (Exception e) {
e.printStackTrace();
return "error";
}
return "success";//返回到成功页面
}else {
return "error";//返回到失败的页面
}
}
2.5:好了,到此我们就可以实现上传功能了,发布在Tomact容器里,然后就可以进行上传文件了。在浏览中输入:http://localhost:8080/SpringMvcFileUpload/uploadForm
具体的页面请求如下,然后浏览具体的文件,点击上传按钮:
选择好了文件,点击上传
到了这一步还没完,我们再往下看,有没有写入目标文件夹,也就是在D:\userUploadFile\Files目录下看是否存在我的上传文件,查看是存在的也就是正确写入了
三:将上传文件绑定到具体的对象上
3.1:首先我们来定义一个实体类User,这个实体类中的headimage属性的主要作用就是用来映射我们上传的文件,可以看到它是MultipartFile类型的:
public class User implements Serializable{//用户实体类
private String userName;
private MultipartFile headimage;//上传文件会自动绑定到该属性
//省略getter和setter方法
}
3.2:然后写我们的 jsp上传页面,这里我们来模拟一个用户注册上传头像的场景,新建一个registerForm.jsp页面,然后写一个form表单,如下:
<body>
<h2>用户注册</h2>
<form action="register" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>用户头像:</td>
<td><input type="file" name="headimage"></td>
</tr>
<tr>
<td>上传:</td>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
</body>
3.3:写我们的方法控制器处理注册逻辑的层的代码,注意其中的user对象加入了@ModelAttribute注解,其主要作用是用来映射把上面的form表单的headimage属性自动注入到对象里面,还有Map<String,Object> map主要是为了存放user对象,放在requestScope里面,这样就可用el表达式把其中的值取出来了。
@RequestMapping(value="/register",method=RequestMethod.POST)
public String reg(@ModelAttribute User user,HttpServletRequest request,Map<String,Object> map){
final String wrong="error";
final String good="success";
MultipartFile headimage = user.getHeadimage();
boolean empty = headimage.isEmpty();
if (!empty) {
String realPath = request.getServletContext().getRealPath("/images");
String uploadPath="D:\\userUploadFile\\Files";
String headimageName = headimage.getOriginalFilename();
File imageFile = new File(uploadPath,headimageName);
try {
headimage.transferTo(new File(uploadPath+File.separator+headimageName));
} catch (Exception e) {
e.printStackTrace();
return wrong;
}
map.put("user", user);
return "userInfo";
}else {
return wrong;
}
}
3.4:我们来新建一个jsp页面,取名为userinfo.jsp,其主要作用是显示刚才的我们的文件名:
<body>
用户头像:${requestScope.user.headimage.originalFilename}
</body>
3.5:页面写完了,我们在来模拟测试一下,在客户端Ie浏览器中,输入http://localhost:8080/SpringMvcFileUpload/registerForm:
四:实现用户下载的功能
4.1:首先我们来改造一下刚才的userInfo.jsp页面,主要目的是为了把它变成一个下载的连接,然后用我们就可以写我们的控制器用来处理href的请求来了。其中可以看到我们使用了el表达式把url传递给下一个控制器,控制器可以取出这些值进行处理:
<body>
<h3>文件下载</h3> -->
<a
href="download?filename=${requestScope.user.headimage.originalFilename}">
用户头像:${requestScope.user.headimage.originalFilename}
</a>
</body>
4.2:来看看我们的download控制器代码:注意download方法返回的是ResponseEntity<byte[]> 类型,这个是封装好的返回类型,我们需要传入byte数组、headers、HttpStatus,然后它就会返回具体的下载流,调用客户端去下载资源
@RequestMapping(value="/download",method=RequestMethod.GET) //匹配的是href中的download请求
public ResponseEntity<byte[]> download(HttpServletRequest request,@RequestParam("filename") String filename,
Model model) throws IOException{
String downloadFilePath="D:\\userUploadFile\\Files";//从我们的上传文件夹中去取
File file = new File(downloadFilePath+File.separator+filename);//新建一个文件
HttpHeaders headers = new HttpHeaders();//http头信息
String downloadFileName = new String(filename.getBytes("UTF-8"),"iso-8859-1");//设置编码
headers.setContentDispositionFormData("attachment", downloadFileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//MediaType:互联网媒介类型 contentType:具体请求中的媒体类型信息
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);
}
4.3:我们来测试一下写的东西是否能准确运行,点击超链接,注意此链接指向的地址:http://localhost:8080/SpringMvcFileUpload/download?filename=“myheadimage”.jpg,这就表示这个链接会去请求控制器,然后控制器进行处理下载, 这样就完成了文件的下载功能了:
点击超链接:
五:总结
本篇博文介绍了SpringMvc上传和文件的功能,需要注意的地方就是对于文件上传包common-fileupload.jar包的使用,还有在配置文件上配置mulitipartResolver这个bean。下面又介绍了用java 实体类去映射上传文件的属性对应的文件,这点的好处就是它会自动映射,然后把对象放入到我们的请求域中,就可以展示给界面用户层,这也是mvc思想模式的体现。接下来是介绍去下载文件,只需要从我们的写入的目标地址去取出文件,再进行responseEntity对象的封装,就可以实现下载功能