RESTful

15 篇文章 1 订阅

目录

一、简介

1.资源

2.资源的表述

3.状态转移

4.特点

二、实现

三、RESTful基础案例

1.准备工作

①配置web.xml

②配置SpringMVC.xml

③功能

④实现

🦆使用HiddenHttpMethodFilter处理put和delete请求

⭐HiddenHttpMethodFilter 处理put和delete请求的条件:

HiddenHttpMethodFilter的源码 

四、RESTful具体案例

1.创建实体类、dao模拟数据、创建控制层

2. 功能清单

3.处理静态资源

​编辑4.添加功能

①在SpringMVC.xml中配置视图控制器

②添加页面 

③控制层 

④结果

5.修改功能

①修改页面 

②控制层

6.删除功能


一、简介

REST:Representational State Transfer,表现层资源状态转移。

RESTFUL:是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源

1.资源

资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。

每个资源是服务器上一个可命名的抽象概念。

因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、 数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端 应用开发者能够理解。

与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。

一个资源可以由一个或多个URI来标识URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。

2.资源的表述

资源的表述是一段对于资源在某个特定时刻的状态的描述。

可以在客户端-服务器端之间转移(交 换)。资源的表述可以有多种格式,例如HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。

请求 —— 响应方向的表述通常使用不同的格式。

3.状态转移

在客户端和服务器端之间转移(transfer)代表资源状态的表述。

通过转移和操作资源的表述,来间接实现操作资源的目的。

4.特点

  • 每一个URI代表1种资源;
  • 客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
  • 通过操作资源的表现形式来操作资源;
  • 资源的表现形式是XML或者HTML;
  • 客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

二、实现

HTTP 协议里面,四个表示操作方式的动词:GET(获取资源)、POST(新建资源)、PUT(更新资源)、DELETE(删除资源)。

REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。

三、RESTful基础案例

1.准备工作

①配置web.xml

<?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">

    <!-- 设置spring的编码过滤器 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 设置SpringMVC的前端控制器 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <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>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

②配置SpringMVC.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/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd">

    <!-- 扫面控制层组件 -->
    <context:component-scan base-package="com.atguigu.controller"></context:component-scan>
    <!-- 配置Thymeleaf视图解析器 -->
    <bean id="viewResolver"
          class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/><!--order:优先级-->
        <property name="characterEncoding" value="UTF-8"/><!--characterEncoding:编码-->
        <property name="templateEngine"><!--templateEngine:模板引擎-->
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver"><!--templateResolver:模板解析器-->
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!--  物理视图:/WEB-INF/templates/index.xml  -->
                        <!--  物理视图 = 视图前缀 + 逻辑视图 + 视图后缀  -->
                        <!--  逻辑视图:index(可以通过逻辑视图访问到物理视图)  -->
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/><!-- 模板模型:HTML5  -->
                        <property name="characterEncoding" value="UTF-8" /><!--  渲染视图默认的编码:UTF-8  -->
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <!-- 开启mvc的注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 配置视图控制器 -->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
</beans>

③功能

/**
 * 查询所有的用户信息 ——> /user ——> get
 * 根据id查询用户信息 ——> /user/1 ——> get
 * 添加用户信息 ——> /user ——> post
 * 修改用户信息 ——> /user ——> put
 * 删除用户信息 ——> /user/1 ——> delete
 */
@Controller
public class TestRestController {
}

④实现

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>

<body>
    <h1>index.html</h1>
    <a th:href="@{/user}">查询所有的用户信息</a><br>
    <a th:href="@{/user/1}">查询id为1的用户信息</a><br>
    <form th:action="@{/user}" method="post">
        <input type="submit" value="添加用户信息">
    </form>
    <form th:action="@{/user}" method="post">
        <input type="hidden" name="_method" value="put">
        <input type="submit" value="修改用户信息">
    </form>
    <form th:action="@{/user/5}" method="post">
        <input type="hidden" name="_method" value="delete">
        <input type="submit" value="删除用户信息">
    </form>
</body>
</html>
package com.atguigu.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * 查询所有的用户信息 ——> /user ——> get
 * 根据id查询用户信息 ——> /user/1 ——> get
 * 添加用户信息 ——> /user ——> post
 * 修改用户信息 ——> /user ——> put
 * 删除用户信息 ——> /user/1 ——> delete
 */
@Controller
public class TestRestController {
//    @RequestMapping(value = "/user",method = RequestMethod.GET)
    @GetMapping("/user")
    public String getAllUser(){
        System.out.println("查询所有的用户信息 ——> /user ——> get");
        return "success";
    }
//    @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    @GetMapping("/user/{id}")
    //获取请求参数
    public String getUserById(@PathVariable("id") Integer id){
        System.out.println("根据id查询用户信息 ——> /user/" + id +" ——> get");
        return "success";
    }

//    @RequestMapping(value = "/user",method = RequestMethod.POST)
    @PostMapping("/user")
    public String insertUser(){
        System.out.println("添加用户信息 ——> /user ——> post");
        return "success";
    }

//    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    @PutMapping("/user")
    public String updateUser(){
        System.out.println("修改用户信息 ——> /user ——> put");
        return "success";
    }

//    @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
    @DeleteMapping("/user/{id}")
    public String deleteUser(@PathVariable("id") Integer id){
        System.out.println("删除用户信息 ——> /user/" + id +"——> delete");
        return "success";
    }
}

🦆使用HiddenHttpMethodFilter处理put和delete请求

由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?

SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求

⭐HiddenHttpMethodFilter 处理put和delete请求的条件:

  • 当前请求的请求方式必须为post
  • 当前请求必须传输请求参数_method

满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数 _method的值,因此请求参数_method的值才是最终的请求方式

在web.xml中注册HiddenHttpMethodFilter

<!-- 设置处理请求方式的过滤器 -->
<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>

HiddenHttpMethodFilter的源码 

public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    private static final List<String> ALLOWED_METHODS;
    public static final String DEFAULT_METHOD_PARAM = "_method";
    private String methodParam = "_method";

    public HiddenHttpMethodFilter() {
    }

    public void setMethodParam(String methodParam) {
        Assert.hasText(methodParam, "'methodParam' must not be empty");
        this.methodParam = methodParam;
    }

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        HttpServletRequest requestToUse = request;
        if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
            String paramValue = request.getParameter(this.methodParam);
            if (StringUtils.hasLength(paramValue)) {
                String method = paramValue.toUpperCase(Locale.ENGLISH);
                if (ALLOWED_METHODS.contains(method)) {
                    requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
                }
            }
        }

        filterChain.doFilter((ServletRequest)requestToUse, response);
    }

    static {
        ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    }

    private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
        private final String method;

        public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
            super(request);
            this.method = method;
        }

        public String getMethod() {
            return this.method;
        }
    }
}

四、RESTful具体案例

1.创建实体类、dao模拟数据、创建控制层

package com.atguigu.pojo;

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    //1 male, 0 female
    private Integer gender;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Employee(Integer id, String lastName, String email, Integer
            gender) {
        super();
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
    }
    public Employee() {
    }
}
package com.atguigu.dao;

import com.atguigu.pojo.Employee;
import org.springframework.stereotype.Repository;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class EmployeeDao {
    private static Map<Integer, Employee> employees = null;
    static{
        employees = new HashMap<Integer, Employee>();
        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
    }
    private static Integer initId = 1006;
    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }
        employees.put(employee.getId(), employee);
    }
    public Collection<Employee> getAll(){
        return employees.values();
    }
    public Employee get(Integer id){
        return employees.get(id);
    }
    public void delete(Integer id){
        employees.remove(id);
    }
}

import org.springframework.stereotype.Controller;

/**
 * 查询所有的员工信息 ——> /employee ——> get
 * 跳转到添加页面 ——> /to/add ——> get
 * 新增员工信息 ——> /employee ——> post
 * 跳转到修改页面 ——> /employee/1 ——> get
 * 修改员工信息 ——> /employee ——> put
 * 删除员工信息 ——> /employee/1 ——> delete
 * *
 */

@Controller
public class EmployeeController {
}

2. 功能清单

3.处理静态资源

html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>employee list</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
<table>
    <tr>
        <th colspan="5">employee list</th>
    </tr>
    <tr>
        <th>id</th>
        <th>lastName</th>
        <th>email</th>
        <th>gender</th>
        <th>options</th>
    </tr>
    <tr th:each="employee : ${allEmployee}">
        <td th:text="${employee.id}"></td>
        <td th:text="${employee.lastName}"></td>
        <td th:text="${employee.email}"></td>
        <td th:text="${employee.gender}"></td>
        <td>
            <a href="">delete</a>
            <a href="">update</a>
        </td>
    </tr>
</table>
</body>
</html>

控制层: 

@Controller
public class EmployeeController {
    @Autowired
    private EmployeeDao employeeDao;

