【图书管理系统】深入解析基于 MyBatis 数据持久化操作:全栈开发图书管理系统:查询图书属性接口(注解实现)、修改图书属性接口(XML 实现)


查询图书属性接口


约定前后端交互接口


约定前后端交互接口,进入修改页面,需要显示当前图书的信息;

tex 复制代码
请求  
/book/queryBookById?bookId=25  

参数  
无  

响应  
{  
  "id": 25,  
  "bookName": "图书21",  
  "author": "作者2",  
  "count": 999,  
  "price": 222.00,  
  "publish": "出版社1",  
  "status": 2,  
  "statusCN": null,  
  "createTime": "2023-09-04T04:01:27.000+00:00",  
  "updateTime": "2023-09-05T03:37:03.000+00:00"  
}

根据图书ID,获取当前图书的信息。


实现服务器代码


控制层 BookController



业务层 BookService



数据层 BookInfoMapper


根据图书ID,查询图书信息。

java 复制代码
@Select("select id, book_name, author, count, price, publish, `status`, 
create_time, update_time " +
"from book_info where id=#{bookId} and status<>0")
BookInfo queryBookById(Integer bookId);

接口测试


重新运行程序,打开页面127.0.0.1:9090/book/queryBookById?bookId=5


修改图书属性接口


约定前后端交互接口


点击修改按钮,修改图书信息。

tex 复制代码
请求  
/book/updateBook  
Content-Type: application/x-www-form-urlencoded; charset=UTF-8  

参数  
id=1&bookName=图书1&author=作者1&count=23&price=36&publish=出版社1&status=1  

响应  
""  // 失败信息, 成功时返回空字符串

我们约定,浏览器给服务器发送一个 /book/updateBook 这样的 HTTP 请求,form表单的形式来提交数据;

服务器返回处理结果,返回""表示添加图书成功,否则,返回失败信息。


实现服务器代码


控制层 BookController




业务层 BookService



数据层 BookInfoMapper


更新逻辑相对较为复杂,因为一本书不是每个属性都需要进行修改的;

所以 bookInfo 对象的哪些属性传递了值,我们就更新哪些值,需要使用动态SQL

对于初学者而言,注解的方式拼接动态SQL不太友好,煮啵采用xml的方式来实现。

因为注解和 XML 可以同时在一个 interface 中共存,所以煮啵就不创建新接口了;


添加依赖和配置 XML 路径


配置 xml 路径:

yaml 复制代码
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

最终整体的 yml 配置文件为:


xml 实现:


创建BookInfoMapper.xml文件,并初始化





接口测试


重新运行程序:


结果层层筛查和尝试,煮啵才锁定问题:


查看以前的博客,煮啵发现:spring 和 mybatis 是同级别的层次,煮啵把 mybatis 设置成了 spring 的小弟


修改好代码之后,重新提供 Postman 构造请求,终于成功返回响应:


提前开香槟,我们这一路走来不容易,多少次流着泪说不分离~~~(bushi)

验证数据库表信息是否被修改:



查找、修改图书客户端代码实现


查找图书


我们希望点击修改按钮时:


跳转的输入框中有原来的值:


修改好数据后,点击确认按钮,会调用后端:


接下来,我们来写前端代码:

我们希望,点击修改页面后,马上调用后端,补全输入框中的信息:


点击修改按钮之后,我们看到 URL 中 bookId 的赋值是未被定义的参数:


按修改按钮时,会跳转页面,但是跳转的 URL 参数 bookId 赋值是 book.bookId ,与后端属性名 id 不同,自然无法识别 bookId:




修复好 book_list 跳转 book_update 的 URL 参数后,我们继续补齐 book_update 的 ajax 请求:

location.search 是 JavaScript 中 window.location 对象的一个属性,它返回 URL 中从问号 ? 开始的部分(包括问号),也就是查询字符串部分。

例如:

  • 如果当前 URL 是 http://example.com/book_update.html?bookId=123
  • 那么 location.search 的值就是 "?bookId=123"

在你的代码中:

javascript 复制代码
$.ajax({
   type: "get",
   url: "/book.queryBookId" + location.search,
});

