SpringMVC
一、了解什么是MVC
MVC模型:Model-View-Controller,模型-视图-控制器模式。
MVC是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的代码结构组织得更加合理。
-
Model(模型)
数据模型,提供要展示的数据,因此包含数据和行为,行为是用来处理这些数据的。
不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。
也就是数据由实体类或者javabean来提供,行为由service层来提供。
-
View(视图)
负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
-
Controller(控制器)
直接接收用户请求,委托给模型进行处理,处理完毕后把返回的模型数据交给给视图。
也就是说控制器在中间起到一个调度的作用。
在我们之前的学习中,其实就是把Servlet作为Controller(控制器),把jsp作为View(视图),把javabean作为Model(模型)中的数据,service层作为Model(模型)中的行为。
注意:MVC和三层架构的区别
三层架构是整体后端服务架构,而MVC只是控制了视图和模型之间的关联关系。
可以理解为MVC只工作在三层中的Web层。
二、SpringMVC概述
SpringMVC就是Spring框架提供的一个模块,通过实现MVC模式来很好地将数据、业务与展现进行分离,SpringMVC框架的主要目的是简化Web层开发。
SpringMVC中提供了一种非常好用的组件Controller,它的功能基本与之前使用过的Servlet相同,但是比Servlet更加方便易用。它们都可以用来接受请求、获取参数、操作Session和Cookie、返回响应等。除此之外,SpringMVC还以Controller为核心,提供了一系列支持组件,共同维护Controller的功能。
Controller的优势:
- 可以自定义Controller类型,无需像Servlet必须继承固定父类。
- 可以在一个Controller类中处理多个请求,而Servlet通常一个类只能处理一个请求。
- Controller中方法的参数可以根据自己的需求灵活定义,例如request、response、session等。
- 可以根据请求参数自动封装并传入pojo对象。
- 返回各类响应比Servlet方便,例如内部跳转、重定向、返回JSON格式对象等。
- ……
注意:Controller其本身是不能直接接受HTTP请求的,Controller的实现原理实际上还是依赖于Servlet。可以理解为Controller就是对Servlet进行的封装。
SpringMVC框架跟其他的WebMVC框架一样,都是【请求驱动】,并且设计围绕一个能够分发请求到控制器以及提供其他加快web应用开发功能的核心Servlet(叫做DispatcherServlet,即前端控制器)。
Spring的DispatcherServlet实现比其他框架中还要多的功能。它和spring的ioc容器完全整合,并且允许使用Spring中其他的所有功能。
三、第一个Controller案例
1、搭建工程环境
创建一个新的Maven Web项目,名为springmvc。
2、导入依赖
需要导入的依赖如下:
<!-- Servlet核心依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- JSTL标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.29.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.29.RELEASE</version>
</dependency>
3、配置前端控制器
SpringMVC中Controller的核心原理其实很简单,用一个核心Servlet拦截所有请求,再根据请求的URL转发至不同的Controller中进行处理。这个Servlet被称为【前端控制器】。接下来我们需要在web.xml中配置它:
<servlet>
<!-- servlet-name可以自己随便起,和下面servlet-mapping中的name对应即可-->
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 前端控制器拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
4、定义一个Controller
在com.briup.spring.web.controller包下创建一个类名为HelloController:
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mav = new ModelAndView();
// 设置视图名,也就是要跳转的页面
mav.setViewName("/hello.jsp");
// 向作用域中添加一组参数,用于页面显示
mav.addObject("username", "tom");
return mav;
}
}
Controller是一个用来定义所有Controller控制器规范的接口,其中只有一个方法:handleRequest()
。
该方法类似我们之前在Servlet中service()或doGet()/doPost(),都是请求到来时调用的处理方法。
了解ModelAndView
ModelAndView是一种同时代表模型和视图的对象。我们通常都需要在控制器中指定将哪个模型渲染到哪些视图中,并且决定跳转到哪个视图。SpringMVC对这两项操作进行了封装,以一个ModelAndView对象同时表示两项操作。我们只需要通过设置属性的方式,将需要跳转的视图名称,以及需要展示到前端页面的数据设置到一个ModelAndView对象中即可。
5、将Controller配置到Bean容器中
Controller的作用是代替原先的Servlet接受Http请求,接下来我们需要为这个Controller定义URL映射规则。
我们需要将这个Controller定义到一个Bean容器配置文件中,类似之前Spring部分用到的xml配置文件。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.3.xsd">
<!-- 将映射路径配置为bean的id或name属性即可 -->
<bean id="/hello" class="com.briup.springmvc.web.controller.HelloController" />
</beans>
SpringMVC中存在一个组件叫做HandlerMapping处理器映射器,它的功能是解析容器中配置的Controller,并记录每个Controller的访问路径(id属性)。当请求到达的时候,第一步先由前端控制器接收到。然后再由处理器映射器决定将请求转发至哪个Controller。
<!-- 该配置可有可无,Spring有默认配置 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
6、关于xml配置文件的加载
需要注意的是,我们在Web项目中不需要再自己手动创建ApplicationContext对象读取xml配置文件,前端控制器DispatcherServlet在被Web容器加载的时候就会自动去读xml配置文件。
1、默认配置规则
前端控制器会在启动的时候,默认到WEB-INF
目录下寻找一个名为xxxx-servlet.xml
的配置文件并自动读取它。xxxx指的是web.xml中为DispatcherServlet配置的<servlet-name>
值。
例如,上面的案例中我们为前端控制器命名为SpringMVC,那么我们就需要将容器配置文件命名为SpringMVC-servlet.xml
,并将它放置在WEB-INF
目录下。
2、自定义文件名称和路径
如果不想按照规约创建容器配置文件,或想自己指定文件的存放位置(例如Maven中习惯将配置文件统统放到resources中),则需要通过给DispatcherServlet传入参数的形式告知它配置文件的路径和名称。
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 使用Servlet初始化参数向前端控制器传入配置文件路径 -->
<init-param>
<!-- 参数名为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- 参数值为配置文件路径,classpath代表类加载根路径 -->
<param-value>classpath:spring-web-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
7、提供JSP页面
最后,在webapp下给出hello.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>
</head>
<body>
<h1>Hello, ${username } !</h1>
</body>
</html>
将项目部署至Tomcat,启动服务器并访问:http://localhost:8088/springmvc/hello即可。
思考:
1、通过ModelAndView返回的视图,是内部转发还是重定向跳转?
判定跳转的方式可以通过两种途径:
1)观察浏览器提交请求之后,地址栏中的地址是否发生了变化。
如果是请求转发,则不会发生变化。如果是重定向跳转,会显示重定向之后的第二次请求路径。
2)可以在Controller中向request对象中保存一些数据,尝试到JSP中通过EL表达式获取。
如果能够获取到就说明是请求转发,获取不到就是重定向跳转。
结论:setViewName("/hello.jsp"); 这样的方式使用的请求转发的方式。
想要控制跳转方式使用请求转发还是重定向很简单,只需要在视图名前面加上特定的标记即可:
setViewName(“forward:/hello.jsp”); //
forward:
就代表请求转发setViewName(“redirect:/hello.jsp”); //
redirect:
就代表重定向到该路径如果视图名前面没有加这个前缀,默认是服务器内部跳转。
注意:重定向跳转的时候,视图名不需要添加上下文环境。
2、通过ModelAndView设置的参数值,是保存在哪个作用域中的?
在ModelAndView中通过addObject()添加的参数信息,能够在JSP中通过EL表达式获取到。
那就说明addObject()其本质就是向某个作用域中添加数据。
如果采用的是服务器内部跳转,那么addObject()就相当于向requestScope中添加参数信息。
如果采用的重定向跳转,那么在执行重定向的时候,会把addObject()添加的数据作为请求参数附带到下一次请求中。
四、关于前端控制器的拦截路径
上述案例中,我们为前端控制器配置的拦截路径如下:
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
"/"
代表拦截所有请求。
但是这样的配置方式会存在一个问题,导致项目中的静态资源无法访问。也就是说,这样配置的话就只能访问到所有的Controller了。因为前端控制器本身不会对静态资源请求作出任何响应。
想要解决这一问题,可以采用下列几种策略:
1)自定义拦截请求的后缀名
像之前做项目那样,为所有的Servlet都设置一个固定的请求后缀。例如:*.do
、*.action
等。
这是最传统的方式,最简单也最实用(因为前端控制器只需要拦截动态请求)。不会导致静态文件被拦截。
弊端:
Controller的后缀只能固定成某一个
将来不便于实现REST风格的访问
2)拦截所有请求
仍然采用之前的方法:<url-pattern>/</url-pattern>
此处需要特别强调的是:配置中使用的是/
,而不是/*
。如果使用/*
,那么请求时可以通过DispatcherServlet转发到相应的Controller中,但是Controller返回的时候,如果返回的是jsp还会再次被拦截。这样导致404错误,即访问不到jsp。
拦截/
的利弊:
好处:将来容易实现REST风格架构。
弊端:会导致静态文件(jpg、js、css)被拦截后不能正常显示。
解决方式一:利用Tomcat的defaultServlet来处理静态文件
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
或者:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
<url-pattern>*.js</url-pattern>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
特点:
1、要配置多个,每种文件配置一个。
2、必须定义在DispatcherServlet的前面(和tomcat版本有关),让defaultServlet先拦截请求, 这样请求就不会进入Spring了。
3、高性能。
解决方式二: 使用<mvc:resources>
标签,例如:
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
mapping:映射
两个*,表示映射指定路径下所有的URL,包括子路径
location:本地资源路径
这样如果有访问/images或者/js或者/css路径下面的资源的时候,spring就不会拦截了
解决方式三: 使用<mvc:default-servlet-handler/>
标签
在spring配置文件中加入此标签配置即可。
五、了解其他常用组件
1、视图解析器
如果我们返回的所有视图都有固定的路径前缀,以及固定的格式后缀(例如都是html或都是jsp),就可以使用视图解析器来简化视图名的定义。
在Controller中返回的视图名称其实不是一个真正的路径,而是一个逻辑视图名。
逻辑视图名:不是真正的视图名称,需要经过特殊的加工处理才能转换成真正的物理视图名。
现在能够这样访问到页面只是因为默认的视图解析器默认拼接的前缀和后缀都是""
。
mav.setViewName("/hello.jsp");
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/page/"/>
<property name="suffix" value=".jsp"/>
</bean>
定义了上述内容之后,就代表所有返回的视图都固定在/WEB-INF/page/
路径下,并且后缀固定为.jsp
。
假设有文件路径为:/WEB-INF/page/index.jsp
那么我们在Controller中为返回的ModelAndView对象设置视图名时,就可以只设置视图名为index即可。
2、Spring提供的编码过滤器
<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>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
// 该方法功能和Filter接口中的doFilter相同,在上层父类中已经实现了的doFilter中调用了子类自己定义的方法
// 当请求到到达的时候处理过滤过程的方法
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 获取当前用户设置的编码格式
// 该编码格式我们通过web.xml中<init-param>元素传入
String encoding = getEncoding();
// 如果用户没有指定编码格式,过滤器失效,相当于没有配置,直接放行
if (encoding != null) {
// 如果用户设置了强制设置编码,或者当前请求没有被设置过编码,才会设置编码
// 反之,只有当用户没有要求强制设置,并且当前request对象已经被设置过了编码的时候
// 字符编码过滤器才会失效
if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
// 过滤器不会每次都为response设置编码格式
// 只有当用户设置了forceEncoding生效的时候,响应才会被设置编码
if (isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
// 请求放行
filterChain.doFilter(request, response);
}
3、视图控制器
实际项目开发中,我们考虑到资源文件的隐私性和安全性,往往会把它们放到对客户端不可见的WEB-INF目录下。但是这样一来,浏览器就无法通过常规的方式直接访问到这个页面,所以我们必须编写控制器来为客户端返回这些资源。例如:
// 该控制器不处理业务相关的请求,它的功能就是通过服务器内部跳转的方式为用户返回WEB-INF下的资源
public class ToRegisterPageController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView();
mav.setViewName("register");
return mav;
}
}
这样一来,虽然解决了问题,但是新的问题出现了:我们需要给每一个页面都单独编写一个这样的控制器,而每个控制器中的结构和代码又没有太大的区别,所以这样大大增加了代码的臃肿程度。
针对这一问题,SpringMVC中提供了一种专门用来返回视图的控制器叫做ViewController视图控制器。我们无需将这个类定义出来,只需要在容器文件中进行简单的配置,即可达到和上面的Controller类相同的效果。
<mvc:view-controller path="/register" view-name="register"/>
上述配置的含义是,当接收到/register
这一请求时,直接以内部跳转的形式返回一个名称为"register"
的视图。
注意:这里定义的view-name是逻辑视图名,还需要经过视图解析器的解析,所以不要加前缀和后缀。
六、基于注解的Controller
前面Spring的案例中,我们最终使用了很多注解代替掉了XML中繁琐的配置,尤其是Bean的声明。
在SpringMVC中,我们也可以通过注解的方式来配置一个Controller。
定义Controller类如下:
@Component("/annotation")
public class AnnotationController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView();
mav.setViewName("xxxxx");
return mav;
}
}
我们可以使用@Component注解,来代替xml中一个<bean>
的声明。
注解中的参数"/annotation"
用来定义该Bean在容器中的名称,用来代替xml中<bean>
的id属性,代表Controller的拦截路径。
注意,我们还需要在容器配置文件中定义扫描@Component及相关注解的包:
<context:component-scan base-package="com.briup.springmvc.web.controller"/>
上述配置方式其实还和SpringMVC没有任何的关系。因为我们只是以Spring IoC容器的角度,将一个bean从xml配置改为了注解配置而已。
另外,@Component只是一个最基础的用于注册Bean的注解。实际开发中,我们会使用以下三种注解代替它:
- @Controller,Web层组件、控制器
- @Service,Service层组件
- @Repository,Dao层组件
实际上,他们的作用和@Component基本相同,使用上述三个注解只是为了更好地说明组件的用途,增强语义性和可读性。
上述三个注解本身都添加了@Component注解,所以所有添加了上述三个注解的类,也都相当于添加了@Component注解。
七、自定义处理器
之前使用的实现Controller接口只是最基本的一种方法,这种方法会受到很多局限:
- 一个Controller只能处理一个方法用来处理请求
- 参数只能固定接受HttpServletRequest和HttpServletResponse
- 返回值固定为ModelAndView
- ……
由于实现接口,我们必须接受上述种种限制。但这样一来,Controller就和我们之前用过的Servlet没什么区别了。
SpringMVC中支持自定义处理器(即Controller)。
具体表现为:任何一个Java类都可以充当一个Controller。
并且,有了注解的支持,就无需再实现Controller接口。
我们可以在一个类中定义多个方法,每个方法都可以单独配置一个拦截路径,处理一种请求。
一个简单的案例:
@Controller
public class CustomerController {
@RequestMapping("/userLogin")
public void loginAction() {
System.out.println("接收到用户登录请求...");
}
@RequestMapping("/userRegister")
public void registerAction() {
System.out.println("接收到用户注册请求...");
}
}
@Controller注解拥有@Component的功能,代表将当前类的实例注册到Bean容器中。
@RequestMapping用来配置当前方法的映射路径。
上述方式需要由以下配置支持:
<!-- 开启注解配置Controller功能 -->
<mvc:annotation-driven />
<!-- 定义扫描包路径 -->
<context:component-scan base-package="com.briup.springmvc.web"/>
@RequestMapping也可以定义在Controller上,例如:
@Controller
@RequestMapping("/user")
public class CustomerController {
@RequestMapping("/login")
public void loginAction() {
System.out.println("接收到用户登录请求...");
}
@RequestMapping("/register")
public void registerAction() {
System.out.println("接收到用户注册请求...");
}
}
@RequestMapping如果定义在Controller类上,就代表为当前类中所有方法定义了固定的路径前缀。
访问路径:
http://localhost:8088/springmvc/user/login
http://localhost:8088/springmvc/user/register
八、自定义Controller中方法的定义
在自定义的Controller类中,由于不需要实现接口,所有方法的方法名、返回值、参数都由我们自己来定义。
1、返回值定义
自定义Controller中处理方法的返回值决定了返回给浏览器的响应内容。可以有以下几种定义形式:
1)返回ModelAndView,和之前一样
2)返回String类型
String类型的返回值表示跳转的逻辑视图名字。模型可以通过参数传过来。
@RequestMapping("/home")
public String home(Model model){
model.addAttribute("msg", "hello world");
return "index";
}
3)定义为void
没有返回值则代表不通过返回值声明跳转,我们必须手动返回响应。
如果需要使用Request和Response(或其中任何一个),直接将其定义在方法参数列表即可。
@RequestMapping("/home")
public void home(HttpServletRequest request,HttpServletResponse response){
String username = request.getParameter("username");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("hello world! "+username);
//或者使用servlet的方式进行跳转/重定向
}
九、@RequestMapping中的URL路径映射规则
1、普通URL路径映射
声明的URL路径是一个定值,每次需要按照固定内容进行访问。
-
@RequestMapping(value="/test")
-
@RequestMapping("/hello")
注解中只出现一个参数且参数名为value的话,可以将参数名去掉
-
@RequestMapping(value={"/test", “/user/hello”})
多个URL路径可以映射到同一个处理器的功能处理方法。
2、URI模板模式映射
-
@RequestMapping(value="/users/{userId}")
{XXX}是一个占位符,请求的URL可以是"/users/123456"或"/users/abcd"等等。
之后可以通过@PathVariable可以提取URI模板模式中的{XXX}中的值
-
@RequestMapping(value="/users/{userId}/create")
这样也是可以的,请求的URL可以是"/users/123/create"等。
-
@RequestMapping(value="/users/{userId}/topics/{topicId}")
这样也是可以的,请求的URL可以是"/users/123/topics/123"。
3、Ant风格的URL路径映射
-
@RequestMapping(value="/users/**")
可以匹配"/users/abc/abc"。但"/users/123"将会被URI模板模式映射中的"/users/{userId}"模式优先映射到。
-
@RequestMapping(value="/product/?")
可匹配"/product/1"或"/product/a",但不匹配"/product"或"/product/aa";
?
代表有且只有一个字符 -
@RequestMapping(value="/product*")
可匹配"/productabc"或"/product",但不匹配"/productabc/abc";
*
代表0~n个字符 -
@RequestMapping(value="/product/*")
可匹配"/product/abc",但不匹配"/productabc";
4、正则表达式风格的URL路径映射
从Spring3.0 开始支持正则表达式风格的URL路径映射,格式为{变量名:正则表达式},之后通过@PathVariable可以提取{XXX:正则表达式匹配的值}中的XXX这个变量的值。
- @RequestMapping(value="/products/{categoryCode:\d+}-{pageNumber:\d+}")
可以匹配"/products/123-1",但不能匹配"/products/abc-1",这样可以设计更加严格的规则 - @RequestMapping(value="/user/{userId:^\d{4}-[a-z]{2}$}")
可以匹配"/user/1234-ab"
注意:\d表示数字,但是\在java的字符串中是特殊字符,所以需要再加一个\进行转义即可
括号内:
[abc] 查找方括号之间的任何字符。
[^abc] 查找任何不在方括号之间的字符。
[0-9] 查找任何从 0 至 9 的数字。
[a-z] 查找任何从小写 a 到小写 z 的字符。
[A-Z] 查找任何从大写 A 到大写 Z 的字符。
[A-z] 查找任何从大写 A 到小写 z 的字符。
(red|blue|green) 查找任何指定的选项。
元字符:
. 查找单个任意字符,除了换行和行结束符.如果要表示.这个字符,需要转义
\w 查找单词字符。 字母 数字 _
\W 查找非单词字符。非 字母 数字 _
\d 查找数字。
\D 查找非数字字符。
\s 查找空白字符。
\S 查找非空白字符。
\b 匹配单词边界。
\B 匹配非单词边界。
\0 查找 NUL 字符。
\n 查找换行符。
\f 查找换页符。
\r 查找回车符。
\t 查找制表符。
\v 查找垂直制表符。
量词:
n+ 匹配任何包含至少一个 n 的字符串。
n* 匹配任何包含零个或多个 n 的字符串。
n? 匹配任何包含零个或一个 n 的字符串。
n{X} 匹配包含 X 个 n 的序列的字符串。
n{X,Y} 匹配包含 X 到 Y 个 n 的序列的字符串。
n{X,} 匹配包含至少 X 个 n 的序列的字符串。
n$ 匹配任何结尾为 n 的字符串。
^n 匹配任何开头为 n 的字符串。
?=n 匹配任何其后紧接指定字符串 n 的字符串。
?!n 匹配任何其后没有紧接指定字符串 n 的字符串。
正则表达式风格的URL路径映射是一种特殊的URI模板模式映射
URI模板模式映射不能指定模板变量的数据类型,如是数字还是字符串;
正则表达式风格的URL路径映射,可以指定模板变量的数据类型,可以将规则写的相当复杂。
十、请求方法映射限定
一般获取数据为GET请求方法,提交表单一般为POST请求方法。但之前URL路径映射方式对任意请求方法都是接受的,因此我们需要某种方式来告诉相应的功能处理方法只处理如GET方式的请求或POST方式的请求。
-
@RequestMapping(value="/user/{userId:\d+}",method=RequestMethod.GET)
可以匹配"/user/100",并且请求方式只能是GET
-
@RequestMapping(value="/hello", method={RequestMethod.POST,RequestMethod.GET})
可以匹配"/hello",并且请求方式只能是POST或者GET
注意:
1、一般浏览器只支持GET、POST请求方法,如想浏览器支持PUT、DELETE 等请求方法只能模拟。(jquery中的ajax函数可以发送这些方式的请求)
2、除了GET、POST,还有HEAD、OPTIONS、PUT、DELETE、TRACE(观察servlet源码也可获知)
3、DispatcherServlet默认开启对GET、POST、PUT、DELETE、HEAD 的支持;
4、如果需要支持OPTIONS、TRACE,请添加DispatcherServlet 在web.xml 的初始化参数:dispatchOptionsRequest 和dispatchTraceRequest 为true。(查看源码,在DispatcherServlet的父类中可以找到这两个属性)
十一、请求参数映射限定
1、请求数据中有指定参数名
@RequestMapping("/test")
@Controller
public class HomeController {
@RequestMapping(params="create",method=RequestMethod.GET)
public ModelAndView test1(){
return null;
}
@RequestMapping(params="create",method=RequestMethod.POST)
public ModelAndView test2(){
return null;
}
}
可以匹配的路径为:/test?create=xxx。
如果是get 方式的请求则访问test1方法,如果是post方式的请求则访问test2方法
2、请求数据中没有指定参数名
@RequestMapping(params="!create", method=RequestMethod.GET)
3、请求数据中指定参数名=值
@RequestMapping(params=“username=tom”)
4、请求数据中指定参数名!=值
@RequestMapping(params=“username!=tom”)
username参数名可以不出现,但是如果出现了,那么参数值一定不能等于tom。
5、组合使用是"且"的关系
@RequestMapping(params={“create”,“username=tom”})
十二、自定义Controller中方法可以定义的参数
注意:下面这些参数都可以在功能处理方法中直接声明并且没有指定顺序,spring会自动注入的
1、请求和响应对象
ServletRequest/HttpServletRequest 和 ServletResponse/HttpServletResponse
SpringWebMVC框架会自动帮助我们把相应的Servlet请求/响应作为参数传递过来。
2、输入流和输出流对象
InputStream/OutputStream 和 Reader/Writer
分别对应的是:
- request.getInputStream()
- response.getOutputStream()
- request.getReader()
- response.getWriter()
注意:InputStream/OutputStream 和 Reader/Writer两组不能同时使用,只能使用其中的一组。
3、Session对象
public String session(HttpSession session) {
System.out.println(session);
return "success";
}
4、请求参数
我们可以直接将想要获取的请求参数,按照其名称定义在方法参数列表中,不需要通过request获取。
@RequestMapping("/login")
public String loginAction(String username, String password) {
System.out.println(username + "," + password);
return "index";
}
注意:请求参数名必须与方法参数列表中的形参名一致才能自动匹配。
如果不一致可以使用@RequestParam指定参数名。
@RequestMapping("/login")
public String loginAction(@RequestParam("username") String s1,
@RequestParam("password") String s2) {
System.out.println(s1 + "," + s2);
return "index";
}
5、自动封装的Pojo
@RequestMapping("/login")
public String loginAction(User user) {
System.out.println(user);
return "index";
}
我们可以在请求参数列表中定义一个自定义的Pojo对象。当请求到来的时候,SpringMVC会自动将请求参数与Pojo类型对象的属性相匹配,尽可能地为我们封装一个Pojo对象出来。