    @RequestMapping(value = "/employee",method = RequestMethod.GET)
    public String getAllEmployee(Model model){
        //获取所有的员工信息
        Collection<Employee> allEmployee = employeeDao.getAll();
        //将所有的员工信息在请求域中共享
        model.addAttribute("allEmployee",allEmployee);
        //跳转到列表页面
        return "employee_list";
    }

}

SpringMVC.xml

<!-- 配置默认的servlet处理静态资源:
     当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是 /
     tomcat的web.xml配置的DispatcherServlet的url-pattern也是 /
     此时,浏览器发送的请求会优先被DispatcherServlet进行处理,但是DispatcherServlet无法处理静态资源
     若配置了<mvc:default-servlet-handler/>,此时浏览器发送的所有请求都会被DefaultServlet处理
     若配置了<mvc:default-servlet-handler/>和<mvc:annotation-driven/>
     浏览器发送的请求会先被DispatcherServlet处理
     无法处理再交给DefaultServlet处理
 -->
<mvc:default-servlet-handler/>
<!-- 开启mvc的注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置视图控制器 -->
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>

添加样式后

4.添加功能

①在SpringMVC.xml中配置视图控制器

<mvc:view-controller path="/to/add" view-name="employee_add"></mvc:view-controller>

②添加页面 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>add employee</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
    <form th:action="@{/employee}" method="post">
    <table>
        <tr>
            <th colspan="2">add employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName">
            </td>
        </tr>
        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email">
            </td>
        </tr>
        <tr>
            <td>gender</td>
            <td>
                <input type = "radio" name="gender" value="1">male
                <input type = "radio" name="gender" value="0">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="add">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>

③控制层 

@RequestMapping(value = "/employee",method = RequestMethod.POST)
public String addEmployee(Employee employee){
    //保存员工信息
    employeeDao.save(employee);
    //重定向到列表功能:/employee
    return "redirect:/employee";
}
@RequestMapping(value = "to/add",method = RequestMethod.GET)
public String addEmployee(){
    return "employee_add";
}

④结果

5.修改功能

①修改页面 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>update employee</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
    <form th:action="@{/employee}" method="post">
        <input type="hidden" name="_method" value="put">
        <input type="hidden" name="id" th:value="${employee.id}">
    <table>
        <tr>
            <th colspan="2">update employee</th>
        </tr>
        <tr>
            <td>lastName</td>
            <td>
                <input type="text" name="lastName" th:value="${employee.lastName}">
            </td>
        </tr>
        <tr>
            <td>email</td>
            <td>
                <input type="text" name="email" th:value="${employee.email}">
            </td>
        </tr>
        <tr>
            <td>gender</td>
            <td>
                <input type = "radio" name="gender" value="1" th:field="${employee.gender}">male
                <input type = "radio" name="gender" value="0" th:field="${employee.gender}">female
            </td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="update">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>

②控制层

@RequestMapping(value = "/employee",method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
    //修改员工信息
    employeeDao.save(employee);
    //重定向到列表功能:/employee
    return "redirect:/employee";
}

6.删除功能

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>employee list</title>
    <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>

<div id="app">
    <table>
        <tr>
            <th colspan="5">employee list</th>
        </tr>
        <tr>
            <th>id</th>
            <th>lastName</th>
            <th>email</th>
            <th>gender</th>
            <th>options (<a th:href="@{/to/add}">add</a>) </th>
        </tr>
        <tr th:each="employee : ${allEmployee}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.lastName}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.gender}"></td>
            <td>
                <a @click="deleteEmployee()" th:href="@{'/employee/' + ${employee.id}">delete</a>
                <a th:href="@{'/employee/' + ${employee.id}">update</a>
            </td>
        </tr>
    </table>
    <form method="post">
        <input type="hidden" name="_method" value="delete">
    </form>
</div>

  <script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
  <script type="text/javascript">
      var vue = new Vue({
          el:"#app",
          methods:{
              deleteEmployee(){
                  //获取form表单
                  var form = document.getElementsByTagName("form")[0];
                  //将超链接的href属性值赋值给form表单的action属性
                  //event.target表示当前触发时间的标签
                  form.action = event.target.href;
                  //表单提交
                  form.submit();
                  //组织超链接的默认行为
                  event.preventDefault();
              }
          }
      });
  </script>
</body>
</html>

@RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){
    //删除员工信息
    employeeDao.delete(id);
    //重定向到列表功能:/employee
    return "redirect:/employee";
}

          

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

elk-zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值