这意味着:

  1. 当用户从图书列表点击"修改"按钮时,会跳转到 book_update.html?bookId=123(假设图书ID是123)
  2. 在修改页面,location.search 就是 "?bookId=123"
  3. 这个查询字符串会直接附加到请求URL后面,形成完整的请求:/book.queryBookId?bookId=123

为什么不用传data给后端了?


GET请求中,数据通常是通过URL的查询字符串传递的(就像这里做的),而不是像POST请求那样放在请求体中。这是因为:

  1. GET请求的设计初衷就是用于获取数据,其参数直接体现在URL中
  2. 查询字符串 ?bookId=123 本身就是传递给后端的数据
  3. 这种方式更符合RESTful风格,URL本身就标识了要操作的资源

所以在这种情况下,不需要额外使用data参数来传递数据,因为数据已经包含在URL的查询字符串中了。


我们通过 URL 中的信息,想后端发送 get 请求,接下来就通过 success 接收后端的返回结果,并且通过 id 选择器,对前端输入框对应的属性赋值,赋的值是后端对应的属性:



这里需要注意:图书状态的 value = "1" ,"2" ,是与我们后端数据库的定义有关的,要和后端的枚举对应上:


修改图书


我们观察,在列表页时,我们已经补充了[修改]的链接:



补全修改图书的方法:

通过 id 选择器选中 form 表单,使用 serialize() 对表单进行序列化,就拿到了 fom 表单的值,这样就不需要对 bookName,bookAuthor 这些属性分别赋值


对后端返回的数据进行处理:


接口测试


ctrl+s 保存代码,重新运行程序,结果发现输入框并没有值:


通过 deepseek 不断缩小问题范围,最终锁定 bug:


修改 URL ,保存代码,重新运行程序:


此时点击修改按钮,跳转页面的输入框中有值了:


我们试着修改值:


修改数据,点击确定后,页面跳转到图书列表的第一页:


找到原来的那本书,发现又出 bug 了,对应的属性没有更新:


遇到这种问题,我们要先冷静下来,因为后端打印有日志,方便排查问题,所以我们先看后端,再看前端;

找到对应 update 的日志:

我们发现 SQL 对应的 id 赋值为 null,很幸运的找到了出现问题的原因!


我们再仔细看这条日志,发现前端传过来的 id 值为 null,就说明问题出在前端:


我们修改图书信息,是根据图书ID来修改的,所以需要前端传递的参数中,包含图书ID。

有两种方式:

  1. 获取url中参数的值(比较复杂,需要拆分url)
  2. 在form表单中,再增加一个隐藏输入框,存储图书ID,随 $("#updateBook").serialize() 一起提交到后端。

我们采用第二种方式:

在form表单中,添加隐藏输入框。


  • hidden类型的<input>元素。
  • 隐藏表单,用户不可见、不可改的数据,在用户提交表单时,这些数据会一并发送出。
  • 使用场景:正被请求或编辑的内容的ID。这些隐藏的input元素在渲染完成的页面中完全不可见,且没有方法可以使它重新变为可见。



保存代码,重新运行程序,执行上述修改步骤:



相关推荐
二哈喇子!1 分钟前
MyBatis-plus 快速入门
java
zhangpeng4555479405 分钟前
用Java NIO模拟HTTPS
java·https·nio
飞奔的马里奥6 分钟前
30天学Java第九天——线程
java·开发语言
工业互联网专业13 分钟前
基于springboot+vue的秦皇岛旅游景点管理系统
java·vue.js·spring boot·毕业设计·源码·课程设计·旅游景点管理系统
EelBarb19 分钟前
mysql:重置表自增字段序号
数据库·mysql
畅云客42 分钟前
Apache与Nginx网站压测对比
java·nginx·apache
风吹草1 小时前
java程序乱码问题
java·编码方式
落沐萧萧1 小时前
Java利用无外网(下):ClassPathXmlApplicationContext的不出网利用
java·开发语言
写bug写bug1 小时前
Java并发编程:本质上只有一种创建线程的方法
java·后端
十秒耿直拆包选手1 小时前
spring:xml方式调用构造方法创建Bean,调用set方法配置字段
xml·java·spring