常用注解
@RequestParam注解
使用案例:
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
defaultValue:表示默认值,如果不传递值
第一步:创建anno.jsp
<body>
<h3>RequestParam入门案例</h3>
<a href="anno/testRequestParam?name=哈哈&age=22">RequestParam</a>
</body>
第二步:创建AnnoController.java
@Controller
@RequestMapping(path = "/anno")
public class AnnoController {
// 请求参数
@RequestMapping(path = "/testRequestParam")
public String testRequestParam(@RequestParam(value = "name") String username,
@RequestParam(value="age",required = true)Integer age){
System.out.println("Hello SpringMVC!!,测试@RequestParam");
System.out.println(username);
System.out.println(age);
return "success";// 响应结果
}
}
@RequestBody注解
作用:
1:@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)
2:用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。 get请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。
当取值为true时,get请求方式会报错。
如果取值为false,get请求得到是null。
测试案例:
anno.jsp
<h3>@RequestBody</h3>
post请求jsp代码: <br>
<!-- request body注解 -->
<form action="anno/testRequestBody" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
get请求jsp代码: <br>
<a href="anno/testRequestBody?body=test">requestBody注解get请求</a>
AnnoController.java
// 请求参数
@RequestMapping(path = "/testRequestBody")
public String testRequestBody(@RequestBody(required = false) String body){
System.out.println("Hello SpringMVC!!,测试@RequestParam");
System.out.println(body);
return "success";// 响应结果
}
输出结果:
Post请求:
Get请求:
后续在Controller拿到json数据的时候,可以使用@RequestBody获取json数据,然后可以将json的字符串,转换成javabean(后续讲);使用@ResponseBody,可以做响应json数据,将javabean转换成json数据返回。
@PathVariable注解
使用说明
作用:
用于绑定url中的占位符。例如:请求url中 /delete/{id}/{name},这个{id},{name}就是url占位符。
传统方式:/delete?id=3&name=zhangsan
rest风格:/delete/3/zhangsan
url支持占位符是spring3.0之后加入的。是springmvc支持restful风格URL的一个重要标志。
属性:
value:用于指定url中占位符名称。
required:是否必须提供占位符。
测试案例:
anno.jsp
<h3>@PathVariable注解</h3>
<!-- PathVariable注解 -->
<a href="anno/testPathVariable/100">pathVariable注解</a>
AnnoController.java
// 请求参数
@RequestMapping(path = "/testPathVariable/{uid}")
public String testPathVariable(@PathVariable(value = "uid") Integer id){
System.out.println("Hello SpringMVC!!,测试@PathVariable");
System.out.println(id);
return "success";// 响应结果
}
测试结果:
REST风格URL
什么是rest:
REST(英文:Representational State Transfer,简称REST,说的意思是:表现层状态转变,或者叫做 “表述性状态转移”)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP(Simple Object Access protocol,简单对象访问协议)以及XML-RPC更加简单明了,无论是对URL的处理还是对Payload的编码,REST都倾向于用更加简单轻量的方法设计和实现。值得注意的是REST并没有一个明确的标准,而更像是一种设计的风格。
它本身并没有什么实用性,其核心价值在于如何设计出符合REST风格的网络接口。
restful的优点
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
restful的特性:
资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。
它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层 (Representation)。
比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。
HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
传统的实例:唯一的URL地址(统一资源定位符),找到对应的资源
Url 操作 后台访问的方法
/account/findAll: 查询所有account findAll()
/account/findById?id=1: 查询id=1的account findById()
/account/delete?id=1: 删除id=1的account delete()
/account/update: 更新account update()
/account/save: 新增account save()
restful的示例: URI(统一资源标识符)
Uri http(表现层)的协议 操作 后台访问的方法
/account HTTP协议 GET : 查询所有 account findAll()
/account/1 HTTP协议 GET : 得到 id = 1 的 account findById()
/account/1 HTTP协议 DELETE: 删除 id = 1的 account delete()
/account HTTP协议 PUT: 更新id = 1的 account update()
/account HTTP协议 POST: 新增 account save()
基于HiddentHttpMethodFilter的示例(了解)
作用:
由于浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给我们的控制器方法,使得支持 GET、POST、PUT 与DELETE 请求。
使用方法:
第一步:在web.xml中配置该过滤器。
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第二步:请求方式必须使用post请求。
第三步:按照要求提供_method请求参数,该参数的取值就是我们需要的请求方式。
源码分析:
案例:
anno.jsp
resfful风格:jsp中示例代码:
<!-- 保存 -->
<form action="anno/testPathVariable" method="post">
用户名称:<input type="text" name="username"><br/>
<!-- <input type="hidden" name="_method" value="POST"> -->
<input type="submit" value="保存"></form>
<hr/>
<!-- 更新 -->
<form action="anno/testPathVariable" method="post">
用户名称:<input type="text" name="username"><br/>
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="更新">
</form>
<hr/>
<!-- 删除 -->
<form action="anno/testPathVariable/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="删除">
</form>
<hr/>
<!-- 查询一个 -->
<form action="anno/testPathVariable/1" method="post">
<input type="hidden" name="_method" value="GET">
<input type="submit" value="查询">
</form>
<hr/>
AnnoController.java
// 请求参数
@RequestMapping(path = "/testPathVariable",method = RequestMethod.POST)
public String save(User user){
System.out.println("Hello SpringMVC!!,测试@PathVariable,新增-请求方式Post");
System.out.println(user);
return "success";// 响应结果
}
// 请求参数
@RequestMapping(path = "/testPathVariable",method = RequestMethod.PUT)
public String update(User user){
System.out.println("Hello SpringMVC!!,测试@PathVariable,更新-请求方式Put");
System.out.println(user);
return "success";// 响应结果
}
// 请求参数
@RequestMapping(path = "/testPathVariable/{uid}",method = RequestMethod.DELETE)
public String delete(@PathVariable(value = "uid") Integer id){
System.out.println("Hello SpringMVC!!,测试@PathVariable,删除-请求方式Delete");
System.out.println(id);
return "success";// 响应结果
}
// 请求参数
@RequestMapping(path = "/testPathVariable/{uid}",method = RequestMethod.GET)
public String findById(@PathVariable(value = "uid") Integer id){
System.out.println("Hello SpringMVC!!,测试@PathVariable,查询一个-请求方式Get");
System.out.println(id);
return "success";// 响应结果
}
测试结果:
PS:如果PUT请求和DELETE请求响应的时候报错
但是我们可以在控制台看到结果,说明执行了对应的方法,但是在响应到Jsp页面的时候,Jsp页面不支持PUT和DELETE请求的响应,所以抛出异常,我们可以使用@ResponseBody(后面讲)表示不再响应页面,即视图解析器将失效,以文本的形式返回,用在ajax的应用场景(返回文本或者json)
// 修改是PUT协议
@RequestMapping(value = "/testPathVariable",method = RequestMethod.PUT)
public @ResponseBody String update(User user){
System.out.println("put请求,修改");
System.out.println(user);
return "success";
}
// 删除是DELETE协议
@RequestMapping(value = "/testPathVariable/{id}",method = RequestMethod.DELETE)
public @ResponseBody String delete(@PathVariable(name = "id") Integer id,User user){
System.out.println("delete请求,删除");
System.out.println(id);
System.out.println(user);
return "success";
}
如果不想使用基于HiddentHttpMethodFilter,使用idea完成测试
打开idea,Tools下TestRESTful...
GET请求:
DELETE请求:
POST请求:
PUT请求:
@RequestHeader注解(了解)
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
注:
在实际开发中一般不怎么用。
案例:
anno.jsp
<h3>测试@RequestHeader注解</h3>
<!-- RequestHeader注解 -->
<a href="anno/testRequestHeader">获取请求消息头</a>
AnnoController.java
// 请求参数
@RequestMapping(path = "/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="accept")String requestHeader){
System.out.println("Hello SpringMVC!!,测试@RequestHeader");
System.out.println(requestHeader);
return "success";// 响应结果
}
测试结果:
@CookieValue 注解(了解)
作用:
用于把指定cookie名称的值传入控制器方法参数。
属性:
value:指定cookie的名称。
required:是否必须有此cookie。
案例:
anno.jsp
<h3>测试@CookieValue注解</h3>
<!-- CookieValue注解 -->
<a href="anno/testCookieValue">CookieValue注解</a>
AnnoController.java
@RequestMapping(path = "/testCookieValue")
public String testCookieValue(@CookieValue(value = "JSESSIONID")String cookieValue){
System.out.println("Hello SpringMVC!!,测试@CookieValue");
System.out.println(cookieValue);
return "success";// 响应结果
}
测试结果:
查看浏览器,右键点击地址栏
@ModelAttribute注解(了解)
作用:
该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的key。key可以是POJO的属性名称,也可以是map结构的key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为null,此时就可以使用此注解解决问题。
基于POJO属性的基本使用(掌握)
anno.jsp
<h3>测试@ModelAttribute注解</h3>
需求: 修改用户信息,要求用户的日期不能修改 jsp的代码:
<!-- 修改用户信息 -->
<form action="anno/testModelAttribute" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
AnnoController.java
// ModelAttribute的用法
@ModelAttribute // 在执行的方法之前运行
public void showModel(User user) {
System.out.println("执行了showModel方法"+user);
user.setBirthday(new Date());
}
/** * 模拟修改用户方法 * @param user * @return */
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
测试结果:
基于Map的应用场景一:ModelAttribute修饰方法带返回值(了解)
anno.jsp
<h3>测试@ModelAttribute注解</h3>
需求: 修改用户信息,要求用户的日期不能修改 jsp的代码:
<!-- 修改用户信息 -->
<form action="anno/testModelAttribute" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
AnnoController.java
@ModelAttribute // 在执行的方法之前运行
public User showModel(String username) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了showModel方法"+user);
return user;
}
/** * 模拟修改用户方法 * @param user * @return */
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
/** * 模拟去数据库查询 * @param username * @return User*/
private User findUserByName(String username) {
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setBirthday(new Date());
return user;
}
测试结果:
PS:传递username和age的属性值的时候,以页面传递的值为准;如果页面没有传递的参数,可以通过showModel的方法获取其他的参数值。
基于Map的应用场景二:ModelAttribute修饰方法不带返回值(了解)
anno.jsp
<h3>测试@ModelAttribute注解</h3>
需求: 修改用户信息,要求用户的日期不能修改 jsp的代码:
<!-- 修改用户信息 -->
<form action="anno/testModelAttribute" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
AnnoController.java
@ModelAttribute // 在执行的方法之前运行
public void showModel(String username, Map<String,User> maps) {
//模拟去数据库查询
User user = findUserByName(username);
maps.put("abc",user);
System.out.println("执行了showModel方法"+user);
}
/** * 模拟修改用户方法 * @param user */
@RequestMapping("/testModelAttribute")
public String testModelAttribute(@ModelAttribute(value = "abc") User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
/** * 模拟去数据库查询 * @param username * @return User*/
private User findUserByName(String username) {
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setBirthday(new Date());
return user;
}
测试结果:
@SessionAttributes注解(了解)
作用:
用于多次执行控制器方法间的参数共享。 放置到类的上面。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型。
相当于将数据存放到Session中。
anno.jsp
<h3>测试@SessionAttributes注解</h3>
<!-- SessionAttribute注解的使用 -->
<a href="anno/sessionAttributePut">存入SessionAttribute</a> <hr/>
<a href="anno/sessionAttributeGet">取出SessionAttribute</a> <hr/>
<a href="anno/sessionAttributeClean">清除SessionAttribute</a>
AnnoController.java
@Controller
@RequestMapping(path = "/anno")
@SessionAttributes(value ={"username","password"},types={Integer.class})
public class AnnoController {
/**
* * 把数据存入SessionAttribute
* * @param model
* * @return
* * Model是spring提供的一个接口,该接口有一个实现类ExtendedModelMap *
* 该类继承了ModelMap,而ModelMap就是LinkedHashMap子类 */
@RequestMapping("/sessionAttributePut")
public String testPut(Model model){
System.out.println("把数据存入SessionAttribute");
model.addAttribute("username", "泰斯特");
model.addAttribute("password","123456");
model.addAttribute("age", 31);
//跳转之前将数据保存到username、password和age中,因为注解@SessionAttribute中有这几个参数
return "success";
}
/**
* * 获取SessionAttribute
*/
@RequestMapping("/sessionAttributeGet")
public String testGet(ModelMap model){
System.out.println("获取SessionAttribute");
System.out.println(model.get("username")+";"+model.get("password")+";"+model.get("age"));
return "success";
}
/**
* * 清空SessionAttribute
*/
@RequestMapping("/sessionAttributeClean")
public String complete(SessionStatus sessionStatus){
System.out.println("清空SessionAttribute");
sessionStatus.setComplete();
return "success";
}
}
测试结果:
先存入-->再获取(有值)-->再清空-->再获取(null)
这是实现了数据的共享