RESTful
什么是RESTful?
REST:Representational State Transfer,表现层资源状态转移
RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务使能接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源。本质:是一种软件架构风格核心:面向资源设置api
RESTFUL特点包括:
1、每一个URI代表1种资源;
2、客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3、通过操作资源的表现形式来操作资源;
4、资源的表现形式是XML或者HTML;
5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
为什么要使用Restful?
解决问题:降低开发的复杂性;提高系统的可伸缩性
Restful与其他架构有什么区别?
soap webserver 是一种跨编程语言,跨操作平台的远程调用技术。通过http协议发送请求和接收结果时采用xml格式封装,并增加了一些特定的http消息头,这些特定的http消息头和xml内容格式就是soap协议
这俩个架构的区别在:1、效率2、易用性3、安全性
效率和易用性:
soap案例:由于soap添加的是特定的http消息头,如果业务提供方(微信)不提供文档…没有人会使用它的api
安全性:
Restful适用于效率要求很高,但安全性要求不高的场景
soap的成熟性对于安全性要求较高的接口设计带来便利
资源
资源是一种看待服务器的方式,将服务器看做很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念, 所以它不仅仅能代表服务器文件系统的一个文件、数据库中的一张表等具体的东西,也可以将资源看为一种抽象的概念,例如一个资源可以由一个或者多个URI来表示,URI是资源的名称,也是在其Web服务器上的地址。
统一资源标识符(Uniform Resource Identifier,URI)
资源的表述
资源的表述是一段对于资源在某个时刻的状态的描述。可以在客户端-服务器之间转移。资源的表述可以有多种格式,例如HTML、XML、JSON、纯文本、图片、视频、音频等。资源的表述格式可以通过协商机制来确定。
请求-响应方向的表述通常使用不同的格式。
状态转移
状态转移的意思是,在客户端和服务器端之间转移代表资源状态的表述。通过转移和操作资源的表述来间接实现操作资源的目的。
RESTful的实现
RESTful的实现主,主要是GET、POST、PUT、DELTE四种访问方式
浏览器只能发送GET和POST两种请求方式
若直接在form表单中设置method=“put”,此时method失效,默认变为Get请求。
如何实现PUT、DELETE的请求方式?
设置控制器方法
package com.lobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;/**
* className: TestRestController<br/>
* author: MacieSerenity <br/>
* date: 2022/8/21-9:45
**/
@Controller
public class TestRestController {/*** 查询所有用户的信息:/user -> get* 根据用户id查询用户信息:/user/{id} -> get* 添加用户信息:/user ->post* 修改用户的信息:/user -> put* 删除用户的信息:/user/{id} -> delete*//*** 查询所有用户的信息:/user -> get* @return 视图*/
// @RequestMapping(value = "/user",method = RequestMethod.GET)@GetMapping("/user")public String getAllUser(){System.out.printf("查询所有用户的信息:/user -> get");return "success";}/*** 根据用户id查询用户信息:/user/{id} -> get* @param id 用户ID* @return 视图*/
// @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";}/*** 添加用户信息:/user ->post* @return 视图*/
// @RequestMapping(value = "/user",method = RequestMethod.POST)@PostMapping("/user")public String addUser(){System.out.println("添加用户信息:/user ->post");return "success";}/*** 修改用户的信息:/user -> put* @return 视图*/
// @RequestMapping(value = "/user",method = RequestMethod.PUT)@PutMapping("/user")public String modifyUser(){System.out.println("修改用户的信息:/user -> put");return "success";}/*** 删除用户的信息:/user/{id} -> delete* @return 视图*/
// @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)@DeleteMapping("/user/{id}")public String deletedUser(@PathVariable("id") Integer id){System.out.println("删除用户的信息:/user/{"+id+"} -> delete");return "success";}}
设置过滤器
注意Spring的编码过滤器应该在最上方(按照从上到下的顺序),然后再是处理请求方式的方式
若想实现PUT的请求方式,则需要满足以下几个条件:
1、需要在web.xml中配置好编码过滤器
2、当前请求必须为POST
3、设置隐藏域,参数name=“_method” value=“put”
<?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">
<!-- 编码过滤器--><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><!-- 设置处理请求方式的过滤器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><!-- Spring的Servlet控制器--><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>
HTML页面的请求方式
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>首页</title>
</head>
<body><h1>Index页面</h1><hr>/**<br>* 查询所有用户的信息:/user -> get<br>* 根据用户id查询用户信息:/user/{id} -> get<br>* 添加用户信息:/user ->post<br>* 修改用户的信息:/user -> put<br>* 删除用户的信息:/user/{id} -> delete<br>*/<br><hr><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><br>/**<br>* 注意:想要发送PUT请求,则返回的请求方式必须是POST方式<br>* 且需要在当前的请求域中设置一个请求参数_method且value=put<br>*/<br><form th:action="@{/user}" method="post"><input type="hidden" name="_method" value="put"><input type="submit" value="修改用户信息"></form><br>/** <br>使用DELETE请求方式,根据用户ID删除 <br>*/ <br><form th:action="@{/user/1}" method="post"><input type="hidden" name="_method" value="delete"><input type="submit" value="删除用户信息"></form><br>
</body>
</html>
点击【修改用户信息】按钮之后,查看后台使用的方法:
可以看到,通过隐藏域的参数,成功访问了put和delete的请求方式
案例
初始化实体类Employee
package com.lobo.entity;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Employee {private Integer id;private String lastName;private String email;//性别,1表示男,0表示女private Integer gender;
}
模拟数据Dao层
package com.lobo.dao;
import com.lobo.entity.Employee;
//要记得加注解:
@Repository
public class EmployeeDao {private static Map<Integer, Employee>employeeMap = null;static {employeeMap=new HashMap<>();employeeMap.put(1001,new Employee(1001,"E-AA","aa@163.com",1));employeeMap.put(1002,new Employee(1002,"E-BB","bb@163.com",1));employeeMap.put(1003,new Employee(1003,"E-CC","cc@163.com",0));employeeMap.put(1004,new Employee(1004,"E-DD","dd@163.com",0));employeeMap.put(1005,new Employee(1005,"E-EE","ee@163.com",1));}public static Integer initId=1006;public void save(Employee employee){if (employee.getId()==null){employee.setId(initId++);}employeeMap.put(employee.getId(), employee);}public Collection<Employee> getAll(){return employeeMap.values();}public Employee get(Integer id){return employeeMap.get(id);}public void delete(Integer id){employeeMap.remove(id);}
}
功能清单
功能 | URL地址 | 请求方式 |
---|---|---|
访问首页 | / | GET |
查询全部数据 | /employee | GET |
删除 | /employee/{id} | DELETE |
跳转到添加数据界面 | /toAdd | GET |
执行保存 | /employee | POST |
跳转到更新数据界面 | /employee/{id} | GET |
执行更新 | /employee | PUT |
功能实现
1、访问首页
spring配置文件中:
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd "><!-- 扫描控制层组件--><context:component-scan base-package="com.lobo"/><!-- 配置Thymeleaf视图解析器--><bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"><property name="order" value="1"/><property name="characterEncoding" value="utf-8"/><property name="templateEngine"><bean class="org.thymeleaf.spring5.SpringTemplateEngine"><property name="templateResolver"><bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"><!-- 视图前缀--><property name="prefix" value="/WEB-INF/templates/"/><!-- 视图后缀--><property name="suffix" value=".html"/><property name="templateMode" value="HTML"/><property name="characterEncoding" value="UTF-8"/></bean></property></bean></property></bean><!-- 开启注解驱动--><mvc:annotation-driven/>
<!-- 开启试图控制器--><mvc:view-controller path="/" view-name="index" /></beans>
EmployeeController
@GetMapping("/")public String toIndex(){return "index";}
访问首页我们可以通过配置xml文件中的<mvc:view-controller path=“/” view-name=“index” />来进行配置,也可以通过使用Mapping的方式。
2、查看所有Employee信息
index.html
/** <br>
Employee的功能 <br>
*/ <br>
<a th:href="@{/employee}">查询所有员工的信息</a><br>
employee_list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>EmployeeList</title><link rel="stylesheet" th:href="@{static/css/index_work.css}"><link rel="stylesheet" th:href="@{static/css/index_like.css}"><link rel="stylesheet" th:href="@{static/css/style.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( <a th:href="@{/to/add}">添加</a> )</th></tr><tr th:each="employee : ${employees}"><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>
控制器
package com.lobo.controller;
@Controller
public class EmployeeController {@AutowiredEmployeeDao employeeDao;@GetMapping("/")public String toIndex(){return "index";}@GetMapping("/employee")public String queryAll(Model model){Collection<Employee> employees = employeeDao.getAll();model.addAttribute("employees",employees);return "employee_list";}
}
添加样式
employee_list.html
<link rel="stylesheet" th:href="@{static/css/index_work.css}"><link rel="stylesheet" th:href="@{static/css/index_like.css}"><link rel="stylesheet" th:href="@{static/css/style.css}">
此时如果我们想要添加css、js等静态资源,由于Servlet被Spring管理了,而DispatherServlet无法处理静态资源的请求,所以无法对请求的静态资源进行解析,所以会返回404错误。
具体原因如下:
配置默认的Servlet处理静态资源 同样需要开启注解驱动
当前工程的web.xml配置的前端控制器DispatcherServlet的url-pattern是/
tomcat的web.xml配置的DefaultServlet的url-pattern也是/
此时浏览器发送的请求会优先被DisPathcerServlet处理,但是DispatcherServlet无法处理静态资源解决方法:若配置了<mvc:default-servlet-handler />,此时浏览器发送的所有请求都会被DefaultServlet处理
若配置了<mvc:default-servlet-handler />和<mvc:annotation-driven/>
浏览器的请求会先被DispatcherServlet处理,无法处理后再交给DefaultServlet处理
所以我们需要在spring的配置文件中,将默认的Servlet的控制器打开,当Spring无法处理这种静态资源的请求时,会自动交由默认的Servlet进行处理,此时就能正确访问资源:
<mvc:default-servlet-handler />
<!-- 开启注解驱动--><mvc:annotation-driven/>
<!-- 开启试图控制器--><mvc:view-controller path="/" view-name="index" />
注意:记得出了开启默认的Servlet,还要开启注解驱动,否则使用注解的Spring无法进行解析,也会发生访问不到网页的错误。
3、添加用户
新建添加页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>添加用户</title><link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body><h1>添加用户</h1><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" id="LastName"></td></tr><tr><td>Email</td><td><input type="text" name="email" id="Email"></td></tr><tr><td>Gender</td><td><input type="radio" name="Gender" value="1">male<input type="radio" name="Gender" value="1">female</td></tr><tr><td colspan="2"><input type="submit" value="添加"></td></tr></table></form>
</body>
</html>
在employee_list.html中添加链接
<th>options( <a th:href="@{/to/add}">添加</a> )</th>
控制器方法
使用重定向重新执行get请求方式的/employee
@PostMapping("/employee")public String addEmployee(Employee employee){employeeDao.save(employee);return "redirect:/employee";}
4、修改用户
添加修改页面
copy新建界面即可,然后更改名称
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>修改用户</title><link rel="stylesheet" th:href="@{/static/css/index_work.css}">
</head>
<body>
<h1>修改用户</h1>
<form method="post" th:action="@{/employee}"><input name="_method" type="hidden" value="put"><input name="id" th:value="${employee.id}" type="hidden"><table><tr><th colspan="2">update Employee</th></tr><tr><td>LastName</td><td><input id="LastName" name="lastName" th:value="${employee.lastName}" type="text"></td></tr><tr><td>Email</td><td><input id="Email" name="email" th:value="${employee.email}" type="text"></td></tr><tr><td>Gender</td><td><input name="Gender" th:field="${employee.gender}" type="radio" value="0">male<input name="Gender" th:field="${employee.gender}" type="radio" value="1">female</td></tr><tr><td colspan="2"><input type="submit" value="修改"></td></tr></table>
</form></body>
</html>
注意这里的请求地址是/employee,我们传送的数据是带了id的Employee,我们Dao层读取到Employee的id后,就知道是修改,然后就会根据ID进行更新。
@GetMapping("/employee/{id}")public String toUpdateEmployeePage(@PathVariable("id") Integer id, Model model) {Employee employee = employeeDao.get(id);model.addAttribute("employee", employee);return "update_employee";}@PutMapping(value = "/employee")public String updateEmployee(Employee employee) {employeeDao.save(employee);return "redirect:/employee";}
第一个方法是根据ID查询出用户的信息,然后将信息返回到修改的页面:
然后这里的修改就是写一个PUT方法,然后将用户存储,然后通过重定向到List界面即可
5、删除用户
删除用户的按钮需要我们对list网页进行部分的修改,然后引入vue.js将a标签修改为form表单提交。
修改employee_list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>EmployeeList</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}">添加</a> )</th></tr><tr th:each="employee : ${employees}"><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 name="_method" type="hidden" 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",data: {},methods: {deleteEmployee() {//获取Form表单var form = document.getElementsByTagName("form")[0];//将超链接的href复制给form表单active属性//表示当前触发事件的标签form.action = event.target.href;//表单提交(触发提交)form.submit();//阻止超链接的默认行为(默认跳转页面)event.preventDefault();}}})
</script>
</body>
</html>
注意这里需要先引入vue,然后再写一个script标签,在之后的这个script标签中书写JS
还有就是VUE这里是methods,不要拼错了。
控制器方法
主要是根据ID删除,所以需要传一个ID参数
@DeleteMapping("/employee/{id}")public String deleteEmployee(@PathVariable("id") Integer id) {employeeDao.delete(id);return "redirect:/employee";}