SpringMVC入门

MVC是一种架构模式;Controller(控制器)、Model(模型)、View(视图);
SpringMVC是Spring体系的轻量级WebMVC框架,其核心是Controller控制器,用于处理请求,产生响应;在MVC中,界面不允许直接访问后端的业务逻辑;SpringMVC基于SpringIOC容器运行,所有对象被IOC管理。
Spring 5.x版本变化;最重要的新特性支持响应式编程;点击一个按钮就会触发一个单机的事件。

创建工程

创建Maven工程:

1.直接点击maven工程创建即可;

2.使工程具备web能力:

spring mvc里自带的切面功能 spring mvc介绍_java


spring mvc里自带的切面功能 spring mvc介绍_spring_02

spring mvc里自带的切面功能 spring mvc介绍_java_03


3.配置两个文件:

Web.xml:

spring mvc里自带的切面功能 spring mvc介绍_java_04

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_05


页面存放位置:

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_06


运行创建一个artifact

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_07


一般选择第一个,以一个目录的方式运行。

spring mvc里自带的切面功能 spring mvc介绍_控制器_08


创建成功

spring mvc里自带的切面功能 spring mvc介绍_spring_09


创建一个任何的index.html在webapp的目录下(以后的web页面也是放在这个地方的)

配置tomcat,一定要把项目放到tomcat上,否则就算运行了tomcat也没办法显示出正常页面。

spring mvc里自带的切面功能 spring mvc介绍_web_10

SpringMVC环境配置

1.maven依赖Springmvc

<!--配置阿里云镜像-->
<repositories>
    <repository>
        <id>aliyun</id>
        <name>aliyun</name>
        <url>https://maven.aliyun.com/repository/public</url>
    </repository>
</repositories>
<!--增加springmvc依赖-->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>

2.Web.xml配置dispatcherServlet

<servlet>
    <!--名字随意-->
    <servlet-name>springmvc</servlet-name>
    <!--固定配置org.springframework.web.servlet.DispatcherServlet-->
    <!--DispatcherServlet是SpringMVC的核心对象-->
    <!--DispatcherServlet用于拦截http请求-->
    <!--并根据请求的url调用与之对应的controller方法,来完成http请求的处理-->
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--配置applicationContext.xml-->
    <init-param>
        <!--固定写法-->
        <param-name>contextConfigLocation</param-name>
        <!--classpath表示类路径-->
        <param-value>classpath:applicationContext.xml</param-value>
    </init-param>
    <!--web应用启动的时候,自动创建Spring IOC容器
        并初始化DispatcherServlet;
        如果不写的话就在第一次访问的时候才进行创建
    -->
    <load-on-startup>0</load-on-startup>

</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--/代表拦截所有请求-->
    <url-pattern>/</url-pattern>
</servlet-mapping>

3.配置applicationContext的mvc标记

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="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
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--
context:component-scan 标签作用
在Spring IOC初始化过程中,自动创建并管理com.imooc.springmvc及子包中
拥有以下注解的对象.
@Repository
@Service
@Controller
@Component
-->
    <context:component-scan base-package="com.imooc.springmvc"></context:component-scan>

    <!--启用Spring MVC的注解开发模式-->
    <mvc:annotation-driven />

    <!-- 将图片/JS/CSS等静态资源排除在外,可提高执行效率 -->
    <mvc:default-servlet-handler/>
</beans>

4.开发controller控制器

@Controller
public class springmvc {
    @GetMapping("/test")//提供一个Get请求的映射
    @ResponseBody//向响应提供一个数据,不进行任何页面跳转
    public String test(){
        return "success";
    }
}

5.对tomcat进行配置,将依赖添加到项目中:

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_11


这个是将依赖对应jar包添加到项目中

spring mvc里自带的切面功能 spring mvc介绍_spring_12

spring mvc里自带的切面功能 spring mvc介绍_java_13


@getMapping()将test()方法绑定到了/test路径,在我们访问的时候就进入这个方法;

spring mvc里自带的切面功能 spring mvc介绍_控制器_14

SpringMVC处理示意图

浏览器发送请求,到tomcat服务器上;首先被dispatchservlet给拦截下来,因为我们在给dispatchservlet配置的时候是拦截所有请求;然后dispatchservlet会根据请求的访问地址去寻找当前的controller方法上有对应访问地址的映射,然后就会进入到对应的方法中;根据对应的返回值会顺着原路径被附在响应中,所以响应体就包含了返回值;当浏览器接收完了就会将数据现实在MVC中。

