SpringMVC
什么是Springmvc
-
SpringMVC:是基于spring的一个框架,是spring的一个模块。专门做web开发的,可以理解为servlet的升级
web开发的底层是servlet,框架是在servlet的基础之上加入一些功能,方便web开发。 -
springmvc是一个spring。而spring是一个容器,ioc能管理对象,使用,@Component,@Repository,@Service,@Controller。
-
spring MVC也可以创建对象,放到容器中(springMVC容器),springmvc容器中放的是控制器对象。
我们要做的就是使用@Controller注解创建控制器对象,把对象放入到spirngmvc容器中,把创建的对象作为控制器使用。这个控制器对象能接收用户的请求,显示处理结果,就当作是一个servlet使用。
使用@Controller注解创建的是一个普通类的对象,不是servlet。springmvc赋予了控制器对象一些额外的功能。
springmvc如何处理请求
web开发底层是servlet,而springmvc容器中的对象可以当作servlet来理解,但毕竟不是servlet,而是一个普通类的对象。所以springmvc是如何处理请求的?
springmvc中有一个对象是servlet:DispatcherServlet(中央调度器)
DispatcherServlet:负责接收用户的所有请求。用户把请求给了DispatcherServlet,之后DispatcherServlet把请求转发给我们的Controller对象,最后Controller对象来处理请求。
index.jsp—>DispatcherServlet(Servlet)----->转发,分配给---->Controller对象(@Controller注解创建的对象)
web项目的目录结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-adMAauTl-1666596136635)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220404140711589.png)]
ch01-hello-springmvc
需求:用户在页面发起请求,请求交给springmvc的控制对象,并显示请求的处理结果。
实现步骤:
-
新建web maven工程
-
加入依赖
spring-webmvc依赖,间接把spring的依赖都加入到项目
jsp,servlet依赖<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependecy> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> </dependecy>
-
重点:在web.xml中注册springmvc框架的核心对象是DispatherServlet
- DispatherServlet叫做中央调度器,是一个servlet,它的父类是继承HttpServlet
- DispatherServlet也叫做前端控制器(front controller)
- DispatherServlet负责接收用户提交的请求,调用其他的控制器对象,并把请求的处理结果显示给用户
-
创建一个发起请求的页面 index.jsp
-
创建按控制器类
-
在类的上面加入@Controller注解,创建注解,并放入到springmvc容器中
-
在类中的方法上面加入@RequestMapping注解
@Controller public MyController{ @RequestMapping(value = "/some.do") //该请求地址的请求,全由下面这个方法来处理 public ModelAndView doSome(){ ModelAndView mv = new ModelAndView(); mv.addObject(key,value); //key是String,value是Object return mv; } }
-
-
创建一个作为结果的jsp,显示请求的处理结果
${key}
-
创建springmvc的配置文件(spring配置文件一样)
-
声明组件扫描器,指定@Controller注解所在的包名
-
声明视图解析器,帮助处理试图
<context:component-scan base-package="com.bjpowernode.controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
-
springmvc请求处理流程
- 发起some.do
- tomcat(web.xml–url–pattern知道*.do的请求给DispatcherServlet)
- DispatcherServlet(根据springmvc配置文件知道some.do请求由doSome方法处理)
- DispatcherServlet把some.do转发给MyController.doSome()方法
- 框架执行doSome()把得到ModelAndView进行处理,转发到show.jsp
springmvc执行过程源代码分析
-
tomcat启动,创建容器的过程,通过load-on-start标签指定的1,创建DispatcherServlet对象。
DispatcherServlet它的父类是继承HttpServlet的,他是一个servlet,在被创建时,会执行init()方法。
在Init()方法中:
//创建容器,读取配置文件 WebApplicationContext ctx = new ClassPathApplication("springmvc.xml"); //把容器都西昂放入到ServletContext中 getServletContext().setAttribute(key,ctx);
创建容器的作用:创建@controller注解所在类的对象,创建MyController对象,这个对象放入到springmvc的容器中,容器是map,类似map.input(“myControlller”,MyController对象);
-
请求的处理过程
-
执行servlet的service()
protected void service(HttpServletRequest request,HttpServletResponse response) protected void doService(HttpServletRequest request,HttpServletReponse response) DispatcherServlet.doDispatch(request,response){ //调用MyController的.doSome()方法 }
-
配置视图解析器
为了防止用户直接输入show.jsp从而访问结果页面,应该对不希望用户直接访问的页面加以控制。
可以将结果页面放入到web-INF目录下,因为web-INF目录下的内容对用户是不开放的。
如果结果页面太多,每次都要设置mv.setViewName(“/WEB-INF/view/xxx.jsp”),为了方便,需要设置视图解析器。
在springmvc配置文件中声明。
<!--声明springmvc框架中的视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" vlaue=".jsp"/>
</bean>
当配置了视图解析器后,可以使用逻辑名称(文件名),指定视图。
框架会使用视图解析器的 前缀+逻辑名称+后缀 组成完整路径,这里就是字符链接操作。
mv.setViewName("show");
//框架会自动将字符串拼接,形成 “/WEB-INF/view/show.jsp”
DispatcherServlet方法接收参数
处理器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用
- HttpServletRequest 代表请求
- HttpServletResponse 代表应答
- HttpSession 代表会话
- 请求中所携带的请求参数 代表用户真正要提交的数据,两种接收方案,逐个接收和对象接收
public ModelAndView doSome(HttpServletRequest request,HttpServletResponse response,HttpSession session){
//框架会自动给形参赋值
}
逐个接收:
框架接收请求参数
-
使用request对象接收请求参数
String strName = request.getParameter("name"); String strAge = request.getParameter("age");
-
springmvc框架通过DispatcherServlet调用MyController的doSome()方法
调用方法时,按名称对应,把接收的参数赋值给形参
doSome(String name,Integer age); //框架会自动赋值 String name = strName; //因为name和getParameter中的name一致 Integer age = Integer.valueOf(StrAge); //类型转换是框架自动进行的 //400状态码是客户端错误,表示提交请求参数过程中,发生了问题,如果age不填写,框架类型转换时就会出现异常,于是就会报400错误。 //但是如果形参age是用Integer修饰的,那么空值也是可以的
如果形参和提交的请求参数名不一致,则无法接收到请求的参数值,可以通过注解解决
/*
@RequestParam:解决请求中参数名形参名不一样的问题
属性:1.value 请求中的参数名称
2.required 是一个boolean,默认是true
表示请求中必须有该参数,否则报错
位置:在处理器方法的形参定义到前面
*/
@Controller
public class MyController{
@RequestMapping(value={"some.do","other.do"})
//请求中名为“rname”的参数的值,要赋给name,这样就可以解决名称不统一的问题
public ModelAndView receiveParam(@RequestParam(value="rname") String name,
@RequestParam(value="rage") Integer age )
}
注意:在提交请求参数时,get请求方式中文没有乱码
使用post方式提交请求时,中文有乱码,需要使用过滤器处理乱码的问题。
过滤器:过滤器可以自定义,也可以使用框架中提供的过滤器 characterEncodingFilter
在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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
对象接收:
package vo中的类就是springmvc中用对象接收请求参数中所用到的对象。
对象中的属性名和请求的参数名需要一致。
@RequestMapping
//Student类是定义好在vo package中的
public ModelAndView doSome(Student stu){
stu.getName();
stu.getAge();
}
返回值类型
四大类返回值:
-
返回ModelAndView
如果处理器方法处理完后,需要跳转到其他资源,且又要在跳转的资源间传递数据,此时使用ModelAndView。
-
返回String
如果处理器方法处理完后,只需要跳转到其他页面而不需要传递数据,则返回String是最方便的
@RequestMapping(value = "/returnstring.do",method = RequestMethod.POST) public String doReturnString(String name,Integer age){ //返回的show与视图解析器一起组成完整路名 //框架对视图进行forward转发操作 return "show"; }
-
返回void
在处理ajax的时候,可以使用void返回值,通过HttpServletResponse输出数据,响应ajax请求.
<!--复习一下ajax和jquery--> <!--前端--> <!--ajax入口函数--> $(function(){ $.get({ url:"url", data:{data}, dataType:"json", success:function(resp){ <!--处理resp--> } }) })
//后端 @RequestMapping("returnVoid-ajax.do") public void doReturnVoid(HttpServletResponse resp,Student stu){ String json = null; PrintWriter pw = null; //转换为json各式 ObjectMapper om = new ObjectMapper(); try{ json = om.writerValueAsString(stu); resp.contextType("application/json;charset=utf-8"); pw = resp.getWriter(); }catch(JsonProcessingException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } pw.println(json); pw.flush(); pw.close(); }
-
返回Object
处理器方法可以直接返回Object对象,返回的Object表示数据,是model,和视图无关。但返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。
返回对象,需要使用@ResponseBody注解,将转换后的Json数据放入到响应体中,可以适用对象表示的数据,响应Ajax请求。
实现步骤:
-
加入处理json的工具库依赖,springmvc默认使用的jackson
-
在springmvc配置文件中加入< mvc:annotation-driven >注解驱动,这一步是做了 om.writeValueAsString(Object) 的工作
<mvc:annotation-driven>注解驱动完成了Java对象到json,xml,text,二进制等数据格式的转换。利用了下面的接口完成转换 HttpMessageConverter接口:消息转换器 public interface HttpMessageConverter<T> { boolean canRead(Class<?> var1, @Nullable MediaType var2); //canWrite用于检查处理器方法的返回值是否能转为var2表示的数据格式,MediaType表示数据格式的 boolean canWrite(Class<?> var1, @Nullable MediaType var2); //无需在意 List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException; //write吧处理器方法的返回值对象,调用jackson中的ObjectMapper转为json字符串 void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException; }
<mvc:annotation-driven>注解驱动在加入到springmvc配置文件后,会自动创建HttpMessageConverter接口的7个实现类对象,包括MappingJackson2HttpMessageConverter(使用jackson工具库中的ObjectMapper实现java对象转为json)
-
在处理器方法上面加入@ResponseBody注解
这一部分的工作就是 resp.contextType("application/json;charset=utf-8"); pw = resp.getWriter(); pw.println(json);
url-pattern
tomcat本身能处理静态资源的访问,,像html,图片,js文件都是静态资源。
tomcat之所以能处理是因为tomcat中的conf中的web.xml中有default的servlet,
这个servlet属于org.apache.catalina.servlets.DefaultServlet。
这个servlet会处理所有未映射到其他servlet的请求,和静态资源。
而之所以这个default的servlet能处理上述两个作用,是因为他的url-pattern被设置成/了
所以我的项目中url-pattern设置成/,那么就取代了tomcat的default servlet,但是dispatcherServlet默认情况下没有处理静态资源的能力。没有控制器对象能处理静态资源的访问,所以这些静态资源都是404。
如果希望设置url-pattern为/且可以访问静态资源,则:
-
第一种处理静态资源的方式
需要在springmvc配置文件中加入< mvc:default-servlet-handler >标签即可。
原理是:加入这个标签后,框架会创建控制器对象DefaultServletHttpRequestHandler(类似我们自己创建的MyController)。
DefaultServletHttpRequestHandler这个对象可以把接受的请求转发给tomcat的default这个servlet。
注意:< mvc:default-servlet-handler > 和@RequestMapping注解有冲突,因为前者会把所有请求都转给tomcat处理,所以需要用<mvc:annotation-driven >来讲动态资源交给我们自定义的controller来处理。
-
第二种处理静态资源的方式
在spring3.0之后,spring定义了一个专门处理静态资源访问请求的处理器ResourceHttpRequestHandler.bingtianjiale < mvc:resources/>标签,用于解决静态资源无法访问的问题。
需要在springmvc配置为年间中添加如下形式的配置:
<mvx:resources location="/images/" mapping="/images/**"/> location 表示静态资源所在目录,目录不要使用WEB-INF及其子目录。 mapping 表示对该资源的请求
地址
在前端,jsp,html中使用的地址,都是在前端页面中的地址,都是相对地址。
地址分类
-
绝对地址,带有协议名称的是绝对地址。http://www.baidu.com ,ftp://202.122.23.1
-
相对地址,没有协议开头的,例如user/some.do,,相对的是当前页面的地址
在页面的请求地址中加斜杠的方式
<a href="some">some</a>
<!--
这是相对当前页面的地址,比如我在localhost8080/ch05发起请求,那么完整请求地址就是
localhost8080/ch05/some
-->
<a href="/some">some</a>
<!--
这是基于服务器的地址,比如我在localhost8080/ch05发起请求,那么其中localhost8080就是我的服务器地址,发起请求的地址是
localhost8080/some
如果非要在页面使用第二种加斜杠的方式,那么需要EL表达式来指出你的请求地址指向哪一个项目
${pageContext.request.contextPath} 这个代表了ch05的意思,如果之后你的项目换成了ch06,他也会自动知道。
<a href="${pageContext.request.contextPath}/user/some.do"></a> 此时EL表达式之前就没有斜杠了。
-->
在页面的请求地址中不加斜杠的方式
假设我现在有一个页面跳转到自己
我从localhost8080/ch06发起请求,跳回自己
@RequestMapping("/user/some")
public ModelAndView doSome(Student stu){
ModelAndView mv = new ModelAndView();
mv.setViewName("index.jsp")
return index.jsp
}
请求页面:
<a href="user/some">发起user/some请求</a>
此时当前页面的网址变成了localhost8080/ch06/user/some,
其中localhost8080/ch06/user/是路径,
some是资源,
那么当我再次从该页面发起user/some请求时,地址就会变成localhost8080/ch06/user/user/some
而这个地址没有任何资源,所以就会找不到。
所以为了解决地址变动导致找不到资源的问题,有两种解决办法
- 加入${pageContext.request.contextPath},也就是第一种加斜杠的方式
- 加入一个base标签,这个是html标签,表示当前页面中所有没有斜杠开头的访问地址的基地址。
<%
String basePath = request.getScheme()+"://"+ //获取协议名
request.getServerName()+":"+ //获取服务器名
request.getServerPort()+"/"+ //获取端口号
request.getContextPath()+"/"; //http://localhost:8080/ch06/中的ch06部分
%>
<head>
<base href="<%=basePath%>"/>
</head>
整合SSM
关于springmvc的依赖:
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
关于spring的依赖:
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId> 处理事务的依赖
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId> jdbc
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId> 使用aspectj实现事务
关于mybatis的依赖:
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>整合用到的
<artifactId>mybatis-spring</artifactId>
jackson依赖 用于json的
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
mysql依赖:
<groupId>mysql</groupdId>
<artifactId>mysql-connector-java</artifactId>
druid连接池 数据库的
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
jsp
servlet依赖:
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
实现步骤
1.新建maven web项目
2.加入依赖
3.写web.xml
1) 注册DispatcherServlet,目的:1.创建sprignmvc容器对象,才能创建Controller类对象
2.创建的是servlet,才能接收用户的请求
2) 注册spring的监听器:ContextLoaderListener,目的:创建spring容器,才能创建service,dao等对象
3) 注册字符集过滤器characterEncodingFilter,目的:解决post请求乱码问题
4.创建包,Controller包,service,dao,实体类包名创建好
5.写配置文件
1)spring配置文件
2)springmvc配置文件
3)mybatis配置文件
4)数据库的属性配置文件
6.写代码,dao接口和mapper文件,service和实现类,controller,实体类
7.写jsp页面
在pom.xml中
<!--name和url是生成网站时用到的,暂时用不到
<name>ch01-hello-springmvc Maven Webapp</name>
FIXME change it to the project's website –>
<url>http://www.example.com</url>
-->
<!--spring配置文件:声明service,dao,工具类等对象-->
<!--声明数据源,连接数据库-->
<!--配置文件加载-->
<context:property-placeholder location="classpath:conf/jdbc.properties"/>
<!--声明数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--声明sqlSessionFactoryBean,目的是创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>
<!--声明mybatis扫描器,创建dao对象-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.bjpowernode.dao"/>
</bean>
<!--声明service的注解@service所在的包名位置-->
<context:component-scan base-package="com.bjpowernode.service"/>
<!--事务配置:注解配置,aspectj的配置-->
<!--mybatis.xml-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--设置别名-->
<typeAliases>
<!--实体类所在包名-->
<package name="com.bjpowernode.entity"/>
</typeAliases>
<!--mapper的文件-->
<mappers>
<package name="com.bjpowernode.dao"/>
</mappers>
<!--springmvc.xml-->
<context:component-scan base-package="com.bjpowernode.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
<property name="prefix" value="/WEB-INF/view/"/>
</bean>
<!--
1.响应ajax请求,返回json
2.解决静态资源访问问题
-->
<mvc:annotation-driven/>
<!--静态资源-->
<mvc:resources mapping="static/**" location="/static/"/>
<!--web.xml-->
<!--注册中央调度器-->
<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:conf/dispathcerServlet.xml</param-value> <!--dispatcherServlet就是springmvc配置文件-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--注册监听器-->
<!--指定自定义的spring配置文件路径,否则listener会去默认位置找-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:conf/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--解决post请求中文乱码问题-->
<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>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
idea service窗口中文乱码
tomcat conf 中的logging.properties中catalina.org.apache 和localhost.org.apache 和java.util.logging这三行改成gbk即可;
SpringMVC核心技术
请求 转发和重定向 forward and redirect
forward:表示转发,实现reqeust.getRequestDispatcher(“.jsp”).forward()
redirect:表示重定向,实现response.sendRedirect(“xxx.jsp”)
注意:对于请求转发的页面,可以是WEB-INF中页面;而重定向的页面,是不能维WEB-INF中的页面的。因为重定向相当于用户在此发出一次请求,而用户是不能直接访问WEB-INF中的资源的。
/*
* 处理器方法返回ModelAndView,实现转发forward
* 语法:setViewName("forward:完整页面的路径名");
* forward:不和视图解析器一同使用。
* */
@RequestMapping(value = "/doForward.do")
public ModelAndView doForward(Student stu){
ModelAndView mv = new ModelAndView();
mv.addObject("name",stu.getName());
mv.addObject("age",stu.getAge());
//forward:显式转发
mv.setViewName("forward:/WEB-INF/view/show.jsp");
return mv;
}
/*
* 处理器方法返回ModelAndView,实现重定向redirect
* 语法:setViewName("redirect:完整页面的路径名");
* redirect:不和视图解析器一同使用。
* */
@RequestMapping(value = "/doRedirect.do")
public ModelAndView doRedirect(Student stu){
ModelAndView mv = new ModelAndView();
mv.addObject("name",stu.getName());
mv.addObject("age",stu.getAge());
//重定向,重定向的页面不能是WEB-INF中的页面
mv.setViewName("redirect:/hello.jsp");
return mv;
}
<h3>name数据:${param.name}</h3><br/>
<h3>age数据:${param.age}</h3>
<h3>name数据:<%=request.getParameter("name")%></h3><br/>
集中统一处理异常
异常处理:
springmvc框架采用的是统一,全局的异常处理
把controller中的所有异常处理都集中到一个地方。采用的是aop的思想。把业务逻辑和异常处理代码分开,解耦合。
使用两个注解:
1.@ExceptionHandler
2.@ControllerAdvice
/*
* 特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器
* 指定@ControllerAdvice所在的包名
* */
@ControllerAdvice
public class GlobalExceptionHandler {
/*
* 定义方法,处理发生的异常
* 处理异常的方法和控制器方法的定义一样,返回值,形参之类的,控制方法能用的,处理异常方法页能用。
*
* 形参Exception表示Controller中抛出的异常对象
*
* @ExceptionHandler(异常的class):表示异常的类型,当发生此类型异常时,由当前方法处理
* */
@ExceptionHandler(value = NameException.class)
public ModelAndView doNameException(Exception exception){
/*
* 处理NameException异常
*
* 异常发生时的处理逻辑:
* 1.需要把异常记录下来,记录到数据库,日志文件
* 记录异常发生的时间,哪个方法发生的,异常错误内容
* 2.发送通知,把异常信息通过邮件,短信,微信发送给相关人员
* 3.给用户友好的提示。
* */
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "姓名必须是张三,其他用户不能访问");
mv.addObject("ex",exception);
mv.setViewName("nameError");
return mv;
}
拦截器Interception
-
拦截器是拦截请求,做预处理的。过滤器则是过滤请求参数的,设置编码字符集等工作的。
拦截器是拦截用户的请求,做请求做判断处理的。
-
拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器,他们在一起拦截用户请求。
拦截器常用在:用户登录请求,权限检查,记录日志
拦截器是基于java的反射机制的,过滤器则是基于函数回调。
自定义拦截器需要实现HandlerInterception接口,
public class MyInterception implements HandlerInterception
实现步骤:
- 定义类实现HandlerInterception接口
- 在springmvc配置文件中声明拦截器,让框架知道拦截器的存在。
拦截器的执行时间:
-
在请求处理之前,也就是controller类中的方法执行之前先被拦截
- 在控制器方法自行之后也会执行拦截器
- 在请求处理完成后也会执行拦截器
多个拦截器的执行:
拦截器1的prehandler为true–拦截器2的prehandler为true–处理器方法执行–拦截器2的posthandler执行–拦截器1的posthandler执行–拦截器2的afterHandler执行–拦截器1的afterhandler执行
如果第一个拦截器的prehandler为true,第二个拦截器的preHandler为False,那么第一个拦截器的afterhandler一定执行。
拦截器与过滤器的区别:
-
过滤器是servlet中的对象,拦截器是框架中的对象
-
过滤器实现Filter接口的对象,拦截器是实现HandlerInterceptor接口
-
过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的
拦截器是用来验证请求的,能截断请求
-
过滤器是在拦截器之前先执行的
-
过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
-
过滤器是一个执行时间点
拦截器由三个执行时间点
-
过滤器可以处理jsp,js,html等等
拦截器侧重拦截对Controller的对象,如果请求不能被dispatcherServlet接收,这个请求也不会被拦截器拦截
-
拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
springmvc内部请求的处理流程:也就是springmvc接收请求,到处理完成的过程
-
用户发起请求some.do
-
DispatcherServlet接收请求some.do,把请求转交给处理器映射器(HandlerMapping)
处理器映射器:springmvc框架中的一种对象,框架把实现了HandlerMapping接口的类都叫做映射器(多个)
处理器映射器的作用:根据请求,从springmvc容器对象中获取处理器对象(MyController controller = ctx.getBean(“some.do”))
框架把找到的处理器对放到一个叫做**处理器执行链(**HandlerExecutionChain)的类中保存。
HandlerExecutionChain:类中保存着 1. 处理器对象(MyController) 2.项目中的所有的拦截器List< HandlerInterceptor >
-
DispatcherServlet把2中的HandlerExecutionChain中的处理器对象交给了处理器适配器对象(多个)
处理器适配器:springmvc框架中的对象,需要实现HandlerAdaptor接口
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModelAndView)
-
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:springmvc中的对象,需要实现ViewResolver(可以有多个)
视图解析器作用:组成视图完整路径。
View是一个接口,表示视图的
InternalResolverView:视图类,表示jsp文件,视图解析器会创建InternalResolverView类对象。
-
DispatcherServlet把4中创建好的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域,执行对象试图的forward。请求结束
er controller = ctx.getBean(“some.do”))
框架把找到的处理器对放到一个叫做**处理器执行链(**HandlerExecutionChain)的类中保存。
HandlerExecutionChain:类中保存着 1. 处理器对象(MyController) 2.项目中的所有的拦截器List< HandlerInterceptor >
-
DispatcherServlet把2中的HandlerExecutionChain中的处理器对象交给了处理器适配器对象(多个)
处理器适配器:springmvc框架中的对象,需要实现HandlerAdaptor接口
处理器适配器作用:执行处理器方法(调用MyController.doSome()得到返回值ModelAndView)
-
DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象。
视图解析器:springmvc中的对象,需要实现ViewResolver(可以有多个)
视图解析器作用:组成视图完整路径。
View是一个接口,表示视图的
InternalResolverView:视图类,表示jsp文件,视图解析器会创建InternalResolverView类对象。
-
DispatcherServlet把4中创建好的View对象获取到,调用View类自己的方法,把Model数据放入到request作用域,执行对象试图的forward。请求结束