【图书管理系统】深入解析使用 MyBatis 数据持久化操作全栈开发 Controller、Service、Mapper 层添加图书接口及应用 @slf4j 日志级别打印信息、完善前端代码并与后端交互

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


添加图书接口


约定前后端交互接口


[请求]
/book/addBook
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

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

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

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

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


实现服务器代码


控制层:BookController


在 BookController 补充代码:

image-20250408091218222


addBook() 接口第一步,需要校验传入的书对象各个属性,属性类型为 String 和 Integer,校验的方式也有所不同:

image-20250408091926622

  • 先进行参数校验,校验通过了进行图书添加
  • 实际开发中,后端开发人员不关注前端是否进行了参数校验,一律进行校验
  • 原因是:后端接口可能会被黑客攻击,不通过前端来访问,如果后端不进行校验,会产生脏数据.(咱们学习阶段,暂不涉及安全领域模块的开发,防攻击一般是企业统一来做)
  • 此处校验非常粗糙,我们还可以校验传入的书名长度等等…

image-20250408092529962


校验好参数后,我们完善添加图书和返回结果的逻辑:

image-20250408092905119

使用 try…catch… 是为了防止比 Controller 层更底层出现错误,如: Mapper 层中的 SQL 的错误;


修改上图报错,只保留下列两个接口,其他的接口后续重新改进:

image-20250408094801384


引入 @slf4j 日志


因为添加图书异常,已经可以涉及到 error 的日志级别,我们也可以打印日志:

在这里插入图片描述


在这里插入图片描述

打日志的数量也要合理,如果日志打印的数量过多,也会影响性能;


业务层:BookService


需补充业务逻辑代码

image-20250408093756325


数据层:BookInfoMapper


创建 BookInfoMapper 接口文件

image-20250408094217420


在这里插入图片描述


接口测试


重新运行程序,使用 Postman 进行接口测试:

image-20250408095302137


虽然参数不会暴露在 URL 中,但是并不意味着就安全了,参数是否出现在 URL 对安全与否影响不大

注意:要构造的请求不是 GET 请求,而是 POST 请求,因为通过 x-www-form-urlencoded 或 JSON 传递参数时,编码由 HTTP 客户端(如 Postman)自动处理,能正确保留中文

image-20250408101100529

从 GET 改为 POST 后请求,主要涉及 HTTP 协议规范、参数传递方式和 Spring MVC 处理机制的差异。以下是具体原因分析:


GET vs POST 的参数传递方式差异

特性GET 请求POST 请求
参数位置附加在 URL 后(Query String)放在请求体(Request Body)中
编码处理URL 自动编码可能丢失中文Body 内容可完整保留原始编码
长度限制受 URL 长度限制(约 2KB)无严格限制
Spring 参数绑定需要显式声明 @RequestParam支持直接绑定到对象属性

刷新数据库对应表,检查 addBook() 接口成功被调用:

image-20250408101326772


实现客户端代码


提供的前面页面中,js已经提前留了空位。

在这里插入图片描述

点击确定按钮,会执行 add() 方法。


接下来,把请求传给后端,传递的数据 data 为 bookInfo 各个属性:
在这里插入图片描述


在这里插入图片描述


我们根据上图标签中的 id 属性,决定使用 id 选择器拿到前端输入的数据,再传给后端:

在这里插入图片描述


我们再来换一种构造 data 的方式:

在这里插入图片描述


补全 add() 的方法:

  • 提交整个表单的数据:
    • $("#addBook").serialize()
  • 提交的内容格式:
    • bookName=图书1&author=作者1&count=23&price=36&publish=出版社1&status=1
  • form 标签包括的所有输入表单(inputselect)内容都会被提交。

在这里插入图片描述


接口测试


ctrl+s 保存前端代码,重新运行程序;

添加图书前,数据库内容。

在这里插入图片描述


点击“添加图书”按钮

在这里插入图片描述


跳转到添加图书的页面,填写图书信息。

image-20250408114454690


填入信息:

在这里插入图片描述


点击“确定”按钮,页面跳转到图书列表页

在这里插入图片描述

图书列表还未实现,页面上看不出效果


查看数据库数据,确认数据插入成功:

在这里插入图片描述


测试输入不合法的场景(比如什么信息都不填,直接点击“确定”),页面也得到正确响应。

在这里插入图片描述


完整代码


BookController

package com.bit.book.Controller;

import com.bit.book.model.BookInfo;
import com.bit.book.service.BookService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/book")
@Slf4j
public class BookController {
    @Autowired
    private BookService bookService;

    @RequestMapping("/addBook")
    public String addBook(BookInfo bookInfo){
        log.info("添加图书, request:{}" + bookInfo);
        // 1. 参数校验
        if(!StringUtils.hasLength(bookInfo.getBookName())){
            log.error("添加图书, 参数不合法, request:{}", bookInfo);
        }
        if(!StringUtils.hasLength(bookInfo.getAuthor())){
            return "图书作者不能为空!";
        }
        if(bookInfo.getCount()==null){
            return "图书数量不能为空";
        }
        if(bookInfo.getPrice()==null){
            return "图书价格不能为空";
        }
        if(!StringUtils.hasLength(bookInfo.getPublish())){
            return "图书出版社不能为空";
        }
        if(bookInfo.getStatus()==null){
            return "图书状态不能为空";
        }

        // 2. 存储数据
        try{
            bookService.addBook(bookInfo);
            return "";
        }catch (Exception e){
            log.error("添加图书异常, e:" ,e);
            // 3. 返回结果
            return "添加图书发生异常, 请联系管理员!";
        }
    }
}

BookService

package com.bit.book.service;

import com.bit.book.mapper.BookMapper;
import com.bit.book.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class BookService {
    @Autowired
    private BookMapper bookMapper;

    public void addBook(BookInfo bookInfo) {
        bookMapper.addBook(bookInfo);
    }
}

BookMapper

package com.bit.book.mapper;

import com.bit.book.model.BookInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BookMapper {

    @Insert("insert into book_info " +
            "(book_name, author, count, price, publish, status) " +
            "values (#{bookName}, #{author}, #{count}, #{price}, #{publish}, #{status})")
    Integer addBook(BookInfo bookInfo);
}

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值