您的位置:首页 > 健康 > 美食 > 360搜索建站公司_企业网络推广培训_软件网站排行榜_2022年小学生新闻摘抄十条

360搜索建站公司_企业网络推广培训_软件网站排行榜_2022年小学生新闻摘抄十条

2025/4/8 4:01:29 来源:https://blog.csdn.net/2301_80898480/article/details/146073527  浏览:    关键词:360搜索建站公司_企业网络推广培训_软件网站排行榜_2022年小学生新闻摘抄十条
360搜索建站公司_企业网络推广培训_软件网站排行榜_2022年小学生新闻摘抄十条

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗

如有错误,欢迎指出~


前⾯图书管理系统,咱们只完成了⽤⼾登录和图书列表,并且数据是Mock的.接下来我们把其他功能进 ⾏完善.

功能列表: 1. ⽤⼾登录 2. 图书列表 3. 图书的增删改查 4. 翻⻚功能

创建数据库book_test

-- 创建数据库 
DROP DATABASE IF EXISTS book_test;
CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;
-- ⽤⼾表 
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR ( 128 ) NOT NULL,`password` VARCHAR ( 128 ) NOT NULL,`delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` ),
UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC )) ENGINE = INNODB DEFAULT 
CHARACTER 
SET = utf8mb4 COMMENT = '⽤⼾表';
-- 图书表 
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`book_name` VARCHAR ( 127 ) NOT NULL,`author` VARCHAR ( 127 ) NOT NULL,`count` INT ( 11 ) NOT NULL,`price` DECIMAL (7,2 ) NOT NULL,`publish` VARCHAR ( 256 ) NOT NULL,`status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-⽆效, 1-正常, 2-不允许借阅',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 初始化数据 
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "admin", "admin" );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "zhangsan", "123456" );
-- 初始化图书数据 
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('活
着', '余华', 29, 22.00, '北京⽂艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('平凡的
世界', '路遥', 5, 98.56, '北京⼗⽉⽂艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('三
体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('⾦字塔
原理', '⻨肯锡', 16, 178.00, '⺠主与建设出版社');

引⼊MyBatis和MySQL驱动依赖

修改pom⽂件

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version>
</dependency>
<dependency><groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId><scope>runtime</scope>
</dependency>

配置数据库&⽇志

# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 111111driver-class-name: com.mysql.cj.jdbc.Driverapplication:name: demo-book
mybatis:configuration:map-underscore-to-camel-case: true #配置驼峰自动转换log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句
logging:file:name: spring-book.log

Model创建 

UserInfo


import lombok.Data;
import java.util.Date;
@Datapublic class UserInfo {private Integer id;private String userName;private String password;private Integer deleteFlag;private Date createTime;private Date updateTime;
}

BookInfo 

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

接口1: ⽤⼾登录

约定前后端交互接⼝

  • [请求] /user/login Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  • [参数] name=zhangsan&password=123456
  • [响应] true //账号密码验证正确, 否则返回false

浏览器给服务器发送 /user/login 这样的HTTP请求,服务器给浏览器返回了⼀个Boolean类型 的数据.返回true,表⽰账号密码验证正确

实现服务器代码

从数据库中,根据名称查询⽤⼾,如果可以查到,并且密码⼀致,就认为登录成功

控制层UserController
@Slf4j
@RestController
@RequestMapping("/user")public class UserController {@Autowiredprivate UserService userService;@RequestMapping(value = "/login", method = RequestMethod.POST)public boolean login(String userName, String password, HttpSession session){//参数输入,打印日志log.info("接收到参数: " + userName);Boolean result = userService.checkUserAndPassword(userName, password, session);log.info("用户登入结果: name:{}, password:{}, 结果: {}", userName,password , result);return result;}
}
业务层userService 
package com.example.demo.service;import com.example.demo.Constants;
import com.example.demo.Mapper.UserInfoMapper;
import com.example.demo.model.UserInfo;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;public Boolean checkUserAndPassword(String userName, String password, HttpSession session){//账号, 密码为空if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}//在数据库中查询是否存在用户名UserInfo userInfo = userInfoMapper.queryUserByName(userName);if(userInfo == null){return false;}if( password.equals(userInfo.getPassword())){//存储在Session中//账号密码正确session.setAttribute(Constants.SESSION_USER_KEY,userName);return true;}return false;}
}
数据层userInfoMapper 
@Mapper
public interface UserInfoMapper {@Select("select * from user_info where delete_flag = 0 and user_name = #{name}")UserInfo queryUserByName(String name);
}

访问数据库,使⽤MyBatis来实现,所以把之前dao路径下的⽂件可以删掉,⽤mapper⽬录来代替,创 建UserInfoMapper 当然,继续使⽤dao⽬录也可以, dao和mapper通常都被认为是数据库层

接口2: 添加图书

约定前后端交互接⼝

  • [请求] /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

//添加图书@RequestMapping(value = "/addBook", produces = "application/json")public ResultVO<String> addBook(BookInfo bookInfo) {log.info("添加图书, bookInfo:{}", bookInfo);//参数校验if (!StringUtils.hasLength(bookInfo.getBookName())||!StringUtils.hasLength(bookInfo.getAuthor())|| bookInfo.getCount() == null|| bookInfo.getPrice() == null||!StringUtils.hasLength(bookInfo.getPublish())) {return new ResultVO<>(400, "参数不合法,图书名称、作者、库存、价格、出版社均为必填项", "");}//2,插入数据try {Integer result = bookService.insertBook(bookInfo);if (result == 1) {return new ResultVO<>(200, "图书添加成功", "");}return new ResultVO<>(500, "图书添加失败,插入结果异常", "");} catch (Exception e) {log.error("数据插入发生异常, e: ", e);return new ResultVO<>(500, "数据插入失败,请联系管理员,具体异常:" + e.getMessage(), "");}}

BookService

 public Integer insertBook(BookInfo bookInfo) {return bookMapper.insertBook(bookInfo);}

 BookMapper

Integer insertBook(BookInfo bookInfo);

ResultVO类

package com.example.demo.model;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class ResultVO<T> {private Integer code; // 状态码,例如 200 表示成功,其他表示失败private String message; // 提示信息private T data; // 数据部分,如果有需要返回的数据
}

接口3: 图书列表

可以看到,添加图书之后,跳转到图书列表⻚⾯,并没有显⽰刚才添加的图书信息,接下来我们来实现图 书列表 需求分析

我们之前做的表⽩墙查询功能,是将数据库中所有的数据查询出来并展⽰到⻚⾯上,试想如果数据库 中的数据有很多(假设有⼗⼏万条)的时候,将数据全部展⽰出来肯定不现实,那如何解决这个问题呢? 使⽤分⻚解决这个问题。每次只展⽰⼀⻚的数据,⽐如:⼀⻚展⽰10条数据,如果还想看其他的数 据,可以通过点击⻚码进⾏查询

  • 第1⻚:显⽰1-10条的数据
  • 第2⻚:显⽰11-20条的数据
  • 第3⻚:显⽰21-30条的数据
  • 以此类推...

要想实现这个功能,从数据库中进⾏分⻚查询,我们要使⽤ LIMIT 关键字,格式为:limit开始索引 每⻚显⽰的条数(开始索引从0开始)

查询第1⻚的SQL语句: SELECT * FROM book_info LIMIT 0,10

查询第2⻚的SQL语句: SELECT * FROM book_info LIMIT 10,10

观察以上SQL语句,发现:开始索引⼀直在改变,每⻚显⽰条数是固定的 开始索引的计算公式:开始索引=(当前⻚码currentPage-1)*每⻚显⽰条数pageSize

对于后端而言,前端需要提供参数: currentPage, pageSize

后端给前端返回: 当前页的记录

实现服务器代码

BookController

    //查询图书信息@RequestMapping("/getListByPage")public PageResponse<BookInfo> getListByPage(PageRequest pageRequest, HttpServletRequest request) {log.info("获取图书列表, pageRequest: {}", pageRequest);////参数校验省略PageResponse<BookInfo> bookInfoPageResponse = bookService.getListByPage(pageRequest);return bookInfoPageResponse;}

BookService

    //查询图书信息public PageResponse<BookInfo> getListByPage(PageRequest pageRequest){//1, 总记录数Integer count = bookMapper.count();//        List<BookInfo> bookInfos = bookDao.mockData();//        //2. 当前页记录数List<BookInfo> bookInfos = bookMapper.queryBookByPage(pageRequest.getOffset(),pageRequest.getPageSize());for(BookInfo bookInfo : bookInfos){
//            if(bookInfo.getStatus() == 0){
//                bookInfo.setStatusCN("删除");
//            }else if(bookInfo.getStatus() == 1){
//                bookInfo.setStatusCN("可借阅");
//            }else{
//                bookInfo.setStatusCN("不可借阅");
//            }bookInfo.setStatusCN(BookStatusEnum.getStatusByCode(bookInfo.getStatus()).getDesc());}return new PageResponse<BookInfo>(count,bookInfos,pageRequest);}

BookMapper

    //查询图书信息@Select("select * from book_info order by id limit #{offset}, #{limit}")List<BookInfo> queryBookByPage(Integer offset, Integer limit);

接口4: 修改图书

约定前后端交互接⼝

进⼊修改⻚⾯,需要显⽰当前图书的信息

[请求] /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,获取当前图书的信息 点击修改按钮,修改图书信息

[请求] /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

    //更新图书@RequestMapping("/updateBook")public ResultVO<String> updateBook(BookInfo bookInfo) {log.info("更新图书, bookInfo: {}", bookInfo);try {Integer result = bookService.updateBook(bookInfo);if (result > 0) {return new ResultVO<>(200, "图书更新成功", "");} else if (result == 0) {return new ResultVO<>(200, "图书内容未发生变化,无需更新", "");}return new ResultVO<>(500, "图书更新失败", "");} catch (Exception e) {log.error("更新图书失败,e:", e);return new ResultVO<>(500, "数据库操作失败:" + e.getMessage(), "");}}

BookService

    //更新图书public Integer updateBook(BookInfo bookInfo) {return bookMapper.updateBook(bookInfo);}

BookMapper

    //更新图书,用xml的方式 注解和xml的方式可以混用Integer updateBook(BookInfo bookInfo);

BookMapperInfo.xml 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.Mapper.BookMapper"><!--    更新图书--><update id="updateBook">update book_info<set><if test="bookName!=null">book_name =#{bookName},</if><if test="author!=null">author =#{author},</if><if test="count!=null">count =#{count},</if><if test="price!=null">price =#{price},</if><if test="publish!=null">publish =#{publish},</if><if test="status!=null">status =#{status},</if></set>where id = #{id}</update>
</mapper>

接口5: 通过id查询图书

实现服务器代码

BookController

    //通过id查询图书@RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId){log.info("获取图书信息, bookId: "+ bookId);//参数校验,不能为null,不能<=0...省略return bookService.queryBookById(bookId);}

BookService

    //通过id查询图书public BookInfo queryBookById(Integer bookId) {return bookMapper.queryBookById(bookId);}

BookMapper

    //通过id查询图书@Select("select * from book_info where id = #{bookId}")BookInfo queryBookById(Integer bookId);

接口6:删除图书

约定前后端交互接⼝ 删除分为逻辑删除和物理删除

  1. 逻辑删除也称为软删除、假删除、SoftDelete,即不真正删除数据,⽽在某⾏数据上增加类型 is_deleted的删除标识,⼀般使⽤UPDATE语句
  2. 物理删除也称为硬删除,从数据库表中删除某⼀⾏或某⼀集合数据,⼀般使⽤DELETE语句 删除图书的两种实现⽅式

逻辑删除: update book_info set status=0 where id = 1

物理删除:  delete from book_info where id=25 

实现服务器代码

BookController

    @RequestMapping("/deleteBook")public String deleteBook(Integer bookId){log.info("删除图书, bookId: {}", bookId);try{BookInfo bookInfo = new BookInfo();bookInfo.setId(bookId);bookInfo.setStatus(BookStatusEnum.DELETED.getCode());Integer result = bookService.updateBook(bookInfo);if(result > 0){//1return "";}return "图书删除失败";}catch(Exception e){log.error("删除图书失败,e:",e);return "数据库操作失败";}}

 接口5: 批量删除图书

批量删除,其实就是批量修改数据

约定前后端交互接⼝

  1. [请求] /book/batchDeleteBook Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  2. [参数] ids = [1, 2, 3, 4]
  3. [响应] boolean true //删除成功 false //删除失败

点击[批量删除]按钮时,只需要把复选框选中的图书的ID,发送到后端即可 多个id,我们使⽤List的形式来传递参数

实现服务器代码

BookController

    //批量删除@RequestMapping("/batchDeleteBook")public Boolean batchDeleteBook(@RequestParam List<Integer> ids){log.info("批量删除图书, ids:{}", ids);try{//执行sqlbookService.batchDeleteBook(ids);return true;}catch(Exception e){log.error("批量删除图书, ids:{}", ids);}return false;}

BookService

    public void batchDeleteBook(List<Integer> ids) {bookMapper.batchDelete(ids);}

BookMapper

 void batchDelete(List<Integer> ids);

 BookMapperInfo.xml 

<!--    批量删除--><update id="batchDelete">update book_infoset status = 0where id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach></update>

接口6: 强制登录

虽然我们做了⽤⼾登录,但是我们发现,⽤⼾不登录,依然可以操作图书. 这是有极⼤⻛险的.所以我们需要进⾏强制登录. 如果⽤⼾未登录就访问图书列表或者添加图书等⻚⾯,强制跳转到登录⻚⾯.

实现思路分析 ⽤⼾登录时,我们已经把登录⽤⼾的信息存储在了Session中.那就可以通过Session中的信息来判断⽤ ⼾都是登录.

1. 如果Session中可以取到登录⽤⼾的信息,说明⽤⼾已经登录了,可以进⾏后续操作

2. 如果Session中取不到登录⽤⼾的信息,说明⽤⼾未登录,则跳转到登录⻚⾯. 以图书列表为例 现在图书列表接⼝返回的内容如下:

实现服务器代码

BookController

    //查询图书信息,翻页使用@RequestMapping("/getListByPage")public Result<PageResponse<BookInfo>> getListByPage(PageRequest pageRequest, HttpServletRequest request) {log.info("获取图书列表, pageRequest: {}", pageRequest);HttpSession session = request.getSession(false);//如果拿不到session就会返回nullif(session == null|| session.getAttribute(Constants.SESSION_USER_KEY) == null|| !StringUtils.hasLength((String)session.getAttribute(Constants.SESSION_USER_KEY))){//用户未登录return Result.unlogin();}//参数校验省略PageResponse<BookInfo> bookInfoPageResponse = new PageResponse<>();try{bookInfoPageResponse = bookService.getListByPage(pageRequest);}catch(Exception e){log.error("获取图书列表失败");return Result.fail();}return Result.success(bookInfoPageResponse);}

Constants

package com.example.demo.constants;public class Constants {//成功public static final int SUCCESS_CODE = 200;//程序出错public static final int FAIL_CODE = -2;//未登录public static final int UNLOGIN_CODE = -1;public static final String SESSION_USER_KEY = "session_user_key";}

Result

package com.example.demo.model;import com.example.demo.constants.Constants;
import lombok.Data;@Data
public class Result<T> {private int code; //200-成功  -1 用户未登录  -2 程序出错   业务状态码, 非http状态码private String errMsg;private T data;public static <T> Result success(T data){Result result = new Result();result.setCode(Constants.SUCCESS_CODE);result.setErrMsg("");result.setData(data);return result;}public static <T> Result unlogin(){Result result = new Result();result.setCode(Constants.UNLOGIN_CODE);result.setErrMsg("用户未登录");return result;}public static <T> Result fail(T data){Result result = new Result();result.setCode(Constants.FAIL_CODE);result.setErrMsg("程序发生错误!");return result;}public static <T> Result fail(String errMsg){Result result = new Result();result.setCode(Constants.FAIL_CODE);result.setErrMsg(errMsg);return result;}public static <T> Result fail(String errMsg, int code){Result result = new Result();result.setCode(code);result.setErrMsg(errMsg);return result;}public static <T> Result fail(){Result result = new Result();result.setCode(Constants.FAIL_CODE);result.setErrMsg("程序发生错误!");return result;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com