Springmvc学习笔记

目录

一.认识SpringMVC

1.1 mvc架构的回顾

  1. 模型(Model):负责封装应用的状态,并实现应用的功能。通常分为数据模型和业务逻辑模型,数据模型用来存放业务数据,比如订单信息、用户信息等;而业务逻辑模型包含应用的业务操作,比如订单的添加或者修改等。通常由java开发人员编写程序完成,代码量最多
  2. 视图(View):视图通过控制器从模型获得要展示的数据,然后用自己的方式展现给用户,相当于提供界面来与用户进行人机交互。通常有前端和java开发人员完成,代码量较多。
  3. 控制器(Controller):用来控制应用程序的流程和处理用户所发出的请求。当控制器接收到用户的请求后,会将用户的数据和模型的更新相映射,也就是调用模型来实现用户请求的功能;然后控制器会选择用于响应的视图,把模型更新后的数据展示给用户。起到总调度的作用,Controller通常由框架实现,使用时基本不需要编写代码
    在这里插入图片描述

1.2.SpringMVC介绍

  • 大部分java应用都是web应用,展现层是web应用最为重要的部分。Spring为展现层提供了一个优秀的web层框架——SpringMVC。和众多其他web框架一样,它基于MVC的设计理念,此外,它采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。
  • SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,无需实现任何接口,同时,- SpringMVC还支持REST风格的URL请求。
  • 此外,SpringMVC在数据绑定、视图解析、本地化处理以及静态资源处理上都有许多不俗的表现。
  • 它在框架设计、扩展性、灵活性等方面全面超越了Struts、WebWork等MVC框架,从原来的追赶者一跃成为MVC的领跑者。
  • SpringMVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet是SpringMVC框架的总导演、总策划,它负责截获请求并将其分派给相应的处理器处理。

1.3.SpringMVC架构

在这里插入图片描述

二、第一个springmvc程序(Hello World)

2.1.创建工程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.引入jar包及源码包

  1. 从spring-framework-4.3.12.RELEASE\libs目录下copy一下jar包:
    在这里插入图片描述
    Spring-web:web开发相关的基础功能包
    Spring-webmvc:SpringMVC框架核心包

在这里插入图片描述

2.3.配置web.xml

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>springmvc</display-name>
  
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<!-- 
  		/*:拦截所有请求,包括jsp
  		/ :拦截所有请求,不包含jsp
  		*.do,*.action
  	 -->
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

2.4.springmvc的配置文件

2.4.1.{servlet-name}-servlet.xml

用户发送请求到web容器,并被DispatchServlet拦截之后进入springmvc容器,springmvc该怎么处理那,这就需要springmvc的配置文件。
那么springmvc的配置文件该放在什么位置,又该怎么命名呢?

找到DispatchServlet这个类:
在这里插入图片描述
在这里插入图片描述
由此知道,springmvc默认读取/WEB-INF/{servlet-name}-servlet.xml这个配置文件,因为我们在web.xml中的servlet-name配置的是springmvc,所以在WEB-INF目录下创建springmvc-servlet.xml文件:

在这里插入图片描述
springmvc配置文件的头信息和spring一样。

<?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:p="http://www.springframework.org/schema/p"
	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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

</beans>


2.4.2.HandlerMapping映射器

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.4.3.HandlerAdapter适配器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4.4.ViewResolver试图解析器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由此可见,视图解析器的规则是:prefix+viewName+suffix

2.4.5.完整的配置

<?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:p="http://www.springframework.org/schema/p"
	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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 配置映射器,把bean的name属性作为一个url -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
	
	<!-- 配置适配器 -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
	
	<bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>


2.5.HelloController

在这里插入图片描述


HelloController内容:
/**
 * 在整体架构中,通常称为Handler
 * 在具体实现中,通常称为Controller
 * @author joedy
 *
 */
public class HelloController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello"); // 试图名称
        mv.addObject("msg", "这是我的第一个SpringMVC程序!!"); // 数据模型
        return mv;
    }

}

2.6.添加jsp页面(hello.jsp)

在这里插入图片描述

Jsp内容:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div style="color:red; font-size:30px">${msg }</div>
</body>
</html>

2.7.运行测试

在这里插入图片描述
通过浏览器访问:http://localhost:8080/springmvc/hello.do

在这里插入图片描述

2.8.添加log日志

在这里插入图片描述
Log4j.properties内容:

log4j.rootLogger=DEBUG,A1
log4j.logger.org.mybatis=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

2.9.日志打印信息
在这里插入图片描述

2.10.流程分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.11.优化helloworld程序

入门程序虽然完成了,但是还有可以改进的空间。结合Spring入门流程,我们一步步的优化入门程序。

2.11.1.web.xml

2.11.1.1.load-on-startup
  • 结合启动日志,发现入门程序在tomcat的运行完成后并没有加载servlet,而是在用户第一次访问之后才加载。生产环境会影响网站的相应速度
  • 解决方案:让tomcat启动时就去加载DispatcherServlet并初始化Spring容器。
    在这里插入图片描述
2.11.1.2.指定SpringMVC的配置文件
  • 通常情况下SpringMVC的命名规则是{servlet-name}-servlet.xml,一个配置文件名而已,问题不大。
  • 但是,SpringMVC的配置文件的存放路径,如果采用默认配置路径(WEB-INF下),这在项目开发时不利于统一维护管理。能不能把SpringMVC的配置文件和其他Spring配置文件放在一起,方便统一管理呢?
  • 通过dispatcherServlet的初始化参数告诉SpringMVC它的配置文件在哪里。
  • 例如:现在把配置文件移动到src根目录下
    在这里插入图片描述
    这时就需要在web.xml中去指定springMVC的存放路径,配置方式:
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<!-- 指定springMVC的配置文件,多个可以用逗号和空格隔开 -->
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:springmvc-servlet.xml</param-value>
  	</init-param>
  	<!-- 值为非负的情况下,tomcat启动时,就加载该servlet。值越小加载的优先级就越高 -->
  	<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<!-- 
  		/*:拦截所有请求,包括jsp
  		/ :拦截所有请求,不包含jsp
  		*.do,*.action
  	 -->
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>

原理:参见DispatcherServlet父类的注释
在这里插入图片描述

2.11.2.{servlet-name}-servlet.xml

DispatchServlet.class源码中:
在这里插入图片描述
找到DispatchServlet.properties文件:
在这里插入图片描述
在这里插入图片描述
在这个默认的配置文件中,已经配置了映射器和适配器。
所以在springmvc-servlet.xml文件中可以省略之前配置的映射器和适配器

在这里插入图片描述
再次测试:
在这里插入图片描述

2.12.helloword的缺点

1)每个类需要都实现Controller接口
2)每个类(Controller)只能完成一个用户请求(或者只能处理一个业务逻辑)
3)每个类(Controller)都要在配置文件里,进行配置
解决方案:
注解程序

三、注解

3.1.默认注解配置

在DispatchServlet.properties文件中,已经提供了默认的注解映射器和适配器,所以咱们可以直接书写注解的代码
在这里插入图片描述

3.1.1.创建hello2Controller

在这里插入图片描述
内容:


@Controller
public class Hello2Controller {
    
    @RequestMapping("show1")
    public ModelAndView test1(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "这是SpringMVC的第一个注解程序!");
        return mv;
    }

}

3.1.2.配置扫描器

在springmvc-servlet.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:p="http://www.springframework.org/schema/p"
	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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 配置映射器,把bean的name属性作为一个url -->
	<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> -->
	
	<!-- 配置适配器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> -->
	
	<!-- <bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" /> -->
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

3.1.3.测试

在这里插入图片描述

3.1.4.日志

输出的是默认配置的映射器,说明这种配置OK
在这里插入图片描述

3.1.5.缺点

找到默认的注解映射器和适配器,发现他们都已过时。
在这里插入图片描述
既然默认配置的映射器和适配器都已经过期,并且springmvc也推荐了相应的支持注解的映射器和适配器

3.2.推荐使用的注解配置

3.2.1.springmvc-servlet.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:p="http://www.springframework.org/schema/p"
	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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 配置映射器,把bean的name属性作为一个url -->
	<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> -->
	<!-- 推荐使用的注解映射器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
	
	<!-- 配置适配器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> -->
	<!-- 推荐使用的注解适配器 -->
	<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
	
	<!-- <bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" /> -->
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

3.2.2.测试

在这里插入图片描述

3.2.3.日志

输出的是推荐使用的映射器,说明这种配置OK
在这里插入图片描述

3.3.最佳方案(注解驱动)

3.3.1.注解驱动的配置

在springmvc-servlet.xml中配置注解驱动

<mvc:annotation-driven />
	<!-- 配置映射器,把bean的name属性作为一个url -->
	<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> -->
	<!-- 推荐使用的注解映射器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> -->
	
	<!-- 配置适配器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> -->
	<!-- 推荐使用的注解适配器 -->
	<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> -->
	
	<!-- 注解驱动,替代推荐使用的注解映射器和适配器,并提供了对json的支持 -->
	<mvc:annotation-driven />
	
	<!-- <bean name="/hello.do" class="com.atguigu.springmvc.controller.HelloController" /> -->
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

3.3.2.注解驱动的原理

AnnotationDrivenBeanDefinitionParser的注释
在这里插入图片描述

3.4.注解配置最终方案

使用注解驱动后springmvc-servlet.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:p="http://www.springframework.org/schema/p"
	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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- 注解驱动,替代推荐使用的注解映射器和适配器,并提供了对json的支持 -->
	<mvc:annotation-driven />
	
	<!-- 配置注解扫描,和Spring的配置方式一样 -->
	<context:component-scan base-package="com.atguigu.springmvc" />
	
	<!-- 配置视图解析器 -->
	<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

目前这些配置已经能够完成springmvc的基本使用,后续还会添加一些高级用法的配置,例如:拦截器、自定义试图、文件上传等

四、RequestMapping(映射请求)

  • 标准URL映射
  • Ant风格的映射
  • Rest风格的映射
  • 限定请求方法的映射
  • 限定参数的映射
  • 限定请求头信息的映射

4.1.标准URL映射

/**
@RequestMapping(value=”xxx”)
在springmvc众多Controller以及每个Controller的众多方法中,请求时如何映射到具体的处理方法上
它可以定义在方法上,也可以定义在类上
请求映射的规则:
类上的@RequestMapping的value+方法上的@RequestMapping的value,如果value不以“/”开头,springmvc会自动加上
类上的@RequestMapping可省略,这时请求路径就是方法上的@RequestMapping的value
路径不可重复*/
@RequestMapping("hello")
@Controller
public class Hello2Controller {
    
    @RequestMapping("show1")
    public ModelAndView test1(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "这是SpringMVC的第一个注解程序!");
        return mv;
    }

}

测试:
在这里插入图片描述

4.2.Ant风格的映射(通配符)

	/**
	?:通配一个字符
	*:通配0个或者多个字符
	**:通配0个或者多个路径
	   */
    @RequestMapping("aa?/show2")
    public ModelAndView test2(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "ant风格的映射:?");
        return mv;
    }
    
    @RequestMapping("bb*/show3")
    public ModelAndView test3(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "ant风格的映射:*");
        return mv;
    }
    
    @RequestMapping("**/show4")
    public ModelAndView test4(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "ant风格的映射:**");
        return mv;
    }


  • 测试
    在这里插入图片描述
  • 思考:
    如果把test3方法的请求路径,改为“*/show3”, test4方法的请求路径,改为“**/show3”,
    1.访问路径:localhost:8080/springmvc/hello//show3.do会进入test3方法还是test4方法呢
    2.访问路径:localhost:8080/springmvc/hello/bb/show3.do会进入test3方法还是test4方法呢?

4.3.占位符的映射

在这里插入图片描述

/**
@RequestMapping(value=“/user/{userId}/{name} ")
请求URL:http://localhost:8080/user/1001/zhangsan.do
这种方式虽然和通配符“*”类似,却比通配符更加强大,占位符除了可以起到通配的作用,最精要的地方是在于它还可以传递参数。
比如:通过@PathVariable(“userId”) Long id, @PathVariable(“name”)String name获取对应的参数。
注意:@PathVariable(“key”)中的key必须和对应的占位符中的参数名一致,而方法形参的参数名可任意取
*/

    @RequestMapping("show5/{name}/{id}")
    public ModelAndView test5(@PathVariable("name")String name, @PathVariable("id")Long id){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "rest风格的映射:name=" + name + ",id=" + id);
        return mv;
    }


测试:
在这里插入图片描述
如果传递的参数类型和接受参数的形参类型不一致,则会自动转换,如果转换出错(例如:id传了abc字符串,方法形参使用Long来接受参数),则会报400错误(参数列表错误)。
在这里插入图片描述

4.4.限定请求方法的映射

@RequestMapping(value=””, method=RequestMethod.POST)
    @RequestMapping(value = "show6", method = RequestMethod.POST)
    public ModelAndView test6(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "限定请求方法的映射:POST");
        return mv;
    }


用到了框架提供的RequestMethod枚举类,源代码截图:
在这里插入图片描述

此时show6限定请求方法为POST请求,如果通过浏览器地址栏输入请求路径(也就是GET请求),结果:
在这里插入图片描述

地址栏无法模拟POST请求,需要使用浏览器插件,模拟POST请求,下面为chrome浏览器的模拟插件,参见课前资料
安装过程参见教程:
在这里插入图片描述

安装完成后的使用:
在这里插入图片描述
在这里插入图片描述

限定多种请求方法
@RequestMapping(value=””, method={RequestMethod.POST, RequestMethod.GET})
    @RequestMapping(value = "show7", method = {RequestMethod.POST, RequestMethod.GET})
    public ModelAndView test7(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "限定请求方法的映射:POST");
        return mv;
    }


4.5.限定请求参数的映射

@RequestMapping(value=””,params=””)
params=”userId”:请求参数中必须带有userId
params=!userId”:请求参数中不能包含userId
params=”userId=1”:请求参数中userId必须为1
params=”userId!=1”:请求参数中userId必须不为1,参数中可以不包含userId
params={“userId”, ”name”}:请求参数中必须有userId,name参数

    @RequestMapping(value = "show8", params = "id")
    public ModelAndView test8() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "springmvc的映射之限定请求参数,id");
        return mv;
    }

    @RequestMapping(value = "show9", params = "!id")
    public ModelAndView test9() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "springmvc的映射之限定请求参数,!id");
        return mv;
    }

    @RequestMapping(value = "show10", params = "id=1")
    public ModelAndView test10() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "springmvc的映射之限定请求参数,id=1");
        return mv;
    }

    @RequestMapping(value = "show11", params = "id!=1")
    public ModelAndView test11() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "springmvc的映射之限定请求参数,id!=1");
        return mv;
    }

    @RequestMapping(value = "show12", params = { "id", "name" })
    public ModelAndView test12() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "springmvc的映射之限定请求参数,id,name");
        return mv;
    }


4.6.限定请求头信息

@RequestMapping(value=””, heads=””)
    /**
     * 1.请求头信息必须包含User-Agent
     * 2.User-Agent头参数的值必须为Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
     *   即:限定浏览器必须是谷歌浏览器,而且版本还是Chrome/69.0.3497.100
     * @return
     */
    @RequestMapping(value = "show13", headers = "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36")
    public ModelAndView test13() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "限定请求头信息");
        return mv;
    }

谷歌浏览器测试:
在这里插入图片描述
火狐浏览器测试:
在这里插入图片描述

4.7.组合注解

GetMapping:相当于RequestMapping(method = RequestMethod.GET)
PostMapping:相当于RequestMapping(method = RequestMethod.POST)
PutMapping:相当于RequestMapping(method = RequestMethod.PUT)
DeleteMapping:相当于RequestMapping(method = RequestMethod.DELETE)
    @GetMapping(value = "show14")
    public ModelAndView test14() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "GetMapping");
        return mv;
    }

    @PostMapping(value = "show15")
    public ModelAndView test15() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "PostMapping");
        return mv;
    }

    @PutMapping(value = "show16")
    public ModelAndView test16() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "PutMapping");
        return mv;
    }

    @DeleteMapping(value = "show17")
    public ModelAndView test17() {
        ModelAndView mv = new ModelAndView("hello");
        mv.addObject("msg", "DeleteMapping");
        return mv;
    }

五、接收数据及数据绑定

a.接收servlet的内置对象
b.springMVC特有内置对象
c.接收占位符请求路径中的参数
d.接收普通的请求参数
e.接受请求头信息
f.获取cookie参数
g.基本数据类型的绑定
h.Pojo对象的绑定
i.集合的绑定

请求参数—>方法形参,方法形参没有顺序。

5.1.接收servlet的内置对象

并且这些对象的接收非常简单,只需要在方法形参中有该对象就能接收,不需要任何配置


    @RequestMapping("show18")
    public ModelAndView test18(HttpServletRequest request, HttpServletResponse response, HttpSession session){
        ModelAndView mv = new ModelAndView("hello");
        StringBuffer sb = new StringBuffer();
        sb.append("request: " + request.toString() + "<br />");
        sb.append("response: " + response.toString() + "<br />");
        sb.append("session: " + session.toString() + "<br />");
        mv.addObject("msg", sb.toString());
        return mv;
    }

测试:
在这里插入图片描述

5.2.SpringMVC特有内置对象

  • controller方法除了返回ModelAndView,还可以返回String。当返回值是String时,默认是视图名称。
  • 那么数据模型怎么办?SpringMVC提供了特有的内置对象:Model ModelMap 本质都是Map

    @RequestMapping("show19")
    public String test19(Model model, ModelMap modelMap, Map<String, Object> map){
        // model.addAttribute("msg", "Model数据模型");
        // modelMap.addAttribute("msg", "ModelMap数据模型");
        map.put("msg", "Map数据模型");
        return "hello";
    }

测试
在这里插入图片描述

5.3.接收占位符参数

之前玩过Rest风格的URL,rest风格的url可以更优雅的传递参数。这些参数可以通过@PathVariable注解获取

@PathVariable(value=”id”)获取占位符中的参数
注意:(value=”id”)不能省
    @RequestMapping("show20/{name}")
    public String test20(@PathVariable("name")String name, Model model){
        model.addAttribute("msg", "获取占位符参数:" + name);
        return "hello";
    }


测试:
在这里插入图片描述

5.4.接收普通的请求参数

@RequestParam(value=””, required=true/false, defaultValue=””)
1.value:参数名
2.required:是否必须,默认为true,标示请求参数中必须包含该参数,如果不包含则抛出异常
3.defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果请求中不包含该参数则使用默认值。
    @RequestMapping("show21")
    public String test21(@RequestParam("name")String name, Model model){
        model.addAttribute("msg", "获取普通参数:" + name);
        return "hello";
    }
    
    @RequestMapping("show22")
    public String test22(@RequestParam(value = "name", required = false)String name, Model model){
        model.addAttribute("msg", "获取普通参数:" + name);
        return "hello";
    }
    
    @RequestMapping("show23")
    public String test23(@RequestParam(value = "name", defaultValue = "lisi")String name, Model model){
        model.addAttribute("msg", "获取普通参数:" + name);
        return "hello";
    }



5.5.获取请求头信息

@RequestHeader可以获取请求头信息,用法跟@RequestParam注解类似:
name:作用等价于value,通常使用value
required:是否必须,默认是true,请求头信息中必须包含该参数,否则抛出异常
defaultValue:默认值。如果设置了该值,required=true将失效,自动为false,如果请求中不包含该参数则使用默认值。
在这里插入图片描述


    @RequestMapping("show24")
    public String test24(@RequestHeader("User-Agent")String userAgent, Model model){
        model.addAttribute("msg", "获取请求头信息参数:" + userAgent);
        return "hello";
    }

测试:
在这里插入图片描述

5.6.获取cookie

@CookieValue使用方法同@RequestParam
    @RequestMapping("show25")
    public String test25(@CookieValue("JSESSIONID")String sessionId, Model model){
        model.addAttribute("msg", "获取cookie中的参数:" + sessionId);
        return "hello";
    }

测试:
在这里插入图片描述

5.7.基本数据类型的绑定

字符串、整型、浮点型、布尔型、数组。
在WebContent目录下,创建user.html表单:
在这里插入图片描述


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="/show26.do">
        name : <input type = "text" name="name"> <br />
        age:<input type="text" name="age"> <br/>
        isMarry: <input type="checkbox" name="isMarry"> <br>
        income : <input type="text" name="income"> <br>
        interests : <input type="checkbox" name="interests" value="bb"> basketball
        <input type="checkbox" name="interests" value="fb"> football
        <input type="checkbox" name="interests" value="vb"> volleyball <br>

        <input type="submit" value="提交">
    </form>

</body>
</html>

可以通过localhost:8080/user.html访问


    /**
     * 方法的返回值为void时,处理完业务逻辑后
     * 可以通过@ResponseStatus注解设置响应状态码
     * 告诉浏览器已经处理成功
     * @param name
     * @param age
     * @param isMarry
     * @param income
     * @param interests
     */
    @RequestMapping("show26")
    @ResponseStatus(value = HttpStatus.OK)
    public void test26(@RequestParam("name") String name, @RequestParam("age") Integer age,
            @RequestParam("isMarry") Boolean isMarry, @RequestParam("income") Double income,
            @RequestParam("interests") String[] interests) {
        StringBuffer sb = new StringBuffer();
        sb.append("name: " + name + "\n");
        sb.append("age: " + age + "\n");
        sb.append("isMarry: " + isMarry + "\n");
        sb.append("income: " + income + "\n");
        sb.append("interests: [");
        for (String interest : interests) {
            sb.append(interest + " ");
        }
        sb.append("]");
        System.out.println(sb.toString());

相应状态HttpStatus是一个枚举类:
在这里插入图片描述
测试:
在这里插入图片描述
由于Controller方法没有任何返回值,所以浏览器没有任何信息:
在这里插入图片描述
控制台:
在这里插入图片描述

5.8.Pojo对象的绑定

SpringMVC会将请求参数名和POJO实体中的属性名(set方法)进行自动匹配,如果名称一致,将把值填充到对象属性中,并且支持级联(例如:user.dept.id)。
Controller方法:

    @RequestMapping("show27")
    public String test27(User user, @RequestParam("name") String name, Model model) {
        model.addAttribute("msg", user.toString() + "<br />" + name);
        return "hello";
    }

测试:
在这里插入图片描述

User类:
在这里插入图片描述
User内容:

package cn.itcast.springmvc.pojo;

import java.util.Arrays;

public class User {
	private String name;
	private String userName;
	private Integer id;
	private Integer age;
	private Double income;
	private Boolean isMarry;
	private String[] interests;
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Double getIncome() {
		return income;
	}
	public void setIncome(Double income) {
		this.income = income;
	}
	public Boolean getIsMarry() {
		return isMarry;
	}
	public void setIsMarry(Boolean isMarry) {
		this.isMarry = isMarry;
	}
	public String[] getInterests() {
		return interests;
	}
	public void setInterests(String[] interests) {
		this.interests = interests;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + ", income=" + income + ", isMarry=" + isMarry + ", interests="
				+ Arrays.toString(interests) + "]";
	}
	
}

思考:对象中嵌套对象该怎么接受呢?

5.9.集合的绑定

反例:直接接受集合对象


    @RequestMapping("show28")
    public String test28(Model model, List<User> users) {
        model.addAttribute("msg", users.toString());
        return "hello";
    }

在这里插入图片描述
如果方法需要接受的list集合,不能够直接在方法中形参中使用List
List的绑定,需要将List对象包装到一个类中才能绑定
要求:表单中input标签的name的值和集合中元素的属性名一致。
UserVO:
在这里插入图片描述
内容:

package cn.itcast.springmvc.pojo;

import java.util.List;

public class UserVO {
	private List<User> users;

	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

}

Controller方法使用UserVO接收集合对象:
在这里插入图片描述
效果:
在这里插入图片描述

六、转发及重定向(forward、redirect)

通过前面的学习已知,controller方法的返回值有三种:
1.ModelAndView
2.String
3.void(了解)
前两种返回值都有视图名称字符串。当视图名称字符串是以”forward:”或者”redirect:”开头,则会被认为是转发或者重定向。
使用方式如下:
转发:forward:/hello/show.do或者forward:show.do
重定向:redirect:/hello/show.do或者redirect:show.do
注意:后面必须跟上URL路径而非视图名
传统的重定向及转发:

	request.getRequestDispatcher("show31.do?id=111&key=forward").forward(request, response);
response.sendRedirect("show31.do?id=222&key=redirect");

    /**
     * 测试转发
     * 并传递参数:id、key
     * @return
     */
    @RequestMapping("show29")
    public String test29() {
        
        return "forward:show31.do?id=111&key=forward";
    }
    
    /**
     * 测试重定向
     * 并传递参数:id、key
     * @return
     */
    @RequestMapping("show30")
    public String test30() {
        
        return "redirect:show31.do?id=222&key=redirect";
    }
    
    @RequestMapping("show31")
    public String test31(Model model, @RequestParam("id")Long id, @RequestParam("key")String key) {
        model.addAttribute("msg", "forward?redirect: id=" + id + ", key=" + key);
        return "hello";
    }


在RestClient测试转发(show29.do):
在这里插入图片描述
在浏览器中测试转发:
在这里插入图片描述
使用RestClient测试重定向:
在这里插入图片描述

在浏览器地址栏测试重定向(show25.do):
在这里插入图片描述

七、jstl标签的使用

JSTL:标准标签库
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。

7.1.导入jstl依赖包

在这里插入图片描述

7.2.静态页面

在这里插入图片描述
内容

<!DOCTYPE html>
<html>
<head>
<title>JSTL Demo</title>
</head>
<body>
	<table cellpadding=0 cellspacing=0 border="1">
		<thead>
			<tr>
				<th>ID</th>
				<th>UserName</th>
				<th>Name</th>
				<th>Age</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>1001</td>
				<td>zhangsan</td>
				<td>张三</td>
				<td>18</td>
			</tr>
			<tr>
				<td>1002</td>
				<td>lisi</td>
				<td>李四</td>
				<td>19</td>
			</tr>
			<tr>
				<td>1003</td>
				<td>wangwu</td>
				<td>王五</td>
				<td>20</td>
			</tr>
			<tr>
				<td>1004</td>
				<td>gary</td>
				<td>张三</td>
				<td>18</td>
			</tr>
			<tr>
				<td>1005</td>
				<td>gary</td>
				<td>张三</td>
				<td>18</td>
			</tr>
			<tr>
				<td>1006</td>
				<td>gary</td>
				<td>张三</td>
				<td>18</td>
			</tr>
			<tr>
				<td>1007</td>
				<td>gary</td>
				<td>张三</td>
				<td>18</td>
			</tr>
			<tr>
				<td>1008</td>
				<td>gary</td>
				<td>张三</td>
				<td>18</td>
			</tr>
		</tbody>
	</table>
</body>
</html>


7.3.jsp头信息

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>


7.4.引入核心标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


7.5.使用<c:foreach>标签

在这里插入图片描述

7.6.Controller方法

    @RequestMapping("show32")
    public String test32(Model model){
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(i + 1);
            user.setName("马云" + i);
            user.setUserName("mayun" + i);
            user.setAge(20 + i);
            users.add(user);
        }
        model.addAttribute("users", users);
        return "users";
    }

7.7.效果

在这里插入图片描述

7.8.SpringMVC标签

jsp内容


<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>Insert title here</title>
	</head>
	<body>
		<!-- 
			form:form是form标签。
				action属性是提交给服务器的地址
				method 是提交的方式
				modelAttribute是form标签需要关联的表单对应模型
		 -->
		<form:form action="${ pageContext.request.contextPath }/hello/save.do" method="post" modelAttribute="user">
			<!-- form:input 相当于一个普通的输入框类型。
					path属性就是生成的表单项的name属性,然后它可以找到表单对象模型中的属性进行输出
			 -->
			userName:<form:input path="userName"/><br/>
			age:<form:input path="age"/><br/>
			salary:<form:input path="salary"/><br/>
			isMarry:<form:checkbox path="isMarry"/><br/>
			interests:<form:checkbox path="interests" value="football1"/>football
			<form:checkbox path="interests" value="basketball"/>basketball
			<form:checkbox path="interests" value="vollyball"/>vollyball
			<input type="submit" />
		</form:form>
	</body>
</html>

controller


@RequestMapping("user")
    public String toUser(Model model){
        model.addAttribute("user", new User());
        return "user";
    }
    
    @RequestMapping("save")
    @ResponseStatus(value=HttpStatus.OK)
    public void save(User user){
        System.out.println(user.toString());
    }

