• Spring Boot前后端分离之后端开发



    📃个人主页: 不断前进的皮卡丘
    🌞博客描述: 梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记
    🔥系列专栏: Spring Boot专栏

    前后端分离开发概述

    相关术语

    前端和后端:
    前端和后端是针对于技术来说的。
    前端: 负责页面展示相关的技术,比如html,css,js,jquery,vue,bookstrap等
    后端:与数据,还有业务逻辑相关,比如Java,MySQL等
    移动端:移动设置相关的技术,比如Android(java,kotilin),iOS(swift)
    全栈工程师:前端,后端,移动端
    全过程工程师:产品设计,代码开发,测试,运维

    前台和后台
    前台和后台是相对于使用者来说的
    前台:它是相对于普通用户来说,比如用户可以看到的网站
    后台:它是对应程序的管理人员和运维人员而言的,后台也包括前端(页面)和后端(数据和业务)

    前后端分离开发概述

    前后端分离模式概述

    早期的时候,web应用中的数据,页面,渲染都在服务端完成,但是随着时代的发展,前端设备越来越多(手机,平板,桌面电脑等),后来就慢慢兴起前后端分离的思想:后端负责数据处理,前端负责数据渲染,前端静态页面调用指定api获取固定格式的数据
    为了实现前后端分离,必须要有一种统一的机制,方便不同的前端设备和后端进行通信
    image.png
    image.png

    接口规范

    RESTful API的理解

    • RESTful是什么
      • RESTful是当前比较流行的一种互联网软件架构模型,通过统一的规范来完成不同终端的数据访问和交换,REST全称是Representaional State Transfer(资源表现层状态转换)
      • RESTful的优点:结构清晰,有统一的标准、扩展性好
      • 是前后端交互的规范
    • Resources
      • 资源指的是网络中的某一个具体文件,类型不限,可以是文本、图片、音频、视频、数据流等,也可能是一个学生的信息,添加,删除,查询等都被看成是不同资源操作。
      • 如何获取?可以通过统一资源标识符找到这个实体,URI,每一个资源都有特定的URI,通过URL可以找到一个具体的资源HTTP 协议详解 —— URI、HTTP protocol、HTTP headers
      • image.png
    • Pepresentation
      • 资源表现层,资源的具体表现形式,比如一段文字,可以使用TXT,JSON,HTML,XML等不同的形式来描述
      • 对互联网的任何操作,都看成是对资源的操作
    • State Transfer
      • 状态转化是指客户端和服务端之间的数据交换,因为HTTP请求不能传输数据的状态(HTTP协议是无状态请求),所有的状态都保存在服务端,如果客户端希望访问服务端的数据,就需要使其发生状态改变,同时这种状态转化是建立在表现层,完成转换就表示资源的表现形式发生了改变
      • 对于资源的操作行为的表现方式称为转换
      • 状态指的是对资源的操作行为

    RESTful风格的特点

    1.URL传参更加简洁

    2.完成不同终端之间的资源共享,RESTful提供了一套规范,不同终端之间只要遵守这个规范,就可以实现数据交互。

    RESTful具体来说是四种表现形式,HTTP请求中四种请求类型(GET、POST、PUT、DELETE)分别表示四种常规操作,CRUD。通过不同的请求方式来完成不同的操作

    • GET用来获取资源
    • POST用来创建资源
    • PUT用来修改资源
    • DELETE用来删除资源

    两个终端要完成数据交互,基于RESTful的方式,增删改查操作分别需要使用不同的HTTP请求类型来访问。
    传统的web开发中form表单只支持GET和POST请求,如何解决呢?我们可以通过添加HiddenHttpMethodFilter过滤器,可以把POST请求转为PUT或者DELETE
    RESTful风格的话,响应的数据格式要求是json

    URI规范

    • uri是统一资源标识符

    路径

    • 只能有名词,要求和数据库中的表名对应
    • 建议名词使用复数
    • 在URI中使用小写字母
    • 不要在末尾使用/
    • 使用连字符(-),每个公司可能要求不一样
    http://api.example.com/school/students
    http://api.example.com/school/students/{100}
    
    • 1
    • 2

    请求方式

    • GET用来获取资源
    • POST用来创建资源
    • PUT用来修改资源
    • DELETE用来删除资源
    GET    http://api.example.com/school/students 查询所有学生信息
    GET    http://api.example.com/school/students/{id} 查询指定id的学生信息
    POST   http://api.example.com/school/students 添加学生信息
    PUT    http://api.example.com/school/students/{id} 修改指定id的学生信息
    DELETE http://api.example.com/school/students/{id} 删除指定id的学生信息
    
    • 1
    • 2
    • 3
    • 4
    • 5

    过滤条件

    如果记录数量很多,服务器不可能返回所有信息给用户,API需要提供参数,来过滤返回的结果

    ?limit=10 指定返回记录的数量
    ?offset=10 指定返回记录的开始位置
    ?page=2&pageCount=100 指定第几页,以及每页的记录数
    ?orderby=name&order=asc 指定返回结果按照哪一个属性排序,以及排序顺序
    ?age>=20指定筛选条件
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其他说明

    有的公司的请求方式还是使用GET和POST请求,然后通过路径来区分目的

    /stus/query  查询操作
    /stus/delete/{sid} 根据id删除
    
    • 1
    • 2

    返回结果

    返回数据的格式必须要使用json格式,返回结果建议包含三个部分的信息,状态码,提示信息和真实数据

    状态码和信息

    常见的HTTP状态码

    json介绍

    JSON(JavaScript Object Notation, JS对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
    json的数据格式分成json Object(json对象)和json array(json数组)

    json Object数据格式:

    • 外层加大括号
    • 内层是k:v的形式(属性名:属性值的格式),属性之间用逗号间隔
    • 属性名必须是字符串
    • 比如{“id”:100,“name”:“tom”}
    • 数值支持的数据类型:数值,字符串,布尔,null,json对象,json数组
    学生信息:
    {
    	"id":100,
    	"name":"tom",
    	"cls":{
    	"id":1,
    	"name":"计算机一班"
        	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    json array数据格式

    • 外层中括号
    • 数组元素的数据类型:数值,字符串,布尔,null,json对象,json数组
    所有班级信息的数组:
    ["计算机一班","计算机二班","软件一班", "软件二班"]
    
    • 1
    • 2

    在线json校验

    image.png
    image.png

    postman

    我们知道浏览器它只能发送GET请求,这样的话,其他的请求方式,我们是没法测试的。
    接下来就介绍前后端分离开发,经常用到的工具postman

    安装

    官网地址:https://www.postman.com/downloads/
    image.png
    我们可以选择把exe文件放在指定文件家,然后双击
    image.png

    image.png
    然后可以去登录,或者跳过登录
    image.png

    使用

    image.png
    image.png
    image.png

    点击send(代码实现在后面介绍)
    image.png

    Spring MVC的restful实现

    查询所有班级信息

    restful风格要求返回的字符串是json格式
    @ResponseBody可以把Java对象转化为json对象,并返回给客户端
    我们写一个小demo测试一下(数据是从数据库中查询出来的)
    实体类(班级表对应的实体类)

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Cls {
        private Integer id;
        private String name;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Controller(可以直接用@RestController)
    image.png

    @Controller
    @ResponseBody
    public class ClsController {
        @Autowired
        private ClsService clsService;
        /**
         * 查询所有班级信息
         */
        @GetMapping("/school/cls")
    
        public List<Cls> queryAllCls() {
            try {
                List<Cls> clsList = clsService.queryAllCls();
                return clsList;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Service

    public interface ClsService {
        /**
         * 查询所有班级信息
         * @return
         */
        List<Cls> queryAllCls() throws Exception;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Service实现类

    @Service
    public class ClsServiceImpl implements ClsService {
        @Autowired
        private ClsMapper clsMapper;
        @Override
        public List<Cls> queryAllCls() throws Exception {
            return clsMapper.queryAllCls();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Mapper

    @Mapper
    public interface ClsMapper {
       /**
        * 查询所有班级信息
       */
       @Select("select * from cls")
       List<Cls> queryAllCls() throws Exception;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image.png
    下面这张图片显示的数据和上面图片的不一样,是因为后来我把格式进行修改了,也就是对代码进行了修改,后面会进行说明
    image.png

    单元测试

    @SpringBootTest
    class ClsMapperTest {
        @Autowired
        private ClsMapper clsMapper;
        @Test
        public void testQueryAllCls() throws Exception {
            List<Cls> cls = clsMapper.queryAllCls();
            for (Cls c:cls){
                System.out.println(c);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输出内容:

    
    
    Cls(id=1, name=计科1)
    Cls(id=2, name=计科2)
    Cls(id=3, name=软工1)
    Cls(id=4, name=软工2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    查询指定班级信息

    @PathVariable:把请求路径的变量和形参名进行绑定
    Controller

    @RestController
    public class ClsController {
        @Autowired
        private ClsService clsService;
        /**
         * 查询所有班级信息
         */
        @GetMapping("/school/cls")
    
        public List<Cls> queryAllCls() {
            try {
                List<Cls> clsList = clsService.queryAllCls();
                return clsList;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
         /**
         * 查询指定编号的班级信息
         */
        @GetMapping("/school/cls/{id}")
        public Cls queryClsById(@PathVariable("id") Integer id){
            Cls cls= null;
            try {
                cls = clsService.queryClsById(id);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return cls;
        }
    
    }
    
    
    • 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

    Service

    public interface ClsService {
        /**
         * 查询所有班级信息
         * @return
         */
        List<Cls> queryAllCls() throws Exception;
    
        /**
         * 查询指定编号的班级信息
         * @param id
         * @return
         * @throws Exception
         */
        Cls queryClsById(Integer id) throws Exception;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    Service实现类

    @Service
    public class ClsServiceImpl implements ClsService {
        @Autowired
        private ClsMapper clsMapper;
        @Override
        public List<Cls> queryAllCls() throws Exception {
            return clsMapper.queryAllCls();
        }
    
        @Override
        public Cls queryClsById(Integer id) throws Exception {
            return clsMapper.queryClsById(id);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Mapper

    @Mapper
    public interface ClsMapper {
       /**
        * 查询所有班级信息
       */
       @Select("select * from cls")
       List<Cls> queryAllCls() throws Exception;
    
       /**
        * 查询指定编号的班级信息
        * @param id
        * @return
        */
       @Select("select * from  cls where id=#{id}")
       Cls queryClsById(@Param("id") Integer id);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    image.png
    image.png

    关于格式的说明

    :::info
    接口返回类型:
    json格式
    ------code:状态码
    ------message:状态信息
    ------data:真实数据
    :::
    我们如果想要达到这样的效果的话,有两种方法,第一种就是我们写一个实体类,第二种方法就是通过map来存数据
    通过定义实体类
    image.png
    通过map
    image.png
    image.png
    image.png
    image.png

    根据id删除班级信息

    /**
         * 根据id来删除班级信息
         * @param id
         * @return
         */
        @RequestMapping(value = "/school/cls/{id}" ,method = RequestMethod.DELETE)
        public ResultInfo deleteById(@PathVariable("id") Integer id){
            ResultInfo info = new ResultInfo();
            try {
                clsService.deleteById(id);
                info.setOk();
    
            } catch (Exception e) {
                e.printStackTrace();
                info.setError();
            }
            return info;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    插入数据

    默认是接收key-value格式的数据,如果前端传入的是json格式的数据,那么数据就会接收失败,如果我们希望前端传送的数据是json格式的数据,那么,我们就需要在Controller中,在参数前面加上@RequestBody注解(把请求体中的json格式转换为对应Java实体类格式)
    Controller

      /**
         * 添加班级 前端需要传参数进来
         * @return
         */
       @PostMapping("/school/cls")
        public ResultInfo addCls(Cls cls){
            ResultInfo info = new ResultInfo();
            try {
                clsService.insert(cls);
                info.setOk();
                info.setData(cls);
            } catch (Exception e) {
                e.printStackTrace();
                info.setError();
            }
            return info;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Service

    public interface ClsService {
        /**
         * 查询所有班级信息
         * @return
         */
        List<Cls> queryAllCls() throws Exception;
    
        /**
         * 查询指定编号的班级信息
         * @param id
         * @return
         * @throws Exception
         */
        Cls queryClsById(Integer id) throws Exception;
    
        void deleteById(Integer id) throws Exception;
    
        void insert(Cls cls) throws Exception;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Service实现类

    @Service
    public class ClsServiceImpl implements ClsService {
        @Autowired
        private ClsMapper clsMapper;
        @Override
        public List<Cls> queryAllCls() throws Exception {
            return clsMapper.queryAllCls();
        }
    
        @Override
        public Cls queryClsById(Integer id) throws Exception {
            return clsMapper.queryClsById(id);
        }
    
        @Override
        public void deleteById(Integer id) throws Exception {
            clsMapper.deleteById(id);
        }
        //添加数据
        @Override
        public void insert(Cls cls) throws Exception {
            clsMapper.insert(cls);
        }
    }
    
    
    • 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

    Mapper

    @Mapper
    public interface ClsMapper {
       /**
        * 查询所有班级信息
       */
       @Select("select * from cls")
       List<Cls> queryAllCls() throws Exception;
    
       /**
        * 查询指定编号的班级信息
        * @param id
        * @return
        */
       @Select("select * from  cls where id=#{id}")
       Cls queryClsById(@Param("id") Integer id);
    
       /**
        * 根据id删除数据
        * @param id
        */
       @Delete("delete from  cls where id=#{id}")
        void deleteById(@Param("id") Integer id);
    
       /**
        * 插入班级
        * @param cls
        */
       @Insert("insert into cls values(default,#{name})")
       @Options(useGeneratedKeys = true,keyColumn = "id",keyProperty = "id")
       void insert(Cls cls);
    }
    
    
    • 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

    image.png
    通过数据库查询的前后两次对比可以很清楚的发现,插入数据成功了
    image.png

    根据班级编号修改数据

    Controller

     @PutMapping("/school/cls/{id}")
        public ResultInfo updateById(@PathVariable("id") Integer id,String name){
            ResultInfo info = new ResultInfo();
            try {
                clsService.updateById(id,name);
                info.setOk();
                info.setData(new Cls(id,name));
            } catch (Exception e) {
                e.printStackTrace();
                info.setError();
            }
            return info;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Service

    public interface ClsService {
        /**
         * 查询所有班级信息
         * @return
         */
        List<Cls> queryAllCls() throws Exception;
    
        /**
         * 查询指定编号的班级信息
         * @param id
         * @return
         * @throws Exception
         */
        Cls queryClsById(Integer id) throws Exception;
    
        void deleteById(Integer id) throws Exception;
    
        void insert(Cls cls) throws Exception;
    
        void updateById(Integer id, String name) throws Exception;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Service实现类

    @Service
    public class ClsServiceImpl implements ClsService {
        @Autowired
        private ClsMapper clsMapper;
        @Override
        public List<Cls> queryAllCls() throws Exception {
            return clsMapper.queryAllCls();
        }
    
        @Override
        public Cls queryClsById(Integer id) throws Exception {
            return clsMapper.queryClsById(id);
        }
    
        @Override
        public void deleteById(Integer id) throws Exception {
            clsMapper.deleteById(id);
        }
    
        @Override
        public void insert(Cls cls) throws Exception {
            clsMapper.insert(cls);
        }
    
        @Override
        public void updateById(Integer id, String name) throws Exception {
            clsMapper.updateById(id,name);
        }
    }
    
    
    • 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

    Mapper

    @Mapper
    public interface ClsMapper {
       /**
        * 查询所有班级信息
       */
       @Select("select * from cls")
       List<Cls> queryAllCls() throws Exception;
    
       /**
        * 查询指定编号的班级信息
        * @param id
        * @return
        */
       @Select("select * from  cls where id=#{id}")
       Cls queryClsById(@Param("id") Integer id);
    
       /**
        * 根据id删除数据
        * @param id
        */
       @Delete("delete from  cls where id=#{id}")
        void deleteById(@Param("id") Integer id);
    
       /**
        * 插入班级
        * @param cls
        */
       @Insert("insert into cls values(default,#{name})")
       @Options(useGeneratedKeys = true,keyColumn = "id",keyProperty = "id")
       void insert(Cls cls);
    
       /**
        * 根据id修改数据
        * @param id
        * @param name
        */
       @Update("update cls set name=#{name} where id=#{id} ")
       void updateById(@Param("id") Integer id, @Param("name") String name);
    }
    
    
    • 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

    image.png
    通过查询数据库中的数据,也可以发现数据改变了
    image.png

    结束语

    在下一篇文章中会讲到跨域处理
    在这里插入图片描述

  • 相关阅读:
    PMO大会的主办方是PMO评论
    FreeMarker详细介绍
    6-3 pytorch使用GPU训练模型
    直面秋招:非科班生背水一战,最终拿下阿里字节等大厂offer
    WEB漏洞原理之---【组件安全】
    Chapter3.3:时域分析法
    定档11月2日,YashanDB 2023年度发布会即将启航
    踩坑日记 uniapp 底部 tabber遮挡住购物车结算
    学习linux从0到工程师(命令)-4
    PCL 投影点云
  • 原文地址:https://blog.csdn.net/qq_52797170/article/details/126314252