SpringMVC
关于三层架构和MVC
1.三层架构
- 开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序
- 使用java语言我们基本上是开发B/S架构的程序,所以我们将B/S又分成了三层架构
- 三层架构
- 表现层:web层,用来和客户端进行数据交互,表现层一般我们使用MVC模型。代表:SpringMVC
- 业务层:处理具体业务逻辑。代表:spring框架
- 持久层:用来操作数据库。代表:Mybatis
2.MVC设计模型
- MVC,全名为model view controller 模型视图控制器,每个部分的各司其职
- Model: 数据模型,JavaBean类,用来数据封装
- View: 视图 JSP
- Controoler控制器:Servlet
什么是SpringMVC
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring
FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。
Spring 框架提供了构建 Web 应用程序的全功 能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。
SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成为最优秀的 MVC 框架。
它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
SpringMVC的优势
- 清晰的角色划分,将每个部分分为一个个模块去处理。
- 分工明确,而且扩展点相当灵活。
- 由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。
- 和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。
- 可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。
- 可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。
- 功能强大的数据验证、格式化、绑定机制。
- 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。
- 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
- 强大的 JSP 标签库,使 JSP 编写更容易。
- RESTful风格的支持
- 简单的文件上传
- 约定大于配置的契约式编程支持
- 基于注解的零配置支持
SpringMVC快速入门
创建一个maven工程选择骨架并选择 maven-archetype-webapp (一个简单的Java Web应用程序)
- 导入坐标
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.1.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</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.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
- 编写web.xml配置前端控制器和加载我们的spring配置
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- springMVC的前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--若不写则默认去WEB-INF下扫描*servlet.xml文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 启动顺序,数字越小,启动越早 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都拦截-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 编写spring的配置文件
<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/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="cn.okt"></context:component-scan>
<!--视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--开启SpringMVC框架注解支持-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
- 编写控制类
//控制器
@Controller
public class HelloController {
/**
* @RequestMapping:请求匹配,其值为servlet路径
* @return
*/
@RequestMapping("/hello")
public String sayHello(){
System.out.println("hello springmvc");
return "success";
}
}
- 编写index.html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>springmvc快速入门</title>
</head>
<body>
<H3>入门程序</H3>
<a href="hello">入门程序</a>
</body>
</html>
- 流程总结
常用注解
@RequestMapping
- RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
- 它的作用位置可以在方法上也可以在类上
- 在类上它作为一个一级目录
- 在方法上它作为一个二级目录
- 细节:路径可以不编写 / 表示应用的根目录开始
- 细节::${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
- RequestMapping的属性
- path/value:请求指定路径url
- method:指定该方法的请求方式
- params:用于指定限制请求参数的条件。
- header:发送的请求必须包含请求头
@RequestParam
-
作用:
- 把请求中的指定名称的参数给控制器的形参赋值
-
属性
- value:请求参数中的名称。
- required:请求参数中是否必须提供此参数。默认值为true。表示必须提供,如果不提供将报错
-
演示
/** * 常用注解 */ @Controller @RequestMapping("anno") public class AnnoController { // 请求无需带参数 /* @RequestMapping("testRequestParam") public String testRequestParam(@RequestParam(name="name",required = false) String username){ System.out.println("执行了"); System.out.println(username); return "success"; }*/ //请求必须带参数 @RequestMapping("testRequestParam") public String testRequestParam(@RequestParam(name="name") String username){ System.out.println("执行了"); System.out.println(username); return "success"; } }
@RequetBody
-
作用:
- 用于获取请求体的内容(注意:get方法不可以)
-
属性:
- required:是否必须有请求体,默认值是true
-
演示
/*** * 获取到请求体内容,此处是form表单 * @param body * @return */ @RequestMapping("testRequestBody") public String testRequestParam(@RequestBody String body){ System.out.println("执行了"); System.out.println(body); return "success"; }
@PathVariable
-
作用:
- 拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位)
-
属性:
- value:指定url中的占位符名称
-
RESTful风格的URL
- 请求路径一样,可以根据不同的请求方式去执行后台的不同方法
- restful风格的URL优点
- 结构清晰
- 符合标准
- 易于理解
- 容易扩展
- RESTful编程风格和原来的区别,通过请求的方式不同来辨别请求哪个方法
1.
-
演示
/*** * PathVariable注解 * @param id * @return */ @RequestMapping("testPathVariable/{id}") public String testRequestParam(@PathVariable(name="id")String id){ System.out.println("执行了"); System.out.println(id); return "success"; }
@CookieValue
-
作用:
- :用于获取指定cookie的名称的值
-
属性:
- value:指定url中的占位符名称
-
演示
/*** * PathVariable注解 * @param id * @return */ @RequestMapping("testCookieValue") public String testRequestParam(@CookieValue(name="JSESSIONID")String id){ System.out.println("执行了"); System.out.println(id); return "success"; }
@ModelAtrribute
-
作用:
- 出现在方法上:表示当前方法会在控制器方法执行前线执行。
- 出现在参数上:获取指定的数据给参数赋值。
-
属性:
- value:用于获取数据的key。key可以是POJO的属性名称,也可以是map结构的key
-
应用场景
- 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
-
演示
-
有返回值的@ModelAtrribute
/** * ModelAttribute注解 * @param user * @return */ @RequestMapping("testModelAttribute") public String testModelAttribute(User user){ System.out.println("执行了"); System.out.println(user); return "success"; } /** * 该方法会先执行 */ @ModelAttribute public User showUser(String uname){ System.out.println("show执行了"); //通过用户名查询数据库 User user=new User(); user.setUname(uname); user.setAge(20); user.setDate(new Date()); return user; }
-
无返回值的@ModelAtrribute
/** * ModelAttribute注解 * @param user * @return */ @RequestMapping("testModelAttribute") public String testModelAttribute(@ModelAttribute("abc") User user){ System.out.println("执行了"); System.out.println(user); return "success"; } /** * 该方法会先执行 */ @ModelAttribute public void showUser(String uname, Map<String,User> map){ System.out.println("show执行了"); //通过用户名查询数据库 User user=new User(); user.setUname(uname); user.setAge(20); user.setDate(new Date()); map.put("abc",user); }
-
@SessionAttribute
- 作用:
- 用于多次执行控制器方法间的参数共享
- 属性:
- value:指定存入属性的名称
请求参数绑定
-
请求参数的绑定说明
- 绑定机制
- 表单提交的数据都是k=v格式的 username=haha&password=123
- SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
- 提交表单的name和参数的名称是相同的
- 支持的数据类型(方法参数)
- 基本数据类型和字符串类型
- 实体类型(JavaBean)
- 集合数据类型(List、map集合等)
- 绑定机制
-
基本数据类型和字符串类型
- 提交表单的name和参数的名称是相同的
- 区分大小写
-
实体类型(javabean)
- 提交表单的name和参数的名称是相同的
- 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如: address.name
-
给集合属性数据封装
- list类型则在jsp的name中写:集合名称[索引].属性名
- map类型则在jsp的name中写:Map[‘键’].属性名
-
解决参数返回值中文乱码问题
-
<!--在web.xml中配置解决中文乱码的过滤器--> <filter> <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
-
类型转换器
-
表单提交的数据都是由字符类型来提交,但是在我们封装的时候是有Integer类型,显然在Spring框架内部会默认进行类型转换,当然我们也可以自定义转换类型
-
我们可以自己自定义一个类型转换器,实现Converter的接口 就可以了
/** * 把字符串转换为日期 */ public class StringToDate implements Converter<String, Date> { /*** * * @param s 传入进来的字符串 * @return */ @Override public Date convert(String s) { if (s==null){ throw new RuntimeException("字符串为空"); } DateFormat df=new SimpleDateFormat("yyyy-MM-dd"); //把字符串变为日期 try { return df.parse(s); } catch (ParseException e) { throw new RuntimeException("数据类型转换出现错误"); } } }
-
在springmvc的配置文件中注册服务
<!--配置自定义类型转换器--> <bean id="ConversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.okt.utils.StringToDate"></bean> </set> </property> </bean> <!-- 开启SpringMVC框架注解支持 <mvc:annotation-driven>默认将我们的映射器,配置器生效,但没有为我们的转换器生效所以得添 加conversion-service="ConversionServiceFactoryBean"使其生效 --> <mvc:annotation-driven conversion-service="ConversionServiceFactoryBean"></mvc:annotation-driven>
-
响应数据和结果视图
返回类型分类
-
String返回类型
- Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
/** * String方法 * @param model * @return */ @RequestMapping("testString") public String testString(Model model){ System.out.println("这个方法执行了"); return "success"; }
-
应用场景
/** * String方法 * @param model * @return */ @RequestMapping("testString") public String testString(Model model){ System.out.println("这个方法执行了"); //模拟从数据库中查询出 User user=new User(); user.setUsername("okt"); user.setPassword("123456"); user.setAge(22); model.addAttribute("user",user); return "success"; }
<html> <head> <title>success</title> </head> <body> <h3>执行成功</h3> 姓名:${user.username}<br> 密码:${user.password}<br> 年龄:${user.age} </body> </html>
-
Void返回类型
-
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
-
默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
-
可以使用请求转发或者重定向跳转到指定的页面
/** * void方法 * @param request * @param response */ @RequestMapping("testVoid") public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("这个方法执行了"); //编写请求转发的程序(不经过视图解析器) //request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response); //重定向(不经过视图解析器) //response.sendRedirect(request.getContextPath()+"/index.jsp"); //直接会进行响应(新的页面显示) response.getWriter().println("hello"); }
-
-
ModelAndView返回类型
-
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
-
可以将对象存入request域中,也可以设置跳转到哪个页面,跳转页面经过前端控制器
@RequestMapping("testModelAndView") public ModelAndView testModelAndView(){ ModelAndView mv=new ModelAndView(); System.out.println("testModelAndView这个方法执行了"); //模拟从数据库中查询出 User user=new User(); user.setUsername("okt"); user.setPassword("123456"); user.setAge(22); //把User对象存入到mv对象,它底层会把user对象存入到request对象 mv.addObject("user",user); //想跳转到哪个页面 mv.setViewName("success"); return mv; }
-
Spring框架提供的转发和重定向
-
forward转发
-
controller方法返回String类型,想进行请求转发也可以编写成
@RequestMapping("testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect这个方法执行了"); //使用关键字forward来重定向 return "forward:/WEB-INF/pages/success.jsp"; }
-
-
redirect重定向
-
controller方法返回String类型,想进行重定向也可以编写成
@RequestMapping("testForwardOrRedirect") public String testForwardOrRedirect(){ System.out.println("testForwardOrRedirect这个方法执行了"); //重定向,不需要加项目名称(request.getContextPath()) return "redirect:/index.jsp"; }
ResponseBody响应json数据
-
想要响应json数据我们必须依赖Jquery这个js文件,在我们之前springmvc的配置,DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而 不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
-
<!-- 设置静态资源不过滤 --> <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 --> <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 --> <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
-
-
前台通过Ajax请求服务端,服务端接收请求数据
-
前台代码
<script> //页面加载 $(function () { $("#btn").click(function () { //alert("hello btn"); $.ajax({ url:"user/testAjax", contentType:"application/json;charset=UTF-8", data:'{"username":"hehe","password":"19970930","age":"30"}', dataType:"json", type:"post", success:function (data) { //data服务器端响应的数据,进行解析 } }); }); }); </script> <button id="btn">发送请求</button>
-
服务端代码
/*** * 模拟异步请求和响应 * @return */ @RequestMapping("testAjax") public void testAjax(@RequestBody String body){ System.out.println("testAjax这个方法执行了"); System.out.println(body); }
-
-
后台接收前台的ajax请求发来的数据,并将其封装成对象以json数据返回给前台
-
使用@RequestBody注解把json的字符串转换成JavaBean的对象,再使用@ResponseBody将返回的对象转成json格式发送给前端
/*** * 模拟异步请求和响应 * @return */ @RequestMapping("testAjax") public @ResponseBody User testAjax(@RequestBody User user){ System.out.println("testAjax这个方法执行了"); //客户端发送的是ajax请求,传的是json字符串,后端把json字符串封装到对象当中 System.out.println(user); //做响应,模拟查询数据库 user.setUsername("okt"); user.setAge(22); //响应 return user; }
-
-
JSON和javabean的相互转换需要依赖这些包
<!--jackson(2.7版本用不了)--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency>
SpringMVC文件上传
-
借助第三方组件实现文件上传
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和 commons-io。 commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持
-
传统的上传文件方式
-
控制器代码
-
/** * 文件上传案例 */ @Controller @RequestMapping("file") public class FileUploadController { /** * 文件上传 * @return */ @RequestMapping("fileUpload1") public String fileUpload1(HttpServletRequest request) throws Exception { System.out.println("文件上传"); //使用FileUpload组件完成文件上传 //上传的位置 String path = request.getSession().getServletContext().getRealPath("/uploads/"); System.out.println("path:"+path); File file = new File(path); System.out.println("文件夹是否存在"+file.exists()); if(!file.exists()){ //创建文件夹 file.mkdirs(); } //解析request对象,获取文件上传项 DiskFileItemFactory factory=new DiskFileItemFactory(); ServletFileUpload upload=new ServletFileUpload(factory); List<FileItem> fileItems = upload.parseRequest(request); for (FileItem fileItem : fileItems) { //进行判断,当前item对象是否是上传文件项 if(fileItem.isFormField()){ //说明普通表单项 }else{ //说明上传文件项 //获取上传文件名称 String name = fileItem.getName(); //把文件的名称设置为唯一值 String uuid = UUID.randomUUID().toString().replace("-", ""); name=uuid+"_"+name; //完成文件上传 fileItem.write(new File(path,name)); //删除临时文件 fileItem.delete(); } } return "success"; }
-
-
前端代码
-
<body> <h3>文件上传</h3> <form action="file/fileUpload1" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"><br> <input type="submit" value="上传"> </form> </body>
-
-
-
SpringMVC方式文件上传
-
原理分析
1.在前端页面中文件上传发送请求到服务端 2.服务端接收到后经过前端控制器 3.前端控制器将请求分配到配置文件解析器中解析request 4.解析出请求中的我们上传的文件项发送到Controller 5.通过参数绑定的方式使用MultipartFile upload已经和文件项绑定了可直接使用
-
实现步骤
-
在springmvc的配置文件中配置解析器
<!-- 配置文件上传解析器 --> <!-- id 的值是固定的--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置最大上传大小,单位为字节--> <property name="maxUploadSize" value="10485760"></property> </bean>
-
-
-
SpringMVC跨服务器方式的文件上传
-
分服务器的目的
在实际开发中,我们会有很多处理不同功能的服务器。例如: 应用服务器:负责部署我们的应用 数据库服务器:运行我们的数据库 缓存和消息服务器:负责处理大并发访问的缓存和消息 文件服务器:负责存储用户上传文件的服务器。 (注意:此处说的不是服务器集群)
-
实现步骤
-
导入相关依赖包
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-client --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.19.4</version> </dependency> <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-core --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-core</artifactId> <version>1.19.4</version> </dependency>
-
编写java代码
/** * SpringMVC跨服务器文件上传 * * @return */ @RequestMapping("fileUpload3") public String fileUpload3(MultipartFile upload) throws Exception { System.out.println("springmvc跨服务器文件上传"); //定义上传文件服务器路径 String path="http://localhost:8088/uploads"; //使用FileUpload组件完成文件上传 //说明上传文件项 //获取上传文件名称 String name = upload.getOriginalFilename(); //把文件的名称设置为唯一值 String uuid = UUID.randomUUID().toString().replace("-", ""); name = uuid + "_" + name; //完成文件上传,跨服务器上传 //创建客户端对象 Client client= Client.create(); //和图片服务器进行连接 WebResource resource = client.resource(path+"/"+name); //上传文件 resource.put(upload.getBytes()); return "success"; }
-
-
SpringMVC异常处理
-
SpringMVC异常处理的机制
-
处理异常的步骤
-
编写自定义异常类(提示信息的)
/** * 自定义异常类 */ public class SysException extends Exception{ //存储异常信息 private String message; public SysException(String message) { this.message = message; } @Override public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
-
编写异常处理器,实现接口HandlerExceptionResolver
/** * 异常处理器 * 实现了HandlerExceptionResolver这个类则变为异常处理器 */ public class SysExceptionResolver implements HandlerExceptionResolver { /** * 处理异常业务逻辑 * @param httpServletRequest * @param httpServletResponse * @param o * @param e * @return */ @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { //获取到异常对象 SysException sysException=null; //instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。 if(e instanceof SysException){ sysException=(SysException)e; } else{ sysException=new SysException("系统正在维护"); } ModelAndView mv=new ModelAndView(); mv.addObject("errorMsg",sysException.getMessage()); mv.setViewName("error"); return mv; } }
-
在Springmvc配置文件中配置异常处理器(跳转到提示页面)
<!--配置异常处理器--> <bean id="SysExceptionResolver" class="cn.okt.exception.SysExceptionResolver"></bean>
-
SpringMVC拦截器
-
过滤器和拦截器的区别
- 过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。
- 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
- 过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
- 拦截器它是只会拦截访问的控制器(Controller)方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的
-
拦截器链
- 拦截器链就是将拦截器按一定的顺 序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用
-
实现步骤
-
编写拦截器类,实现接口HandlerInterceptor,重写接口方法,此处编写了两个拦截器
/** * 自定义拦截器 */ public class MyInterceptor implements HandlerInterceptor { /** * 拦截器预处理方法,在controller执行前完成 * return true 放行,执行下一个拦截器,如果没有,执行Controller中的方法 * return false 不放行 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器预处理执行"); //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); return true; } /** * 后处理方法,在controller执行后完成 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器预处理放行,Controller执行方法后执行"); //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); } /** * 在所有完成后执行 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是最后的"); } }
/** * 自定义拦截器2 */ public class MyInterceptor2 implements HandlerInterceptor { /** * 拦截器预处理方法,在controller执行前完成 * return true 放行,执行下一个拦截器,如果没有,执行Controller中的方法 * return false 不放行 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("拦截器2预处理执行"); //request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response); return true; } /** * 后处理方法,在controller执行后完成 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("拦截器2预处理放行,Controller执行方法后执行"); } /** * 在所有完成后执行 * @param request * @param response * @param handler * @param ex * @throws Exception */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("我是第二个最后的"); } }
-
配置拦截器
<!--配置拦截器--> <mvc:interceptors> <mvc:interceptor> <!--要拦截的具体的方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法--> <!-- <mvc:exclude-mapping path=""/>--> <!--配置拦截器对象--> <bean class="cn.okt.interceptor.MyInterceptor"></bean> </mvc:interceptor> <!--配置第二个拦截器--> <mvc:interceptor> <!--要拦截的具体的方法--> <mvc:mapping path="/user/*"/> <!--不要拦截的方法--> <!-- <mvc:exclude-mapping path=""/>--> <!--配置拦截器对象--> <bean class="cn.okt.interceptor.MyInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
-
前端页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h3>执行成功</h3> <%System.out.println("success.jsp执行了");%> </body> </html>
-
执行结果
拦截器预处理执行 拦截器2预处理执行 拦截器执行成功 拦截器2预处理放行,Controller执行方法后执行 拦截器预处理放行,Controller执行方法后执行 success.jsp执行了 我是第二个最后的 我是最后的
-
-
总结
从执行结果我们可以看出,其执行的顺序与我们的拦截器链图中一致,拦截器可以应用在许多场景,例如登录界面等有权限的场景