• RESTful


    目录

    一、简介

    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

    1. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    4. version="4.0">
    5. <filter>
    6. <filter-name>CharacterEncodingFilterfilter-name>
    7. <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    8. <init-param>
    9. <param-name>encodingparam-name>
    10. <param-value>UTF-8param-value>
    11. init-param>
    12. <init-param>
    13. <param-name>forceEncodingparam-name>
    14. <param-value>trueparam-value>
    15. init-param>
    16. filter>
    17. <filter-mapping>
    18. <filter-name>CharacterEncodingFilterfilter-name>
    19. <url-pattern>/*url-pattern>
    20. filter-mapping>
    21. <servlet>
    22. <servlet-name>SpringMVCservlet-name>
    23. <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    24. <init-param>
    25. <param-name>contextConfigLocationparam-name>
    26. <param-value>classpath:SpringMVC.xmlparam-value>
    27. init-param>
    28. <load-on-startup>1load-on-startup>
    29. servlet>
    30. <servlet-mapping>
    31. <servlet-name>SpringMVCservlet-name>
    32. <url-pattern>/url-pattern>
    33. servlet-mapping>
    34. web-app>

    ②配置SpringMVC.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:context="http://www.springframework.org/schema/context"
    4. xmlns:mvc="http://www.springframework.org/schema/mvc"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
    7. http://www.springframework.org/schema/mvc
    8. http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
    9. http://www.springframework.org/schema/context
    10. http://www.springframework.org/schema/context/spring-context-4.2.xsd">
    11. <context:component-scan base-package="com.atguigu.controller">context:component-scan>
    12. <bean id="viewResolver"
    13. class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    14. <property name="order" value="1"/>
    15. <property name="characterEncoding" value="UTF-8"/>
    16. <property name="templateEngine">
    17. <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
    18. <property name="templateResolver">
    19. <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    20. <property name="prefix" value="/WEB-INF/templates/"/>
    21. <property name="suffix" value=".html"/>
    22. <property name="templateMode" value="HTML5"/>
    23. <property name="characterEncoding" value="UTF-8" />
    24. bean>
    25. property>
    26. bean>
    27. property>
    28. bean>
    29. <mvc:annotation-driven/>
    30. <mvc:view-controller path="/" view-name="index">mvc:view-controller>
    31. beans>

    ③功能

    1. /**
    2. * 查询所有的用户信息 ——> /user ——> get
    3. * 根据id查询用户信息 ——> /user/1 ——> get
    4. * 添加用户信息 ——> /user ——> post
    5. * 修改用户信息 ——> /user ——> put
    6. * 删除用户信息 ——> /user/1 ——> delete
    7. */
    8. @Controller
    9. public class TestRestController {
    10. }

    ④实现

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>首页title>
    6. head>
    7. <body>
    8. <h1>index.htmlh1>
    9. <a th:href="@{/user}">查询所有的用户信息a><br>
    10. <a th:href="@{/user/1}">查询id为1的用户信息a><br>
    11. <form th:action="@{/user}" method="post">
    12. <input type="submit" value="添加用户信息">
    13. form>
    14. <form th:action="@{/user}" method="post">
    15. <input type="hidden" name="_method" value="put">
    16. <input type="submit" value="修改用户信息">
    17. form>
    18. <form th:action="@{/user/5}" method="post">
    19. <input type="hidden" name="_method" value="delete">
    20. <input type="submit" value="删除用户信息">
    21. form>
    22. body>
    23. html>
    1. package com.atguigu.controller;
    2. import org.springframework.stereotype.Controller;
    3. import org.springframework.web.bind.annotation.*;
    4. /**
    5. * 查询所有的用户信息 ——> /user ——> get
    6. * 根据id查询用户信息 ——> /user/1 ——> get
    7. * 添加用户信息 ——> /user ——> post
    8. * 修改用户信息 ——> /user ——> put
    9. * 删除用户信息 ——> /user/1 ——> delete
    10. */
    11. @Controller
    12. public class TestRestController {
    13. // @RequestMapping(value = "/user",method = RequestMethod.GET)
    14. @GetMapping("/user")
    15. public String getAllUser(){
    16. System.out.println("查询所有的用户信息 ——> /user ——> get");
    17. return "success";
    18. }
    19. // @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    20. @GetMapping("/user/{id}")
    21. //获取请求参数
    22. public String getUserById(@PathVariable("id") Integer id){
    23. System.out.println("根据id查询用户信息 ——> /user/" + id +" ——> get");
    24. return "success";
    25. }
    26. // @RequestMapping(value = "/user",method = RequestMethod.POST)
    27. @PostMapping("/user")
    28. public String insertUser(){
    29. System.out.println("添加用户信息 ——> /user ——> post");
    30. return "success";
    31. }
    32. // @RequestMapping(value = "/user",method = RequestMethod.PUT)
    33. @PutMapping("/user")
    34. public String updateUser(){
    35. System.out.println("修改用户信息 ——> /user ——> put");
    36. return "success";
    37. }
    38. // @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
    39. @DeleteMapping("/user/{id}")
    40. public String deleteUser(@PathVariable("id") Integer id){
    41. System.out.println("删除用户信息 ——> /user/" + id +"——> delete");
    42. return "success";
    43. }
    44. }

    🦆使用HiddenHttpMethodFilter处理put和delete请求

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

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

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

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

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

    在web.xml中注册HiddenHttpMethodFilter

    1. <filter>
    2. <filter-name>HiddenHttpMethodFilterfilter-name>
    3. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
    4. filter>
    5. <filter-mapping>
    6. <filter-name>HiddenHttpMethodFilterfilter-name>
    7. <url-pattern>/*url-pattern>
    8. filter-mapping>

    HiddenHttpMethodFilter的源码 

    1. public class HiddenHttpMethodFilter extends OncePerRequestFilter {
    2. private static final List ALLOWED_METHODS;
    3. public static final String DEFAULT_METHOD_PARAM = "_method";
    4. private String methodParam = "_method";
    5. public HiddenHttpMethodFilter() {
    6. }
    7. public void setMethodParam(String methodParam) {
    8. Assert.hasText(methodParam, "'methodParam' must not be empty");
    9. this.methodParam = methodParam;
    10. }
    11. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    12. HttpServletRequest requestToUse = request;
    13. if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) {
    14. String paramValue = request.getParameter(this.methodParam);
    15. if (StringUtils.hasLength(paramValue)) {
    16. String method = paramValue.toUpperCase(Locale.ENGLISH);
    17. if (ALLOWED_METHODS.contains(method)) {
    18. requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method);
    19. }
    20. }
    21. }
    22. filterChain.doFilter((ServletRequest)requestToUse, response);
    23. }
    24. static {
    25. ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
    26. }
    27. private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
    28. private final String method;
    29. public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
    30. super(request);
    31. this.method = method;
    32. }
    33. public String getMethod() {
    34. return this.method;
    35. }
    36. }
    37. }

    四、RESTful具体案例

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

    1. package com.atguigu.pojo;
    2. public class Employee {
    3. private Integer id;
    4. private String lastName;
    5. private String email;
    6. //1 male, 0 female
    7. private Integer gender;
    8. public Integer getId() {
    9. return id;
    10. }
    11. public void setId(Integer id) {
    12. this.id = id;
    13. }
    14. public String getLastName() {
    15. return lastName;
    16. }
    17. public void setLastName(String lastName) {
    18. this.lastName = lastName;
    19. }
    20. public String getEmail() {
    21. return email;
    22. }
    23. public void setEmail(String email) {
    24. this.email = email;
    25. }
    26. public Integer getGender() {
    27. return gender;
    28. }
    29. public void setGender(Integer gender) {
    30. this.gender = gender;
    31. }
    32. public Employee(Integer id, String lastName, String email, Integer
    33. gender) {
    34. super();
    35. this.id = id;
    36. this.lastName = lastName;
    37. this.email = email;
    38. this.gender = gender;
    39. }
    40. public Employee() {
    41. }
    42. }
    1. package com.atguigu.dao;
    2. import com.atguigu.pojo.Employee;
    3. import org.springframework.stereotype.Repository;
    4. import java.util.Collection;
    5. import java.util.HashMap;
    6. import java.util.Map;
    7. @Repository
    8. public class EmployeeDao {
    9. private static Map employees = null;
    10. static{
    11. employees = new HashMap();
    12. employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
    13. employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
    14. employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
    15. employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
    16. employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
    17. }
    18. private static Integer initId = 1006;
    19. public void save(Employee employee){
    20. if(employee.getId() == null){
    21. employee.setId(initId++);
    22. }
    23. employees.put(employee.getId(), employee);
    24. }
    25. public Collection getAll(){
    26. return employees.values();
    27. }
    28. public Employee get(Integer id){
    29. return employees.get(id);
    30. }
    31. public void delete(Integer id){
    32. employees.remove(id);
    33. }
    34. }
    1. import org.springframework.stereotype.Controller;
    2. /**
    3. * 查询所有的员工信息 ——> /employee ——> get
    4. * 跳转到添加页面 ——> /to/add ——> get
    5. * 新增员工信息 ——> /employee ——> post
    6. * 跳转到修改页面 ——> /employee/1 ——> get
    7. * 修改员工信息 ——> /employee ——> put
    8. * 删除员工信息 ——> /employee/1 ——> delete
    9. * *
    10. */
    11. @Controller
    12. public class EmployeeController {
    13. }

    2. 功能清单

    3.处理静态资源

    html:

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>employee listtitle>
    6. <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    7. head>
    8. <body>
    9. <table>
    10. <tr>
    11. <th colspan="5">employee listth>
    12. tr>
    13. <tr>
    14. <th>idth>
    15. <th>lastNameth>
    16. <th>emailth>
    17. <th>genderth>
    18. <th>optionsth>
    19. tr>
    20. <tr th:each="employee : ${allEmployee}">
    21. <td th:text="${employee.id}">td>
    22. <td th:text="${employee.lastName}">td>
    23. <td th:text="${employee.email}">td>
    24. <td th:text="${employee.gender}">td>
    25. <td>
    26. <a href="">deletea>
    27. <a href="">updatea>
    28. td>
    29. tr>
    30. table>
    31. body>
    32. html>

    控制层: 

    1. @Controller
    2. public class EmployeeController {
    3. @Autowired
    4. private EmployeeDao employeeDao;
    5. @RequestMapping(value = "/employee",method = RequestMethod.GET)
    6. public String getAllEmployee(Model model){
    7. //获取所有的员工信息
    8. Collection allEmployee = employeeDao.getAll();
    9. //将所有的员工信息在请求域中共享
    10. model.addAttribute("allEmployee",allEmployee);
    11. //跳转到列表页面
    12. return "employee_list";
    13. }
    14. }

    SpringMVC.xml

    1. <mvc:default-servlet-handler/>
    2. <mvc:annotation-driven/>
    3. <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>

    ②添加页面 

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>add employeetitle>
    6. <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    7. head>
    8. <body>
    9. <form th:action="@{/employee}" method="post">
    10. <table>
    11. <tr>
    12. <th colspan="2">add employeeth>
    13. tr>
    14. <tr>
    15. <td>lastNametd>
    16. <td>
    17. <input type="text" name="lastName">
    18. td>
    19. tr>
    20. <tr>
    21. <td>emailtd>
    22. <td>
    23. <input type="text" name="email">
    24. td>
    25. tr>
    26. <tr>
    27. <td>gendertd>
    28. <td>
    29. <input type = "radio" name="gender" value="1">male
    30. <input type = "radio" name="gender" value="0">female
    31. td>
    32. tr>
    33. <tr>
    34. <td colspan="2">
    35. <input type="submit" value="add">
    36. td>
    37. tr>
    38. table>
    39. form>
    40. body>
    41. html>

    ③控制层 

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

    ④结果

    5.修改功能

    ①修改页面 

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>update employeetitle>
    6. <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    7. head>
    8. <body>
    9. <form th:action="@{/employee}" method="post">
    10. <input type="hidden" name="_method" value="put">
    11. <input type="hidden" name="id" th:value="${employee.id}">
    12. <table>
    13. <tr>
    14. <th colspan="2">update employeeth>
    15. tr>
    16. <tr>
    17. <td>lastNametd>
    18. <td>
    19. <input type="text" name="lastName" th:value="${employee.lastName}">
    20. td>
    21. tr>
    22. <tr>
    23. <td>emailtd>
    24. <td>
    25. <input type="text" name="email" th:value="${employee.email}">
    26. td>
    27. tr>
    28. <tr>
    29. <td>gendertd>
    30. <td>
    31. <input type = "radio" name="gender" value="1" th:field="${employee.gender}">male
    32. <input type = "radio" name="gender" value="0" th:field="${employee.gender}">female
    33. td>
    34. tr>
    35. <tr>
    36. <td colspan="2">
    37. <input type="submit" value="update">
    38. td>
    39. tr>
    40. table>
    41. form>
    42. body>
    43. html>

    ②控制层

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

    6.删除功能

    1. html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>employee listtitle>
    6. <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    7. head>
    8. <body>
    9. <div id="app">
    10. <table>
    11. <tr>
    12. <th colspan="5">employee listth>
    13. tr>
    14. <tr>
    15. <th>idth>
    16. <th>lastNameth>
    17. <th>emailth>
    18. <th>genderth>
    19. <th>options (<a th:href="@{/to/add}">adda>) th>
    20. tr>
    21. <tr th:each="employee : ${allEmployee}">
    22. <td th:text="${employee.id}">td>
    23. <td th:text="${employee.lastName}">td>
    24. <td th:text="${employee.email}">td>
    25. <td th:text="${employee.gender}">td>
    26. <td>
    27. <a @click="deleteEmployee()" th:href="@{'/employee/' + ${employee.id}">deletea>
    28. <a th:href="@{'/employee/' + ${employee.id}">updatea>
    29. td>
    30. tr>
    31. table>
    32. <form method="post">
    33. <input type="hidden" name="_method" value="delete">
    34. form>
    35. div>
    36. <script type="text/javascript" th:src="@{/static/js/vue.js}">script>
    37. <script type="text/javascript">
    38. var vue = new Vue({
    39. el:"#app",
    40. methods:{
    41. deleteEmployee(){
    42. //获取form表单
    43. var form = document.getElementsByTagName("form")[0];
    44. //将超链接的href属性值赋值给form表单的action属性
    45. //event.target表示当前触发时间的标签
    46. form.action = event.target.href;
    47. //表单提交
    48. form.submit();
    49. //组织超链接的默认行为
    50. event.preventDefault();
    51. }
    52. }
    53. });
    54. script>
    55. body>
    56. html>
    1. @RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE)
    2. public String deleteEmployee(@PathVariable("id") Integer id){
    3. //删除员工信息
    4. employeeDao.delete(id);
    5. //重定向到列表功能:/employee
    6. return "redirect:/employee";
    7. }

              

  • 相关阅读:
    边缘计算系统逻辑架构:云、边、端协同,定义及关系
    盘点49个Python网站项目Python爱好者不容错过
    Redis在Windows和Linux下的安装方法(超级详细)
    ASP.NET Core框架探索之Authorization
    Azure DevOps (十) 通过流水线完成Docker镜像的部署
    #include “ascii_font.c“ 引入源文件,Keil5为什么没有提示重复定义错误,详解!!!
    A-LEVEL经济知识点讲解:国际收支的结构
    CTF--攻防世界杂项--第二课
    [编程思想录]无锁之CAS
    左偏树
  • 原文地址:https://blog.csdn.net/m0_52982868/article/details/126192994