1.SpringMVC 也叫 Spring web mvc。是 Spring 框架的一部分,是在 Spring3.0 后发布的.
2.SpringMVC:是基于spring的一个框架, 实际上就是spring的一个模块, 专门是做web开发的。其实就是servlet的一个升级.
3 . web开发底层是servlet , 框架是在servlet基础上面加入一些功能,让你做web开发方便。
4.SpringMVC就是一个Spring。 Spring是容器,ioc能够管理对象,使用, @Component, @Repository, @Service, @Controller
SpringMVC能够创建对象, 放入到容器中(SpringMVC容器), springmvc容器中放的是控制器对象,
5.我们要做的是 使用@Contorller创建控制器对象, 把对象放入到springmvc容器中, 把创建的对象作为控制器使用
这个控制器对象能接收用户的请求, 显示处理结果,就当做是一个servlet使用。
6.使用@Controller注解创建的是一个普通类的对象, 不是Servlet。 springmvc赋予了控制器对象一些额外的功能。
7.web开发底层是servlet, springmvc中有一个对象是Servlet : DispatherServlet(中央调度器)
DispatherServlet: 负责接收用户的所有请求, 用户把请求给了DispatherServlet, 之后DispatherServlet把请求转发给我们的Controller对象, 最后是Controller对象处理请求。
1.2 SpringMVC 优点:
1.基于 MVC 架构
基于 MVC 架构,功能分工明确。解耦合,
2.容易理解,上手快;使用简单。
可以开发一个注解的 SpringMVC 项目,SpringMVC 也是轻量级的,jar 很小。不依赖的特定的接口和类。
3.作 为 Spring 框 架 一 部 分 , 能 够 使 用 Spring 的 IoC 和 Aop 。 方 便 整 合Strtus,MyBatis,Hiberate,JPA 等其他框架。
4.SpringMVC 强化注解的使用,在控制器,Service,Dao 都可以使用注解。方便灵活。使用@Controller 创建处理器对象,@Service 创建业务对象,@Autowired 或者@Resource在控制器类中注入 Service, Service 类中注入 Dao。
所谓 SpringMVC 的注解式开发是指,在代码中通过对类与方法的注解,便可完成处理器
在 springmvc 容器的注册。注解式开发是重点。
项目:primary-annotation
完成功能:用户提交一个请求,服务端处理器在接收到这个请求后,给出一条欢迎信息,在响应页面中显示该信息。
2 . 加入依赖
spring-webmvc依赖,间接把spring的依赖都加入到项目
jsp,servlet依赖
<dependencies>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-apiartifactId>
<version>5.7.0version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
dependencies>
3 .重点: 在web.xml中注册springmvc框架的核心对象DispatcherServlet
1)DispatcherServlet叫做中央调度器, 是一个servlet, 它的父类是继承HttpServlet
2)DispatcherServlet页叫做前端控制器(front controller)
3)DispatcherServlet负责接收用户提交的请求, 调用其它的控制器对象,
并把请求的处理结果显示给用户
<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>myWebservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>myWebservlet-name>
<url-pattern>*.dourl-pattern>
servlet-mapping>
web-app>
4 .创建一个发起请求的页面 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<p>第一个springmvc项目p>
<p><a href="some.do">发起some.do的请求a> p>
<p><a href="other.do">发起other.do的请求a> p>
body>
html>
5 .创建控制器(处理器)类
1)在类的上面加入@Controller注解,创建对象,并放入到springmvc容器中
2)在类中的方法上面加入@RequestMapping注解。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @Controller :创建处理器对象,对象放在springmvc中 位置在类上面
* 和spring中的Service,@Component 一样都是用来创建对象的
*/
@Controller
public class MyController {
/**
* 处理用户提交的请求 springmvc中是用方法来处理的
* 方法名称是自定义的 多种参数 有多种返回值
* 能处理请求的都是控制器(处理器) MyController能处理请求
* MyController 叫做后端处理器 (back Controller)
*/
/**
* 准备使用 doSome方法来处理请求
* @RequestMapping 请求映射 作用是把一个请求地址和一个方法绑定在一起
* 属性: value 是一个String ,表示请求地址 value的值必须是唯一的
* 在使用的时候 推荐使用以 /开头
* 位置 : 1在方法的上面
* 2.类的上面
* 说明:使用@RequestMapping 修饰的方法叫做处理器方法或者叫控制器方法
* @RequestMapping修饰的方法是可以处理请求的 类似 Servlet中的 doGet 和doPost方法
* value = "/some.do /:表示根地址
* @return 返回值是ModelAndView 本次处理请求的结果 数据和视图的展示
* Model: 表示处理完请求后 要返回的数据
* View :请求完之后需要返回的地址 比如jsp等等
*/
@RequestMapping(value = "/some.do")
public ModelAndView doSome(){
//处理som.do的请求 以下的操作 假设已经从service层处理完业务逻辑 开始向客户端返回处理结果
ModelAndView mv = new ModelAndView();
//添加数据 ,框架在请求的最后部分 把这个数据放入到request作用域中 相当于 request.setAttribute()
mv.addObject("msg","欢迎使用springmvc开发");
mv.addObject("fun","执行的是doSome方法");
//指定视图 指定视图的完整路径 框架对视图执行的是 forward()
mv.setViewName("/show.jsp");
//返回mv对象
return mv;
}
}
6 .创建一个作为结果的jsp,显示请求的处理结果。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<h3>/WEB-INF/view/show.jsp从request作用域获取数据h3><br/>
<h3 >msg数据:${requestScope.msg}h3><br/>
<h3>fun数据:${requestScope.fun}h3>
body>
html>
7 .创建springmvc的配置文件(spring的配置文件一样)
1)声明组件扫描器, 指定@Contorller注解所在的包名
2)声明视图解析器。帮助处理视图的。
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启组件扫描器 用于注解的方式创建对象 -->
<context:component-scan base-package="com.maven.springmvc.servlet"> </context:component-scan>
</beans>
springmvc请求的处理流程
1)发起some.do
2)tomcat(web.xml–url-pattern知道 *.do的请求给DispatcherServlet)
3)DispatcherServlet(根据springmvc.xml配置知道 some.do—doSome())
4)DispatcherServlet把some.do转发个MyController.doSome()方法
5)框架执行doSome()把得到ModelAndView进行处理, 转发到show.jsp
springmvc执行过程源代码分析
1. tomcat启动,创建容器的过程
通过load-on-start标签指定的1,创建DisaptcherServlet对象,
DisaptcherServlet它的父类是继承HttpServlet的, 它是一个serlvet, 在被创建时,会执行init()方法。
在init()方法中
//创建容器,读取配置文件
WebApplicationContext ctx = new ClassPathXmlApplicationContext(“springmvc.xml”);
//把容器对象放入到ServletContext中
getServletContext().setAttribute(key, ctx);
上面创建容器作用: 创建@controller注解所在的类的对象, 创建MyController对象,
这个对象放入到 springmvc的容器中, 容器是map , 类似 map.put(“myController”,MyController对象)
2.请求的处理过程
1)执行servlet的service()
protected void service(HttpServletRequest request, HttpServletResponse response)
protected void doService(HttpServletRequest request, HttpServletResponse response)
DispatcherServlet.doDispatch(request, response){
调用MyController的.doSome()方法
}
doDispatch:springmvc中DispatcherServlet的核心方法, 所有的请求都在这个方法中完成的。
8.修改视图解析器的注册
9. @RequestMapping:是一个数组,可以有多个值,可以是不同的请求访用同一个方法处理
@RequestMapping(value = {"/other.do","/second.do"})
2.1指定模块名称
上,也可以注解在类上,但意义是不同的。value 属性值常以“/”开始。
@RequestMapping 的 value 属性用于定义所匹配请求的 URI。但对于注解在方法上与类上,其 value 属性所指定的 URI,意义是不同的。
一个@Controller 所注解的类中,可以定义多个处理器方法。当然,不同的处理器方法所匹配的 URI 是不同的。这些不同的 URI 被指定在注解于方法之上的@RequestMapping 的value 属性中。但若这些请求具有相同的 URI 部分,则这些相同的 URI,可以被抽取到注解在类之上的@RequestMapping 的 value 属性中。此时的这个 URI 表示模块的名称。URI 的请求是相对于 Web 的根目录。
换个角度说,要访问处理器的指定方法,必须要在方法指定 URI 之前加上处理器类前定义的模块名称.
对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交
方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。
Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GET 与
RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。
以上处理器方法只能处理 POST 方式提交的请求。客户端浏览器常用的请求方式,及其提交方式有以下几种:
也就是说,只要指定了处理器方法匹配的请求提交方式为 POST,则相当于指定了请求
发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用。
当然,若不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配。即对于请求的提交方式无要求。
Step2:修改 index 页面
2.3 处理器方法的参数
处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序
员可在方法内直接使用。
➢ HttpServletRequest
➢ HttpServletResponse
➢ HttpSession
➢ 请求中所携带的请求参数
2.3.1 逐个参数接收
1.HttpServletRequest 对象接受
页面请求效果:
2.4.1逐个接受post请求 表单发送过来的数据
后端处理请求代码
前端请求代码:
2.4.2解决post请求中文乱码问题
get提交默认的字符集是utf-8所以不会乱码,而post是ISO-8859-1,所以需要手动设置为utf-8才不会乱码.
复习思维导图
2.5.1校正请求参数名@RequestParam
所谓校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时,则需在处理方法参数前,添加一个注解@RequestParam(“请求参数名”),指定请求 URL 所携带参数的名称。该注解是对处理器方法参数进行修饰的。value 属性指定请求参数的名称。
required 属性:
2.6.1对象参数接收
前端请求:
需要一个student的实体类
public class Student {
//属性名和请求中的参数名要一致
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName:"+name);
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
System.out.println("setAge:"+age);
this.age = age;
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public Student() {
System.out.println("student无参数构造方法");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用@Controller 注解的处理器的处理器方法,其返回值常用的有四种类型:
➢ 第一种:ModelAndView
➢ 第二种:String
➢ 第三种:无返回值 void
➢ 第四种:返回自定义类型对象
根据不同的情况,使用不同的返回值。
2.7.1 返回 ModelAndView
2.7.2 返回 String
处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物
Java 框架 SpringMVC5
前端请求代码:
后端处理器方法:
返回内部资源逻辑视图名
若要跳转的资源为内部资源,则视图解析器可以使用 InternalResourceViewResolver 内部资源视图解析器。此时处理器方法返回的字符串就是要跳转页面的文件名去掉文件扩展名后的部分。这个字符串与视图解析器中的 prefix、suffix 相结合,即可形成要访问的 URI。
2.7.3 返回 void(了解)
对于处理器方法返回 void 的应用场景,AJAX 响应.
若处理器对请求处理后,无需跳转到其它任何资源,此时可以让处理器方法返回 void。
2.8.4 返回对象 Object
处理器方法也可以返回 Object 对象。这个 Object 可以是 Integer,String,自定义对象,Map,List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。返回对象,需要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中。
现在做ajax, 主要使用json的数据格式。 实现步骤:
1.加入处理json的工具库的依赖, springmvc默认使用的jackson。
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.0version>
<scope>compilescope>
2.在sprigmvc配置文件之间加入 mvc:annotation-driven 注解驱动。
<mvc:annotation-driven />
3.在处理器方法的上面加入@ResponseBody注解
@RequestMapping(value = {"/returnStudentJson.do"})
@ResponseBody
public Student doStudentObject (String name, Integer age) {
//student 就表示返回的结果数据
Student student = new Student();
student.setName("小明");
student.setAge(20);
return student;
}
2.8.5 返回list集合
/**
* 处理器方法返回List集合 发给服务端的是json数组
*
*/
@RequestMapping(value = {"/returnStudentJsonArray.do"})
@ResponseBody
public List<Student> doStudentObject () {
//student 就表示返回的结果数据
List<Student> students = new ArrayList<Student>();
students.add(new Student("小明",20));
students.add(new Student("小花",18));
return students;
}
2.8.6 返回String类型(txt文本)
返回一个String String表示数据 不是视图
如何区分返回String是视图还是数据 就看方法上有没有 :@ResponseBody 注解 有就是数据 反之亦然
默认使用的是 ISo-8859-1 作为 ContentType 导致中文乱码]
解决方案:在RequestMapping中添加 produces 这个属性设置新的ContentType 值
1 . 框架会把返回String类型,调用框架的中ArrayList中每个类的canWrite()方法检查那个HttpMessageConverter接口的实现类能处理String类型的数据–>StringHttpMessageConverter
2.框架会调用实现类的write(), StringHttpMessageConverter的write()方法 把字符按照指定的编码处理 text/plain;charset=ISO-8859-1
3.框架会调用@ResponseBody把结果数据输出到浏览器, ajax请求处理完成
后端代码:
@ResponseBody
@RequestMapping(value = {"/returnStringData.do"},produces = "text/plain;charset=utf-8")
public String doStringData () {
//String 表示返回的结果数据
return "hello Spring 返回对象 表示数据";
}
前端代码:
$(function(){
$("button").click(function(){
alert("button click");
$.ajax({
url:"user/returnStringData.do",
data:{
name:"小明",
age:20
},
type:"post",
dataType:"text",
success:function(resp){
console.log(resp);
}
})
})
})
2.9. 解读url-pattern
2.9.1配置详解
可以写为/,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、.js、.jpg、.png等资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。
tomcat本身能处理静态资源的访问, 像html, 图片, js文件都是静态资源
使用斜杆 / 当这里使用了 / tomcat中的default Servlet就没有了导致所有的静态资源都给DispatcherServlet处理, 默认情况下DispatcherServlet没有处理静态资源的能力。没有控制器对象能处理静态资源的访问。所以静态资源(html,js,图片,css)都是404.
解决方案1:
第一种解决方案是:在springmvc.xml配置文件中:
default-servlet-handler 和 @RequestMapping注解 有冲突, 需要加入annotation-driven 解决问题
原理就是:给内存增加一个处理器对象,DefaultHttpRequestHandler,让这个对象去处理静态资源的访问.
解决方案2:
第二种解决方案:需要在springmvc中加上resources标签
mvc:resources和@RequestMapping有一定的冲突,所以需要加上:
静态资源的目录结构:
url-pattern 使用 / 的好处就是:
处理器方法上的 @RequestMapping注解中的value属性就不在需要.do或者是.mvc等标志了,直接就是属性值;
在jsp , html中使用的地址, 都是在前端页面中的地址,都是相对地址
地址分类:
1.绝对地址 , 带有协议名称的是绝对地址, http://www.baidu.com , ftp://202.122.23.1等
2.相对地址, 没有协议开头的, 例如 user/some.do , /user/some.do
第一种路径写法:
在你的页面中的,访问地址不加 “/”
当你的地址 没有斜杠开头,例如 user/some.do , 当你点击链接时, 访问地址是当前页面的地址加上链接的地址。
http://localhost:8080/工程名/ + user/some.do
相对路径加base标签:
spring:可以换为自己的工程名
第二种路径写法:
在路径之前加上 / 的时候 就表示从 http://localhost:8080开始找所以没有带上工程名的时候会找不到地址,需要带上工程名地址才会正确.
使用el表达式在路径的前面动态的获取到工程名
第一种方式看起来似乎很完美,但是是有问题的,加入你把项目部署到服务器上面就不行,还需要有点小小的改动.以下这种方式才是一劳永逸的方式.
区别: 第一种的话是推荐使用的,页面所以的跳转都是基于base标签的,其余的跳转都会根据base标签进行跳转,第二种的话,就是治标不治本,需要每个跳转的地址都要使用el表达式手动加上工程名,这样比较麻烦,如果页面的跳转很多,那就需都加上.
SSM 编程,即 SpringMVC + Spring + MyBatis 整合,是当前最为流行的 JavaEE 开发技术架构。其实 SSM 整合的实质,仅仅就是将 MyBatis整合入 Spring。因为 SpringMVC原本就是 Spring的一部分,不用专门整合。
SSM 整合的实现方式可分为两种:基于 XML 配置方式,基于注解方式。
SSM整合也叫做SSI (IBatis也就是mybatis的前身), 整合中有容器。
1.第一个容器SpringMVC容器, 管理Controller控制器对象的。
2.第二个容器Spring容器,管理Service,Dao,工具类对象的
我们要做的把使用的对象交给合适的容器创建,管理。 把Controller还有web开发的相关对象交给springmvc容器, 这些web用的对象写在springmvc配置文件中
service,dao对象定义在spring的配置文件中,让spring管理这些对象。
springmvc容器和spring容器是有关系的,关系已经确定好了
springmvc容器是spring容器的子容器, 类似java中的继承。 子可以访问父的内容
在子容器中的Controller可以访问父容器中的Service对象, 就可以实现controller使用service对象
项目地址:bookSSM
当处理器对请求处理完毕后,向其它资源进行跳转时,有两种跳转方式:请求转发与重定向。而根据所要跳转的资源类型,又可分为两类:跳转到页面与跳转到其它处理器。
**注意:**对于请求转发的页面,可以是WEB-INF中页面;而重定向的页面,是不能为WEB-INF中页的。因为重定向相当于用户再次发出一次请求,而用户是不能直接访问 WEB-INF 中资
源的。
SpringMVC 框架把原来 Servlet 中的请求转发和重定向操作进行了封装。现在可以使用简单的方式实现转发和重定向。
forward:表示转发,实现 request.getRequestDispatcher(“xx.jsp”).forward()
redirect:表示重定向,实现 response.sendRedirect(“xxx.jsp”)
1 请求转发:
处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:,且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图。
视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径。
forward:好处就是可以访问到WEB-INF下的的静态资源,当需要跳转的路径不是配置在视图解析器中的时候,可以使用forward进行灵活的跳转
2.请求重定向
在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转。
前端可以通过这样的方式获取重定向携带的参数:
SpringMVC 框架处理异常的常用方式:使用@ExceptionHandler 注解处理异常。
@ExceptionHandler 注解:
使用注解@ExceptionHandler 可以将一个方法指定为异常处理方法。该注解只有一个可
选属性 value,为一个 Class>数组,用于指定该注解的方法所要处理的异常类,即所要匹
配的异常。
而被注解的方法,其返回值可以是 ModelAndView、String,或 void,方法名随意,方法
参数可以是 Exception 及其子类对象、HttpServletRequest、HttpServletResponse 等。系统会
自动为这些方法参数赋值。
对于异常处理注解的用法,也可以直接将异常处理方法注解于 Controller 之中。
使用两个注解
1.@ExceptionHandler
2.@ControllerAdvice
1. 自定义异常类:
定义三个异常类:NameException、AgeException、MyUserException。其中 MyUserException是另外两个异常的父类。
//当年龄有问题时,抛出的异常
public class AgeException extends MyUserException {
public AgeException() {
super();
}
public AgeException(String message) {
super(message);
}
}
-------------------------------------------------------
//表示当用户的姓名有异常,抛出NameException
public class NameException extends MyUserException {
public NameException() {
super();
}
public NameException(String message) {
super(message);
}
}
--------------------------------------------------
public class MyUserException extends Exception {
public MyUserException() {
super();
}
public MyUserException(String message) {
super(message);
}
}
2.修改 Controller 抛出异常
/**
* @RequestMapping:
* value : 所有请求地址的公共部分,叫做模块名称
* 位置: 放在类的上面
*/
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name,Integer age) throws MyUserException {
//处理some.do请求了。 相当于service调用处理完成了。
ModelAndView mv = new ModelAndView();
//根据请求参数抛出异常
if (!"zs".equals(name)) {
throw new NameException("姓名不正确!!!");
}
if (age == null || age > 80) {
throw new AgeException("年龄比较大!!!");
}
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
3.定义异常响应页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
ageError.jsp <br/>
提示信息:${msg} <br/>
系统异常消息:${ex.message}
</body>
</html>
不过,一般不这样使用。而是将异常处理方法专门定义在一个类中,作为全局的异常处
理类。
需要使用注解@ControllerAdvice,字面理解就是“控制器增强”,是给控制器对象增强
功能的。使用@ControllerAdvice 修饰的类中可以使用@ExceptionHandler。
当使用@RequestMapping 注解修饰的方法抛出异常时,会执行@ControllerAdvice 修饰的
类中的异常处理方法。
@ControllerAdvice 是使用@Component 注解修饰的,可以
创建对象。
4.定义全局异常处理类
/**
* @ControllerAdvice : 控制器增强(也就是说给控制器类增加功能--异常处理功能)
* 位置:在类的上面。
* 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器。
* 指定@ControllerAdvice所在的包名
*/
@ControllerAdvice
public class GlobalExceptionHandler {
//定义方法,处理发生的异常
/*
处理异常的方法和控制器方法的定义一样, 可以有多个参数,可以有ModelAndView,
String, void,对象类型的返回值
形参:Exception,表示Controller中抛出的异常对象。
通过形参可以获取发生的异常信息。
@ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,
由当前方法处理
*/
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception){
//处理NameException的异常。
/*
异常发生处理逻辑:
1.需要把异常记录下来, 记录到数据库,日志文件。
记录日志发生的时间,哪个方法发生的,异常错误内容。
2.发送通知,把异常的信息通过邮件,短信,微信发送给相关人员。
3.给用户友好的提示。
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg","姓名必须是zs,其它用户不能访问");
mv.addObject("ex",exception);
mv.setViewName("nameError");
return mv;
}
//处理AgeException
@ExceptionHandler(value = AgeException.class)
public ModelAndView doAgeException(Exception exception){
//处理AgeException的异常。
/*
异常发生处理逻辑:
1.需要把异常记录下来, 记录到数据库,日志文件。
记录日志发生的时间,哪个方法发生的,异常错误内容。
2.发送通知,把异常的信息通过邮件,短信,微信发送给相关人员。
3.给用户友好的提示。
*/
ModelAndView mv = new ModelAndView();
mv.addObject("msg","你的年龄不能大于80");
mv.addObject("ex",exception);
mv.setViewName("ageError");
return mv;
}
//处理其它异常, NameException, AgeException以外,不知类型的异常
@ExceptionHandler
public ModelAndView doOtherException(Exception exception){
//处理其它异常
ModelAndView mv = new ModelAndView();
mv.addObject("msg","你的年龄不能大于80");
mv.addObject("ex",exception);
mv.setViewName("defaultError");
return mv;
}
}
5.定义 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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.exception.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
bean>
<context:component-scan base-package="com.exception.handler" />
<mvc:annotation-driven> mvc:annotation-driven>
beans>
SpringMVC 中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在“处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。
拦截器:
1)拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。
2)拦截器和过滤器类似,功能方向侧重点不同。 过滤器是用来过滤器请求参数,设置编码字符集等工作。
拦截器是拦截用户的请求,做请求做判断处理的。
3)拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查, 记录日志。
拦截器的使用步骤:
1.定义类实现HandlerInterceptor接口
2.在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在。
拦截器的执行时间:
1)在请求处理之前, 也就是controller类中的方法执行之前先被拦截。
2)在控制器方法执行之后也会执行拦截器。
3)在请求处理完成后也会执行拦截器。
4)拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理。
使用的aop的思想
拦截器的使用
1.自定义拦截器
public class MyInterceptor implements HandlerInterceptor {
private long btime = 0;
/**
* preHandle叫做预处理方法。
* 重要:是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。
* preHandle返回false,请求到此方法就截止。
*
* 参数:
* Object handler : 被拦截的控制器对象
* 返回值boolean
* true:请求是通过了拦截器的验证,可以执行处理器方法。
* 拦截器的MyInterceptor的preHandle()
* =====执行MyController中的doSome方法=====
* 拦截器的MyInterceptor的postHandle()
* 拦截器的MyInterceptor的afterCompletion()
*
* false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
* 拦截器的MyInterceptor的preHandle()
*
*
* 特点:
* 1.方法在控制器方法(MyController的doSome)之前先执行的。
* 用户的请求首先到达此方法
*
* 2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
* 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
* 如果验证失败,可以截断请求,请求不能被处理。
* 如果验证成功,可以放行请求,此时控制器方法才能执行。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("1:拦截器的Interceptor的preHandle方法");
String name = request.getParameter("name");
if (name.equals("root")){
return true;
}
return false;
}
/**
* postHandle:后处理方法。
* 参数:
* Object handler:被拦截的处理器对象MyController
* ModelAndView mv:处理器方法的返回值
*
* 特点:
* 1.在处理器方法之后执行的(MyController.doSome())
* 2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
* 数据和视图,可以影响到最后的执行结果。
* 3.主要是对原来的执行结果做二次修正,
*
* ModelAndView mv = MyController.doSome();
* postHandle(request,response,handler,mv);
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("2:拦截器的MyInterceptor的postHandle()");
}
/**
* afterCompletion:最后执行的方法
* 参数
* Object handler:被拦截器的处理器对象
* Exception ex:程序中发生的异常
* 特点:
* 1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
* 2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("3:拦截器的MyInterceptor的afterCompletion()");
}
}
<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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.interceptor.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
bean>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.interceptor.handler.MyInterceptor"> bean>
mvc:interceptor>
mvc:interceptors>
beans>
拦截器和过滤器的区别
1.过滤器是servlet中的对象, 拦截器是框架中的对象
2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。 拦截器是用来验证请求的,能截断请求。
4.过滤器是在拦截器之前先执行的。
5.过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
6.过滤器是一个执行时间点。
拦截器有三个执行时间点
7.过滤器可以处理jsp,js,html等等
拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
多个拦截器的执行顺序
当有多个拦截器时,形成拦截器链。拦截器链的执行顺序,与其注册顺序一致。需要再次强调一点的是,当某一个拦截器的 preHandle()方法返回 true 并被执行到时,会向一个专门的方法栈中放入该拦截器的 afterCompletion()方法。
执行流程简单分析
(1)浏览器提交请求到中央调度器
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。