REST(Representational State Transfer):表现层资源状态转移
①资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上可命名的抽象概念。因为资源是一种抽象概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,与面向对象设计类似,资源是以名词为核心来阻止的。一个资源可以由一个或多个URL来标识。URL既是资源的名称,也是资源在web上的地址。
②资源的描述
资源的描述是一段对于资源在某个特定的时刻的转台的描述,可以在客户端-服务器之间转移(交换),资源的表述含可以核对格式。如HTML/XML/JSON/纯文本等。资源的表述格式可以通过协商机制来确定,请求-响应方式的表述通常使用不同的格式。
③状态转移
状态转移说的是:在客户端-服务器之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述来间接实现操作资源的目的。
具体说,就是http协议里面,四个标识操作方式的动词:GET、POST、PUT、DELETE
它们分别对应四种基本操作:GET用来获取资源、POST用来新建资源、PUT用来更新资源、DELETE用来删除资源。
REST风格提倡URL地址使用同一风格设计,从前到后各个单词是使用斜杠分开,不适用问号键值对方式形式携带请求参数。而不是将发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。
操作 | 传统方式 | REST风格 |
---|---|---|
查询操作 | getUserById?id=1 | user/1---->get请求方式 |
新增操作 | saveUser | user----->post请求方式 |
删除操作 | deleteUser?id=1 | user/1---->delete请求 |
更新操作 | updateUser | user—>put请求 |
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.1version>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
<version>3.0.12.RELEASEversion>
dependency>
<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>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>springMVCRESTservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:SpringMVCRESTFul.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springMVCRESTservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
<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.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.xsd">
<context:component-scan base-package="com.louis.controller">context:component-scan>
<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="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
bean>
property>
bean>
property>
bean>
<mvc:view-controller path="/" view-name="test_REST">mvc:view-controller>
<mvc:annotation-driven>mvc:annotation-driven>
beans>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>Titletitle>
head>
<body>
恭喜!成功了!
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>Titletitle>
head>
<body>
<a th:href="@{/user}">查询所有用户信息a><br/>
<a th:href="@{/user/1}">根据id查询用户信息a><br/>
<form th:action="@{/user}" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="添加"><br/>
form>
body>
html>
@Controller
public class UserController {
/**
* 使用RESTFul模拟用户资源增删改查
* /user GET 查询所有的用户信息
* /user/1 GET 根据用户id查询用户信息
* /user POST 添加用户信息
* /user/1 DELETE 删除用户信息
* /user PUT 修改用户信息
*/
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getAllUser(){
System.out.println("查询所有用户信息");
return "success";
}
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public String getUserById(){
System.out.println("根据用户ID查询用户信息");
return "success";
}
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String insertUser(String username, String password){
System.out.println("username = " + username + " password = " + password);
return "success";
}
}
需要注意的是,不能直接使用PUT和DELETE操作,在SpringMVC中提供了一个过滤器(HiddenHttpMethodFilter),它是一个隐藏的HTTP请求方式,想要获取PUT和DELETE请求,必须满足两个条件,条件一是请求方式必须为POST,条件二是必须传输一个参数_method,但是它不需要用户传入,是一个隐藏的参数。
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
注意:在配置文件中有多个过滤器的时候,由
的前后顺序决定,所以为了正确性,需要将设置编码的过滤武器放在首位。
<form th:action="@{/user}" method="post">
<input type="hidden" name="_method" value="put">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="修改"><br/>
form>
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser(String username, String password){
System.out.println("修改用户信息 = " + username + "," + password);
return "success";
}
和(修改)PUT请求不同的是,删除(DELETE)通常是超链接。所以在实现删除操作的时候的思路是在超链接上绑定点击事件,在点击事件中需要先阻止超链接的跳转,获得当前的某一个表单,将表单的提交方式设置为post,在其中添加一个隐藏域,设置name=“_method”。
场景:在不连接数据库的情况下使用静态数据集合实现员工信息的增删改查。
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.1version>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
<version>3.0.12.RELEASEversion>
dependency>
<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>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
<servlet>
<servlet-name>DispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springMVC.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>DispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<context:component-scan base-package="com.louis">context:component-scan>
<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="HTML5"/>
<property name="characterEncoding" value="UTF-8"/>
bean>
property>
bean>
property>
bean>
beans>
package com.louis.bean;
/**
* @author XRY
* @date 2023年07月01日16:33
*/
public class User {
private Integer id;
private String username;
private String email;
private Integer gender;
public User() {
}
public User(Integer id, String username, String email, Integer gender) {
this.id = id;
this.username = username;
this.email = email;
this.gender = gender;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
public class UserDao {
private static Map<Integer, User> users = null;
static{
users = new HashMap<Integer, User>();
users.put(1001, new User(1001, "E-AA", "[email protected]", 1));
users.put(1002, new User(1002, "E-BB", "[email protected]", 1));
users.put(1003, new User(1003, "E-CC", "[email protected]", 0));
users.put(1004, new User(1004, "E-DD", "[email protected]", 0));
users.put(1005, new User(1005, "E-EE", "[email protected]", 1));
}
private static Integer initId = 1006;
//新增和修改的方法
public void save(User user){
if(user.getId() == null){
user.setId(initId++);
}
users.put(user.getId(), user);
}
//查询全部
public Collection<User> getAll(){
return users.values();
}
//通过Id查询
public User get(Integer id){
return users.get(id);
}
//通过Id删除
public void delete(Integer id){
users.remove(id);
}
}
package com.louis.controller;
import com.louis.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* @author XRY
* @date 2023年07月03日19:30
*/
@Controller
public class UserController {
@Autowired
private UserDao userDao;
}
功能 | URL地址 | 请求方式 |
---|---|---|
访问首页 | / | GET |
查询全部数据 | /user | GET |
删除 | /user/2 | DELETE |
跳转到添加页面 | /toAdd | GET |
执行保存操作 | /user | POST |
跳转到更新页面 | /user/2 | GET |
执行更新 | /user | PUT |
在templates下创建首页index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>首页title>
head>
<body>
<h3>首页h3>
<a th:href="@{/user}">查看员工信息a>
body>
html>
在配置文件springMVC.xml中添加
标签
<mvc:view-controller path="/" view-name="index">mvc:view-controller>
<mvc:annotation-driven>mvc:annotation-driven>
@Controller
public class UserController {
@Autowired
private UserDao userDao;
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getAllUser(Model model){
/*只需要将数据放在一个较小的域中即可*/
Collection<User> userList = userDao.getAll();
model.addAttribute("userList", userList);
return "employee_list";
}
}
创建
user_list.html
用来显示数据
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>Employee Infotitle>
head>
<body>
<table border="1" cellspacing="0" cellpadding="0" style="text-align: center">
<tr>
<th colspan="5">Employee Infoth>
tr>
<tr>
<th>idth>
<th>usernameth>
<th>emailth>
<th>genderth>
<th>optionsth>
tr>
<tr th:each="user : ${userList}">
<td th:text="${user.id}">td>
<td th:text="${user.username}">td>
<td th:text="${user.email}">td>
<td th:text="${user.gender}">td>
<td>
<a href="">deletea>
<a href="">updatea>
td>
tr>
table>
body>
html>
不能通过超链接发送请求,需要通过超链接控制表单。
获取需要删除的id,使用vue将超链接和表单连接,需要引入vue。
user_list.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>Employee Infotitle>
head>
<body>
<table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center">
<tr>
<th colspan="5">Employee Infoth>
tr>
<tr>
<th>idth>
<th>usernameth>
<th>emailth>
<th>genderth>
<th>optionsth>
tr>
<tr th:each="user : ${userList}">
<td th:text="${user.id}">td>
<td th:text="${user.username}">td>
<td th:text="${user.email}">td>
<td th:text="${user.gender}">td>
<td>
<a @click="deleteUser" th:href="@{'/user/'+${user.id}}">deletea>
<a href="">updatea>
td>
tr>
table>
<form id="deleteForm" method="post">
<input type="hidden" value="delete" name="_method">
form>
<script type="text/javascript" th:src="@{/static/js/vue.js}">script>
<script type="text/javascript">
var vue = new Vue({
/*需要绑定容器,包裹需要操作的标签*/
el:"#dataTable",
/*需要在超链接上绑定点击事件*/
methods:{
deleteUser(event){
/*获取当前form表单,添加deleteForm*/
let deleteForm = document.getElementById("deleteForm");
/*设置form表单的提交路径与超链接地址一致*/
deleteForm.action = event.target.href;
/*提交表单*/
deleteForm.submit();
/*取消标签的默认行为,阻止超链接直接跳转*/
event.preventDefault();
}
}
})
script>
body>
html>
创建删除的控制器
@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public String deleteUser(@PathVariable("id") Integer id){
userDao.delete(id);
/*删除之后与原来的表单就没有数据连接了*/
return "redirect:/user";
}
需要注意资源未引入的情况,需要重新进行打包。
重新打包
以上是解决服务器中没有vue资源文件,同时vue需要被默认的servlet处理,在springMVC中添加开放对静资源访问标签
<mvc:default-servlet-handler/>
测试
在表头部分的action表格中加入一个添加的超链接。
user_list.html
<tr>
<th>idth>
<th>usernameth>
<th>emailth>
<th>genderth>
<th>options(<a th:href="@{/toAdd}">adda>)th>
tr>
由于添加操作不需要处理其他的业务逻辑,所以可以在springMVC.xml中使用view-controller标签去实现控制器功能。
<mvc:view-controller path="/toAdd" view-name="user_add">mvc:view-controller>
创建user_add.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>add usertitle>
head>
<body>
<form th:action="@{/user}" method="post">
username:<input type="text" name="username"><br/>
email:<input type="text" name="email"><br/>
gender:<input type="radio" name="gender" value="1">male
<input type="radio" name="gender" value="0">female<br/>
<input type="submit" value="add">
form>
body>
html>
控制器
@RequestMapping(value = "/user", method = RequestMethod.POST)
public String addUser(User user){
userDao.save(user);
return "redirect:/user";
}
测试
更新操作和删除操作类似,但是需要表单显示相关内容并提交(回显)。
user_list.html
<a th:href="@{'/user/' + ${user.id}}">updatea>
控制器
@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
/*需要通过id查询数据,同时还需要将查询出来的数据在域中实现共享*/
public String getUserById(@PathVariable("id") Integer id, Model model){
User user = userDao.get(id);
model.addAttribute("user", user);
return "user_update";
}
创建user_update.html实现回显
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" xmlns:th="http://www.thymeleaf.org">
<title>add usertitle>
head>
<body>
<form th:action="@{/user}" method="post">
<input type="hidden" name="_method" value="put">
<input type="hidden" name="id" th:value="${user.id}">
username:<input type="text" name="username" th:value="${user.username}"><br/>
email:<input type="text" name="email" th:value="${user.email}"><br/>
gender:<input type="radio" name="gender" value="1" th:field="${user.gender}">male
<input type="radio" name="gender" value="0" th:field="${user.gender}">female<br/>
<input type="submit" value="update">
form>
body>
html>
创建修改的控制器
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser(User user){
userDao.save(user);
return "redirect:/user";
}
测试