SpringMVC实现文件上传
准备JAR包
在正常的web项目包中,添加commons-fileupload和commons-io包
代码展示
- 前端代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jQuery-3.5.1.js"></script>
</head>
<body>
<form action="handle/test" method="post" enctype="multipart/form-data">
<input type="file" name="file">
描述:<input name="desc" type="text">
<input type="submit" value="上传">
</form>
</body>
</html>
- Controller层代码:
package indi.dsl.controller;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import indi.dsl.entry.Student;
@Controller
@RequestMapping(value = "handle")
public class SpringMVCController {
@RequestMapping(value = "test")
public String test(@RequestParam(value="desc") String desc,@RequestParam(value="file") MultipartFile file) throws IOException {
System.out.println("文件描述信息:"+desc);
//读取前端页面中上传的文件进内存
InputStream input = file.getInputStream();
//获取原文件名
String fileName = file.getOriginalFilename();
//将文件从内存中输出到硬盘的指定位置abc.txt
FileOutputStream out = new FileOutputStream("e:\\"+fileName);
//定义字节缓冲数组
byte[] by = new byte[1024];
int len = -1;
while ((len = input.read(by))!=-1) {
//将数据写入硬盘
out.write(by, 0, len);
}
out.close();
input.close();
return "success";
}
}
- 配置文件中需要配置的bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<!-- 配置扫描器,扫描指定的包中的注解 -->
<context:component-scan
base-package="indi.dsl.controller"></context:component-scan>
<!-- 配置视图解析器,拦截Controller层中要跳转的页面,进行简单的前缀和后缀处理 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 拦截前端请求,跳转下个页面 -->
<mvc:view-controller path="handle/test"
view-name="success" />
<!-- SpringMVC基础配置,配置完成后Controller层中@RequestMapping注解的方法同期生效 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 当SpringMVC中没有对应的RequestMapping时,将该请求交给自定义的Servlet处理,如果不存在则交给tomcat中默认的Servlet处理 -->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- 该处ID名字必须为multipartResolver,SpringIOVC容器在初始化时,会寻找id="multipartResolver"的bean,如果找不到就会忽略此bean -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
</beans>
特别注意
- 第一步:需要在将CommonsMultipartResolver类注入进SpringIOC容器中,并且id值必须固定不变为multipartResolver,即id=“multipartResolver”;
- 第二部:前端jsp页面中,上传部分必须指明如下属性:enctype=“multipart/form-data”,只有这样发送的请求才能被CommonsMultipartResolver类获取到。
- 在Controller中可以利用file.getOriginalFilename()属性获取源文件的文件名。
SpringMVC实现拦截器
- 前端代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jQuery-3.5.1.js"></script>
</head>
<body>
<!-- <form action="handle/test" method="post" enctype="multipart/form-data">
<input type="file" name="file">
描述:<input name="desc" type="text">
<input type="submit" value="上传">
</form> -->
<a href="handle/test">test</a>
</body>
</html>
- Controller层代码
package indi.dsl.controller;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import indi.dsl.entry.Student;
@Controller
@RequestMapping(value = "handle")
public class SpringMVCController {
@RequestMapping(value = "test")
public String test(){
System.out.println("方法已经被执行----");
return "success";
}
}
- 拦截器代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<!-- 配置扫描器,扫描指定的包中的注解 -->
<context:component-scan
base-package="indi.dsl.controller"></context:component-scan>
<!-- 配置视图解析器,拦截Controller层中要跳转的页面,进行简单的前缀和后缀处理 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 指定拦截的路径,path的值基于ant风格编写 -->
<mvc:mapping path="/**" />
<!-- 指定哪个路径不被拦截 -->
<mvc:exclude-mapping path="handle/test" />
<!-- 将拦截器注入SpringIOC中 -->
<bean class="indi.dsl.Interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
特别注意
- 第一步:编写拦截器类,并实现HandlerInterceptor接口重写其中方法,其中preHandle方法的拦截时机是在请求调用之后调用@RequestMapping注释的方法之前,即第一步拦截请求,postHandle方法拦截时机为服务器接收到请求后做出的响应时,afterCompletion方法拦截时机为经过前端页面渲染完成时。
- 第二部:将编写好的拦截器加入SpringIOC容器中,如存在多个拦截器可以参照如下配置,具体配置如下:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 第一个拦截器 -->
<mvc:interceptor>
<!-- 指定拦截的路径,path的值基于ant风格编写 -->
<mvc:mapping path="/**" />
<!-- 指定哪个路径不被拦截 -->
<mvc:exclude-mapping path="handle/test" />
<!-- 将拦截器注入SpringIOC中 -->
<bean class="indi.dsl.Interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<!---------------------------------------------------------------->
<!-- 第二个拦截器 -->
<mvc:interceptor>
<!-- 指定拦截的路径,path的值基于ant风格编写 -->
<mvc:mapping path="/**" />
<!-- 指定哪个路径不被拦截 -->
<mvc:exclude-mapping path="handle/test" />
<!-- 将拦截器注入SpringIOC中 -->
<bean class="indi.dsl.Interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
- 如果存在多个多个拦截器,则多个拦截器中各方法的执行顺序为:preHandle拦截器1–>preHandle拦截器2–>postHandle拦截器2–>postHandle拦截器1–>afterCompletion拦截器2。特别注意afterCompletion方法只会执行一次,并且只会执行最后一个拦截器中的afterCompletion方法,具体如图所示: