SpringMVC08:拦截器+文件上传下载

拦截器

概述
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
  • servlet规范中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
  • 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
自定义拦截器
那如何实现拦截器呢?
想要自定义拦截器,必须实现 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的配置文件中配置拦截器
                                   [InvalidCharacterError: "MVC:MAPPING PATH="" did not match the Name production]
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
[InvalidCharacterError: "A HREF="${PAGECONTEXT.REQUEST.CONTEXTPATH}" did not match the Name production]
7、启动tomcat 测试一下!
验证用户是否登录 (认证用户)
实现思路
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
测试:
1、编写一个登陆页面  login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>    Title

登录页面


[InvalidCharacterError: "FORM ACTION="${PAGECONTEXT.REQUEST.CONTEXTPATH}" did not match the Name production]
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" %>    Title

登录成功页面


${user} [InvalidCharacterError: "A HREF="${PAGECONTEXT.REQUEST.CONTEXTPATH}" did not match the Name production]
4、在 index 页面上测试跳转!启动Tomcat 测试,未登录也可以进入主页!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>      $Title$      

首页

 
<%--登录--%>  [InvalidCharacterError: "A HREF="${PAGECONTEXT.REQUEST.CONTEXTPATH}" did not match the Name production]
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的配置文件中注册拦截器
           [InvalidCharacterError: "MVC:MAPPING PATH="" did not match the Name production]
7、再次重启Tomcat测试!
OK,测试登录拦截功能无误.
文件上传和下载
准备工作
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
  • text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
[InvalidCharacterError: "FORM ACTION="" ENCTYPE="MULTIPART" did not match the Name production]
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
  • 而Spring MVC则提供了更简单的封装。
  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
  • CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
文件上传
1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
   commons-fileupload    commons-fileupload    1.3.3    javax.servlet    javax.servlet-api    4.0.1
2、配置bean:multipartResolver
注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!
[InvalidCharacterError: "BEAN ID="MULTIPARTRESOLVER"  CLASS="ORG.SPRINGFRAMEWORK.WEB.MULTIPART.COMMONS.COMMONSMULTIPARTRESOLVER"" did not match the Name production]
CommonsMultipartFile 的 常用方法:
  • String getOriginalFilename():获取上传文件的原名
  • InputStream getInputStream():获取文件流
  • void transferTo(File dest):将上传文件保存到一个目录文件中
我们去实际测试一下
3、编写前端页面
[InvalidCharacterError: "FORM ACTION="" did not match the Name production]
4、Controller
package com.kuang.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest; import java.io.*;
@Controller public class FileController {    //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象    //批量上传CommonsMultipartFile则为数组即可    @RequestMapping("/upload")    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
       //获取文件名 : file.getOriginalFilename();        String uploadFileName = file.getOriginalFilename();
       //如果文件名为空,直接回到首页!        if ("".equals(uploadFileName)){            return "redirect:/index.jsp";       }        System.out.println("上传文件名 : "+uploadFileName);
       //上传路径保存设置        String path = request.getServletContext().getRealPath("/upload");        //如果路径不存在,创建一个        File realPath = new File(path);        if (!realPath.exists()){            realPath.mkdir();       }        System.out.println("上传文件保存地址:"+realPath);
       InputStream is = file.getInputStream(); //文件输入流        OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流
       //读取写出        int len=0;        byte[] buffer = new byte[1024];        while ((len=is.read(buffer))!=-1){            os.write(buffer,0,len);            os.flush();       }        os.close();        is.close();        return "redirect:/index.jsp";   } }
5、测试上传文件,OK!
采用file.Transto 来保存上传的文件
1、编写Controller
/* * 采用file.Transto 来保存上传的文件 */ @RequestMapping("/upload2") public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
   //上传路径保存设置    String path = request.getServletContext().getRealPath("/upload");    File realPath = new File(path);    if (!realPath.exists()){        realPath.mkdir();   }    //上传文件地址    System.out.println("上传文件保存地址:"+realPath);
   //通过CommonsMultipartFile的方法直接写文件(注意这个时候)    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
   return "redirect:/index.jsp"; }
2、前端表单提交地址修改
3、访问提交测试,OK!
文件下载
文件下载步骤:
1、设置 response 响应头
2、读取文件 -- InputStream
3、写出文件 -- OutputStream
4、执行操作
5、关闭流 (先开后关)
代码实现:
@RequestMapping(value="/download") public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{    //要下载的图片地址    String  path = request.getServletContext().getRealPath("/upload");    String  fileName = "基础语法.jpg";
   //1、设置response 响应头    response.reset(); //设置页面不缓存,清空buffer    response.setCharacterEncoding("UTF-8"); //字符编码    response.setContentType("multipart/form-data"); //二进制传输数据    //设置响应头    response.setHeader("Content-Disposition",            "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
   File file = new File(path,fileName);    //2、 读取文件--输入流    InputStream input=new FileInputStream(file);    //3、 写出文件--输出流    OutputStream out = response.getOutputStream();
   byte[] buff =new byte[1024];    int index=0;    //4、执行 写出操作    while((index= input.read(buff))!= -1){        out.write(buff, 0, index);        out.flush();   }    out.close();    input.close();    return null; }
前端
[InvalidCharacterError: "A HREF="" did not match the Name production]
测试,文件下载OK,大家可以和我们之前学习的JavaWeb原生的方式对比一下,就可以知道这个便捷多了!
拦截器及文件操作在我们开发中十分重要,一定要学会使用!