SpringMVC文件上传、异常处理、拦截器
SpringMVC文件上传、异常处理、拦截器
基本配置准备:maven项目模块
application.xml
<?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:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"><!-- 加载扫描--><context:component-scan base-package="com.etime"></context:component-scan><!--处理器映射器:根据请求路径匹配映射路径找到对应的执行器--><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean><!--处理器适配器:根据处理器映射器返回的执行器对象,去执行执行器对象--><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean><!--视图解析器:解析视图--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"></property><property name="suffix" value=".jsp"></property></bean><mvc:annotation-driven/><mvc:default-servlet-handler></mvc:default-servlet-handler><!-- 文件解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean><!-- 配置拦截器--><mvc:interceptors><mvc:interceptor>
<!-- 拦截器路径--><mvc:mapping path="/"/>
<!-- 放行路径--><mvc:exclude-mapping path="/interceptor/test02"/>
<!-- 指定当前配置的拦截器--><bean class="com.etime.interceptor.MyInterceptor"></bean></mvc:interceptor><mvc:interceptor>
<!-- 拦截器路径--><mvc:mapping path="/"/>
<!-- 放行路径--><mvc:exclude-mapping path="/interceptor/test02"/>
<!-- 指定前配置的拦截器--><bean class="com.etime.interceptor.SecondInterceptor"></bean></mvc:interceptor><mvc:interceptor><mvc:mapping path="/"/><mvc:exclude-mapping path="/loginController/login"/><bean class="com.etime.interceptor.LoginInterceptor"></bean></mvc:interceptor></mvc:interceptors>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping><filter><filter-name>characterEncoding</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>characterEncoding</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter><filter-name>hiddenMethodFilter</filter-name><filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping><filter-name>hiddenMethodFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
</web-app>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.etime</groupId><artifactId>day08</artifactId><version>1.0-SNAPSHOT</version><properties><spring.version>5.2.5.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.9</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency></dependencies></project>
SpringMVC的文件上传
文件上传需要做的准备
form表单的enctype取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)enctype:是表单请求正文的类型method属性取值必须是Post提供一个文件选择域< input type="file"/>
文件上传原理
当form表单的enctype取值不是默认值后,request.getParameter()将失效。enctype="application/x-www-form-urlencoded"时,form表单的正文内容是:key=value&key=value&key=value;当form表单的enctype 取值Mutilpart/form-data时,请正文内容就变成:每一部都是MIME类型描述的正文:enctype="application/x-www-form-urlencoded"key=value&key=value&key=value;request.getParameter();底层:form表单是一个大的请求体:每一个组件都是一个小的请求体:enctype=Mutilpart/form-datarequest.getParameter();失效每一组都是一个小的请求体:username = lisiage = 21file = xxx.jpg
SpringMVC的文件上传
构建maven工程添加相关依赖
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version></dependency>commons-fileupload 依赖了commons-io Apache提供的
编写jsp页面
index.jsp
//多文件上传
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><form action="upload/test" method="post" enctype="multipart/form-data">选中文件:<input type="file" name="photo"><br>选中文件:<input type="file" name="photo"><br>选中文件:<input type="file" name="photo"><br><input type="submit"></form>
<%--<a href="exception/test">测试</a>--%>
</body>
</html>
控制器
UploadController.java
package com.etime.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;@Controller
@RequestMapping("upload")
public class UploadController {@PostMapping("test")public String test(MultipartFile[] photo){String path = "D:\\\\test";File file = new File(path);if (!file.exists()){file.mkdirs();}
// //获取文件名
// String fileName = photo.getOriginalFilename();
// //上传
// try {
// photo.transferTo(new File(file, fileName));
// } catch (IOException e) {
// e.printStackTrace();
// }for (MultipartFile f:photo) {String fileName = f.getOriginalFilename();try {f.transferTo(new File(file,fileName));} catch (IOException e) {e.printStackTrace();}}return "main";}
}
配置文件解析器
注意: id必须固定~
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
运行结果:
SpringMVC的异常处理
项目开发中异常处理的方式
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。
异常处理的设计思路
系统的dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理。
异常处理的步骤
编写异常类和错误页面
package com.etime.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("exception")
public class ExceptionController {@GetMapping("test")public String test(){System.out.println("进啦");int num = 7/0;return "main";}
}<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body>
臭宝~前路不通!!!
</body>
</html>
自定义异常处理器
package com.etime.util;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class MyException implements HandlerExceptionResolver {//只是掩盖了异常,该处理的异常还是得处理public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {ModelAndView modelAndView = new ModelAndView();modelAndView.setViewName("error");return modelAndView;}
}
运行结果:当该异常出现时,捕获到异常然后接连的通过跳转到提示页面,将该页面出现的页面掩饰,但是异常依然存在,仍然要处理
SpringMVC的拦截器
拦截器的介绍和作用
SpringMVC的处理器拦截器类似于 Servlet 开发中的过滤器Filter,用于处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。还要向大家提到一个词为Interceptor Chain。拦截器就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
拦截器与过滤器的区别
过滤器是servlet规范中的一部分,任何java web 工程可以使用。拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
过滤器在web.xml中的url-pattern 标签中配置了/*之后,可以对所有要访问的资源拦截。html js css image
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp 是不会进行拦截的。它也是AOP思想的具体应用。
我们要想自定义拦截器,要求必须实现:HandlerInterceptor接口
过滤器:/* : js css html
拦截器: / :只是拦截控制器方法。
自定义拦截器
jsp:package com.etime.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("interceptor")
public class InterceptorController {@GetMapping("test01")public String test01(){System.out.println("test01真的进来了");return "main";}@GetMapping("test02")public String test02(){System.out.println("test02真的进来了");return "main";}
}
编写一个普通类实现HandlerInterceptor接口
package com.etime.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 {//Controller方法运行前运行public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("Controller方法运行前");//返回值为false拦截器Controller方法不执行//返回值为true拦截器Controller方法执行return false;}//Controller方法返回值时public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("Controller方法返回值时");//return;}//Controller方法运行后public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("Controller方法运行后");//return;}
}
配置拦截器
application.xml
<!-- 配置拦截器--><mvc:interceptors><mvc:interceptor>
<!-- 拦截器路径--><mvc:mapping path="/"/>
<!-- 放行路径--><mvc:exclude-mapping path="/interceptor/test02"/>
<!-- 指定当前配置的拦截器--><bean class="com.etime.interceptor.MyInterceptor"></bean></mvc:interceptor></mvc:interceptors>
拦截器的注意事项
拦截器的放行
拦截器中的放行指的是:如果下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
public boolean preHandle(HttpServletRequest request , HttpServletResponse response,Object handler)方法返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法。
多个拦截器的执行顺序
拦截器1;
package com.etime.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 {//Controller方法运行前运行public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("Controller方法运行前");//返回值为false拦截器Controller方法不执行//返回值为true拦截器Controller方法执行return false;}//Controller方法返回值时public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("Controller方法返回值时");//return;}//Controller方法运行后public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("Controller方法运行后");//return;}
}拦截器2:package com.etime.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 SecondInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("第二个拦截器,Controller方法执行前");return true;}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("第二个拦截器,Controller方法返回数据");}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("第二个拦截器,Controller方法执行后");}
}配置:application.xml<mvc:interceptor>
<!-- 拦截器路径--><mvc:mapping path="/"/>
<!-- 放行路径--><mvc:exclude-mapping path="/interceptor/test01"/>
<!-- 指定前配置的拦截器--><bean class="com.etime.interceptor.SecondInterceptor"></bean></mvc:interceptor>
运行结果:
拦截器综合案例
实现思路分析:
1、定义登录页面,并定义请求映射。
2、判断用户名密码是否正确
3、如果正确 向 session 中写入用户信息
4、返回登录成功。
5、拦截用户请求,判断用户是否登录
6、如果用户已经登录。放行
7、如果用户未登录,跳转到登录页面
示例代码:
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title>
</head>
<body><form action="loginController/login" method="post" >账号:<input type="text" name="username" >密码:<input type="password" name="password"><input type="submit" value="登录"></form>
</body>
</html>控制器:package com.etime.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
@RequestMapping("/loginController")
public class LoginController {@PostMapping("login")public ModelAndView login(String username, String password, ModelMap modelMap){boolean res=true;ModelAndView modelAndView = new ModelAndView();if (res){modelMap.addAttribute("username",username);modelAndView.setViewName("success");}return modelAndView;}
}拦截器:package com.etime.interceptor;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;@Controller
@RequestMapping("/loginInterceptor")
public class LoginInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//登录过滤,未登录的情况,某些功能不能使用HttpSession session = request.getSession();if (session.getAttribute("username")==null){//未登录System.out.println("未登录");response.sendRedirect("../login.jsp");return false;}else {System.out.println("已登录");return true;}}
}application.xml<mvc:interceptor><mvc:mapping path="/"/><mvc:exclude-mapping path="/loginController/login"/><bean class="com.etime.interceptor.LoginInterceptor"></bean></mvc:interceptor>
运行结果: