本文纲要
REST风格简介RESTful入门案例RESTful快速开发与注解简化- 案例:基于
RESTful的图书管理后台与前端交互
4.1 后台接口开发
4.2 静态资源访问处理
4.3 前端页面数据交互
REST风格简介
REST 是 Representational State Transfer(表述性状态转移)的缩写。
它不是一种规范,而是一种设计风格,被广泛采纳为 Web 服务的资源访问标准。
1 ) 传统风格与REST风格对比
传统风格直接暴露操作行为,URL 类似:
// 查询用户
localhost/user/getById?id=1
// 保存用户
localhost/user/saveUser
REST 风格通过 URL + 请求方法 来定位资源和操作,隐藏了具体动作,使 URL 更简洁:
// 查询用户 (GET)
localhost/users/1
// 保存用户 (POST)
localhost/users
2 ) 对比表格:
| 操作 | 传统风格 URL | REST 风格 URL | 请求方法 |
|---|---|---|---|
| 查询全部用户 | /user/getAll | /users | GET |
| 查询单个用户 | /user/getById?id=1 | /users/1 | GET |
| 新增用户 | /user/save | /users | POST |
| 修改用户 | /user/update | /users | PUT |
| 删除用户 | /user/delete?id=1 | /users/1 | DELETE |
优点:
- URL 简化:去除了动词,只用名词复数描述资源。
- 隐藏访问行为:通过 HTTP 方法确定操作,安全性和语义更清晰。
- 统一接口:便于前后端分离和团队协作。
3 ) HTTP 方法的角色
Spring MVC 支持常用的 4 种请求方法:
| HTTP 方法 | 对应操作 | 说明 |
|---|---|---|
| GET | 查询 | 获取资源 |
| POST | 新增 | 创建资源 |
| PUT | 修改 | 更新资源(完整替换) |
| DELETE | 删除 | 删除资源 |
Spring MVC 底层支持 8 种请求方法,但日常开发高频率使用这四种。
下面通过一个流程图展示 RESTful 的请求分发:
RESTful入门案例
下面通过案例演示如何将传统控制器改造为 RESTful 风格。
1 ) 项目结构(入门演示:springmvc_06_rest)
springmvc_06_rest
└── src/main/java/com/wb/
├── config/
│ ├── ServletContainersInitConfig.java
│ └── SpringMvcConfig.java
├── controller/
│ ├── UserController.java # REST入门示例
│ ├── BookController.java # 注解简化示例
│ └── BookController2.java # 标准REST写法
└── domain/
├── Book.java
└── User.java
2 ) 基础实现:UserController
该控制器使用 @RequestMapping 的 method 属性限定请求方法,并使用 @PathVariable 接收路径参数。
package com.wb.controller;
import com.wb.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class UserController {
// 设置当前请求方法为POST,表示REST风格中的添加操作
@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
public String save() {
System.out.println("user save...");
return "{'module':'user save'}";
}
// 设置当前请求方法为DELETE,表示REST风格中的删除操作
// @PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,且名称一致
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id) {
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}
// 设置当前请求方法为PUT,表示REST风格中的修改操作
@RequestMapping(value = "/users", method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user) {
System.out.println("user update..." + user);
return "{'module':'user update'}";
}
// 查询单个:GET + /users/{id}
@RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id) {
System.out.println("user getById..." + id);
return "{'module':'user getById'}";
}
// 查询全部:GET + /users
@RequestMapping(value = "/users", method = RequestMethod.GET)
@ResponseBody
public String getAll() {
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}
}
关键点:
- 路径参数:
/users/{id}为占位符,@PathVariable将占位符的值赋给形参。 - 请求体接收:使用
@RequestBody接收 JSON 数据并转换为对象。
3 ) 配套配置类
// SpringMvcConfig.java
package com.wb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan("com.wb.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
// ServletContainersInitConfig.java
package com.wb.config;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 乱码处理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
RESTful快速开发与注解简化
入门代码中,每个方法都需要 @RequestMapping(method=...) 和 @ResponseBody,书写较为繁琐。Spring MVC 提供了一系列组合注解简化开发。
1 ) 简化过程演变
以 BookController.java 中的注释代码为线索,展示从原始写法到最终简化写法的变化。
步骤1:原始 @RequestMapping + @ResponseBody
@Controller
public class BookController {
@RequestMapping(value = "/books", method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody Book book) {
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
// ... 其他方法类似
}
步骤2:类上提取公共路径,使用 @ResponseBody 或 @RestController
@Controller
@RequestMapping("/books")
public class BookController {
// 每个方法不再需要写 "/books"
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody Book book){...}
}
// 如果所有方法都需要@ResponseBody,可以用@RestController替代@Controller+@ResponseBody
步骤3:方法专用注解替代 @RequestMapping
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book) {
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id) {
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
@PutMapping
public String update(@RequestBody Book book) {
System.out.println("book update..." + book);
return "{'module':'book update'}";
}
@GetMapping("/{id}")
public String getById(@PathVariable Integer id) {
System.out.println("book getById..." + id);
return "{'module':'book getById'}";
}
@GetMapping
public String getAll() {
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
2 ) 演变总结表:
| 原始写法 | 简化写法 | 说明 |
|---|---|---|
@RequestMapping(method=RequestMethod.GET) | @GetMapping | 限定GET请求 |
@RequestMapping(method=RequestMethod.POST) | @PostMapping | 限定POST请求 |
@RequestMapping(method=RequestMethod.PUT) | @PutMapping | 限定PUT请求 |
@RequestMapping(method=RequestMethod.DELETE) | @DeleteMapping | 限定DELETE请求 |
@Controller + @ResponseBody | @RestController | 整合为一个注解 |
3 ) 最终简化后的完整控制器(BookController)
package com.wb.controller;
import com.wb.domain.Book;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book) {
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id) {
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
@PutMapping
public String update(@RequestBody Book book) {
System.out.println("book update..." + book);
return "{'module':'book update'}";
}
@GetMapping("/{id}")
public String getById(@PathVariable Integer id) {
System.out.println("book getById..." + id);
return "{'module':'book getById'}";
}
@GetMapping
public String getAll() {
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
这种方式成为实际项目的标准写法。
案例:基于RESTful的图书管理后台与前端交互
本案例演示一个完整的图书管理模块,包括后台模拟数据接口和基于 Vue + ElementUI + axios 的前端页面。
1 ) 项目结构 (springmvc_07_rest_case)
springmvc_07_rest_case
├── pom.xml
└── src/main/
├── java/com/wb/
│ ├── config/
│ │ ├── ServletContainersInitConfig.java
│ │ ├── SpringMvcConfig.java
│ │ └── SpringMvcSupport.java # 静态资源放行配置
│ ├── controller/
│ │ └── BookController.java # 图书控制器(模拟数据)
│ └── domain/
│ └── Book.java # 图书实体类
└── webapp/
└── pages/
└── books.html # 前端页面
2 ) 后台接口开发
实体类 Book
package com.wb.domain;
public class Book {
private Integer id;
private String type;
private String name;
private String description;
// getters and setters 省略,实际应提供
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
@Override
public String toString() {
return "Book{" +
"id=" + id +
", type='" + type + '\'' +
", name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
}
控制器 BookController
提供两个接口:全量查询(GET)和新增(POST),数据保存在内存列表中(模拟)。
package com.wb.controller;
import com.wb.domain.Book;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public String save(@RequestBody Book book) {
System.out.println("book save ==> " + book);
return "{'module':'book save success'}";
}
@GetMapping
public List<Book> getAll() {
System.out.println("book getAll is running ...");
List<Book> bookList = new ArrayList<>();
Book book1 = new Book();
book1.setType("计算机");
book1.setName("SpringMVC入门教程");
book1.setDescription("小试牛刀");
bookList.add(book1);
Book book2 = new Book();
book2.setType("计算机");
book2.setName("SpringMVC实战教程");
book2.setDescription("一代宗师");
bookList.add(book2);
Book book3 = new Book();
book3.setType("计算机丛书");
book3.setName("SpringMVC实战教程进阶");
book3.setDescription("一代宗师呕心创作");
bookList.add(book3);
return bookList;
}
}
3 ) 使用 Postman 测试:
GET http://localhost/books→ 返回图书列表的 JSON 数组POST http://localhost/books,请求体为:{ "type":"计算机", "name":"SpringMVC深入浅出", "description":"精品" }
在控制台打印接收到的对象。
4 ) 静态资源访问处理
因为 DispatcherServlet 拦截了 / 路径,默认会拦截对静态资源(html, js, css, plugins)的请求,导致 404。我们需要让这些请求直接由 Tomcat 处理,而不是 Spring MVC。
5 ) 配置类 SpringMvcSupport
继承 WebMvcConfigurationSupport 并重写 addResourceHandlers 方法,指定资源路径映射。
package com.wb.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 当访问 /pages/ 时,去 /pages/ 目录下查找对应内容
registry.addResourceHandler("/pages/").addResourceLocations("/pages/");
registry.addResourceHandler("/js/").addResourceLocations("/js/");
registry.addResourceHandler("/css/").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/").addResourceLocations("/plugins/");
}
}
同时,记得在 SpringMvcConfig 中将该配置类纳入扫描:
@Configuration
@ComponentScan({"com.wb.controller", "com.wb.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
6 ) 前端页面数据交互
前端页面使用 Vue + ElementUI,通过 axios 发送 RESTful 请求。
页面加载时调用 getAll() 获取数据并渲染表格;点击“新建”后,saveBook() 将表单数据以 POST 方式提交。
关键代码(books.html 中的
<script>
var vue = new Vue({
el: '#app',
data: {
dataList: [], // 当前页列表数据
formData: {}, // 表单数据
dialogFormVisible: false,
pagination: {}
},
created() {
this.getAll(); // 页面初始化加载数据
},
methods: {
resetForm() {
this.formData = {};
},
openSave() {
this.dialogFormVisible = true;
this.resetForm();
},
saveBook() {
axios.post("/books", this.formData).then((res) => {
// 可在此处刷新列表或关闭弹窗
});
},
getAll() {
axios.get("/books").then((res) => {
this.dataList = res.data;
});
}
}
})
</script>
7 ) 交互流程图
总结
本章从 REST 基本概念出发,通过入门案例逐步掌握 @RequestMapping + method 与 @PathVariable 的使用,再借助 @RestController、@GetMapping 等注解实现快速开发。
最后通过图书管理案例,演示了后台接口测试、静态资源放行以及前端与后端通过 RESTful API 交互的全过程。
以上内容涵盖了 Spring MVC 中 RESTful 开发的全部核心知识,可在实际项目中直接应用。
763



被折叠的 条评论
为什么被折叠?