测试

访问user.jsp:

在这里插入图片描述

输入内容,点击提交:

在这里插入图片描述

八、JSON

在实际开发过程中,json是最为常见的一种方式,所以springmvc提供了一种更为简便的方式传递数据。
@ResponseBody 是把Controller方法返回值转化为JSON,称为序列化
@RequestBody 是把接收到的JSON数据转化为Pojo对象,称为反序列化

8.1.引入jackson依赖包

在这里插入图片描述

8.2.原理

Json的转化是由注解驱动完成的。
注解驱动会判断是否引入了jackson依赖,并决定是否加载json转化的消息转化器

在这里插入图片描述

8.3.@ResponseBody

当一个处理请求的方法标记为@ResponseBody时,表示该方法需要输出其他视图(json、xml),springmvc通过默认的json转化器转化输出
Controller方法:

    /**
     * 需要把什么转化为json,就返回什么数据
     * 1.当方法上有@ResponseBody注解,代表方法的返回值需要输出其他视图
     * 2.把方法的返回值转化为其他视图(json)
     * @param model
     * @return
     */
    @RequestMapping("show33")
    @ResponseBody
    public List<User> test33(Model model){
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId(i + 1);
            user.setName("马云" + i);
            user.setUserName("mayun" + i);
            user.setAge(20 + i);
            users.add(user);
        }
        return users;
    }

测试:

在这里插入图片描述

8.3.1.@JsonFormat

格式化json中的时间字符串。
首先在User中添加日期类型的birthday字段。
在这里插入图片描述
改造show33方法:
在这里插入图片描述
在浏览器中测试:
在这里插入图片描述
显示格式及其不友好。
在birthday字段上使用@JsonFormat注解格式化日期:@JsonFormat(pattern=”yyyy-MM-dd HH:mm:ss”)
在这里插入图片描述
再次测试:
在这里插入图片描述

8.3.2.@JsonIgnore

有些字段出于安全考虑,不太适合响应到浏览器(比如:password),像这类字段我们可以在查询时忽略该字段,也可以通过@JsonIgnore注解。
在User类中添加password字段及getter和setter方法
在这里插入图片描述
再次改造show33方法:
在这里插入图片描述
测试:
在这里插入图片描述
在User类中的password字段上使用@JsonIgnore注解:
在这里插入图片描述

8.4.@RequestBody

    @RequestMapping("show34")
    public String test34(@RequestBody User user, Model model){
        model.addAttribute("msg", user.toString());
        return "hello";
    }

在这里插入图片描述

九、文件上传

SpringMVC的文件上传,底层也是使用的Apache的Commons-fileupload

9.1.添加文件上传依赖包

在这里插入图片描述

9.2.文件上传解析器

在springmvc-servlet.xml中配置

	<!-- 文件上传解析器 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<!-- 设定文件编码 -->
		<property name="defaultEncoding" value="utf-8"></property>
		<!-- 设定文件上传最大值,单位为B -->
		<property name="maxUploadSize" value="5242880"></property>
	</bean>

9.3.Controller方法

    @RequestMapping(value = "show35")
    public String test35(Model model, @RequestParam("file") MultipartFile file)
            throws IllegalStateException, IOException {
        if (file != null) {
            file.transferTo(new File("c:\\tmp\\" + file.getOriginalFilename()));
        }
        return "redirect:/success.html";
    }

9.4.成功页面

在这里插入图片描述
在webapp目录下创建success.html文件


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div style="font-size: 30px; color: red;">上传成功</div>
</body>
</html>


9.5.效果

在这里插入图片描述

十、异常处理 的四种方式

10.1. 第一种、实现HandlerExceptionResolver接口

在这里插入图片描述
实现:

@Component
public class MyException implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {
        
        ModelAndView mv = new ModelAndView();
        
        // 判断不同的异常,跳转到不同的页面或者现实显示不同的提示信息
        if (ex instanceof MaxUploadSizeExceededException) {
            mv.setViewName("hello");
            mv.addObject("msg", "您上传的文件太大了!!");
        } else if (ex instanceof RuntimeException) {
            mv.setViewName("hello");
            mv.addObject("msg", "抛出了运行时异常!!");
        }
        
        return mv;
    }

}


10.2.第二种、使用SimpleMappingExceptionResolver类映射异常跳转(失效)

HandlerExceptionResolver异常解析器接口,提供了一些默认的实现类,其中有一个SimpleMappingExceptionResolver:
在这里插入图片描述
我们只需要简单的配置一下就可以使用了。

	<!-- 配置SimpleMappingExceptionResolver简单异常解析器 -->
	<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<!-- 配置异常映射属性 -->
		<property name="exceptionMappings">
			<props>
				<!-- 
					key:类的全路径
					在prop标签中填写跳转路径
				 -->
				<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">forward:/errors/error1.jsp</prop>
				<prop key="java.lang.RuntimeException">forward:/errors/error2.jsp</prop>
			</props>
		</property>
	</bean>

