当前位置:   article > 正文

Springboot 之 RESTFul风格_springboot restful

springboot restful

3.4 Spring Boot 实现 RESTful 风格

3.4.1 关于RESTFul

REST(英文:Representational State Transfer,简称 REST)

RESTFul是一种互联网软件架构设计的风格,但它并不是标准,它只是提出了一组客户端和服务器交互时的架构理念和设计原则,基于这种理念和原则设计的接口可以更简洁,更有层次,REST这个词,是 Roy Thomas Fielding 在他 2000 年的博士论文中提出的。

任何的技术都可以实现这种理念,如果一个架构符合 REST 原则,就称它为 RESTFul 架构。

比如:

我们要访问一个 http 接口:http://localhost:8080/boot/order?id=1021&status=1

采用 RESTFul 风格则 http 地址为:http://localhost:8080/boot/order/1021/1

简单点来说RESTful就是把参数放到请求路径中,而省略了参数名

3.4.2 Spring Boot 开发 RESTFul

Spring boot 开发 RESTFul 主要是几个注解实现

RESTFul风格要求后端响应请求的方式通常是有明确性的,即使用表示意义明确的注解标注方法响应类型

(1) @PathVariable

该注解是实现 RESTFul 最主要的一个注解 ,我们一般通过该注解获取 url 中的数据

使用
@RestController
public class studentController {

    @GetMapping(value = "/student/details/{id}")
    public Object studentDetails(@PathVariable("id") Integer id){
        return "ID -> " + id;
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上面代码中,后端接收的参数写在value中,用{}括起来,在方法参数内的@PathVariable(“id”) Integer id表示将接收到的参数赋值给Integer类型的引用id,其中@PathVariable内的参数与value中的参数应一致。

浏览器测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ER3zijWV-1623212761041)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210608215143861.png)]

多个参数
@GetMapping(value = "/student/details/{id}/{name}")
public Object studentDetails2(@PathVariable("id") Integer id, @PathVariable("id") String name){
    return "ID -> " + id + " NAME -> " + name;
}
  • 1
  • 2
  • 3
  • 4

可以看到是没有问题的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bjDIOHOl-1623212761043)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210608220427527.png)]

注意

下面的写法实际并不会产生报错:

@RestController
public class studentController {

    @GetMapping(value = "/student/details")
    public Object studentDetail(Integer id){
        return "id -> " + id;
    }

    @GetMapping(value = "/student/details/{id}")
    public Object studentDetails(@PathVariable("id") Integer id){
        return "ID -> " + id;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M0eWc9ij-1623212761044)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210608215557663.png)]

可以看到,两个方法都是能响应的。

这是因为传统的http请求风格将方法接收的参数视为请求中传来的参数,而RESTFul风格的写法将传来的参数视为url的一部分,这是不一样的。

但是下面这种写法是会报错的:

@RestController
public class studentController {

    @GetMapping(value = "/student/details/{id}/{name}")
    public Object studentDetails2(@PathVariable("id") Integer id, @PathVariable("name") String name){
        return "ID -> " + id + " NAME -> " + name;
    }

    @GetMapping(value = "/student/details/{id}/{grade}")
    public Object studentDetails3(@PathVariable("id") Integer id, @PathVariable("grade") String grade){
        return "ID -> " + id + " GRADE -> " + grade;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行后会报如下错误:

java.lang.IllegalStateException: Ambiguous handler methods mapped for '/student/details/1/%E7%8E%8B%E4%BA%94': {public java.lang.Object com.example.springbootworkspace.web.studentController.studentDetails3(java.lang.Integer,java.lang.String), public java.lang.Object com.example.springbootworkspace.web.studentController.studentDetails2(java.lang.Integer,java.lang.String)}
  • 1

这是因为两个方法接收的参数类型顺序是一致的,无法分辨响应请求的到底是哪一个方法。

想要解决请求冲突,只能通过改写请求方式 或者 对url进行更加详细的描写

其他注解
@PostMapping

接收和处理 Post 方式的请求

@DeleteMapping

接收 delete 方式的请求,可以使用 GetMapping 代替

@PutMapping

接收 put 方式的请求,可以用 PostMapping 代替

@GetMapping

接收 get 方式的请求

3.4.3 使用 RESTful 风格模拟对学生信息的增删改查操作

集成 MyBatis、springboot,模拟实现对学生的增删改查操作

(1) pom.xml 文件

应具备如下内容

<dependencies> 
    <!--SpringBoot框架web项目起步依赖--> 
    <dependency> 
        <groupId>org.springframework.boot</groupId> 
		<artifactId>spring-boot-starter-web</artifactId> 
        </dependency> 
    <!--MyBatis集成SpringBoot框架起步依赖--> 
    <dependency> 
        <groupId>org.mybatis.spring.boot</groupId> 
        <artifactId>mybatis-spring-boot-starter</artifactId> 
        <version>2.0.1</version> 
    </dependency> 
    <!--MySQL驱动--> 
    <dependency> 
        <groupId>mysql</groupId> 
        <artifactId>mysql-connector-java</artifactId> 
    </dependency> 
</dependencies> 

<build> 
    <!--指定配置资源的位置--> 
    <resources> 
        <resource> 
            <directory>src/main/java</directory> 
            <includes> 
                <include>**/*.xml</include> 
            </includes> 
        </resource> 
    </resources> 
    <plugins> 
        <!--mybatis代码自动生成插件--> 
        <plugin> 
            <groupId>org.mybatis.generator</groupId> 
            <artifactId>mybatis-generator-maven-plugin</artifactId> 
            <version>1.3.6</version> 
            <configuration> 
                <!--配置文件的位置--> 
                <configurationFile>GeneratorMapper.xml</configurationFile> 
                <verbose>true</verbose> 
                <overwrite>true</overwrite> 
            </configuration> 
        </plugin> 

        <plugin> 
            <groupId>org.springframework.boot</groupId> 
            <artifactId>spring-boot-maven-plugin</artifactId> 
        </plugin> 
	</plugins> 
</build> 
  • 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
(2) application.yml 核心配置文件
server:
	port: 8090
  	servlet:
    	context-path: /

#配置数据源 
spring:   
	datasource: 
    	driver-class-name: com.mysql.cj.jdbc.Driver     
    	url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8     
    	username: root
    	password: qks218126 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
(3) 逆向工程生成 DAO

根目录下的GeneratorMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

    <!-- 指定连接数据库的 JDBC 驱动包所在位置,指定到你本机的完整路径 -->
    <classPathEntry location="C:\Users\15998\.m2\repository\mysql\mysql-connector-java\8.0.25\mysql-connector-java-8.0.25.jar"/>

    <!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
    <context id="tables" targetRuntime="MyBatis3">

        <!-- 抑制生成注释器,因为生成的注释都是英文的,可以不让它生成 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 配置数据库连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/springboot"
                        userId="root"
                        password="qks218126">
        </jdbcConnection>

        <!-- 生成 model 类,targetPackage 指定 model 类的包名, targetProject 指定
       生成的 model 放在 eclipse 的哪个工程下面-->
        <javaModelGenerator targetPackage="com.example.springbootworkspace.model"
                            targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
            <property name="trimStrings" value="false" />
        </javaModelGenerator>

        <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的
       包名, targetProject 指定生成的 mapper.xml 放在 eclipse 的哪个工程下面 -->
        <sqlMapGenerator targetPackage="com.example.springbootworkspace.mapper"
                         targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包
       名, targetProject 指定生成的 Mapper 接口放在 eclipse 的哪个工程下面 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.example.springbootworkspace.mapper"
                             targetProject="src/main/java">
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 数据库表名及对应的 Java 模型类名 -->
        <table tableName="t_student" domainObjectName="Student"
               enableCountByExample="false"
               enableUpdateByExample="false"
               enableDeleteByExample="false"
               enableSelectByExample="false"
               selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>
  • 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

逆向工程生成DAO

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jPKxflas-1623212761046)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210609103447605.png)]

(4)编写代码

控制层

@RestController
public class RESTfulController {

    @Autowired
    private StudentService studentService;

    /**
     * 增加学生信息
     * @param id
     * @param name
     * @return
     */
    @PostMapping(value = "/student/{id}/{name}/{age}")
    public Object addStudent(@PathVariable("id") Integer id, @PathVariable("name") String name, @PathVariable("age") Integer age) {
        Student student = new Student();
        student.setId(id);
        student.setStuName(name);
        student.setStuAge(age);
        return studentService.insert(student);
    }

    /**
     * 删除学生信息
     * @param id
     * @return
     */
    @DeleteMapping(value = "/student/{id}")
    public Object removeStudent(@PathVariable("id") Integer id) {
        return studentService.deleteByPrimaryKey(id);
    }

    /**
     * 修改学生信息
     * @param id
     * @return
     */
    @PutMapping(value = "/student/{id}/{name}")
    public Object modifyStudent(@PathVariable("id") Integer id, @PathVariable("name") String name) {
        Student student = new Student();
        student.setId(id);
        student.setStuName(name);
        return studentService.modifyStudentById(student);
    }

    /**
     * 通过id查询学生信息
     * @param id
     * @return
     */
    @GetMapping(value = "/student/{id}")
    public Object queryStudent(@PathVariable("id") Integer id) {
        Student student = studentService.queryStudentById(id);
        return student;
    }
} 	
  • 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

业务层

public interface StudentService {

    /*
    * 根据学生id获取学生详情
    * */

    Student queryStudentById(Integer id);

    /**
     * 根据student对象更新学生信息
     * @param student
     * @return
     */
    int modifyStudentById(Student student);

    /**
     * 根据id删除学生信息
     * @param id
     * @return
     */
    int deleteByPrimaryKey(Integer id);

    /**
     * 增加学生信息
     * @param student
     * @return
     */
    int insert(Student student);
}
  • 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

业务层实现类

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentMapper studentMapper;

    @Override
    public Student queryStudentById(Integer id) {
        return studentMapper.selectByPrimaryKey(id);
    }

    @Override
    public int modifyStudentById(Student student){
        return studentMapper.updateByPrimaryKeySelective(student);
    }

    @Override
    public int deleteByPrimaryKey(Integer id) {
        return studentMapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(Student student) {
        return studentMapper.insert(student);
    }
}
  • 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
(5) 使用 Postman 测试

插入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DbxPZFMD-1623212761047)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210609120739675.png)]

删除

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hnxUF1w3-1623212761048)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210609121056628.png)]

查询

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CFa2nuZt-1623212761049)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210609120838992.png)]

修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WGPuQgGS-1623212761049)(C:\Users\15998\AppData\Roaming\Typora\typora-user-images\image-20210609121439196.png)]

(6)RESTful好与坏

好处就是:传递参数变简单了,服务提供者对外只提供了一个接口服务,而不是传统的 CRUD 四个接口

坏处就是除了需要指定特定的请求方式之外,还需要对url进行更加细致的划分

3.4.5 RESTful 原则

  • 增 post 请求、删 delete 请求、改 put 请求、查 get 请求

  • 请求路径不要出现动词例如:查询订单接口

​ /boot/order/1021/1(推荐)
​ /boot/queryOrder/1021/1(不推荐)

  • 分页、排序等操作,不使用斜杠传参数例如:订单列表接口

​ /boot/orders?page=1&sort=desc

  • 一般传的参数不是数据库表的字段,可以不采用斜杠
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/580043
推荐阅读
相关标签
  

闽ICP备14008679号