SpringMVC RequestMapping 详解
RequestMapping这个注解在SpringMVC扮演着非常重要的角色,可以说是随处可见。它的知识点很简单。今天我们就一起学习SpringMVC的RequestMapping这个注解。文章主要分为两个部分:RequestMapping 基础用法和RequestMapping 提升用法。
准备工作
pom.xml 这里是需要的jar包和相关的配置。这里设置了maven-compiler-plugin的java版本为1.7,避免打包出错和中文乱码的问题。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
com.springmvc
springmvc
0.0.1-SNAPSHOT
war
maven-compiler-plugin
1.7
1.7
UTF-8
4.1.3.RELEASE
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-aop
${spring.version}
org.springframework
spring-core
${spring.version}
org.springframework
spring-web
${spring.version}
javax.servlet
javax.servlet-api
4.0.0
provided
web.xml 设置字符拦截器,避免中文乱码
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_3_0.xsd"
id="WebApp_ID" version="3.0">
springmvc
dispatcher
org.springframework.web.servlet.DispatcherServlet
1
dispatcher
/
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encodingFilter
/*
SpringMVC的配置文件(dispatcher-servlet.xml)没有变,这里就不再贴出来了。可以去上一章找
RequestMapping 基础用法
核心类 ApiStudyController,这是重点需要看的java文件。里面主要介绍了@RequestMapping 的基础用法。
你需要重点学习的有: 获取请求参数值的@RequestParam注解;通过占位符获取参数值的@PathVariable注解;指定请求方式的method属性;用于将数据存储到作用域中返回给前端的Map,Model和ModelMap参数;以及如何使用POJO对象作为方法的参数。
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("apiStudy")
public class ApiStudyController {
private static final String SUCCESS = "apistudy";
private static final String RESULT_KEY = "result";
/**
* 常用知识点:在类或者方法上使用 @RequestMapping 注解
* 若没有修饰类,则访问路径是: http://ip:port/项目名/方法的@RequestMapping值
* 若类有修饰类,则访问路径是: http://ip:port/项目名/类的@RequestMapping值/方法的@RequestMapping值
*/
/**
* 方法中用map作为参数,可以将数据存储到request作用域中,放回到页面上。
* 同样用法的有 Model 类型 和 ModelMap 类型
*/
@RequestMapping("/testMapResult")
public String testMapResult(Map map, Model model, ModelMap modelMap){
String apiDocs = "Map,Model,ModelMap (常用方法) : 在方法中添加Map的参数,可以将数据放到request 作用域中!";
map.put(RESULT_KEY, apiDocs);
model.addAttribute("model", "Model");
modelMap.addAttribute("modelMap", "ModelMap");
return SUCCESS;
}
/**
* 常用知识点:使用 method 属性来指定请求方式
* 若用GET方式请求,会提示:HTTP Status 405 - Request method 'GET' not supported 错误信息
*/
@RequestMapping(value = "/testRequestMethod", method=RequestMethod.POST)
public String testRequestMethod(Map map) {
String apiDocs = "RequestMethod (常用方法) : 若设置只有POST请求才能进入,则用GET方式请求,会报405的错误。反之亦然!";
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 常用知识点:使用注解 @PathVariable 映射 URL绑定占位,属于REST风格。
* 注意两点:
* 1. 严格用法: @PathVariable("arg") String arg; 前一个arg参数,必须要和占位参数{arg}保持一致。后面一个arg参数可以自定义。
* 2. 偷懒用法: @PathVariable String arg; 这里的参数名 arg 必须要和占位参数{arg}保持一致,不然会提示400的错误
*/
@RequestMapping("/testPathVariable/{arg}")
public String testPathVariable(@PathVariable("arg") String arg, Map map) {
String apiDocs = "PathVariable (常用方法) : 通过映射 URL绑定占位获取的值是 " + arg;
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 常用知识点:使用注解 @RequestParam 来映射请求参数
* 该注解有三个参数,
* value 请求的参数名,
* required 请求的参数是否必填 ,默认是true,
* defaultValue 请求的参数默认值.
* 参数的类型建议是封装数据类型,因为float默认值是0.0 ,若该参数是非必填,则会报错 HTTP Status 500
*/
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("account") String account,
@RequestParam(value="password", required=true) String password,
@RequestParam(value="price", required=false, defaultValue="0.0") float price,
Map map) {
String apiDocs = "RequestParam (常用方法) : 获取映射请求参数的值有 account : " + account + " password : " + password + " price : " + price;
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 常用知识点:方法参数是POJO对象
* 前端的请求参数名一定要和POJO对象属性一致。支持级联
*/
@RequestMapping(value = "/testPojo", method = RequestMethod.POST)
public String testPojo(User user, Map map) {
map.put(RESULT_KEY, user);
return SUCCESS;
}
/**
* 不常用方法:params 和 headers
* @RequestMapping 注解中,除了常用的value和method外,还有两个较为常用的params和headers
* 他们可以是请求跟精确,制定那些参数的请求不接受,同时也可以指定那些参数的请求接收。
* params={param1,param2}
* param1 表示 请求必须包含名为param1的请求参数
* !param1 表示 请求不能包含名为param1的请求参数
* param1!=value1 表示请求包含param1的请求参数,但是其值不能是value1
*/
@RequestMapping(value="/testParamsAndHeaders", params={"itdragon"},
headers = { "Accept-Language=zh-CN,zh;q=0.8" })
public String testParamsAndHeaders(Map map) {
String apiDocs = "params,headers (了解用法) : 这里表示当请求参数中包含了itdragon的时候才能进来";
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 不常用方法:ant风格
* ?匹文件名中一个字
* *匹文件名中任意字
* ** 匹多 层径
*/
@RequestMapping("/*/testAntUrl")
public String testAntUrl(Map map) {
String apiDocs = "Ant风格 (了解用法) : ?匹文件名中一个字 ; *匹文件名中任意字 ; ** 匹多 层径 ";
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 不常用方法:@RequestHeader 注解获取请求头数据。
*/
@RequestMapping("/testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept-Language") String al,
Map map) {
String apiDocs = "@RequestHeader (了解用法) : 获取请求头数据的注解, 如Accept-Language 的值是 : " + al;
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
/**
* 不常用方法:@CookieValue: 映射一个 Cookie值
*/
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String sessionId,
Map map) {
String apiDocs = "@CookieValue(了解用法) : 映射一个 Cookie值的注解, 如JSESSIONID 的Cookie值是 : " + sessionId;
map.put(RESULT_KEY, apiDocs);
return SUCCESS;
}
}
用于测试的前端页面 index.jsp
pageEncoding="UTF-8"%>
SpringMVC 快速入门@RequestMapping 注解基本用法
史上最丑的HelloWorld
Map,Model,ModelMap的使用方法
用GET请求方式测试POST方法
@PathVariable获取占位数据
@RequestParam获取请求参数值
account:
level:
salary:
params 和 headers用法
Ant风格URL请求
@RequestHeader 注解获取请求头数据
@CookieValue 注解获取 Cookie值
方便查看结果的apistudy.jsp页面
pageEncoding="UTF-8"%>
SpringMVC 快速入门@RequestMapping 注解基本用法
request 作用域 :
${requestScope.result}
${requestScope.model}
${requestScope.modelMap}
session 作用域 :
${sessionScope.result}
最后是两个用于测试的POJO对象,分别是User和Position
public class User {
private Integer id;
private String account;
private String password;
private Position position;
public User() {
}
public User(Integer id, String account, String password) {
this.id = id;
this.account = account;
this.password = password;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
this.position = position;
}
@Override
public String toString() {
return "User [id=" + id + ", account=" + account + ", password=" + password + ", position="
+ position + "]";
}
}
public class Position {
private Integer id;
private String level;
private Double salary;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Position [level=" + level + ", salary=" + salary
+ "]";
}
}
测试的效果图
RequestMapping 提升用法
这里的知识点有:输出模型数据 ModelAndView类型,Map(Model,ModelMap),@ModelAttribute注解,@SessionAttributes注解的使用,和 原生的Servlet Api的使用。
ModelAndView数据类型:见名知意,即包含了模型数据,又包含了视图数据。设置模型数据有两种方式:modelAndView.addObject(String attributeName, Object attributeValue) 方分别表示Key和Value。modelAndView.addAllObjects(modelMap) 存的参数是一个Map(Model,ModelMap其实都是Map数据类型)。
设置视图数据常用方法也有两种方式:
ModelAndView modelAndView = new ModelAndView(viewName) 初始化ModelAndView的时候设置。
modelAndView.setViewName(viewName) 初始化后再she'zh
@ModelAttribute 注解:被该注解修饰的方法, 会在每个目标方法执行之前被 SpringMVC 调用。实际开发中其实用的并不是很多。在我们更新数据的时候,一般都会先查询,后更新。该注解就扮演督促查询的角色,在执行更新的方法前先执行该注解修饰的查询数据方法。
@SessionAttributes 注解:只能修饰在类上,将模型数据暂存到HttpSession中,从而使多个请求的数据共享。常用方法有@SessionAttributes(value={"obj1", "obj2"}, types={String.class, Obj1.class})。表示可以将数据类型是String或者是对象Obj1的模型数据放到HttpSession中。也可以将变量名是obj1,obj2的模型数据放到HttpSession中。用这个注解容易出一个问题。HttpSessionRequiredException 异常,原因在代码注释中。
原生的Servlet Api:如果发现不能引入javax.servlet.* 的文件,可能是因为项目里面中没有servlet-api.jar。
普通项目解决方法:右击项目工程名称 ---> Build Path ---> Configure Build Path... ---> 选择 Libraries 点击 Add External JARS ---> 在按照tomcat的里面下,找到lib目录,里面就有。
Maven项目解决方法:如果按照上面的方法处理,虽然引入文件,当打包的时候会提示"找不到符号",是因为servlet-api.jar 没有真正的加入到classpath下。最简单的方法就是在pom.xml加入servlet-api.jar。
看代码:
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("apiStudy")
@SessionAttributes(value={"user"}, types={String.class})
public class ApiStudyController {
private static final String SUCCESS = "apistudy";
private static final String RESULT_KEY = "result";
/**
* @SessionAttributes 将数据存储到session中,达到多个请求数据共享的目的。
* 只能修饰在类上的注解
* 通过属性名value,指定需要放到会话中的属性
* 通过模型属性的对象类型types,指定哪些模型属性需要放到会话中
*/
/**
* 常用方法:ModelAndView 方法的返回值设置为 ModelAndView 类型。
* ModelAndView 顾名思义,是包含视图和模型信息的类型。
* 其数据存放在 request 域对象中.
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
String viewName = SUCCESS; // 需要返回的视图名
String apiDocs = "ModelAndView(常用方法) : 之前学习的方法返回值是字符串,数据是通过Map返回到前端。现在可以通过ModelAndView类型直接完成。";
ModelAndView modelAndView = new ModelAndView(viewName);
modelAndView.addObject(RESULT_KEY, apiDocs); // 添加数据到model中
return modelAndView;
}
/**
* SpringMVC 确定目标方法 POJO 类型入参的过程
* 第一步: 确定一个 key
* 若方法形如 "testModelAttribute(User user)" , 则key为 user(POJO 类名第一个字母小写)
* 若方法形如"testModelAttribute(@ModelAttribute("userObj") User user)" ,则key为 userObj
* 第二步: 在 implicitModel 中查找 key 对应的对象
* 若 implicitModel 存在, 则作为入参传入
* 若 implicitModel 中不存在, 则检查当前Handler 是否使用 @SessionAttributes 注解
* 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常.
* 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
* implicitModel? SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
*/
@RequestMapping("/testModelAttribute")
public ModelAndView testModelAttribute(User user){
ModelAndView modelAndView = new ModelAndView(SUCCESS);
modelAndView.addObject(RESULT_KEY, "update : " + user); // 添加数据到model中
return modelAndView;
}
/**
* 常用方法:@ModelAttribute 修饰方法。 被该注解修饰的方法, 会在每个目标方法执行之前被 SpringMVC 调用
* 运行流程:
* 第一步: 在执行 testModelAttribute(User user) 方法前,会先执行被@ModelAttribute 注解修饰的方法 getUser()
* 第二步: 执行getUser() 后,将执行放入到Map中,其中的key 必须和目标方法User对象的首字母小写user
* 第三步: SpringMVC 从 Map 中取出 User 对象,然后把对象传入目标方法的参数.
*
* 未使用 @ModelAttribute testModelAttribute方法 打印的信息 :
* update : User [id=1, account=itdragon, password=null, position=null]
* 使用@ModelAttribute testModelAttribute方法 打印的信息 :
* update : User [id=1, account=itdragon, password=zhangdeshuai, position=null]
*/
@ModelAttribute
public void getUser(@RequestParam(value="id",required=false) Integer id,
Map map){
if(id != null){
//模拟从数据库中获取对象
User user = new User(1, "itdragon", "zhangdeshuai");
map.put("user", user); // 这里的key 一定是该对象User的首字母小写user
}
}
/**
* 常用方法:可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型
*
* HttpServletRequest
* HttpServletResponse
* HttpSession
* InputStream
* OutputStream
* Reader
* Writer
*/
@RequestMapping("/testServletAPI")
public void testServletAPI(HttpServletRequest request,
HttpServletResponse response, Writer out) throws IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
out.write("Hello Servlet API,和用Servlet一样(0——0) ;
request : " + request + " ;
response : " + response);
}
}
一样的前端index.jsp
pageEncoding="UTF-8"%>
SpringMVC 快速入门@RequestMapping 注解提升用法
ModelAndView的使用方法
account:
使用原生的Servlet API
两个实体类和查看结果的jsp页面没有变
效果图: