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}

请求方式

  • 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的学生信息

过滤条件

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

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

其他说明

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

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

返回结果

返回数据的格式必须要使用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":"计算机一班"
        }
}

json array数据格式

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

在线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;
}

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;
    }
}

Service

public interface ClsService {
    /**
     * 查询所有班级信息
     * @return
     */
    List<Cls> queryAllCls() throws Exception;
}

Service实现类

@Service
public class ClsServiceImpl implements ClsService {
    @Autowired
    private ClsMapper clsMapper;
    @Override
    public List<Cls> queryAllCls() throws Exception {
        return clsMapper.queryAllCls();
    }
}

Mapper

@Mapper
public interface ClsMapper {
   /**
    * 查询所有班级信息
   */
   @Select("select * from cls")
   List<Cls> queryAllCls() throws Exception;
}

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);
        }
    }
}

输出内容:



Cls(id=1, name=计科1班)
Cls(id=2, name=计科2班)
Cls(id=3, name=软工1班)
Cls(id=4, name=软工2班)

查询指定班级信息

@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;
    }

}

Service

public interface ClsService {
    /**
     * 查询所有班级信息
     * @return
     */
    List<Cls> queryAllCls() throws Exception;

    /**
     * 查询指定编号的班级信息
     * @param id
     * @return
     * @throws Exception
     */
    Cls queryClsById(Integer id) throws Exception;
}

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);
    }
}

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);
}

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;
    }

插入数据

默认是接收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;
    }

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;
}

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);
    }
}

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);
}

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;
    }

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;
}

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);
    }
}

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);
}

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

相关文章
|
25天前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
2278 42
|
28天前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
3月前
|
前端开发 Java API
利用 Spring WebFlux 技术打造高效非阻塞 API 的完整开发方案与实践技巧
本文介绍了如何使用Spring WebFlux构建高效、可扩展的非阻塞API,涵盖响应式编程核心概念、技术方案设计及具体实现示例,适用于高并发场景下的API开发。
325 0
|
7月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
486 7
|
2月前
|
安全 数据可视化 Java
AiPy开发的 Spring 漏洞检测神器,未授权访问无所遁形
针对Spring站点未授权访问问题,现有工具难以检测如Swagger、Actuator等组件漏洞,且缺乏修复建议。全新AI工具基于Aipy开发,具备图形界面,支持一键扫描常见Spring组件,自动识别未授权访问风险,按漏洞类型标注并提供修复方案,扫描结果可视化展示,支持导出报告,大幅提升渗透测试与漏洞定位效率。
|
7月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
7月前
|
前端开发 Java UED
从基础到进阶:Spring Boot + Thymeleaf 整合开发中的常见坑与界面优化
本文深入探讨了 **Spring Boot + Thymeleaf** 开发中常见的参数绑定问题与界面优化技巧。从基础的 Spring MVC 请求参数绑定机制出发,分析了 `MissingServletRequestParameterException` 的成因及解决方法,例如确保前后端参数名、类型一致,正确设置请求方式(GET/POST)。同时,通过实际案例展示了如何优化支付页面的视觉效果,借助简单的 CSS 样式提升用户体验。最后,提供了官方文档等学习资源,帮助开发者更高效地掌握相关技能。无论是初学者还是进阶用户,都能从中受益,轻松应对项目开发中的挑战。
345 0
|
3月前
|
缓存 Java API
Spring WebFlux 2025 实操指南详解高性能非阻塞 API 开发全流程核心技巧
本指南基于Spring WebFlux 2025最新技术栈,详解如何构建高性能非阻塞API。涵盖环境搭建、响应式数据访问、注解与函数式两种API开发模式、响应式客户端使用、测试方法及性能优化技巧,助你掌握Spring WebFlux全流程开发核心实践。
604 0