1.2(Spring MVC学习笔记) Spring MVC核心类及注解
一、DispatcherServlet
DispatcherServlet在程序中充当着前端控制器的作用,使用时只需在web.xml下配置即可。
配置格式如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <display-name>SpringMVC</display-name> <!-- 配置前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class > org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- 初始化时加载配置文件,该配置文件是在src目录下创建的。 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-config.xml</param-value> </init-param> <!-- 当前servlet与容器一起加载 --> <load-on-startup>1</load-on-startup> </servlet> <!-- 所有请求都会被前端控制器拦截--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
其中<init-param>和<load-on-startup>是可选项.
如果<init-param>配置了xml文件的路径,则容器加载时会去指定路径加载文件。
如果没有配置则会在WEB-INF目录下选择命名格式为servletName-servlet.xml的文件。
servletName是我们配置的前端控制器的<servlet-name>,本例为springmvc,则会寻找springmvc-servlet.xml。
<load-on-startup>配置为1,代表当前Servlet在容器启动时加载。
如果没有配置,则在请求该Servelt时才对其进行加载。
二、Controller注解
在控制类可以通过实现Controller接口,也可以通过注解来实现。
通过注解实现只需要在控制类上添加@Controller注解即可。
添加注解后再xml中可通过扫描语句进行扫描。
扫描语句:<context:component-scan base-package = "指定包" />
三、RequestMapping注解
3.1Spring通过@Controller注解找到控制器类后,还需将请求映射到具体的处理程序。
RequesMapping注解就是用于映射请求。
例如:
public class FirstController{ @RequestMapping(value = "/firstController") public String handleRequest(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
上例中间/firstController这个请求映射到handleRequest方法。
在浏览器地址栏输入localhost:8080/SpringMVC/firstController就可以了调用handleRequest方法。
@RequestMapping注解也可以映射到类上。
@RequestMapping(value = "/hello") public class FirstController{ @RequestMapping(value = "/firstController") public String handleRequest(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
映射在类上时,要想访问类中的方法必须加上类的映射请求路径。
例如想访问handleRequest方法,完整路径为:localhost:8080/SpringMVC/hello/firstController
value属性除了上述直接表示一个固定路径外,还有以下写法:
3.2指定变量和值 {变量}
例如
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping(value = "/hello") public class FirstController{ @RequestMapping(value = "/firstController/{id}")//指定变量 public String handleRequest(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub System.out.println("into mv"); System.out.println(id); model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
在地址栏输入loaclhost:8080/SpringMVC/hello/firsstController/xx,才能访问指定路径所映射的方法。
而xxx可以被@pathVariable String id 中的id获取,形参名xx和路径{xx}中的名称要一致。如果没有/xxx则出现404页面。
3.3指定变量和正则表达式 ({变量:正则表达式})
例如将RequestMapping改为:@RequestMapping(value = "/firstController/{id:\\d}")
\\代表\,正则\d中\d代表0-9任意一个数字,这样配置后:
/firstController/0-9任意一个数字可以访问成功(注意是一个数字,多个不符合条件),且可以通过@pathVariable获取id的值。
/firstController/0-9之外的字符或多个数字(大于1个),访问失败,出现404页面。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping(value = "/hello") public class FirstController{ //末尾加上任意一位数字访问成功,反正失败 @RequestMapping(value = "/firstController/{id:\\d}") public String handleRequest(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub System.out.println("into mv"); System.out.println(id); model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
访问失败:
访问成功:
RequestMapping中还有一个属性method,用于指定处理何种类型的请求方法。
例如@RequestMapping(value = "/firstController/{id:\\d}" ,method = RequestMethod.POST)处理POST类型的请求
@RequestMapping(value = "/firstController/{id:\\d}" ,method = RequestMethod.GET)处理GET类型的请求
我们来看一个例子
@Controller @RequestMapping(value = "/hello") public class FirstController{ @RequestMapping(value = "/firstController/{id:\\d}" ,method = RequestMethod.POST)//处理POST类型请求 public String handleRequest(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub System.out.println("into mv"); System.out.println(id); model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
我们将方法设置为处理POST类型请求,使用GET类型的请求去访问会出现不支持GET类型的请求方法。
method可以设置多个值,中间用“,”隔开@RquestMapping(method = {xxx.GET,xx.xPOST})
Spring4.3中又引入了组合注解,例如上例中的@RequestMapping(method = Request.GET)可以简化为:
GetMapping(),从字面上可以看出这个注解是包含了GET和Mapping。处理Get类型的请求映射。
除此之外,还有一些组合注解:
PostMapping,PutMapping,DeleteMapping,PatcherMapping.
params属性:指定请求中必须包含、不包含某些参数、或者指定某些参数名和值要对应,才能被当前方法处理。
例如params = {"name"} 代表请求中要包含name参数。例如:localhost:8080/SpringMVC/hello/firstController/1?name=hcf;
这样的就可以正确访问指定的方法,反之不行。
params={“!name”}代表请求中不包含name参数可以正确访问,反正不行。
params={"name = hcf"},代表请求参数name要和指定的值匹配才可以正常访问,反正不行。例如
localhost:8080/SpringMVC/hello/firstController/1?name=hcf;可以访问,
localhost:8080/SpringMVC/hello/firstController/1?name=h;就不能访问。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping(value = "/hello") public class FirstController{//请求参数name为“hcf”才能访问 @RequestMapping(value = "/firstController/{id:\\d}" ,method = {RequestMethod.POST,RequestMethod.GET},params = {"name=hcf"}) public String handleRequest(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub System.out.println("into mv"); System.out.println(id); model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
访问成功:
访问失败:
四、请求处理方法类型和返回值。
支持的请求参数类型
Request or response objects (Servlet API).
Session object (Servlet API)
org.springframework.web.context.request.WebRequest
or org.springframework.web.context.request.NativeWebRequest
java.util.Locale
java.util.TimeZone
(Java 6+) / java.time.ZoneId
(on Java 8)
java.io.InputStream
/ java.io.Reader
java.io.OutputStream
/ java.io.Writer
org.springframework.http.HttpMethod
java.security.Principal
@PathVariable
@RequestParam
@RequestHeader
@RequestBody
@RequestPart
@SessionAttribute
@RequestAttribute
HttpEntity<?>
java.util.Map
/ org.springframework.ui.Model
/ org.springframework.ui.ModelMap
org.springframework.web.servlet.mvc.support.RedirectAttributes
org.springframework.validation.Errors
/ org.springframework.validation.BindingResult
org.springframework.web.bind.support.SessionStatus
org.springframework.web.util.UriComponentsBuilder
这些是方法参数支持的类型,
例如上例中的:
public String handleRequest(@PathVariable String id ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exce
参数类型都是受支持的参数类型。
支持的返回类型:
上例子中的返回值为“first”,返回字符串被解释为逻辑视图名。
(返回first对应为/WEB-INF/jsp/first.jsp,这是因为在视图解析器中设置了前缀和后缀,后续会有具体使用方法)
五、视图解析器(ViewResolver)
视图解析器将DispatcherServlet中的view参数传递给视图解析器,视图解析器将解析的视图传递给DispatcherServlet。
在视图解析中,可以设置前缀和后缀。
例如我们设置前缀为“/WEB-INF/jsp/”,后缀设置为“.jsp”。
以前面的Controller类为例,Controller执行完后将“first”返回给HandlerAdapter,然后返回DispathcerServlet。
DispatcherServlet将“first”交给视图解析器,视图解析器将“first”添加前缀和后缀,变成“/WEB-INF/jsp/first.jsp”.
然后解析指定路径视图将视图返回给DispatcherServlet。
我们来看下前缀与后缀的具体设置:
<bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 视图解析器--> <!--设置前缀--> <property name="prefix" value = "/WEB-INF/jsp/"></property> <!--设置后缀--> <property name="suffix" value = ".jsp"></property> </bean>
最后结合上述,使用注解实现SpringMVC
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <display-name>SpringMVC</display-name> <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> <!-- 配置前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class > org.springframework.web.servlet.DispatcherServlet </servlet-class> <!-- 初始化时加载配置文件,该配置文件是在src目录下创建的。 --> <!-- <init-param> 该选项不配做会自动寻找WEB-INF下名为springmvc-servlet.xml的文件。--> <!-- <param-name>contextConfigLocation</param-name>--> <!-- <param-value>classpath:springmvc-config.xml</param-value>--> <!--</init-param>--> <!-- 当前servlet与容器一起加载 --> <load-on-startup>1</load-on-startup> </servlet> <!-- 所有请求都会被前端控制器拦截--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
Controller类
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping(value = "/hello") public class FirstController{ @RequestMapping(value = "/firstController/{id:\\d}" ,method = {RequestMethod.POST,RequestMethod.GET},params = {"name=hcf"}) public String handleRequest(String name ,HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { // TODO Auto-generated method stub System.out.println("into mv"); name = request.getParameter("name"); System.out.println(name); //返回类型为String会被解释为逻辑视图名View就解决了。 //Model交由Model对象来完成。 model.addAttribute("msg", "hello SpringMVC"); return "first"; } }
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:context="http://www.springframework.org/schema/context" 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"> <!-- 开启扫描 --> <context:component-scan base-package = "com.springmvc.firstmvc"></context:component-scan> <!-- 配置处理器(Handle),映射/firstController请求 (Controller类),已由注解完成--> <!-- <bean name = "/firstController" class = "com.springmvc.firstmvc.FirstController"/> --> <!-- 配置映射处理器(handlerMapping) 将处理器(Handle)的name作为url进行查找(Spirng4.0以后无需配置) --> <!-- 配置适配处理器(HandlerAdapter) 适配处理器会调用处理器(Handle)即FirstController类(Spirng4.0以后无需配置) --> <!-- 处理器会返回一个ModelAndView,适配处理器将返回的ModelAndView交给前端控制器去处理了 --> <!-- 前端控制器根据ModelAndView中的View选择一个视图解析器(ViewReslover) --> <!-- 前端控制器将Model(msg "hello SpringMVC")填充进视图解析器返回的视图,用户看到最后页面 --> <!-- 设置视图处理器及其前缀后缀 --> <bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value = "/WEB-INF/jsp/"></property> <property name="suffix" value = ".jsp"></property> </bean> <!-- 视图处理器解析后会将视图传递给前端控制器,前端控制对View进行渲染(将模型数据填入视图) --> <!-- 渲染结果会返回客户端浏览器显示 --> </beans>
WEB-INF/jsp/first.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> ${msg} </body> </html>
可以看到加载的是springmvc-servlet.xml
如果firstController/后面不是一位数字,或者name不等于hcf都会出现404页面。
完整结构:
参考资料:
SpringFramework/spring-framework-4.3.6.RELEASE/docs/spring-framework-reference/html/mvc.html