1, Introduction to RESTful
REST: Representational State Transfer, the state transfer of presentation layer resources.
- resources:
Resource is a way of looking at the server, that is, the server is regarded as composed of many discrete resources. Each resource is a named abstraction on the server. Because resource is an abstract concept, it can not only represent a file in the server file system, a table in the database and other specific things, but also design resources as abstract as possible, as long as imagination allows and client application developers can understand. Similar to object-oriented design, resources are organized with nouns as the core, and nouns are the first concern. A resource can be identified by one or more URIs. A URI is not only the name of a resource, but also the address of the resource on the Web. Client applications interested in a resource can interact with it through the URI of the resource. - Description of resources:
The description of resources is a description of the state of resources at a specific time. It can be transferred (exchanged) between client and server. The expression of resources can be in many formats, such as HTML/XML/JSON / plain text / picture / video / audio, etc. The expression format of resources can be determined through negotiation mechanism. The request response direction is usually expressed in different formats. - State transition:
State transfer refers to the expression that transfer represents the state of resources between the client and the server. Through the expression of transfer and operation resources, the purpose of operating resources can be realized indirectly.
2, RESTful implementation
Specifically, there are four verbs representing the operation mode in the HTTP protocol: GET, POST, PUT and DELETE. They correspond to four basic operations: GET is used to obtain resources, POST is used to create new resources, PUT is used to update resources, and DELETE is used to DELETE resources.
REST style advocates the uniform style design of URL address. Each word from front to back is separated by slash. The request parameters are not carried by question mark key value pair, but the data to be sent to the server is taken as a part of the URL address to ensure the consistency of the overall style.
operation | Traditional way | REST style |
---|---|---|
Query operation | getUserById?id=1 | user/1 – > get request method |
Save operation | saveUser | user – > post request mode |
Delete operation | deleteUser?id=1 | user/1 – > delete request method |
update operation | updateUser | user – > put request mode |
Generally speaking, querying, saving, deleting and updating user are all operations on the user resource, so these four operations can be written to user in the resource layer of the URL, and the specific different operations are determined by the request method.
(1) Using RESTful style to implement get and post requests
first, Create a web module, configure web.xml and deploy Tomcat
controller:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class MyController { @RequestMapping(value = "/") public String toIndex(){ return "index"; } /* * Use RESTFul to simulate the addition, deletion, modification and query of user resources: * /user GET Query all user information * /user/1 GET Query user information according to user id * /user POST Add user information */ @RequestMapping(value = "/user",method = RequestMethod.GET) public String selectUsers(){ System.out.println("Query all user information"); return "target"; } @RequestMapping(value = "/user/{id}",method = RequestMethod.GET) public String selectUserById(){ System.out.println("According to user id Query user information"); return "target"; } @RequestMapping(value = "/user",method = RequestMethod.POST) public String addUser(){ System.out.println("Add user information"); return "target"; } }
index.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>home page</title> </head> <body> This is index.html<br> <a th:href="@{/user}">Query all user information</a><br> <a th:href="@{/user/1}">according to id Query user information</a><br> <form th:action="@{/user}" method="post"> user name:<input type="text" name="username"><br> password:<input type="password" name="password"><br> <input type="submit" value="Add user information"><br> </form> </body> </html>
target.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> This is target.html<br> </body> </html>
Run Tomcat:
Click the first link:
IDEA output:
Click the second link:
IDEA output:
Fill out the form:
IDEA output:
(2) Use RESTful style to implement put and delete requests
1.HiddenHttpMethodFilter
Since the browser only supports sending get and post requests, even if you write "put" or "delete" in the method of the form form, it will be regarded as a get request. How do you send put and delete requests?
Spring MVC provides HiddenHttpMethodFilter to help us convert POST requests into DELETE or PUT requests.
Let's take a look at the source code of HiddenHttpMethodFilter:
The following is the actual filtering method of HiddenHttpMethodFilter:
It will first intercept our request and assign the request object to requestToUse. If "POST".equals(request.getMethod()) & & request. Getattribute ("javax. Servlet. Error. Exception") = = null is true, the following code will be executed. The latter part is true without entanglement. We just need to take care of the previous "POST".equals(request.getMethod()), Therefore, to send a put or delete request, we need to set the request to post. Next, string paramValue = request. Getparameter (this. Methodparameter);, this.methodParam is shown in the previous figure_ Method ", that is, the request object is named"_ The parameter value of "method" is passed to paramValue. If you want to execute the following code, you must meet StringUtils.hasLength(paramValue), which means that if paramValue has a length, execute it down. So if we want to send a put or delete request, one more thing to do is to set a name in the request called "_ Method "and assign a value to it. Next, String method = paramValue.toUpperCase(Locale.ENGLISH); This means that all the values of this paramValue are capitalized and passed to the string object method, and then ALLOWED_METHODS.contains(method), if allowed_ The methods collection contains the string represented by method before execution. Let's take a look at ALLOWED_METHODS:
It contains the names of three requests: PUT, DELETE and PATCH. If yes, requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method); A new request object will be created and re assigned to requestToUse. Let's look at the source code of this HttpMethodRequestWrapper class:
It will create a request object that encapsulates the incoming request method. Finally, filterChain.doFilter((ServletRequest)requestToUse, response); fileterChain releases our request object so that we can access the target resource. So far, we have realized sending put or delete requests.
Summary:
HiddenHttpMethodFilter to process put and delete requests:
- The request mode of the current request must be post
- The current request must transmit the request parameters_ method, the parameter value is put or delete
If the above conditions are met, the HiddenHttpMethodFilter filter will convert the request mode of the current request into request parameters_ Method, so the request parameter_ The value of method is the final request method.
2. Send put request
Case: send put request
Register HiddenHttpMethodFilter in web.xml:
<!--Register filter 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>
controller:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class MyController { //Visit the home page @RequestMapping(value = "/") public String toIndex(){ return "index"; } // /User put modify user information @RequestMapping(value = "/user",method = RequestMethod.PUT) public String updateUser(){ System.out.println("Modify user information"); return "target"; } }
index.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>home page</title> </head> <body> This is index.html<br> <form th:action="@{/user}" method="post"> <input type="hidden" name="_method" value="put"><!--Set parameters_method The value of is put. Users do not need to know this, so hidden--> user name:<input type="text" name="username"><br> password:<input type="password" name="password"><br> <input type="submit" value="Modify user information"><br> </form> </body> </html>
Start Tomcat:
IDEA output:
Note: so far, spring MVC has provided two filters: characterencoding filter and HiddenHttpMethodFilter. When registering in web.xml, you must first register CharacterEncodingFilter and then HiddenHttpMethodFilter, otherwise the problem of garbled code will still occur.
reason:
In the characterencoding Filter, set the character set through the request.setCharacterEncoding(encoding) method. The request.setCharacterEncoding(encoding) method requires that there should be no previous operation to obtain the request parameters, while the HiddenHttpMethodFilter has exactly one operation to obtain the request method: string paramvalue = request.getparameter (this. Methodparameter);. When multiple Filter filters are executed, their execution priority is determined by their top-down configuration in web.xml. If HiddenHttpMethodFilter is configured in the first place, there will be a garbled code problem.
3. Send delete request
Instead of giving examples, let's look at the complete case below.
3, RESTful case
(1) Preparatory work
first, Create a web module, configure web.xml and deploy Tomcat
Prepare entity class:
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() { } }
Prepare dao for simulation data and operation data:
import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.atguigu.mvc.bean.Employee; import org.springframework.stereotype.Repository; @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); } }
controller:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class EmployeeController { @Autowired private EmployeeDao employeeDao; }
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"> <!--In multiple Filter When filters are executed, the priority of their execution is determined by their web.xml The order of top-down configuration is determined--> <!--Register filter CharacterEncodingFilter--> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!--To set the encoding of the request to UTF-8--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <!--To set the encoding of the response to UTF-8--> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--Register filter 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> <!-- to configure SpringMVC The front-end controller of the browser uniformly processes the requests sent by the browser --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- Specified by initialization parameters SpringMVC Location and name of the configuration file --> <init-param> <!-- contextConfigLocation Is a fixed value --> <param-name>contextConfigLocation</param-name> <!-- use classpath:Indicates finding a configuration file from a classpath, for example maven In Engineering src/main/resources --> <param-value>classpath:springMVC.xml</param-value> </init-param> <!--As the core component of the framework, there are a lot of initialization operations to be done during startup These operations are performed only when the first request is made, which will seriously affect the access speed Therefore, it is necessary to start the control through this label DispatcherServlet The initialization time of is advanced until the server starts --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!--set up springMVC The request path of the request that can be processed by the core controller of /The matching request can be/login or.html or.js or.css Mode request path however/Cannot match.jsp Request for request path --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
(2) Function list
function | URL address | Request mode |
---|---|---|
Visit home page √ | / | GET |
Query all data √ | /employee | GET |
Delete √ | /employee/2 | DELETE |
Jump to add data page √ | /toAdd | GET |
Execute save √ | /employee | POST |
Jump to update data page √ | /employee/2 | GET |
Execute update √ | /employee | PUT |
(3) Visit the home page
Add in springMVC.xml (introduce mvc namespace before this):
<!--Configure view controller--> <mvc:view-controller path="/" view-name="index"/> <!--open mvc Annotation driven--> <mvc:annotation-driven />
index.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>home page</title> </head> <body> <h1>home page</h1> <a th:href="@{/employee}">View all employee information</a> </body> </html>
(4) Query all employee data
controller:
@RequestMapping(value = "/employee",method = RequestMethod.GET) public String selectAllEmployees(Model model){ Collection<Employee> employeeList = employeeDao.getAll(); model.addAttribute("employeeList",employeeList); return "employee_list"; }
employee_list.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1" cellpadding="0" cellspacing="0" style="text-align: center"> <tr> <th colspan="5">Employee information</th> </tr> <tr> <th>Employee number</th> <th>full name</th> <th>mailbox</th> <th>Gender</th> <th>option</th> </tr> <tr th:each="employee:${employeeList}"> <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="">modify</a> </td> </tr> </table> <a href="">Add employee</a> </body> </html>
(5) Delete function
In employee_ Create a form to handle the delete request in list.html:
<!-- Function: control the submission of forms through hyperlinks post Request converted to delete request --> <form id="delete_form" method="post"> <!-- HiddenHttpMethodFilter Requirement: must be transmitted_method Request parameters, and the value is the final request method --> <input type="hidden" name="_method" value="delete"/> </form>
next, Download vue.js And copy it to webapp/static/js /
employee_ Hyperlink in list.html for deletion:
<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
employee_list.html hyperlink binding click event for deletion:
<!--introduce vue.js,adopt vue Handle delete link click events--> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript"> var vue = new Vue({ el:"#dataTable", methods:{ //Event indicates the current event deleteEmployee:function (event) { //Get form elements by id var deleteForm = document.getElementById("deleteForm"); //Assign the href attribute of the hyperlink that triggers the click event to the action of the form deleteForm.action = event.target.href; //Submit Form deleteForm.submit(); //Block default jump behavior of hyperlinks event.preventDefault(); } } }); </script>
controller:
@RequestMapping(value = "/employee/{id}",method = RequestMethod.DELETE) public String deleteEmployeeById(@PathVariable("id") Integer id){ employeeDao.delete(id); return "redirect:/employee"; }
springMVC.xml:
<!--Open access to static resources--> <!--All requests were rejected DispatcherServlet Processing, the controller has no mapping to access static resources We're going to use it DefaultServlet handle--> <mvc:default-servlet-handler />
The project has been run before, and the static resource vue.js added later does not exist in the packaging result. Repackage it (click packaging in Lifecycle of Maven interface in IDEA)
(6) Jump to the add data page
springMVC.xml:
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
Create employee_add.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>add employee</title> </head> <body> <form th:action="@{/employee}" method="post"> full name:<input type="text" name="lastName"><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 to"><br> </form> </body> </html>
(7) Execute save
controller:
@RequestMapping(value = "/employee", method = RequestMethod.POST) public String addEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }
(8) Jump to update data page
employee_ Hyperlinks for modification in list.html:
<a th:href="@{'/employee/'+${employee.id}}">modify</a>
controller:
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET) public String getEmployeeById(@PathVariable("id") Integer id, Model model){ Employee employee = employeeDao.get(id); model.addAttribute("employee", employee); return "employee_update"; }
Create employee_update.html:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Update Employee</title> </head> <body> <form th:action="@{/employee}" method="post"> <input type="hidden" name="_method" value="put"> <input type="hidden" name="id" th:value="${employee.id}"> full name:<input type="text" name="lastName" th:value="${employee.lastName}"><br> mailbox:<input type="text" name="email" th:value="${employee.email}"><br> <!-- th:field="${employee.gender}"Can be used for echo of radio boxes or check boxes If the radio box is value and employee.gender If the values are consistent, add checked="checked"attribute --> Gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br> <input type="submit" value="to update"><br> </form> </body> </html>
(9) Execute update
controller:
@RequestMapping(value = "/employee", method = RequestMethod.PUT) public String updateEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }