SpringMvc文件上传下载和拦截器

Posted 小崔编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMvc文件上传下载和拦截器相关的知识,希望对你有一定的参考价值。

文件上传

Spring MVC上下文中默认没有装配MultipartResesolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在springMvc配置文件中配置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>

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>
负责上传文件的表单的编码类型必须是“multiart/form-data”.
后台controller代码:

	// 上传文件会自动绑定到MultipartFile中
	 @RequestMapping(value="/upload",method=RequestMethod.POST)
	 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));
			return "success";
		else
			return "error";
		
		 
	 
这里一定要把Apache Commons FileUpload的jar包放到项目的类路径下。要不然会报以下错误:


文件下载

模拟的是先上传后下载:

先上传图像后:

<%@ 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>
再后台下载:

<%@ 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>
<a href="download?filename=$requestScope.user.image.originalFilename">
$requestScope.user.image.originalFilename 
</a>
</body>
</html>

后台代码:

	 
	 @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("user", user);
	        return "userInfo";
		else
			return "error";
		
	
	 
	 @RequestMapping(value="/download")
	 public ResponseEntity<byte[]> download(HttpServletRequest request,
			 @RequestParam("filename") String filename,
			 Model model)throws Exception
		// 下载文件路径
		String path = request.getServletContext().getRealPath(
                "/images/");
		File file = new File(path+File.separator+ filename);
        HttpHeaders headers = new HttpHeaders();  
        // 下载显示的文件名,解决中文名称乱码问题  
        String downloadFielName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
        // 通知浏览器以attachment(下载方式)打开图片
        headers.setContentDispositionFormData("attachment", downloadFielName); 
        // application/octet-stream : 二进制流数据(最常见的文件下载)。
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 201 HttpStatus.CREATED
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),    
                headers, HttpStatus.CREATED);  
	 

拦截器

 SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;

   HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。

   (1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顾名思义,该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。

   (2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解释我们知道这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行,这和Struts2 里面的Interceptor 的执行过程有点类型。Struts2 里面的Interceptor 的执行过程也是链式的,只是在Struts2 里面需要手动调用ActionInvocation 的invoke 方法来触发对下一个Interceptor 或者是Action 的调用,然后每一个Interceptor 中在invoke 方法调用之前的内容都是按照声明顺序执行的,而invoke 方法之后的内容就是反向的。

   (3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 方法,该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。

在springMVC配置上

直接拦截

<mvc:interceptors>
    	<mvc:interceptor>
    		<mvc:mapping path="/upload/*"/>  <!-- 匹配url-->
    		<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求  --> 
    	 	<bean class="org.fkit.interceptor.AuthorizationInterceptor"/>
    	</mvc:interceptor>
    	<!-- <bean class="org.fkit.interceptor.AuthorizationInterceptor"/> -->
    </mvc:interceptors>
代码:

package org.fkit.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.fkit.domain.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;
		
	




以上是关于SpringMvc文件上传下载和拦截器的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC文件上传和拦截器

JAVAEE框架技术之6-springMVC拦截器和文件上传功能

JAVAEE框架技术之6-springMVC拦截器和文件上传功能

JAVAEE框架技术之6-springMVC拦截器和文件上传功能

springMVC

springMVC