从零学习Spring MVC框架「RESTful风格实践」

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风格所必须的注解,不可省略。

原文发布于微信公众号 - Web项目聚集地(web_resource)

原文发表时间:2018-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一个会写诗的程序员的博客

Spring FrameWork 5.0 新功能 概览Spring FrameWork 5.0 新功能 概览

整个框架的代码基于java8 通过使用泛型等特性提高可读性 对java8提高直接的代码支撑

9110
来自专栏玩转JavaEE

使用Spring Boot开发Web项目

按:最近公众号文章主要是整理一些老文章,以个人CSDN上的博客为主,也会穿插一些新的技术点。 ---- 前面两篇博客中我们简单介绍了Spring Boot项目的...

31350
来自专栏阿杜的世界

Spring实战5-基于Spring构建Web应用主要内容

写在前面:关于Java Web,首先推荐一篇文章——写给java web一年左右工作经验的人,这篇文章的作者用精练的话语勾勒除了各种Java框架的缘由和最基本的...

12320
来自专栏Java学习之路

Hibernate学习---基本介绍+作用+配置

从今天开始重新学习(以前学的太匆忙)Hibernate,这篇文章主要就一下几点进行讲解和说明: Hibernate的基本介绍 Hibernate的作用 Hibe...

29370
来自专栏学海无涯

Java Web之Spring Boot

我一直在尝试一个人写demo(Android和iOS)时,如何模拟服务器端返回的 JSON 数据,总的来说,我试过以下几种: 纯Servlet开发,这种方式配合...

29040
来自专栏我的博客

Zend_Config使用笔记

1.zend_Config被设计在应用程序中简化访问和使用配置数据。它为在应用程序代码中访问这样的配置数据提供了一个基于用户接口的嵌入式对象属性。配置数据可能来...

27350
来自专栏互联网大杂烩

Spring MVC框架

前端控制器是DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resol...

7620
来自专栏java工会

Spring工作原理

内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建、...

9310
来自专栏技术博文

file_put_contents— 将一个字符串写入文件

将字符串写入到文件中,我们可以用fwrite写文件函数进行操作,今天写程序的时候,突然觉得其实file_put_contents()函数,用来写入字符串,后来仔...

39770
来自专栏JAVA同学会

Spring Data(一)概念和仓库的定义

Spring Data的主要任务是为数据访问提供一个相似的、一致的、基于Spring的编程模型,同时又保留着下面各个数据存储的特征。它使得使用数据访问技术非常的...

14010

扫码关注云+社区

领取腾讯云代金券