Spring Boot + jQuery 前后端分离图书管理系统:从接口设计到问题排查

Spring Boot + jQuery 前后端分离图书管理系统:从接口设计到问题排查

图书管理系统

1.1 准备前端代码

在本地想要的可以去我的gitee中下载 library 的相关前端代码

1.2 约定前后端交互接口

需求分析

图书管理系统是⼀个相对较大一点的案例,咱们先实现其中的⼀部分功能. 用户登录

1. 登录接口

2. 图书列表展示

字段说明:

字段说明
id图书 ID
bookName图书名称
author作者
count数量
price定价
publish图书出版社
status图书状态 1 - 可借阅 其他 - 不可借阅
statusCN图书状态中文含义

3.4.3 服务器代码

创建图书类 BookInfo

@Data public class BookInfo { //图书ID private Integer id; //书名 private String bookName; //作者 private String author; //数量 private Integer count; //定价 private BigDecimal price; //出版社 private String publish; //状态 0-不允许借阅 1-允许借阅 private Integer status; private String statusCN; //创建时间 private Date createTime; //更新时间 private Date updateTime; } 

创建 UserController, 实现登录验证接口

import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/user") @RestController public class UserController { @RequestMapping("login") public boolean login(String name, String password, HttpSession session){ // 账号密码验证 if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){ return false; } //账号密码正确,账号admin & 密码admin if("admin".equals(name) && "admin".equals(password)){ session.setAttribute("userName",name); return true; } //账号密码错误 return false; } } 

创建 BookController, 获取图书列表

@RequestMapping("/book") @RestController public class BookController { @RequestMapping("/getList") public List<BookInfo> getList(){ // 模拟数据 List<BookInfo> books = mockData(); // 处理页面展示 for (BookInfo book:books){ if (book.getStatus()==1){ book.setStatusCN("可借阅"); }else { book.setStatusCN("不可借阅"); } } return books; } /** * 数据mock 获取图书信息 * @return */ public List<BookInfo> mockData() { List<BookInfo> books = new ArrayList<>(); for (int i = 1; i < 5; i++) { BookInfo book = new BookInfo(); book.setId(i); book.setBookName("书籍" + i); book.setAuthor("作者" + i); book.setCount(i * 3); book.setPrice(new BigDecimal((new Random()).nextInt(100))); book.setPublish("出版社" + i); book.setStatus(1); books.add(book); } return books; } } 
引入一个mock,mock是什么

数据采用 mock 的方式,实际数据应该从数据库中获取mock: 模拟的,假的在开发和测试过程中,由于环境不稳定或者协同开发的同事未完成等情况下,有些数据不容易构造或者不容易获取,就创建一个虚拟的对象或者数据样本,用来辅助开发或者测试工作.简单来说,就是假数据.

public List<BookInfo> mockData(){ List<BookInfo> bookInfos = new ArrayList<>(); for (int i=0; i<15; i++){ BookInfo bookInfo = new BookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书" + i); bookInfo.setBookAuthor("作者"+i); bookInfo.setCount(new Random().nextInt(100)); bookInfo.setPrice(new BigDecimal(new Random().nextInt(100))); bookInfo.setPublish("出版社"+i); bookInfo.setStatus(i%5==0?2:1); bookInfos.add(bookInfo); } return bookInfos; }

注意:我们这样写会显得很乱,所以我们使用这个mock 进行数据的模拟得时候,最后写成一个方法,这个会让代码整齐规范,并且有数据后也更好得修改代码

修改后

public List<BookInfo> mockData(){ List<BookInfo> bookInfos = new ArrayList<>(); for (int i=0; i<15; i++){ BookInfo bookInfo = new BookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书" + i); bookInfo.setBookAuthor("作者"+i); bookInfo.setCount(new Random().nextInt(100)); bookInfo.setPrice(new BigDecimal(new Random().nextInt(100))); bookInfo.setPublish("出版社"+i); bookInfo.setStatus(i%5==0?2:1); bookInfos.add(bookInfo); } return bookInfos; }

这样我们就好管理代码

修改得时候就只加一个方法,和删除MOCK得数据即可

3.4.4 调整前端页面代码

登录页面:添加登录处理逻辑

<script src="js/jquery.min.js"></script> <script> function login() { $.ajax({ type: "post", url: "/user/login", data: { name: $("#userName").val(), password: $("#password").val() }, success: function (result) { if (result) { location.href = "book_list.html"; } else { alert("账号或密码不正确!"); } } }); } </script> 

图书列表展示:删除前端伪造的代码,从后端获取数据并渲染到页面上.

  1. 删除 <body></body>标签中的内容
  2. 完善获取图书方法
function getBookList() { $.ajax({ type: "get", url: "/book/getList", success: function (result) { console.log(result); if (result != null) { var; for (var book of result) { finalHtml += "<tr><input type='checkbox' name='selectBook' + book.id + "' + book.id + "'></td>"; finalHtml += "<td>" + book.id + "</td>"; finalHtml += "<td>" + book.bookName + "</td>"; finalHtml += "<td>" + book.author + "</td>"; finalHtml += "<td>" + book.count + "</td>"; finalHtml += "<td>" + book.price + "</td>"; finalHtml += "<td>" + book.publish + "</td>"; finalHtml += "<td><div>" + book.statusCN + "</div></td>"; finalHtml += "<td><a href='book_update.html?bookId=" + book.id + "'>修改</a>"; finalHtml += "<a href='javascript:void(0)' onclick='deleteBook(" + book.id + ")'> 删除</a></td>"; finalHtml += "</tr>"; } $("tbody").html(finalHtml); } } }); }

排除未达到理想效果的问题出现在哪?

1.检查两端的代码(我们肉眼可以看到的哦都是有限的,一般都是通过debug的方式)根据日志

后端的代码,先看一下postman的结果

   看后端的话第一步先进行看请求是否已经进来了(测试最简单的方法就是在里面打印一下参数之类的可以确认的请求进来的变量)

   如果说接口已经进来了检查参数和结果是否正确

    没有问题交给前端

前端的测试

get和post的实际区别?

在实际开发里,GET 和 POST 的区别并不是 “能不能传参数”,而是 “参数放在哪里”,以及 “放在 Body 时前后端必须一致”。

1. 当参数都放在 URL(Postman 的 Params)时
  • GET 和 POST 看起来 “几乎一样”。
  • 前端把参数拼到 URL 里。
  • 后端从 URL 里取参数。
  • 这种情况下,GET 和 POST 的使用方式对开发者来说区别不大。

你强调的点:只要参数都在 URL,那 GET 和 POST 的使用体验几乎没有区别。

2. 真正的区别出现在 POST 使用 Body 传参时
  • POST 可以把参数放在 Body 里(这是它的主要用途)。
  • GET 不能(规范不允许,即使工具能加也没有意义)。
  • 一旦参数放在 Body,就必须考虑 “格式”。

POST 使用 Body 传参时,前后端必须一致。

例如:

  • 前端用 JSON,后端必须按 JSON 解析。
  • 前端用 form-data,后端必须按 form-data 解析。
  • 前端用 x-www-form-urlencoded,后端也要对应。

否则就会出现 “前端传了,后端收不到” 的经典问题。

3. 总结
  • GET:参数只能在 URL,前后端不会有格式问题。
  • POST:参数可以在 URL 也可以在 Body,但真正常用的是 Body。
  • 一旦用 Body,前后端必须约定好格式,否则无法解析。
  • 所以实际开发中,POST 和 GET 的最大区别就是:POST 的 Body 传参需要前后端一致,而 GET 没有这个问题。

GET 和 POST 的区别(面试)

在实际开发中,GET 和 POST 的区别主要体现在参数位置数据格式约定上。

    • GET 的参数只能放在 URL 中,也就是 Postman 里的 Params。
    • POST 的参数既可以放在 URL,也可以放在 Body 中,而实际开发中最常用的是 Body。
    • GET 因为参数在 URL,后端只需从 URL 解析,不存在格式问题,前后端不会因为格式不一致而出错。
    • POST 如果使用 Body 传参,就必须保证前后端格式一致。例如前端用 JSON,后端必须按 JSON 解析;前端用 form-data,后端也要用对应的方式接收。否则会出现 “前端传了但后端收不到” 的问题。
    • GET 受 URL 长度限制,不适合传大量数据,且参数暴露在 URL 中,不适合敏感信息。
    • POST 无明确大小限制,且参数在 Body 中,相对更安全(需配合 HTTPS)。
    • GET 用于获取资源,是幂等的。
    • POST 用于提交资源,不是幂等的。
语义区别
数据大小与安全性
是否需要前后端格式一致
参数位置不同

这个其实get在理论上得话就是还是可以放到这个body里进行获取得,只是postman进行约束了

Postman 的 “约束” 本质

  • Postman 并非 “强制禁止”,而是遵循了行业最佳实践。它默认隐藏了 GET 请求的 Body 输入框,是为了引导你写出符合规范的代码,避免踩坑。
  • 如果你强行要在 Postman 里给 GET 请求加 Body,也可以通过抓包工具(如 Charles)修改请求包来实现,但这属于非常规操作,没有实际业务价值。

GET 带 Body 为什么是 “坏实践”

  1. 语义冲突:GET 的核心语义是 “获取资源”,幂等且可缓存。带 Body 会让它看起来像一个 “提交” 操作,与 POST 的语义混淆。
  2. 兼容性风险:很多 HTTP 客户端、服务器和中间件(如 Nginx、CDN)的实现都没有处理 GET Body 的逻辑,会直接丢弃这部分数据,导致请求失败。
  3. 缓存失效:缓存服务器通常只根据 URL 来缓存 GET 请求的响应。带 Body 后,相同 URL 但不同 Body 的请求会被错误地缓存为同一个响应。

Read more

Ubuntu编译自定义immortalwrt固件与软件编译

Ubuntu编译自定义immortalwrt固件与软件编译

1 前言 istoreos中有许多可安装的软件,但如果自己需要制作一个特定的固件或者编译开源的源码时就需要编译来生成所需软件 2 所需工具 * 1.Ubuntu系统 * 2.VMware虚拟机 * 3.相应版本的sdk开发包 * 4.ssh连接工具 * 5.git(可选) 3 软件编译 3.1 openwrt与immortalwrt 首先我们需要在VMware中安装Ubuntu 下载链接 可自行选择服务器或桌面版下载 安装好并启动后通过ssh连接 然后下载对应sdk包 注:固件编译istoreos,openwrt与immortalwrt方法相同 中科大镜像 搜索openwrt或immortalwrt来获取相应版本sdk(以immortalwrt为例) 然后选择对应的处理器型号(这里以mediatek为例) 在此页中找到immortalwrt-sdk-24.10.4-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst下载并上传到Ubuntu上解压 使用如下代码解压 tar

By Ne0inhk

ripgrep跨平台使用指南:Windows/macOS/Linux全支持

ripgrep跨平台使用指南:Windows/macOS/Linux全支持 【免费下载链接】ripgrepripgrep recursively searches directories for a regex pattern while respecting your gitignore 项目地址: https://gitcode.com/gh_mirrors/ri/ripgrep ripgrep(简称rg)是一款高性能的命令行搜索工具,它能递归搜索目录中的正则表达式模式,同时尊重你的.gitignore规则。作为开发者日常工作中不可或缺的工具,掌握其在不同操作系统下的安装与使用方法至关重要。本文将详细介绍如何在Windows、macOS和Linux系统中安装、配置和高效使用ripgrep,帮助你提升文件搜索效率。 为什么选择ripgrep? ripgrep之所以能从众多搜索工具中脱颖而出,主要得益于其出色的性能和丰富的功能。与传统的grep、ack和The Silver Searcher等工具相比,ripgrep在搜索速度上具有明显优势。以下是ripgrep与其他工具在L

By Ne0inhk
Flutter 三方库 gtin_toolkit 的鸿蒙化适配指南 - 实现全球标准商品条码(GTIN)的正向解析与合法性校检、支持端侧零售与物流供应链扫码实战

Flutter 三方库 gtin_toolkit 的鸿蒙化适配指南 - 实现全球标准商品条码(GTIN)的正向解析与合法性校检、支持端侧零售与物流供应链扫码实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 gtin_toolkit 的鸿蒙化适配指南 - 实现全球标准商品条码(GTIN)的正向解析与合法性校检、支持端侧零售与物流供应链扫码实战 前言 在进行 Flutter for OpenHarmony 的新零售、仓储管理或跨境物流应用开发时,如何准确识别并验证全球通用的商品条码?GTIN(Global Trade Item Number)涵盖了 EAN-13, EAN-8, UPC-A, UPC-E 以及 ITF-14 等多种格式。gtin_toolkit 是一款专为 GTIN 协议处理设计的工具库。它不仅能解析条码,还能计算动态校检位(Check Digit)。本文将介绍如何在鸿蒙端构建极致的条码数据治理能力。 一、原直观解析 / 概念介绍 1.

By Ne0inhk
Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段工程化利器(适配鸿蒙 HarmonyOS Next ohos

Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段工程化利器(适配鸿蒙 HarmonyOS Next ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 Flutter 三方库 index_generator — 赋能鸿蒙大型项目自动化生成 Export 导出索引,消除繁琐 Import 片段的工程化利器(适配鸿蒙 HarmonyOS Next ohos) 前言 在华为鸿蒙(OpenHarmony)生态的深度开发中,随着业务组件和模型类的爆发式增长,开发者经常会陷入“Import 迷宫”。当你需要引用某个页面时,发现上方堆叠了数十行细碎的文件引用,这不仅影响代码的可读性,更让后续的重构工作(如移动目录)变得极其痛苦。 index_generator 是一款极其高效的命令行工具。它能根据你定义的配置文件,自动扫描指定目录并生成一个统一的“索引文件(Barrel File,通常为 index.dart)”,将目录下的所有组件一键导出。在构建鸿蒙平台的复杂多模块(Multi-module)工程、管理庞大的 UI

By Ne0inhk