创建对应的jsp页面:
在这里插入图片描述

10.3.第三种、使用@HandlerException注解

使用该注解有一个不好的地方就是:进行异常处理的方法必须与出错的方法在同一个Controller里面。

    @ExceptionHandler
    public ModelAndView handleException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "出异常了");
        return mv;
    }
    
    @ExceptionHandler
    public ModelAndView handleException2(RuntimeException ex){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "运行时异常");
        return mv;
    }

一个Controller里面可以定义多个异常处理的方法处理不同异常。
如果一个异常同时满足多个异常处理方法的异常,按照最精确原则匹配异常处理方法

10.4.第四种、使用@ControllerAdvice + @ ExceptionHandler

在这里插入图片描述
内容:

/**
 * @ControllerAdvice可以处理所有Controller中产生的异常
 * @author joedy
 *
 */
@ControllerAdvice
public class HandleExceptionControllerAdvice {

    @ExceptionHandler
    public ModelAndView handleException(Exception ex){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "出异常了-全局");
        return mv;
    }
    
    @ExceptionHandler
    public ModelAndView handleException2(RuntimeException ex){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("hello");
        mv.addObject("msg", "运行时异常-全局");
        return mv;
    }
}

在局部异常处理和全局异常处理同时存在的时候,优先顺序是:
1、局部优先
2、精确优先

十一、拦截器

  • HandlerExecutionChain是一个执行链,当请求到达DispatchServlet时,DispatchServlet根据请求路径到HandlerMapping查询具体的Handler,从HandlerMapping返回给DispatcherServlet,其中包含了一个具体的Handler对象和Interceptors(拦截器集合)。
  • 如何自定义拦截器:
    springmvc的拦截器接口(HandlerInterceptor)定义了三个方法:
    a.preHandle调用Handler之前执行,称为前置方法
    返回值:true表示放行,后续业务逻辑继续执行
    false表示被拦截,后续业务逻辑不再执行,但之前返回true的拦截器的完成方法会倒叙执行
    b.postHandle调用Handler之后执行,称为后置方法
    c.afterCompletion视图渲染完成之后执行

11.1.拦截器的执行过程

在这里插入图片描述
在这里插入图片描述

11.2.编写自定义拦截器

在这里插入图片描述
MyInterceptor内容:

public class MyInterceptor implements HandlerInterceptor {

	/**
	 * 前置方法,在Handler方法执行之前执行,顺序执行
	 * 返回值,返回true拦截器放行 false拦截器不通过,后续业务逻辑不再执行
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("MyInterceptor1,前置方法正在执行");
		return true;
	}

	/**
	 * 后置方法,在执行完Handler方法之后执行,倒序执行
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("MyInterceptor1,后置方法正在执行");
	}

	/**
	 * 完成方法,在视图渲染完成之后执行,倒序执行
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("MyInterceptor1,完成方法正在执行");
	}

}

11.3.配置拦截器

在springmvc-servlet.xml中配置自定义的拦截器,/**:拦截所有请求

	<!-- 注册自定义的拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- 拦截所有请求 -->
			<mvc:mapping path="/**"/>
			<!-- 自定义拦截器的全路径 -->
			<bean class="com.atguigu.springmvc.interceptors.MyInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>

11.4.测试

在这里插入图片描述

11.5.配置多个拦截器

在这里插入图片描述
编写拦截器2:

public class MyInterceptor2 implements HandlerInterceptor {

	/**
	 * 前置方法,在Handler方法执行之前执行
	 * 返回值,返回true拦截器放行 false拦截器不通过,后续业务逻辑不再执行
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("MyInterceptor2,前置方法正在执行");
		return false;
	}

	/**
	 * 后置方法,在执行完Handler方法之后执行
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("MyInterceptor2,后置方法正在执行");
	}

	/**
	 * 完成方法,在视图渲染完成之后执行
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("MyInterceptor2,完成方法正在执行");
	}

}

配置拦截器2:

	<!-- 注册自定义的拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- 拦截所有请求 -->
			<mvc:mapping path="/**"/>
			<!-- 自定义拦截器的全路径 -->
			<bean class="com.atguigu.springmvc.interceptors.MyInterceptor"/>
		</mvc:interceptor>
		<mvc:interceptor>
			<!-- 拦截所有请求 -->
			<mvc:mapping path="/**"/>
			<!-- 自定义拦截器的全路径 -->
			<bean class="com.atguigu.springmvc.interceptors.MyInterceptor2"/>
		</mvc:interceptor>
	</mvc:interceptors>

测试:
在这里插入图片描述
结论:拦截器的前置方法依次执行,
后置方法和完成方法倒续执行
当前置方法返回false时,后续的拦截器以及Handler方法不再执行,但它前序的前置方法返回true的拦截器的完成方法会倒续执行。
完成方法会在视图渲染完成之后才去执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值