spring mvc里自带的切面功能 spring mvc介绍_spring_15

SpringMVC数据绑定

SpringMVC中@controller的某一个方法是如何和url绑定在一起:URL Mapping(URL映射)。
其主要的职能是将URL与Controller方法进行绑定。
通过URL与方法绑定,SpringMVC可以通过tomcat对外暴露服务;所有对外暴露的接口都是一个一个URL网址;我们通过URL来执行后端的服务代码;
其主要有一下注解:
1.@RequestMapping - 通用绑定(不区分post/get请求),通常放在类上面(也可以放在方法上),用于URL全局设置
也可以给其配置method属性进行相应的请求标志:
例如,@RequestMapping只接受get请求,只不过这种方法比较麻烦:

@Controller
public class urlmapping {
    @RequestMapping(value = "/abc",method = RequestMethod.GET)
    @ResponseBody
    public String test(){
        return "abc";
    }
}

2.@GetMapping - 绑定Get请求,通常放在方法上

@GetMapping("/test")//提供一个Get请求的映射
@ResponseBody//向响应提供一个数据,不进行任何页面跳转
public String test(){
    return "success";
}

3.@PostMapping - 绑定post请求,通常放在方法上

@PostMapping("/testOne")//提供一个Post请求的映射
@ResponseBody//向响应提供一个数据,不进行任何页面跳转
public String testOne(){
    return "success";
}

接受请求参数

1.使用controller方法参数接收

spring mvc里自带的切面功能 spring mvc介绍_java_16


SpringMVC可以帮我们进行类型的转换;但是类型不能一致的话就会报400的错(往往是因为数据无法转换成目标类型导致的);例如接收是int,前端传入了abc字符串,会报错。

spring mvc里自带的切面功能 spring mvc介绍_spring_17


使用@RequestParam接收参数,放在参数之前,属性中放入前端传入的参数名:作为请求参数hello_name会被动态的注入到后面的name参数中,java程序通过name获取值

@GetMapping("/test")//提供一个Get请求的映射
@ResponseBody//向响应提供一个数据,不进行任何页面跳转
public String test(@RequestParam("hello_name")String name){
    return "success";
}

2.使用JavaBean接收:
如果前端传的数据比较多,可以使用一个实体类进行数据的保存,SpringMVC可以将其一步搞定;但是javabean中的属性值要跟前端传给的属性保持一致才行,SpringMVC检测到参数是实体类时,他会去实体类属性找对应的属性,如匹配则赋值。如果在Url映射的方法中既有实体类,又有跟实体类属性一样的参数:

@PostMapping("/testBean")//提供一个Post请求的映射
@ResponseBody//向响应提供一个数据,不进行任何页面跳转
public String testBean(User user, String username){
    System.out.println("username"+username+";"+"password"+user.getUsername());
    return "success";
}

结果是不管有几个username的对象,只要匹配了,SpringMVC都会给其进行赋值。

spring mvc里自带的切面功能 spring mvc介绍_web_18

接收日期的参数

在日期参数前加上@DateTimeFormat(pattern=””)注解,专用于按照指定格式的字符串转成date对象,在转化时要指定格式。如果是javaBean类型的话,需要在实体类属性上添加@DateTimeFormat(pattern=””)注解。

@PostMapping("/date")//提供一个Post请求的映射
@ResponseBody//向响应提供一个数据,不进行任何页面跳转
public String testDate(User user, String username, @DateTimeFormat(pattern = "yyyy-mm-dd") Date date){
    System.out.println("username"+username+";"+"password"+user);
    return "success";
}

Javabean对象:

public class User {
    private String username;
    private Long password;
    @DateTimeFormat(pattern = "yyyy-mm-dd")
    private Date date;
}

可以使用全局的时间转换器:

//实现一个转换器的接口;两个泛型,一个是String,另一个是要转换成的类型

public class conver implements Converter<String,Date> {
    @Override
    public Date convert(String s) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd");
        try {
            Date d = simpleDateFormat.parse(s);
            return d;
        } catch (ParseException e) {
            return null;
        }
    }
}

使用全局时间转换器配置xml文件:

<!--启用Spring MVC的注解开发模式-->
<mvc:annotation-driven conversion-service="dateFormat"/>

<!-- 将图片/JS/CSS等静态资源排除在外,可提高执行效率 -->
<mvc:default-servlet-handler/>

<!--通知SpringMVC有哪些自定义的转换类-->
<bean id="dateFormat" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.imooc.conver.conver"></bean>
        </set>
    </property>
</bean>

如果在两者都配置的情况下,以最小范围者为优先。

中文乱码问题

中文乱码的来源:
Tomcat默认使用字符集ISO-8859-1,属于西欧字符集
解决乱码的核心思路是将ISO-8859-1转换为UTF-8

中文乱码的配置

Get请求乱码 在tomcat的配置文件server.xml增加URIEncoding属性;(在tomcat8.0以后的版本默认就是utf-8)

spring mvc里自带的切面功能 spring mvc介绍_java_19


Post请求乱码 在web.xml配置CharacterEncodingFilter这个过滤器

<filter>
    <filter-name>filters</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>
    <!--过滤所有的url-->
    <filter-name>filters</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Response响应乱码 - Spring配置StringHttpMessageConverter

<!--启用Spring MVC的注解开发模式-->
<mvc:annotation-driven conversion-service="dateFormat">
    <!--设置消息转换器,对响应中的消息进行调整-->
    <mvc:message-converters>
        <!--对HTTP响应中的文本消息进行转换-->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>
                        test/html;chaerset=utf-8
                    </value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

响应中产生结果:

@ResponseBody:
产生响应文本;直接产生数据,过程中不涉及任何视图;
可生产标准字符串JSON/XML等格式数据;
会被StringHttpMessageConverter所影响;

ModelAndView 利用模板引擎渲染输出
ModelAndView对象指“模型(数据)”与视图(界面)对象。
通过ModelAndView可将包含数据对象与模板引擎进行绑定
SpringMVC默认的View是JSP,当然也可以使用其他模板引擎;

@PostMapping("/view")
public ModelAndView testDate(){
	//构造函数中传入一个要跳转到jsp页面
    ModelAndView m = new ModelAndView("/view.jsp");
    return m;
}

也可以创建无参构造器,通过setViewName()方法进行页面赋值

ModelAndView m = new ModelAndView();
m.setViewName("/view.jsp");

如果没有斜杠的话表示相对路径,相对于当前这个地址;但是不推荐这么用,避免和外部环境产生过多依赖;尽量使用绝对路径。

@Controller
@RequestMapping("/he")
public class urlmapping {
    @RequestMapping(value = "/abc",method = RequestMethod.GET)
    public ModelAndView testOne(){
        ModelAndView m = new ModelAndView();
        m.setViewName("view.jsp");
        return m;
    }
}

spring mvc里自带的切面功能 spring mvc介绍_java_20


一般返回ModelAndView 用于处理动态数据(将数据和页面绑定在一起);模板引擎根据对应语法取出来展示即可。

@PostMapping("/view")
@ResponseBody
public ModelAndView testDate(){
    ModelAndView m = new ModelAndView("/view.jsp");
    User user = new User();
    user.setUsername("abcd");
    /*在当前的请求中增加一个对象,对象别名为user;第二个参数是要传入的数据*/
    m.addObject("user",user);
    return m;
}

ModelAndView

addObject()方法设置的属性默认存放在当前请求中,传入的参数可以是任意java对象;如果使用重定向,数据将会被清空。
默认ModelAndView进行页面跳转的时候,使用请求转发(forward)至页面;

重定向的使用 new ModelAndView(“redirect:/路径名”);当view和controller处理关系不是特别紧密的时候可以使用重定向。

public ModelAndView testOne(){
    ModelAndView m = new ModelAndView();
    m.setViewName("redirect:/view.jsp");
    return m;
}

Restful开发风格

Rest(理念):表现层状态转换,资源在网络中以某种表现形式进行状态转移。

Restful是基于rest理念的一套开发风格,是具体的开发规则。当前端发送请求过来,后端只返回数据(JSON/XML),不返回任何和展现相关的内容;当数据返回去,在由前端进行渲染和展现

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_21


开发规范:

使用URL作为用户交互入口,图片,css都以URL进行交互

明确的语义规范(GET/POST/DELETE/PUT)

查询/新增/删除/更新

只返回数据(JSON/XML),不包含任何表现形式命名要求(针对URI):

spring mvc里自带的切面功能 spring mvc介绍_控制器_22


PS:解决Jq发送ajax数据后返回的中文乱码:

看其请求头:

spring mvc里自带的切面功能 spring mvc介绍_web_23


