SpringMVC的文件上传与SpringMVC的拦截器
表单项type=“file”
表单的提交方式是post
表单的enctype属性是多部分表单形式,及enctype=“multipart/form-data”
<form action="/weather/summer" method="post" enctype="multipart/form-data"> 文件名:<input type="text" name="name"><br/> 文件:<input type="file" name="fileName"/><br/> 提交:<input type="submit" value="上传"> </form>
application/x-www-form-urlencoded
multipart/form-data时,请求正文内容就变成多部分形式:
commons-fileupload工具包与commons-io
<!-- 导入文件上传的jar包坐标--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
在spring.xml中配置多媒体解析器CommonsMultipartResolver
如果你的前端使用form标签进行值的
<!-- 定义文件上传解析器 --> <!-- 配置文件上传解析器,--> <!--当文件上传解析器未配置的时候,后端的方法是不能从前端的form标签中获取传递来的参数--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设定默认编码 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 设定文件上传的最大值为5MB,5*1024*1024 --> <property name="maxUploadSize" value="5242880"></property> <!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 --> <property name="maxInMemorySize" value="40960"></property> <!-- 上传文件的临时路径 --> <property name="uploadTempDir" value="fileUpload/temp"></property> <!-- 延迟文件解析 --> <property name="resolveLazily" value="true"/>
前端程序:
<form action="/weather/summer" method="post" enctype="multipart/form-data"> 文件名:<input type="text" name="name"><br/> 文件:<input type="file" name="fileName"/><br/> 提交:<input type="submit" value="上传"> </form>
后台程序:
@Controller @RequestMapping(path = "/weather") public class WeatherController { @ResponseBody @RequestMapping(path = "Spring",method = RequestMethod.POST) public void quickSpring(@RequestParam(value = "name") String username, @RequestParam("uploadFile") MultipartFile file){ //当你的名字与你的前端设input的name属性值不同时获取的则是null, // 那是因为没有经过属性映射匹配需要对要获取的属性使用@RequestParams注解来进行映射 System.out.println(username); // System.out.println(file); }
}
@ResponseBody @RequestMapping(path = "autumn") public void autumn(String name,@RequestParam(value = "fileName") MultipartFile uploadFile) throws IOException { System.out.println(name); //获取上传文件的名称 String filename = uploadFile.getOriginalFilename(); System.out.println(filename); //将前端上传地文件存储起来 uploadFile.transferTo(new File("D:\\资料\\test\\"+filename)); }
<form action="/weather/winter" method="post" enctype="multipart/form-data"> 文件名:<input type="text" name="name"><br/> 文件:<input type="file" name="fileName"/><br/> 文件2:<input type="file" name="fileName2"/><br/> 提交:<input type="submit" value="上传"> </form>
后端:
@ResponseBody @RequestMapping(path = "/winter") public void Winter(String name, MultipartFile fileName,MultipartFile fileName2){ // 依次获取对应的文件name System.out.println(name); System.out.println(fileName.getOriginalFilename()); System.out.println(fileName2.getOriginalFilename()); }
@ResponseBody @RequestMapping("autumnOne") public void AutumnOne(String name,MultipartFile [] fileName) throws IOException { // 此时的文件的name也要和前端传递来的一致 System.out.println(name); System.out.println(fileName.length); for (MultipartFile m :fileName) { System.out.println(m.getOriginalFilename()); m.transferTo(new File("D:\\资料\\test\\"+m.getOriginalFilename())); //文件的存储 } }
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(InterceptorChain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。
过滤器器可以拦截抱任何请求信息,包括静态的资源也可以拦截, 而拦截器只可以对controller中的请求方法进行拦截,不可以拦截静态资源
①创建拦截器类实现HandlerInterceptor接口
②配置拦截器
③测试拦截器的拦截效果
1) Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter 适配器类
① preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。
如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
② postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
③ afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
preHandle方法的时候就去看下这个方法是否返回的是true,如果返回的是false则下面的一切都不执行了
编写拦截器:
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器的目标执行方法前的"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器目标方法执行后,视图返回前的"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器的最后方法,我在所有的方法都执行完后执行"); } }
配置:在SpringMVC的配置文件中配置
然后去springMvc.xml中配置你的拦截器
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体是谁--> </mvc:interceptor> </mvc:interceptors>
编写测试程序测试:
编写Controller,发请求到controller,跳转页面
@RequestMapping("/test") @Controller public class TargetControlle { @RequestMapping("/target") public ModelAndView target(ModelAndView modelAndView){ System.out.println("目标资源执行....."); modelAndView.addObject("name","目标资源"); modelAndView.setViewName("target"); return modelAndView; } }
切忌在编写拦截器的时候一定要仔细查看手动实现的拦截器重写的preHandle方法是不是return true只有返回的true才可以进行下面的流程的执行
多个拦截器的使用:
其实可以理解为python的装饰器,层层执行,从上到下依次执行的,
比如有拦截器1和拦截器2就是拦截器1将拦截器2和目标方法包裹住了
请求的流程图如下:(从上到下依次执行)
定义拦截器1
MyInterceptor
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器1的目标执行方法前的preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器1的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器1的最后方法"); } }
定义拦截器2:
public class MyInterceptorTwo implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行"); } }
在springMvc.xml中配置拦截器(拦截器的先后执行就是在此处配置的)
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置--> </mvc:interceptor> </mvc:interceptors> <!-- 配置拦截器2--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/> </mvc:interceptor> </mvc:interceptors>
目标方法
@RequestMapping("/test") @Controller public class TargetControlle { @RequestMapping("/target") public ModelAndView target(ModelAndView modelAndView){ System.out.println("目标资源执行....."); modelAndView.addObject("name","目标资源"); modelAndView.setViewName("target"); return modelAndView; } }
执行的结果为;
我是拦截器1的目标执行方法前的preHandle
我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行
目标资源执行.....
我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前
我是拦截器1的postHandle
我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行
拦截器1的最后方法
我们可以利用拦截器的方法来进行方法的判断和资源信息展示的更改:
拦截器1:来进行携带参数和跳转界面的判断
/** * 手动实现拦截器必须实现HandlerInterceptor接口和它的方法 */ public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器1的目标执行方法前的preHandle"); String param = request.getParameter("username"); if("laowang".equals(param)){ // 判断是否携带参数username,它的值是laowang return true; // 返回true代表放行 }else { request.getRequestDispatcher("/WEB-INF/views/error.jsp").forward(request,response); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("我是拦截器1的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器1的最后方法"); } }
拦截器2:利用postHandle来更改界面返回的参数
public class MyInterceptorTwo implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("我是拦截器2的preHandle方法,我应该在目标方法执行前和拦截器1的preHandle方法后执行"); return true; //返回true代表放行,返回false代表不放行 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("name","我是拦截器2修改后的参数"); System.out.println("我是拦截器2的postHandle方法,我应该在目标资源执行后和方法1的postHandle方法执行前"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是拦截器2的afterCompletion方法我在目标方法执行后,拦截器1的postHandle方法后执行"); } }
拦截器的配置
<!-- 配置拦截器--> <!-- 将mvc的命名空间导入后配置拦截器--> <mvc:annotation-driven /> <mvc:interceptors> <mvc:interceptor> <!-- 对那些资源进行操作--> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptor"/><!--指定你的拦截器的具体位置--> </mvc:interceptor> </mvc:interceptors> <!-- 配置拦截器2--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.springMvc.Interceptor.MyInterceptorTwo"/> </mvc:interceptor> </mvc:interceptors>
结论:
当拦截器的preHandle方法返回true则会执行目标资源,如果返回false则不执行目标资源
多个拦截器情况下,配置在前的先执行,配置在后的后执行
拦截器中的方法执行顺序是:preHandler-------目标资源----postHandle---- afterCompletion