图文教程,技术交流
RESTful风格
学习本文章之前,我们需要知道什么是RESTful API,还对此不了解的朋友可以移步历史文章 RESTful 接口实现简明指南 ,简单来说就是就是用URL定位资源,用HTTP描述操作。
请求同一个接口根据请求方式的不同,会有不同的效果。看完文章相信你已经熟悉并且想立马实践这种规范,今天我们就来讲解如何利用Spring MVC来实现RESTful 风格的接口,配合代码和案例让大家更容易理解。
大家在书写表单时,有一个属性method,可以选择Get或者Post请求。但是没使用过Patch、Delete、Put属性值啊,如果method设置为它们,点击提交是以什么方式请求呢,接下来这个案例解决你的疑问:
1. 项目截图
2. 导入Jar包
3. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
<display-name>SpringMVC04</display-name>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
关于此配置文件的解释在前几篇文章给出,不明白的可以移除历史文章查看:
从零学习Spring MVC框架「一」
从零学习Spring MVC框架「二」
4. spring-mvc-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" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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.3.xsd">
<!-- 启动springMVC注解 -->
<mvc:annotation-driven/>
<!-- 扫描注解所在的包 -->
<context:component-scan base-package="com.**.controller"></context:component-scan>
<!-- 视图解析器 -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 排除静态资源的第一种方式 -->
<mvc:default-servlet-handler/>
</beans>
5. RestController.java
@Controller
public class RestController {
//@PosttMapping("/user")和下一行是等价的
@RequestMapping(value="/user",method=RequestMethod.POST)
public ModelAndView test01(){
System.out.println("POST");
return null;
}
//@GetMapping("/user")和下一行是等价的
@RequestMapping(value="/user",method=RequestMethod.GET)
public ModelAndView test02(){
System.out.println("GET");
return null;
}
//@PatchMapping("/user")和下一行是等价的
@RequestMapping(value="/user",method=RequestMethod.PATCH)
public ModelAndView test03(){
System.out.println("PATCH");
return null;
}
//@DeleteMapping("/user")和下一行是等价的
@RequestMapping(value="/user",method=RequestMethod.DELETE)
public ModelAndView test04(){
System.out.println("DELETE");
return null;
}
//@PutMapping("/user")和下一行是等价的
@RequestMapping(value="/user",method=RequestMethod.PUT)
public ModelAndView test05(){
System.out.println("PUT");
return null;
}
}
注意上方Controller中,虽然都是处理请求到user路径的方法,但是它们的请求方式是不相同的,根据其请求方式的不同打印到控制的结果也就不一样,通过这种简单的方式来讲解。
6. rest.jsp
<body>
<h2>get请求</h2>
<form action="user" method="get">
<input type="submit">
</form>
<h2>Patch请求</h2>
<form action="user" method="patch">
<input type="submit">
</form>
<h2>Delete请求</h2>
<form action="user" method="delete">
<input type="submit">
</form>
<h2>Put请求</h2>
<form action="user" method="put">
<input type="submit">
</form>
<h2>Post请求</h2>
<form action="user" method="post">
<input type="submit">
</form>
</body>
7. 运行页面
我们依次按顺序点击上方提交按钮,查看控制台打印:
8. 控制台打印
原来我们发现表单的请求方式只有Get和Post请求,即使我们把method的属性值手写成Delete、Patch、Put也是按照Get的请求方式请求的,即根本无法启动这三种属性值,只能按照默认的Get请求方式请求。
如何启动Delete、Patch、Put三种请求方式呢?已经如果利用它们完成RESTful风格的接口开发呢?接下来进入正题:
RESTful风格实现
虽然HTTP定义了Patch、Delete、Put、Get、Post方法,但HTML仅支持两种:GET和POST,幸运的是,有两种可能的解决方法:
方式一
使用JavaScript来执行PUT或DELETE等,这种方式非常简单,这里不再解释。
方式二
1. 设置真实的请求方式为Post
2. 添加一个过滤器HiddenHttpMethodFilter,只有添加这个过滤器才可以使用我们其它的请求方式。
3. 需要一个隐藏的文本域,属性_method的值设置为我们想实现的请求方法,如Patch、Delete等。
我们使用较为复杂的方式二进行实践:
1. web.xml(配置过滤器)
<!-- 额外的请求方式 -->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>spring-mvc</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>spring-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
HiddenHttpMethodFilter这个过滤器是一个普通的Servlet过滤器,它的<servlet-name>标签内填写spring-mvc,即名为spring-mvc的DispatcherServlet拦截什么它就过滤什么。
它可以与任何Web框架(不只是Spring MVC)结合使用。只需将此过滤器添加到您的web.xml中,就可以带有隐藏_method参数的POST转换为相应的HTTP方法请求。
2. rest.jsp(注意观察不同)
<body>
<h2>get请求</h2>
<form action="user" method="get">
<input type="submit">
</form>
<h2>Patch请求</h2>
<form action="user" method="post">
<input type="hidden" name="_method" value="patch" >
<input type="submit">
</form>
<h2>Delete请求</h2>
<form action="user" method="post">
<input type="hidden" name="_method" value="delete" >
<input type="submit">
</form>
<h2>Put请求</h2>
<form action="user" method="post">
<input type="hidden" name="_method" value="put" >
<input type="submit">
</form>
<h2>Post请求</h2>
<form action="user" method="post">
<input type="submit">
</form>
</body>
下方截屏是对上方代码的解释:
我们配置了过滤器和更改表单后,再次运行并且依次点击下方「提交」按钮:
查看控制台打印:
利用方式二提到的方法,我们便可以启动Delete、Patch、Delete、Put的请求方式,我们了解了这种方法便可实现RESTful 风格接口了,有了这么多的请求方式我们怎么使用,下面是URL设计的约定:
1. get/user 查询整个列表
2. get/user/user_id 查询一条记录
3. post/user 添加数据
4. put/user/user_id 更新全部数据
5. patch/user/user_id 更新部分数据
6. delete/user/user_id 删除一条数据
涉及文件上传的时候,都使用post请求方式。到了这里讲解了上面涉及的相应的配置后,就可以使用Spring MVC实现RESTful风格了。接下来讲解如何从前端页面传递值到后端,并提出数据绑定的概念:
超链接传值
1. 案例截图
导入的Jar包、web.xml以及spring-mvc-servlet同上,此处不再给出:
2. client.jsp
<a href="user1?id=2">传递一条数据</a>
<a href="user?id=999&tomcat=tomcat">传递两条数据</a>
3. ClientController.java
@Controller
public class ClientController {
@RequestMapping("/user1")
public ModelAndView test(@RequestParam("id")Integer user_id){
System.out.println(user_id);
return null;
}
@RequestMapping("/user")
public ModelAndView test01(Integer id,String tomcat){
System.out.println(id);
System.out.println(tomcat);
return null;
}
}
上方案例中,在Jsp通过超链接的方式进行Get请求,并且传递参数,第一个超链接传递参数id,第二个传递参数id和tomcat。
在Controller中我们又有两种方式可以接到超链接传过来的参数:
方式一:在方法的参数前添加 @RequestParam("id")注解,前端传递的参数id将会赋给此注解紧挨着后面的参数上。此注解还有别的常用属性,比如:required来确定传的值可不可以为空,defaultValue来设置默认值。
方式二:我们只需要保证方法参数名和请求传递的参数名相同即可,如下图:
同样不仅仅是Integer、String类型,数组类型完全可以接到值。我们可以在前端采用input标签的 multiple 属性,multiple 属性规定可同时选择多个选项。 这样传过来的值,参数设置数组就可以接到,但注意参数名要匹配。
数据绑定
我们发现一个问题,我们在Jsp页面添加一个表单:
<form action="test" method="post">
<input name="user_name">
<input name="account">
<input name="age">
<select multiple="multiple" size="4" name="class_name">
<option value="6">六班</option>
<option value="7">七班</option>
<option value="8">八班</option>
<option value="9">九班</option>
</select> <input type="submit" value="提交">
</form>
此表单可以向后端传递user_name、account、age和班级的数组,在后端接值的时候是不是要像下面一样需要把每个参数都写上来接值呢?
@RequestMapping("/test")
public ModelAndView test02(String user_name,String account,Integer age,String[] clazz,Role role){
...
return null;
}
答案是不需要上方复杂繁琐的方法,我们可以建立一个实体类User,只需要User的属性和表单input的name对应即可。
User.java
public class User {
private String user_name;
private String account;
private Integer age;
private String[] clazz;
//set、get和tostring方法此处写不开,所以省略
}
注意:我们还应该自动生成set、get和tostring方法,由于篇幅限制这里不再给出。
ClientContoller.java
@Controller
public class ClientController {
@RequestMapping("/test")
public ModelAndView test02(User user){
System.out.println(user);
return null;
}
}
如此这样,函数参数只需要写实体类即可,这就是Spring MVC的参数绑定,但是input的name的值必须和User实体类中的属性一一对应,通过input的name值来给实体类的属性赋值。
更多关于数据绑定的知识可以移步:https://www.imooc.com/learn/558
特殊情况
此时我们再添加一个实体类Role,作为User对象的一个属性。
1. Role.java
public class Role {
private Integer role_id;
private String role_name;
}
注:篇幅限制,set、get和tostring方法没有给出,自行补充。
2. User.java(添加Role属性)
public class User {
private String user_name;
private String account;
private Integer age;
private String[] clazz;
private Role role;
}
3. cilent.jsp
<form action="test" method="post">
<input name="username">
<input name="account">
<input name="age">
<input name="role.role_name" value="超级管理员">
<select multiple="multiple" size="4" name="class_name">
<option value="6">六班</option>
<option value="7">七班</option>
<option value="8">八班</option>
<option value="9">九班</option>
</select> <input type="submit" value="提交">
</form>
添加Role实体的意图其实是想让大家明白,前端表单name如何写,在后端才能通过数据绑定User实体类接到Role的值,查看上方代码我们得知:
<input name="role.role_name" >采用这种方式,user属性有role,role下才有role_name,这个地方注意即可。
占位符传递数据
1. client.jsp
<a href="userLoad/999">查询一条数据</a>
2. ClientController.java
@Controller
public class ClientController {
@RequestMapping("/userLoad/{id}")
public ModelAndView userLoad(@PathVariable Integer id){
System.out.println(id);
return null;
}
}
前端请求userLoad/999接口,后端可以使用@RequestMapping("/userLoad/{id}")方法来动态接到id的值,也就是说不管是999还是888,都可以通过{id}接到值。但是必须添加@PathVariable注解才会生效,这是才有RESTful风格所必须的注解,不可省略。
推荐阅读
1. 从零学习Spring MVC框架「一」
2.从零学习Spring MVC框架「二」
3. String Builder 源码分析
4. 各个阶级的前端 必须掌握的基本技能汇总
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。