# SpringMVC
# hello world
1.加入Jar包
2.在web.xml中配置DispathcherServlet
3.加入SpringMVC的配置文件
4.编写处理请求的处理器,并标识为处理器
5.编写视图
代码语言:javascript复制<?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_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置DispatcherServlet的一个初始化参数:配置Springmvc配置文件位置和名称-->
<!--
实际上也可以不通过contextConfigLocation来配置SpringMVC的配置文件,而使用默认的。
默认配置文件为:/WEB-INF/<servlet-name>-servlet.xml
-->
<!--
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
代码语言:javascript复制<?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"
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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="top.finen.springmvc"></context:component-scan>
<!--配置视图解析器,如何把handler方法返回值解析为实际的物理视图-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
代码语言:javascript复制package top.finen.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorld {
/**
* 1. 使用 @RequestMapping 注解来映射请求的 URL
* 2. 返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图解析器, 会做如下的解析:
* 通过 prefix returnVal 后缀 这样的方式得到实际的物理视图, 然会做转发操作
*
* /WEB-INF/views/success.jsp
*
* @return
*/
@RequestMapping("helloworld")
public String hello(){
System.out.println("hello world");
return "success";
}
}
# @RequestMapping映射请求
在控制器的类定义以及方法定义出都可以标注
@RequestMapping
-类定义处:提供初步的请求映射信息,相对于WEB应用的根目录。
**-方法处:**提供进一步的细分映射信息,若未定义类标注,则直接标记URL相对于WEB应用的根目录。
DispatcherServlet截获请求后,就通过控制器上@RequestMapping提供的映射信息确定请求所处的处理方法。
代码语言:javascript复制/**
* 1. @RequestMapping 除了修饰方法,还可以修饰类
* 2.
* 1).类定义处:提供初步的请求映射信息,相对于WEB应用的根目录。
* 2).方法处:提供进一步的细分映射信息。
* 相对于类定义处的URL,若类定义处未标注 @RequestMapping,则方法标记处的URL相对于WEB应用的根目录。
* @return
*/
@RequestMapping("/testRequestMapping")
public String testRequestMapping() {
System.out.println("testRequestMapping");
return SUCCESS;
}
/**
* 使用method属性来指定请求方式
* @return
*/
@RequestMapping(value = "/testMethod", method = RequestMethod.POST)
public String testMethod() {
System.out.println("testMethod");
return SUCCESS;
}
# 映射请求参数、请求方法或者请求头
@RequestMapping除了 可以使用请求URL映射请求外,还可以使用请求方法,请求参数以及请求头映射请求。
@RequestMapping的value,method,param以及heads分别表示请求URL,请求方法,请求参数以及请求头的映射条件。他们之间是与的关系。联合使用多个条件可让请求映射更加精确化。
- Ant风格资源地址支持三种匹配符: ?:匹配文件名中一个字符 *:匹配文件中任意字符 ** : ** 匹配多层路径
package top.finen.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/springmvc")
public class SpringMVCTest {
private static final String SUCCESS = "success";
/**
* 1. @RequestMapping 除了修饰方法,还可以修饰类
* 2.
* 1).类定义处:提供初步的请求映射信息,相对于WEB应用的根目录。
* 2).方法处:提供进一步的细分映射信息。
* 相对于类定义处的URL,若类定义处未标注 @RequestMapping,则方法标记处的URL相对于WEB应用的根目录。
* @return
*/
@RequestMapping("testRequestMapping")
public String testRequestMapping() {
System.out.println("testRequestMapping");
return SUCCESS;
}
/**
* 使用method属性来指定请求方式
* @return
*/
@RequestMapping(value = "testMethod", method = RequestMethod.POST)
public String testMethod() {
System.out.println("testMethod");
return SUCCESS;
}
/**
* 了解:使用params和headers来更加精确的映射请求,params和headers支持简单的表达式
* @return
*/
@RequestMapping(value = "testParamsAndHeaders",
params = {"username", "age!=10"},
headers = {"Accept-Language: zh-CN,zh;q=0.9,en;q=0.8"})
public String testParamsAndHeaders() {
System.out.println("testParamsAndHeaders");
return SUCCESS;
}
@RequestMapping("testAntPath/*/abc")
public String testAntPath() {
System.out.println("testAntPath");
return SUCCESS;
}
/**
* @PathVariable 可以来映射URL中的占位符到目标方法的参数中
* @param id
* @return
*/
@RequestMapping("testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id){
System.out.println("testPathVariable" id);
return SUCCESS;
}
}
# REST(资源表现层转化)
资源:网络上的一个实体或者说网络的一个具体信息。URI即为每一个资源的独一无二的识别符。
表现层:把资源具体呈现出来的形式,叫做表现层。
状态转化:如果客户端想要操作服务器,必须通过某种手段,让服务器发生状态转化。HTTP协议中,四个表示操作方式的动词:GET、POST、PUT、DELETE。他们分别是对应四种基本的操作。GET来获取资源。POST来新建资源。PUT来更新资源。DELETE来删除资源。
HiddenHttpMethodFilter:
代码语言:javascript复制/**
* REST 风格的url
* 以CRUD为例:
* 新增: /order POST
* 修改: /order/1 PUT
* 获取: /order/1 GET
* 删除: /order/1 DELETE
* 如何发送PUT请求和DELETE请求
* 1.需要配置HiddenHttpMethodFilter
* 2.需要发送POST请求
* 3.需要在发送POST请求请求时携带一个域name="_method"的隐藏域,值为DELETE或者PUT
*
* 在springmvc的目标方法中如何得到id呢?
* 使用:@PathVariable 注解
* @param id
* @return
*/
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
public String testRest(@PathVariable Integer id) {
System.out.println("testRest GET" id);
return SUCCESS;
}
@RequestMapping(value = "/testRest", method = RequestMethod.POST)
public String testRest() {
System.out.println("testRest POST");
return SUCCESS;
}
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
public String testRestDelete(@PathVariable Integer id) {
System.out.println("testRest DELETE" id);
return SUCCESS;
}
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
public String testRestPut(@PathVariable Integer id) {
System.out.println("testRest GET" id);
return SUCCESS;
}
# 请求处理方法签名
SpringMVC通过分析处理方法的签名,将HTTP请求信息绑定到处理方法的相应入参中。
必要时可以对方法以及方法入参标注相应的注解:@PathVariable @RequestParam @RequestHeader
# 请求参数
代码语言:javascript复制/**
* @RequestParam 来映射请求参数
* value值即为请求参数的参数名
* required 请求参数是否为必须
* defaultValue 请求参数的默认值:默认为true
* @param username
* @param age
* @return
*/
@RequestMapping(value = "testRequestParam")
public String testRequestParam(@RequestParam(value = "username") String username,
@RequestParam(value = "age", required = false) Integer age){
System.out.println("testRequestParam===>" "username: " username " age: " age);
return SUCCESS;
}
代码语言:javascript复制/**
* 映射请求头
* @param al
* @return
*/
@RequestMapping(value = "testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept-Language") String al) {
System.out.println("testRequestHeader===>" al);
return SUCCESS;
}
代码语言:javascript复制/**
* 了解:
* @cookieValue 映射一个cookie值,属性同@RequestParam
* @param sessionId
* @return
*/
@RequestMapping(value = "testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String sessionId){
System.out.println("testCookieValue: " sessionId);
return SUCCESS;
}
# POJO级联属性
代码语言:javascript复制/**
* SpringMVC 会按照请求参数名和POJO属性名进行自动匹配。
* 自动为该对象填充属性值,支持级联属性。如dept.deptId, dept.address.tel
* @param user
* @return
*/
@RequestMapping(value = "testPojo")
public String testPojo(User user){
System.out.println(user);
return SUCCESS;
}
# 使用Servlet API作为入参
原生api:
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale
- InputStream
- OutputStream
- Reader
- Writer
# 处理模型数据
代码语言:javascript复制/**
* 目标方法的返回值可以是 ModelAndView 类型。
* 其中可以包含视图和模型信息
* SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中.
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
String viewName = SUCCESS;
ModelAndView modelAndView = new ModelAndView(viewName);
//添加模型数据到 ModelAndView 中.
modelAndView.addObject("time", new Date());
return modelAndView;
}
Map以及Model
代码语言:javascript复制/**
* 目标方法可以添加 Map 类型(实际上也可以是 Model 类型或 ModelMap 类型)的参数.
* @param map
* @return
*/
@RequestMapping(value = "/testMap")
public String testMap(Map<String, Object> map) {
map.put("name", Arrays.asList("Tom", "Jerry", "Mike"));
return SUCCESS;
}
# SessionAttribute
代码语言:javascript复制/**
* @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),
* 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)
*
* 注意: 该注解只能放在类的上面. 而不能修饰放方法.
*/
@RequestMapping(value = "/testSessionAttributes")
public String testSessionAttributes(Map<String, Object> map){
User user = new User("Tom", "1123", "fine.top@top.com", 15);
map.put("user", user);
return SUCCESS;
}
# ModelAttribute
代码语言:javascript复制/**
* 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用!
* 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
* 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中.
*/
@ModelAttribute
public void getUser(@RequestParam(value = "id", required = false) Integer id,
Map<String, Object> map) {
if (id != null) {
User user = new User("Tom", "123", "ssss@fine.top", 12);
System.out.println(user);
map.put("user", user);
}
}
/**
* 运行流程:
* 1.执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放入到Map中;key为:user
* 2.SpringMVC把Map的中取出User对象,并把表单的请求参数赋给User对象的对应属性
* 3.SpringMVC把上述对象传入目标方法的参数
* 注意:在ModelAttribute修饰的方法中,放入到Map的键需要和目标方法入参类型的第一个小写字母的字符串一致。
*
* SpringMVC确定目标方法POJO类型入参的过程
* 1.确定一个key
* 1).若目标方法的POJO类型的参数没有使用@ModelAttribute作为修饰,则key为POJO类名第一个字母的小写。
* 2).若使用了@ModelAttribute来修饰,则key为@ModelAttribute注解的value属性值。
* 若在@ModelAttribute标记的方法中Map中保存过,且key和1确定的key一致,则会获取到。
* 2.在implicitModel中查找key对应的对象,若存在,则作为入参传入
* 3.若implicitModel不存在key对应的对象,则检查当前的Handler是否使用了@SessionAttribute注解来修饰
* 若使用了该注解,且@SessionAttribute注解的Value属性值中包含了key,则会从HTTPSession中获取key所对应的value值。
* 若存在直接传入目标方法的入参中,若不存在则抛出异常。
* 4.若Handler没有标识@SessionAttribute注解或者@SessionAttribute注解的value值中不包含key,则会通过反射创建POJO类型的参数,传入
* 为目标方法的参数。
* 5.SpringMVC会把key和POJO类型的对象保存到implicitModel中,进而保存到request中。
*
* 源码分析:
* 1.调用@ModelAttribute注解修饰的方法,实际把@ModelAttitude方法中的Map中的数据放在implicitModel中
* 2.解析请求处理器的目标参数,实际上把该目标参数来自于WedDataBinder对象的target属性
* 1).创建WebDataBinder对象
* ① 确定objectName属性:若传入的attrName属性为“”,则objectName为类名第一个字母小写。
* **** 注意:attrName 若目标方法的POJO属性使用了@ModelAttitude来修饰,则attribute值即为@ModelAttitude的value属性值
* ② 确定target属性
* > 在implicitModel中茶盅attrName对应的属性值
* > 若不存在:则验证当前的Handler是否使用了@SessionAttributes进行修饰,若使用了,则尝试从Session中获取attrName所对应的
* 属性值,若session中没有对应的属性值,则抛出异常。
* > 若handler没有使用@SessionAttributes进行修饰,或者@SessionAttribute中没有使用value值指定的键和attrName相匹配。
* 则通过反射进行创建。
* 2).SpringMVC把表单的请求参数赋给了WebDataBinder的target对应到的属性。
* 3).SpringMVC会把WebDataBinder的attrName和target给到implicitModel
* 4).把WebDataBinder的target作为参数传递给目标方法的入参。
*
*
*/
@RequestMapping(value = "testModelAttribute")
public String testModelAttribute(User user){
System.out.println(user);
return SUCCESS;
}
# ViewAndViewResolver
代码语言:javascript复制 @RequestMapping("/testViewAndViewResolver")
public String testViewAndViewResolver(){
System.out.println("testViewAndViewResolver");
return SUCCESS;
}
@RequestMapping("/testView")
public String testView() {
System.out.println("testView");
return "helloView";
}
代码语言:javascript复制 <!--配置转发页面-->
<mvc:view-controller path="/success" view-name="success"></mvc:view-controller>
<!--在实际开发中通常需要配置mvc:annotation-driven-->
<mvc:annotation-driven></mvc:annotation-driven>