REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格
当我们想表示一个网络资源的时候,可以使用两种方式:
http://localhost/user/getById?id=115
查询id为1的用户信息http://localhost/user/saveUser
保存用户信息http://localhost/user/115
http://localhost/user
传统方式一般是一个请求url对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作。
查看REST风格的描述,你会发现请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能
所以REST的优点有:
但是我们的问题也随之而来了,一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作呢?
http://localhost/users
查询全部用户信息 GET(查询)http://localhost/users/115
查询指定用户信息 GET(查询)http://localhost/users
添加用户信息 POST(新增/保存)http://localhost/users
修改用户信息 PUT(修改/更新)http://localhost/users/115
删除用户信息 DELETE(删除)请求的方式比较多,但是比较常用的就4种,分别是GET
,POST
,PUT
,DELETE
。
按照不同的请求方式代表不同的操作类型。
但是注意:
清楚了什么是REST风格后,我们后期会经常提到一个概念叫RESTful
,那什么又是RESTful呢?
后期在进行开发的过程中,大多是都是遵从REST风格来访问后台服务,所以可以说以后都是基于RESTful来进行开发的。
创建一个Web的Maven项目
pom.xml添加Spring依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.dcxuexigroupId>
<artifactId>springmvc_05_restartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<name>springmvc_05_rest Maven Webappname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.15.RELEASEversion>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.4version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.1version>
<configuration>
<port>80port>
<path>/path>
<uriEncoding>UTF-8uriEncoding>
configuration>
plugin>
plugins>
build>
project>
创建对应的配置类
@Configuration
@ComponentScan("com.dcxuexi.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
public class ServlertContainersInitConfig 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};
}
}
\
编写模型类User
public class User {
private String userName;
private Integer userAge;
private String userSex;
private String address;
public User() {
}
public User(String userName, Integer userAge, String userSex, String address) {
this.userName = userName;
this.userAge = userAge;
this.userSex = userSex;
this.address = address;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", userAge=" + userAge +
", userSex='" + userSex + '\'' +
", address='" + address + '\'' +
'}';
}
}
编写UserController
@Controller
public class UserController {
@RequestMapping("/findAll")
@ResponseBody
public List<User> findAll(){
User user1 = new User("张三", 18, "男", "北京");
User user2 = new User("李四", 24, "女", "上海");
User user3 = new User("王二", 20, "男", "天津");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
System.out.println("select userList ==>" +userList);
return userList;
}
@RequestMapping("/insert")
@ResponseBody
public String insertUser(@RequestBody User user){
System.out.println("insert user ==>" + user);
return "insert user success";
}
@RequestMapping("/update")
@ResponseBody
public String updateUser(@RequestBody User user){
System.out.println("update user ==>" + user);
return "update user success";
}
@RequestMapping("/delete")
@ResponseBody
public String deleteUser(String userName){
System.out.println("delete user ==>" +userName);
return "delete user success";
}
}
最终创建好的项目结构如下:
需求:将之前的增删改查替换成RESTful的开发方式。
1.之前不同的请求有不同的路径,现在要将其修改为统一的请求路径
修改前: 新增: /findAll ,修改: /update,删除 /delete…
修改后: 增删改查: /users
2.根据GET查询、POST新增、PUT修改、DELETE删除对方法的请求方式进行限定
3.发送请求的过程中如何设置请求参数?
@Controller
public class UserController {
//设置当前请求方法为POST,表示REST风格中的添加操作
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String insertUser(@RequestBody User user){
System.out.println("insert user ==>" + user);
return "insert user success";
}
}
将请求路径更改为/users
http://localhost/users
使用method属性限定该方法的访问方式为POST
如果发送的不是POST请求,比如发送GET请求,则会报错
@Controller
public class UserController {
//设置当前请求方法为DELETE,表示REST风格中的删除操作
@RequestMapping(value = "/users",method = RequestMethod.DELETE)
@ResponseBody
public String deleteUser(String userName){
System.out.println("delete user ==>" +userName);
return "delete user success";
}
}
/users
http://localhost/users
访问成功,但是删除方法没有携带所要删除数据的userName,所以针对RESTful的开发,如何携带数据参数?
前端发送请求的时候使用:http://localhost/users/xiaochuang
,路径中的xiaochuang
就是我们想要传递的参数。
后端获取参数,需要做如下修改:
/users/{userName}
,目的是和路径匹配@Controller
public class UserController {
//设置当前请求方法为DELETE,表示REST风格中的删除操作
@RequestMapping(value = "/users/{userName}",method = RequestMethod.DELETE)
@ResponseBody
public String deleteUser(@PathVariable String userName){
System.out.println("delete user ==>" +userName);
return "delete user success";
}
}
思考如下两个问题:
(1)如果方法形参的名称和路径{}
中的值不一致,该怎么办?
(2)如果有多个参数需要传递该如何编写?
前端发送请求的时候使用:http://localhost/users/xiaochuang/28
,路径中的xiaochuang
和28
就是我们想要传递的两个参数。
后端获取参数,需要做如下修改:
@Controller
public class UserController {
//设置当前请求方法为DELETE,表示REST风格中的删除操作
@RequestMapping(value = "/users/{name}/{age}",method = RequestMethod.DELETE)
@ResponseBody
public String deleteUser(@PathVariable("name") String userName,@PathVariable("age")Integer userAge){
System.out.println("delete user ==>" +userName);
System.out.println("delete user ==>" +userAge);
return "delete user success";
}
}
@Controller
public class UserController {
//设置当前请求方法为PUT,表示REST风格中的修改操作
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String updateUser(@RequestBody User user){
System.out.println("update user ==>" + user);
return "update user success";
}
}
将请求路径更改为/users
http://localhost/users
访问并携带参数:
@Controller
public class UserController {
//设置当前请求方法为GET,表示REST风格中的查询操作
@RequestMapping(value = "/users/{userName}",method = RequestMethod.GET)
@ResponseBody
public User findByUserName(@PathVariable String userName){
User user1 = new User("张三", 18, "男", "北京");
User user2 = new User("李四", 24, "女", "上海");
User user3 = new User("王二", 20, "男", "天津");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
for (User user:userList
) {
if (user.getUserName().equals(userName)){
System.out.println("select user ==>" +user);
return user;
}
}
return new User();
}
}
将请求路径更改为/users
http://localhost/users/张三
@Controller
public class UserController {
//设置当前请求方法为GET,表示REST风格中的查询操作
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public List<User> findAll(){
User user1 = new User("张三", 18, "男", "北京");
User user2 = new User("李四", 24, "女", "上海");
User user3 = new User("王二", 20, "男", "天津");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
System.out.println("select userList ==>" +userList);
return userList;
}
}
将请求路径更改为/users
http://localhost/users
小结
RESTful入门案例,我们需要学习的内容如下:
(1)设定Http请求动作(动词)
@RequestMapping(value=“”,method = RequestMethod.POST|GET|PUT|DELETE)
(2)设定请求参数(路径变量)
@RequestMapping(value=“/users/{userName}”,method = RequestMethod.DELETE)
@ReponseBody
public String delete(@PathVariable String userName){
}
名称 | @PathVariable |
---|---|
类型 | 形参注解 |
位置 | SpringMVC控制器方法形参定义前面 |
作用 | 绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应 |
关于接收参数,我们学过三个注解@RequestBody
、@RequestParam
、@PathVariable
,这三个注解之间的区别和应用分别是什么?
做完了RESTful的开发,你会发现好麻烦,麻烦在哪?
问题1:每个方法的@RequestMapping注解中都定义了访问路径/users,重复性太高。
问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。
问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。
对于上面所提的这三个问题,具体该如何解决?
@RestController //@Controller + ReponseBody
@RequestMapping("/users")
public class UserController {
//设置当前请求方法为GET,表示REST风格中的查询操作
//@RequestMapping(value = "/users",method = RequestMethod.GET)
//@ResponseBody
@GetMapping
public List<User> findAll(){
User user1 = new User("张三", 18, "男", "北京");
User user2 = new User("李四", 24, "女", "上海");
User user3 = new User("王二", 20, "男", "天津");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
System.out.println("select userList ==>" +userList);
return userList;
}
//设置当前请求方法为GET,表示REST风格中的查询操作
//@RequestMapping(value = "/users/{userName}",method = RequestMethod.GET)
//@ResponseBody
@GetMapping("/{userName}")
public User findByUserName(@PathVariable String userName){
User user1 = new User("张三", 18, "男", "北京");
User user2 = new User("李四", 24, "女", "上海");
User user3 = new User("王二", 20, "男", "天津");
List<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
for (User user:userList
) {
if (user.getUserName().equals(userName)){
System.out.println("select user ==>" +user);
return user;
}
}
return new User();
}
//设置当前请求方法为POST,表示REST风格中的添加操作
//@RequestMapping(value = "/users",method = RequestMethod.POST)
//@ResponseBody
@PostMapping
public String insertUser(@RequestBody User user){
System.out.println("insert user ==>" + user);
return "insert user success";
}
//设置当前请求方法为PUT,表示REST风格中的修改操作
//@RequestMapping(value = "/users",method = RequestMethod.PUT)
//@ResponseBody
@PutMapping()
public String updateUser(@RequestBody User user){
System.out.println("update user ==>" + user);
return "update user success";
}
//设置当前请求方法为DELETE,表示REST风格中的删除操作
//@RequestMapping(value = "/users/{name}/{age}",method = RequestMethod.DELETE)
//@ResponseBody
@DeleteMapping("/{name}/{age}")
public String deleteUser(@PathVariable("name") String userName,@PathVariable("age")Integer userAge){
System.out.println("delete user ==>" +userName);
System.out.println("delete user ==>" +userAge);
return "delete user success";
}
}
对于刚才的问题,我们都有对应的解决方案:
问题1:每个方法的@RequestMapping注解中都定义了访问路径/users,重复性太高。
将@RequestMapping提到类上面,用来定义所有方法共同的访问路径。
问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。
使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替
问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。
1.将ResponseBody提到类上面,让所有的方法都有@ResponseBody的功能
2.使用@RestController注解替换@Controller与@ResponseBody注解,简化书写
名称 | @RestController |
---|---|
类型 | 类注解 |
位置 | 基于SpringMVC的RESTful开发控制器类定义上方 |
作用 | 设置当前控制器类为RESTful风格, 等同于@Controller与@ResponseBody两个注解组合功能 |
名称 | @GetMapping @PostMapping @PutMapping @DeleteMapping |
---|---|
类型 | 方法注解 |
位置 | 基于SpringMVC的RESTful开发控制器方法定义上方 |
作用 | 设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作, 例如@GetMapping对应GET请求 |
相关属性 | value(默认):请求访问路径 |