Spring MVC-学习笔记(5)spring MVC的文件上传、下载、拦截器

1、文件上传。

     spring MVC为文件上传提供了直接的支持,这种支持是即插即用的MultipartResolver(多部分解析器)实现的。spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,spring MVC的文件上传还需要依赖Apache Commons FileUpload的组件。

     spring MVC上下文中默认没有装配MultipartResolver,因此默认情况下不具备文件上传功能。如果需要使用spring的文件上传功能,还需要在上下文配置MultipartResolver。

     Spring MVC的form表单数据类型必须是multipart/form-data类型(二进制流方式),且必须是post方式。使用MultipartFile作为处理方法的参数接收form表单提交的file文件。MultipartFile提供的方法有:

     

   spring MVC上下文默认没有装配MultipartResolver,故要使用上传文件操作,还需要在配置文件中注册MultipartResolver。

<!-- 文件上传配置 -->
     <bean id="multipartResolver"  
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <!-- 上传文件大小上限,单位为字节(10MB) -->
        <property name="maxUploadSize">  
            <value>10485760</value>  
        </property>  
        <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
        <property name="defaultEncoding">
            <value>UTF-8</value>
        </property>
    </bean>

  此外,还需要Apache Commons FileUpload的组件,将commons-fileupload-1.3.3.jar、commons-io-2.6.jar复制到项目lib下。

  举个例子:

  

   引入的jar包为spring-5.0.5、commons-logging-1.2.jar、commons-io-2.6.jar、commons-fileupload-1.3.3.jar。error.jsp、success.jsp仅是提示页面。

   springmvc-config.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
       
      <mvc:default-servlet-handler/>
      
      <!-- 扫描controller -->
      <context:component-scan base-package="com.lfy.controller"/>
      
     <!-- 映射器、适配器策略  -->
      <mvc:annotation-driven/>
      
      <!-- 视图解析器 -->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
            p:prefix="/WEB-INF/content/" p:suffix=".jsp" />
            
      <!-- 文件上传配置 -->
      <bean id="multipartResolver"  
            class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
            <!-- 上传文件大小上限,单位为字节(10MB) -->
            <property name="maxUploadSize">  
                <value>10485760</value>  
            </property>  
            <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
            <property name="defaultEncoding">
                <value>UTF-8</value>
            </property>
      </bean>
</beans>

   uploadForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>文件上传</title>
</head>
<body>
    <h2>文件上传</h2>
    <form action="upload" enctype="multipart/form-data" method="post">
        <table>
            <tr>
                <td>文件描述:</td>
                <td><input type="text" name="description"></td>
            </tr>
            <tr>
                <td>请选择文件:</td>
                <td><input type="file" name="file"></td>
            </tr>
            <tr>
                <td><input type="submit" value="上传"></td>
            </tr>
        </table>
    </form>
</body>
</html>

   FileUploadController.java

package com.lfy.controller;

import java.io.File;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.lfy.bean.User;

@Controller
public class FileUploadController{
    
    @RequestMapping(value="/uploadForm")
    public String uploadForm(){
        // 跳转到文件上传页面
        return "uploadForm";
    }

// 上传文件会自动绑定到MultipartFile中 @RequestMapping(value="/upload") public String upload(HttpServletRequest request, @RequestParam("description") String description, @RequestParam("file") MultipartFile file) throws Exception{ System.out.println(description); // 如果文件不为空,写入上传路径 if(!file.isEmpty()){ // 上传文件路径 String path = request.getServletContext().getRealPath( "/images"); // 上传文件名 String filename = file.getOriginalFilename(); File filepath = new File(path,filename); // 判断路径是否存在,如果不存在就创建一个 if (!filepath.getParentFile().exists()) { filepath.getParentFile().mkdirs(); } // 将上传文件保存到一个目标文件当中 file.transferTo(new File(path+File.separator+ filename)); System.out.println("上传文件路径:" + (path+File.separator+ filename)); return "success"; }else{ return "error"; } } }

    总结:步骤1.引入commons相关jar包;2.注册MultipartResolver;3.编码接收文件的上传。

    ==>使用对象接收文件的上传:文件作为对象的属性保存

    registerForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>用户注册</title>
</head>
<body>
    <h2>用户注册</h2>
    <form action="register" enctype="multipart/form-data" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>请上传头像:</td>
                <td><input type="file" name="image"></td>
            </tr>
            <tr>
                <td><input type="submit" value="注册"></td>
            </tr>
        </table>
    </form>
</body>
</html>

   User.java

package com.lfy.bean;

import java.io.Serializable;

import org.springframework.web.multipart.MultipartFile;


public class User implements Serializable{

    private static final long serialVersionUID = 1L;

    private String username;
    
    private MultipartFile image;

    public User() {
        super();
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public MultipartFile getImage() {
        return image;
    }
    public void setImage(MultipartFile image) {
        this.image = image;
    }
}

    UserImageUpController.java

package com.lfy.controller;

import java.io.File;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.ResponseEntity.BodyBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.lfy.bean.User;

@Controller
public class UserImageUpController{
    
    @RequestMapping(value="/registerForm")
     public String registerForm(){
        // 跳转到文件上传页面
        return "registerForm";
    }
     
    @RequestMapping(value="/register")
     public String register(HttpServletRequest request,
             @ModelAttribute User user,
             Model model)throws Exception{
         System.out.println(user.getUsername());
        // 如果文件不为空,写入上传路径
        if(!user.getImage().isEmpty()){
            // 上传文件路径
            String path = request.getServletContext().getRealPath(
                    "/images");
            // 上传文件名
            String filename = user.getImage().getOriginalFilename();
            File filepath = new File(path,filename);
            // 判断路径是否存在,如果不存在就创建一个
            if (!filepath.getParentFile().exists()) { 
                filepath.getParentFile().mkdirs();
            }
            // 将上传文件保存到一个目标文件当中
            user.getImage().transferTo(new File(path+File.separator+ filename));
            // 将用户添加到model
            model.addAttribute("filename", user.getImage().getOriginalFilename());
            System.out.println("上传文件路径:" + (path+File.separator+ filename));
            return "userInfo";
        }else{
            return "error";
        }
    }
    
     @RequestMapping(value="/download")
     public ResponseEntity<byte[]> download(HttpServletRequest request,
             @RequestParam("filename") String filename,
             @RequestHeader("User-Agent") String userAgent
             )throws Exception{
        // 下载文件路径
        String path = request.getServletContext().getRealPath(
               "/images");
        // 构建File
        File file = new File(path+File.separator+ filename);
        // ok表示Http协议中的状态 200
       BodyBuilder builder = ResponseEntity.ok();
       // 内容长度
       builder.contentLength(file.length());
       // application/octet-stream : 二进制流数据(最常见的文件下载)。
       builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
       // 使用URLDecoder.decode对文件名进行解码
       filename = URLEncoder.encode(filename, "UTF-8");
       // 设置实际的响应文件名,告诉浏览器文件要用于【下载】、【保存】attachment 以附件形式
       // 不同的浏览器,处理方式不同,要根据浏览器版本进行区别判断
       if (userAgent.indexOf("MSIE") > 0) {
               // 如果是IE,只需要用UTF-8字符集进行URL编码即可
               builder.header("Content-Disposition", "attachment; filename=" + filename);
       } else {
               // 而FireFox、Chrome等浏览器,则需要说明编码的字符集
               // 注意filename后面有个*号,在UTF-8后面有两个单引号!
               builder.header("Content-Disposition", "attachment; filename*=UTF-8''" + filename);
       }
       return builder.body(FileUtils.readFileToByteArray(file));
     }
}

   上面完成一个头像的上传功能,并将文件信息存储在User中,然后将这些信息传递到userInfo.jsp,点击对应的连接,再由download()方法处理下载。

    

2、文件下载。

   download处理方法接收到页面传递的文件名filename后,使用Apache Commons FileUpload组件的FileUtils读取项目的images文件夹下的该文件,并将其构建成ResponseEntity对象返回客户端下载。使用它可以很方便的定义返回的HttpHeaders和HttpStatus。

   代码中MediaType,代表的是Internet Media Type,即互联网媒体类型,也叫做MIME类型。在Http协议消息中,使用Content-Type来表示具体请求中的媒体类型信息。HttpStatus类型代表的是Http协议中的状态。

3、拦截器

   Interceptor拦截器,主要作用是拦截用户的请求并进行相应的处理。如用于用户权限验证判断用户是否已经登录