在我们配置的返回响应的list集合中多加一个value

application/json;charset=utf-8

<!--启用Spring MVC的注解开发模式-->
<mvc:annotation-driven conversion-service="dateFormat">
    <!--设置消息转换器,对响应中的消息进行调整-->
    <mvc:message-converters>
        <!--对HTTP响应中的文本消息进行转换-->
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value> test/html;chaerset=utf-8 </value>
                    <value>application/json;charset=utf-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Restcontroller注解与路径变量:

@Restcontroller = @Controller + @Responsebody:直接给前端返回对应数据,不返回任何视图;放在类上,整个类都返回方法类型的数据;放在方法上,只有这个方法映射的路径访问到时,就返回方法的数据类型数据,URI访问其他资源依然返回ModelAndView。

路径变量:放在URI中的变量;POST/article/2(2是可变的值)
使用@PathVariable注解来接收这个参数,值存到id中;只要URI配型即可存入到id中:

@PostMapping("/uri/{rid}")
public String test(@PathVariable("rid") Integer id){
    System.out.println(id);
    return "success";
}

简单请求与非简单请求

简单请求:标准结构的HTTP请求,对应GET/POST请求

非简单请求:复杂要求的HTTP请求,指PUT/DELETE、扩展标准请求。

区别:非简单请求发送前需要发送预检请求;作用:返回当前这个请求能不能够被正常处理,如果服务器接收并返回表明能正常处理,再由浏览器发送实际请求进行处理:

spring mvc里自带的切面功能 spring mvc介绍_spring_24


默认表单在进行发送数据的时候只有GET和POST请求,对于DELETE和PUT是不支持的;所以SpringMVC额外的提供了表单内容过滤器来对PUT和DELETE进行处理:

spring mvc里自带的切面功能 spring mvc介绍_spring_25


spring mvc里自带的切面功能 spring mvc介绍_spring_26


改进,配置过滤器:

<filter>
    <filter-name>form</filter-name>
    <!--固定-->
    <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>form</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

JSON序列变化

Jackson
1.引入依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.9</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.9</version>
</dependency>

2.只要写有@RestController或者@Responsebody注解的类或方法,直接返回要序列化成JSON的类对象:

@GetMapping("/restful/jackson")
public User testJackson(User user){
    User u = new User();
    u.setUsername("aaa");
    u.setPassword(1234l);
    return u;
}

spring mvc里自带的切面功能 spring mvc介绍_控制器_27


返回多条数据的时候使用List集合即可。

缺点如果要返回时间的话,它返回1970年到现在为止的毫秒数;为了解决这个问题,JSON提供了注解@JsonFormat(pattern=”yyyy-MM-dd hh:mm:ss”,timezore=”GMT+8”);可以将日期类型按格式化输出;但是输出也是按照格里尼治时间进行输出(相差8个小时);jackson还可以对货币等进行序列化输出,但是输出时间一定要GMT+8调整一下。

浏览器的跨域访问

跨域访问的根源来自浏览器的同源策略
同源策略阻止一个域加载的脚本去获取另一个域上的资源;有一个网站A和一个网站B在不同的服务器上,如果A某个页面向B的某个URL发送了ajax请求,就会因为同源策略被阻止,因为浏览器为了保护安全;网站的页面和ajax请求只能获取同网站,同域名下的另外资源。

具体尝试可以通过本地域去访问tomcat的localhost域对象;

spring mvc里自带的切面功能 spring mvc介绍_控制器_28


spring mvc里自带的切面功能 spring mvc介绍_spring_29


浏览器只认识localhost这个域名下的页面发送的请求,这样才符合同源策略;

解决方案:通过在请求头中设置访问的范围,就可以允许哪个域名访问我的服务。只要协议,域名,端口有任何一个不同,都被当做是不同的域

浏览器控制台看到access-control-allow-origin就代表跨域了,请求得到的结果并不会被浏览器处理。

举例:

spring mvc里自带的切面功能 spring mvc介绍_web_30


HTML中允许跨域的标签: 显示远程图片,

如何解决:
CORS跨域资源访问:CORS是一种机制,使用额外的HTTP头通知浏览器可以访问其他域的资源(这些其他域的资源是在对应域名下可以被访问的才行);
URL响应头包含Access-Control-*指明请求允许跨域;这不是我们自己能加的,而是对应的远程服务器授权才允许访问。

SpringMVC解决跨域访问:

1.使用@CrossOrigin 注解标记在Controller上;表明当前Controller所映射的URL允许被跨域访问。(局部处理,只在当前控制器生效)

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_31


跨域获取会有这个,cors代表跨域访问

spring mvc里自带的切面功能 spring mvc介绍_java_32


响应端通过Vary这个响应头设置跨域访问权限

代码实现:

@RestController
/*代表所有域名,所有端口都可以访问当前端口中的URL;有重大的安全隐患*/
/*CrossOrigin(origins = “*”*/
/*标注其他哪些域名可以被访问,还有一个maxAge参数:设置预检请求的缓存时间为XXXX秒*/
@CrossOrigin(origins = {"http://localhost:8080","http://www.iloveyou.com"})
public class controller {

    @PutMapping("/restful/request")
    public String test(User user){
        System.out.println(user.getUsername()+":"+user.getPassword());
        return "success";
    }
}

前面说过非简单请求会先发送预检请求:非简单请求每次都会发送两次请求,给服务器带来一些开销,所以引用maxAge可以将预检结果进行缓存,缓存XXX秒,同样的非简单请求在发送过来就不需要预检请求了,直接发送实际请求;这样大大降低了服务器的压力。

2.配置mvc:cors SpringMVC全局跨域配置;可以在配置文件对统一跨域进行设置

<mvc:cors>
    <mvc:mapping path="restful/*"/>
</mvc:cors>

只要是远程的域名访问到了前缀为”/restful”的请求上,都会被 这个策略所管理

管理细节:

<mvc:cors>
    <!--allowed-origins=""增加允许访问的域名,多个域名使用逗号分隔-->
    <mvc:mapping path="restful/*"
                 allowed-origins="http://localhost:8080"
                max-age="3600"
    />
</mvc:cors>

全局配置和注解配置都一样的,只是在请求和相应中附加了一些信息:

说明发送的请求是一个跨域资源访问

spring mvc里自带的切面功能 spring mvc介绍_spring_33


通知浏览器当前的URL是允许被跨域访问的:

spring mvc里自带的切面功能 spring mvc介绍_spring mvc里自带的切面功能_34


这个跨域同源策略只针对网页的,其他小程序什么的用另外的办法。

SpringMVC拦截器(interceptor)

拦截器用于对URL请求进行前置或后置过滤(跟过滤器有些相似)
interceptor与filter用途相似,但实现方式不同
interceptor是SpringMVC的标准组件,在被创建好运行在Spring-ioc容器中;filter是j2ee的标准组件,是J2ee的标准,作为filter是由不同的第三方容器厂商所实现的。
interceptor底层就是基于Spring AOP面向切面实现的;与环绕通知很相似
拦截器开发流程:
1.Maven依赖servlet-api

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <!--范围-->
    <!--作为tomcat环境自带servlet-api;如果打包部署会造成jar包冲突;
    用了provided只有在开发编译才会进行引用,最终打包这个jar会被排除在外-->
    <scope>provided</scope>
</dependency>

引入servlet-api的原因:

spring mvc里自带的切面功能 spring mvc介绍_java_35

2.实现HandlerInterceptor接口:

public class inter implements HandlerInterceptor {
    /*前置执行处理*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return false;
    }

    /*目标资源已被SpringMVC框架处理了;在发送给前端之前*/
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    /*产生响应文本以后*/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

如果方法返回正确,那么会送给后面的拦截器或者控制器;返回false的话,当前请求就会被阻止直接响应回客户端;第二个方法(posthandle)表示处理成功但是未产生响应文本之前所要做的事情(在执行完映射的方法return之后就要去执行这个方法;目标处理成功,响应文本之前);afterCompletion:目标的响应文本产生之后执行这个方法,该方法永远是最后被执行的。

按照时间顺序依次执行的

spring mvc里自带的切面功能 spring mvc介绍_web_36

ApplicationContext配置过滤地址

<mvc:interceptors>
    <mvc:interceptor>
        <!--当前拦截器需要对哪些地址进行拦截;对所有请求进行拦截(两颗星)-->
        <mvc:mapping path="/**"/>
        <!--哪个类对拦截的请求进行处理-->
        <bean class="com.imooc.inter.inter"></bean>
    </mvc:interceptor>
</mvc:interceptors>

拦截器的使用技巧:
拦截器不会受“不接受任何静态资源的影响”这个配置所影响的;在实际使用时,只要访问的url符合的拦截器所拦截的路径,那么都会被拦截下来;每次处理都会经过是三个内容,前置,完成未生成响应,响应。

<mvc:interceptors>
    <mvc:interceptor>
        <!--当前拦截器需要对哪些地址进行拦截;对所有请求进行拦截(两颗星)-->
        <mvc:mapping path="/**"/>
        <!--要排除的地址有哪些;以ico结尾的URI就排除,下例是排除各种静态资源-->
        <mvc:exclude-mapping path="/**.ico" />
        <mvc:exclude-mapping path="/**.jps" />
        <mvc:exclude-mapping path="/**.js" />
        <mvc:exclude-mapping path="/**.css" />
        <mvc:exclude-mapping path="/**.gif" />
        <!--哪个类对拦截的请求进行处理-->
        <bean class="com.imooc.inter.inter"></bean>
    </mvc:interceptor>
</mvc:interceptors>

但是一般静态资源都会很多,所以这样配置效果不会很好;实际开发中,会在webapp目录下创建一些文件夹,将静态资源放入对应文件夹中然后在排除拦截:

<mvc:interceptors>
    <mvc:interceptor>
        <!--当前拦截器需要对哪些地址进行拦截;对所有请求进行拦截(两颗星)-->
        <mvc:mapping path="/**"/>
        <!--对resource目录下的静态资源通通不拦截-->
        <mvc:exclude-mapping path="/resource/**" />
        <!--哪个类对拦截的请求进行处理-->
        <bean class="com.imooc.inter.inter"></bean>
    </mvc:interceptor>
</mvc:interceptors>

或者对应只拦截某些控制器的uri(反向思维);多个URI进行拦截,在下面追加即可。

一个请求被多个拦截器拦截先执行哪个:拦截前按照配置顺序,先配置先执行,拦截后反过来:

spring mvc里自带的切面功能 spring mvc介绍_控制器_37

SpringMVC处理流程:

向web服务器发送请求后,在SpringMVC中所有的请求都被DispatcherServlet拦截,拦截的请求交由SpringMVC进行处理;DispatcherServlet做的第一件事情是查找Handler(处理器,在计算机中也叫句柄)。

作为查找Handler,他的任务是交由HandlerMapper(处理器映射器)这个类来完成的,具体的作用就是通过当前访问的URL,得到我们的执行链(以此来了解先执行哪个,后执行哪个)(也就是获取在访问某一个URL后,依次有哪些拦截器及Controller来进行请求的处理),处理器(Handler)本质就是拦截器和controller的统称。

HandlerMapper只会去获取执行链并不会真正的进行处理,真正进行处理由中央处理器(DispatcherServlet)向HandlerAdapter(处理器适配器)来发起的执行请求,在由HandlerAdapter根据我们Handler的类型(可能是一个拦截器也可能是一个控制器)。

那么HandlerAdapter根据不同的Handler类型执行对应的方法,在执行的时候,HandlerAdapter会根据不同的Handler来决定调用什么方法;比如目标的handler实际类型是一个拦截器,他就会去执行前置的处理方法;如果实际类型是控制器,那么他就会进入控制器的方法来调用与URL对应的那个方法。假设处理的是控制器,最常见的返回时ModelAndView对象,这个对象会被HandlerAdapter进行接收,之后将HandlerAdapter对象返回给DispatcherServlet。

当DispatcherServlet接收到ModelAndView对象后,他就会进行判断,当前返回的ModelAndView由哪个模板引擎进行处理,这时DispatcherServlet根据返回的View的配置发现对应模板引擎,这样由DispatcherServlet会去选择与之对应的视图解析器(ViewResolver),如果使用freemarker就会有freemarker视图解析器进行创建视图,这个视图解析器解析完返回给DispatcherServlet。

DispatcherServlet拿到对象后,就将Model中拿到的数据结合模板进行渲染,形成HTML,这个HTML随着响应返回给客户端的浏览器,浏览器进行对应解释展示给用户。

spring mvc里自带的切面功能 spring mvc介绍_java_38


五大组件:

其中最核心的是DispatcherServlet;HandlerMapper的作用是获取执行链,知道先执行哪个后执行哪个;handleradapter是一个适配器,根据不同的handler来执行interceptor还是执行controller中对应的方法;当controller方法执行完后返回ModelAndView对象,由DispatcherServlet接收到以后,会选择与之对应的ViewResolver来创建对应的View视图对象