- restful测试案例
- springmvc处理Ajax请求
- 使用springmvc注解 接收or返回 JSON格式数据
8、RESTful测试案例
1、准备工作
和传统 CRUD 一样,实现对员工信息的增删改查。
- 为了方便,没有链接数据库,使用DAO中的文本数据。
2、配置文件
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?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>
<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>
<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
当前工程的web.xmL配置的前端控制器Dispatcherservlet的url-pattern是/
tomcat的web.xmL配置的Defaultservlet的url-pattern也是/
此时,浏览器发送的请求会优先被DispatcherservLet进行处理,但是DispatcherservLet无法处理静态资源
若配置了<mvc : default-servLet-handLer />
,此时浏览器发送的所有请求都会被DefaultservLet处理
若配置了<mvc:default-servlet-handler />
和<mvc : annotation-driven />
浏览器发送的请求会先被Dispatcherservlet处理,如果无法处理在交给DefaultservLet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| <?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="pers.dhx_"/>
<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:default-servlet-handler/>
<mvc:annotation-driven> <mvc:message-converters> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="defaultCharset" value="UTF-8" /> <property name="supportedMediaTypes"> <list> <value>text/html</value> <value>application/json</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
<mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/to/add" view-name="employee_add"/> </beans>
|
实体类
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package com.birdy.mvc.bean;
public class Employee {
private Integer id; private String lastName;
private String email; 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() { } } 折叠
|
准备dao模拟数据
java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.birdy.mvc.dao;
import java.util.Collection; import java.util.HashMap; import java.util.Map;
import com.birdy.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); } } 折叠
|
3、功能清单
功能 |
URL 地址 |
请求方式 |
访问首页√ |
/ |
GET |
查询全部数据√ |
/employee |
GET |
删除√ |
/employee/2 |
DELETE |
跳转到添加数据页面√ |
/toAdd |
GET |
执行保存√ |
/employee |
POST |
跳转到更新数据页面√ |
/employee/2 |
GET |
执行更新√ |
/employee |
PUT |
4、访问首页
在spring配置文件中配置view-controller
1
| <mvc:view-controller path="/" view-name="index"/>
|
创建页面
index.html
1 2 3 4 5 6 7 8 9 10 11
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" > <title>Title</title> </head> <body> <h1>首页</h1> <a th:href="@{/employee}">访问员工信息</a> </body> </html>
|
5、查询所有员工数据
1 2 3 4 5 6
| @RequestMapping(value = "/employee", method = RequestMethod.GET) public String getEmployeeList(Model model){ Collection<Employee> employeeList = employeeDao.getAll(); model.addAttribute("employeeList", employeeList); return "employee_list"; }
|
employee_list.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Employee Info</title> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> </head> <body>
<table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable"> <tr> <th colspan="5">Employee Info</th> </tr> <tr> <th>id</th> <th>lastName</th> <th>email</th> <th>gender</th> <th>options(<a th:href="@{/toAdd}">add</a>)</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 class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a> <a th:href="@{'/employee/'+${employee.id}}">update</a> </td> </tr> </table> </body> </html>
|
6、删除员工
a>创建处理delete请求方式的表单
1 2 3 4 5
| <form id="delete_form" method="post"> <input type="hidden" name="_method" value="delete"/> </form>
|
b>删除超链接绑定点击事件
引入vue.js
1
| <script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
|
删除超链接
1
| <a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
|
通过vue绑定点击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <script type="text/javascript"> var vue = new Vue({ el:"#dataTable", methods:{ deleteEmployee:function (event) { var delete_form = document.getElementById("delete_form"); delete_form.action = event.target.href; delete_form.submit(); event.preventDefault(); } } }); </script>
|
控制器方法
1 2 3 4 5
| @RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE) public String deleteEmployee(@PathVariable("id") Integer id){ employeeDao.delete(id); return "redirect:/employee"; }
|
7、跳转到添加数据页面
配置view-controller
1
| <mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
|
创建employee_add.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <!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"> lastName:<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"><br> </form>
</body> </html>
|
8、具体功能:执行保存
a>控制器方法
1 2 3 4 5
| @RequestMapping(value = "/employee", method = RequestMethod.POST) public String addEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }
|
9、跳转到更新数据页面
a>修改超链接
1
| <a th:href="@{'/employee/'+${employee.id}}">update</a>
|
b>控制器方法
1 2 3 4 5 6
| @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"; }
|
c>创建employee_update.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!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}"> lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br> email:<input type="text" name="email" th:value="${employee.email}"><br>
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="update"><br> </form>
</body> </html>
|
10、修改员工信息
控制器方法
1 2 3 4 5
| @RequestMapping(value = "/employee", method = RequestMethod.PUT) public String updateEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }
|
9、SpringMVC处理ajax请求
- Axios 是一个基于 promise 网络请求库,作用于
node.js
和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
Axios API
Axios API参考
可以向 axios
传递相关配置来创建请求
axios(config)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } });
axios({ method: 'get', url: 'http://bit.ly/2mTM3nY', responseType: 'stream' }).then(function (response) { response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) });
|
axios(url[, config])
请求方式别名
为了方便起见,已经为所有支持的请求方法提供了别名。
-
axios.request(config)
-
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
注意
- 在使用别名方法时,
url
、method
、data
这些属性都不必在配置中指定。
9.2、@RequestBody
- @RequestBody可以获取请求体信息,使用@RequestBody注解标识控制器方法的形参,当前请求的请
求体就会为当前注解所标识的形参赋值
1>@RequestBody获取普通请求参数
前端请求
1 2 3 4 5 6 7 8 9
| testAjax(){ axios.post( "/demo04/test/ajax?id=1001", {username:"admin",password:"123456"} ).then(response=>{ console.log(response.data); }) },
|
java代码
1 2 3 4 5
| @RequestMapping("/test/ajax") public void testAjax(Integer id, HttpServletResponse response) throws IOException { System.out.println("id = " + id); response.getWriter().print("hello ,Ajax,success"); }
|
前端请求
1 2 3 4 5 6 7 8 9
| testRequestBody(){ axios.post( "/demo04/test/requestBody/json", {username:"admin",password:"123456","age":"23"} ).then(response=>{ console.log(response.data); }) }
|
java代码
1 2 3 4 5
| @RequestMapping("/requestBody/json") public void testRequestBody(@RequestBody User user, HttpServletResponse response) throws IOException { System.out.println(user); response.getWriter().print("hello ,requestBody,success"); }
|
User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class User { private Integer id; private String username; private String password; private Integer age; User(){}
@Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + '}'; } public User(Integer id, String username, String password, Integer age) { this.id = id; this.username = username; this.password = password; this.age = age; } }
|
1 2 3 4 5
| @RequestMapping("/requestBody/json") public void testRequestBody(@RequestBody Map<String,Object> map, HttpServletResponse response) throws IOException { System.out.println(map); response.getWriter().print("hello ,requestBody,success"); }
|
2>@RequestBody获取json格式的请求参数
- 使用@RequestBody注解标识控制器方法的形参即可将json格式请求参数转换为java对象
在使用了axios发送ajax请求之后,浏览器发送到服务器的请求参数有两种格式:
-
name=value&name=value…,此时的请求参数可以通过request.getParameter()
获取,
对应SpringMVC中,可以直接通过控制器方法的形参获取此类请求参数
-
{key:value,key:value,…},此时无法通过request.getParameter()
获取,之前我们使用操作json的相关jar包gson或jackson处理此类请求参数,可以将其转换为指定的实体类对象或map集合。
- 在SpringMVC中,直接使用@RequestBody注解标识控制器方法的形参即可将此类请求参数转换为java对象
示例:
1 2 3 4 5 6 7 8 9 10
| testRequestBody(){ axios.post( "/demo04/test/requestBody/json", {username:"admin",password:"123456","age":"23"} ).then(response=>{ console.log(response.data); }) } }
|
9.3、@ResponseBody
- @ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器
注意如果使用了ResponseBody就是直接返回数据,不会跳转到页面
1 2 3 4 5 6 7 8 9 10 11
| @RequestMapping("/testResponseBody") public String testResponseBody(){ return "success"; } @RequestMapping("/testResponseBody") @ResponseBody public String testResponseBody(){ return "success"; }
|
@ResponseBody处理json的步骤:
1、导入jackson的依赖
1 2 3 4 5
| <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency>
|
2、开启springmvc注解驱动
在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串
1
| <mvc:annotation-driven />
|
3、写上@ResponseBody
在处理器方法上使用@ResponseBody
注解进行标识,将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串
1 2 3 4 5
| @RequestMapping("/testResponseUser") @ResponseBody public User testResponseUser(){ return new User(1001,"admin","123456",23,"男"); }
|
浏览器的页面中展示的结果:
1
| {"id":1001,"username":"admin","password":"123456","age":23,"sex":"男"}
|
9.4、@RestController注解
- @RestController注解是springMVC提供的一个复合注解,标识在控制器的类上
- 相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解