   Spring MVC中的Interceptor拦截器拦截请求是通过实现HandlerInterceptor接口完成的。spring MVC中定义一个Interceptor拦截器非常简单,只需要实现HandlerInterceptor接口,或者继承抽象类HandlerInterceptorAdapter。

   HandlerInterceptor接口定义了三个方法,spring MVC通过这三个方法来对用户的请求进行拦截处理:

    举个例子:强制登录拦截

    

   引入的jar包为spring、commons-logging、javax.servlet.jsp.jstl-1.2.1.jar、javax.servlet.jsp.jstl-api-1.2.1.jar。

   web.xml引入springmvc-config.xml文件。

   springmvc-config.xml

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">
       
      <mvc:default-servlet-handler/>
      
      <context:component-scan base-package="com.lfy.controller"/>
      
     <!-- 映射器、适配器策略  -->
      <mvc:annotation-driven/>
      
      <!-- 视图解析器 -->
      <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 
            p:prefix="/WEB-INF/content/" p:suffix=".jsp" />
            
      <!-- 配置拦截器  -->
      <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/*"/>
            <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors下面的Interceptor将拦截所有的请求 -->  
             <bean class="com.lfy.Interceptor.AuthorizationInterceptor"/>
        </mvc:interceptor>
      </mvc:interceptors>
</beans>

   loginForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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>登录页面</title>
</head>
<body>
<h3>登录页面</h3>
<form action="login" method="post">
    <!-- 提示信息 -->
    <font color="red">${requestScope.message }</font>
     <table>
         <tr>
             <td><label>登录名: </label></td>
             <td><input type="text" id="loginname" name="loginname" ></td>
         </tr>
         <tr>
             <td><label>密码: </label></td>
             <td><input type="password" id="password" name="password" ></td>
         </tr>
         <tr>
             <td><input type="submit" value="登录"></td>
         </tr>
     </table>
</form>
</body>
</html>

   mian.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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>首页</title>
<style type="text/css">
    table{border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888;background:#efefef;}
    th,td{border-right:1px solid #888;border-bottom:1px solid #888;padding:5px 15px;}
    th{font-weight:bold;background:#ccc;}
</style>
</head>
<body>
<h3>欢迎[${sessionScope.user.username }]访问</h3>
<br>
<table border="1">
    <tr>
        <th>封面</th><th>书名</th><th>作者</th><th>价格</th>
    </tr>
    <c:forEach items="${requestScope.book_list }" var="book">
        <tr>
            <td><img src="images/${book.image }" height="60"></td>
            <td>${book.name }</td>
            <td>${book.author }</td>
            <td>${book.price }</td>
        </tr>
    </c:forEach>
</table>
</body>
</html>

   AuthorizationInterceptor.java

package com.lfy.Interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lfy.bean.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/** 
 * 拦截器必须实现HandlerInterceptor接口
 * */ 
public class AuthorizationInterceptor  implements HandlerInterceptor {

    // 不拦截"/loginForm"和"/login"请求
    private static final String[] IGNORE_URI = {"/loginForm", "/login"};
    
     /** 
     * 该方法将在整个请求完成之后执行, 主要作用是用于清理资源的,
     * 该方法也只能在当前Interceptor的preHandle方法的返回值为true时才会执行。 
     */  
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception exception)
            throws Exception {
        System.out.println("AuthorizationInterceptor afterCompletion --> ");
        
    }
    /** 
     * 该方法将在Controller的方法调用之后执行, 方法中可以对ModelAndView进行操作 ,
     * 该方法也只能在当前Interceptor的preHandle方法的返回值为true时才会执行。 
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView mv) throws Exception {
        System.out.println("AuthorizationInterceptor postHandle --> ");
        
    }

     /** 
     * preHandle方法是进行处理器拦截用的,该方法将在Controller处理之前进行调用,
     * 该方法的返回值为true拦截器才会继续往下执行,该方法的返回值为false的时候整个请求就结束了。 
     */  
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        System.out.println("AuthorizationInterceptor preHandle --> ");
        // flag变量用于判断用户是否登录,默认为false 
        boolean flag = false; 
        //获取请求的路径进行判断
        String servletPath = request.getServletPath();
        // 判断请求是否需要拦截
        for (String s : IGNORE_URI) {
            if (servletPath.contains(s)) {
                flag = true;
                break;
            }
        }
        // 拦截请求
        if (!flag){
            // 1.获取session中的用户 
            User user = (User) request.getSession().getAttribute("user");
            // 2.判断用户是否已经登录 
            if(user == null){
                // 如果用户没有登录,则设置提示信息,跳转到登录页面
                 System.out.println("AuthorizationInterceptor拦截请求:");
                 request.setAttribute("message", "请先登录再访问网站");
                 request.getRequestDispatcher("loginForm").forward(request, response);
            }else{
                // 如果用户已经登录,则验证通过,放行
                 System.out.println("AuthorizationInterceptor放行请求:");
                 flag = true;
            }
        }
        return flag;
    }
}

   User.java

package com.lfy.bean;

import java.io.Serializable;

public class User implements Serializable{

    private static final long serialVersionUID = 1L;
    
    private Integer id;            // id
    private String loginname;    // 登录名
    private String password;    // 密码
    private String username;    // 用户名
    
    public User() {
        super();
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLoginname() {
        return loginname;
    }
    public void setLoginname(String loginname) {
        this.loginname = loginname;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    
    @Override
    public String toString() {
        return "User [id=" + id + ", loginname=" + loginname + ", password="
                + password + ", username=" + username + "]";
    }
}

   Book.java

package com.lfy.bean;

import java.io.Serializable;

public class Book implements Serializable{
    
    private static final long serialVersionUID = 1L;
    
    private Integer id;                // id    
    private String name;            // 书名
    private String author;            // 作者
    private Double price;            // 价格
    private String image;            // 封面图片
    
    public Book() {
        super();
    }
    public Book( String image,String name, String author, Double price) {
        super();
        this.image = image;
        this.name = name;
        this.author = author;
        this.price = price;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    @Override
    public String toString() {
        return "Book [id=" + id + ", name=" + name + ", author=" + author
                + ", price=" + price + ", image=" + image + "]";
    }
}

   FormController.java

package com.lfy.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * 动态页面跳转控制器
 * */
@Controller
public class FormController{

    @GetMapping(value="/loginForm")
     public String loginForm(){
        // 跳转到登录页面
        return "loginForm";
    }
}

   UserController.java

package com.lfy.controller;

import javax.servlet.http.HttpSession;

import com.lfy.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * 处理用户请求控制器
 * */
@Controller
public class UserController {

     /**
     * 处理/login请求
     * */
     @PostMapping(value="/login")
     public ModelAndView login(
             String loginname,String password,
             ModelAndView mv,
             HttpSession session){
        // 模拟数据库根据登录名和密码查找用户,判断用户登录
        if(loginname != null && loginname.equals("lfy")
                && password!= null && password.equals("123456")){
            // 模拟创建用户
            User user = new User();
            user.setLoginname(loginname);
            user.setPassword(password);
            user.setUsername("管理员");
            // 登录成功,将user对象设置到HttpSession作用范围域
            session.setAttribute("user", user);
            // 转发到main请求
            mv.setViewName("redirect:main");
        }else{
            // 登录失败,设置失败提示信息,并跳转到登录页面
            mv.addObject("message", "登录名或密码错误,请重新输入!");
            mv.setViewName("loginForm");
        }
        return mv;
    }
}

   BookController.java

package com.lfy.controller;

import java.util.ArrayList;
import java.util.List;
import com.lfy.bean.Book;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 处理图书请求控制器
 * */
@Controller
public class BookController {
/** * 处理/main请求 * */ @RequestMapping(value="/main") public String main(Model model){ // 模拟数据库获得所有图书集合 List<Book> book_list = new ArrayList<Book>(); book_list.add(new Book("java.jpg","疯狂Java讲义(附光盘)","李刚 编著",74.2)); book_list.add(new Book("ee.jpg","轻量级Java EE企业应用实战","李刚 编著",59.2)); book_list.add(new Book("sql0.png","mysql技术内幕-sql编程","姜成尧 编著",60.6)); book_list.add(new Book("sql1.png","mysql调优","贺春旸 编著",66.6)); // 将图书集合添加到model当中 model.addAttribute("book_list", book_list); // 跳转到main页面 return "main"; } }

  运行结果:

  

原文地址:https://www.cnblogs.com/ZeroMZ/p/11411848.html