【图书管理系统】深度讲解:图书列表展示的后端实现、高内聚低耦合的应用、前端代码讲解

news2025/5/11 5:52:30

1.约定前后端交互接口

[请求]
/book/getListByPage

[参数]
currentPage=1&pageSize=10

[响应]
返回封装的result对象对应的Json数据

2. 整体逻辑

2.1 Controller的逻辑

(1)把接收的参数封装为PageRequest类,里面有属性:currentPage(当前的页码),pageSize(每页设置多少条数据),offset(起始数据的Id)
(2)在PageRequest类中设置构造函数,构造函数里面设置offset的值
(3)检查访问者是否为已登录的用户
(4)检验传来的参数PageResult对象的属性是否合理
(5)把参数传给Service层

2.2 Service层

(1)使用Mapper获取总数据的条数
(2)把得到的参数传给Mapper对应的方法,获取该页的数据
(3)把得到的数据进行处理
(4)返回该Controller

2.3 Mapper层

(1)实现一个方法:查询数据的总数据条数
(2)实现一个方法:使用limit 实现分页查询

3. 后端代码实现

3.1 分页的逻辑和封装的类

(1)假设每页10条数据,逻辑如下:
第一页,第1-10的数据
第二页,第11-20的数据
第三页,第21-30的数据…

(2)数据库中数据的索引是从0开始的,更新逻辑(假设每页10条数据):
第一页,索引为0-9的数据
第二页,索引为10-19的数据
第三页,索引为20-29的数据…

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

limit a,b关键字:a是开始的索引,b是从a开始显示的条数

--第一页
select * from book_info limit 0,10;

--第二页
select * from book_info limit 10,10;

--第三页
select * from book_info limit 20,10;

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

(3)从上述的分析得出,要实现一个分页的查询需要三个属性:当前页码、查询的条数、起始的索引

(4)创建一个类PageRequest,封装这三个属性。这三个属性的逻辑关系还需要另外的处理(开始索引 = (当前页码 - 1) * 每页显示条数),为了方便调用,直接在构造方法中实现三者的逻辑关系

@Data
public class PageRequest {
    // 请求的页数
    private int currentPage=1;

    //请求的该页条数
    private int pageSize=10;

    //开始的索引
    private int offset;

    public PageRequest(int currentPage){
        this.currentPage = currentPage;
        this.offset=(this.currentPage-1)* this.pageSize;
    }

    public PageRequest(){
        this.offset=(this.currentPage-1)*this.pageSize;
    }

    public PageRequest(int currentPage, int pageSize){
        this.currentPage=currentPage;
        this.pageSize=pageSize;
        this.offset=(this.currentPage-1)* this.pageSize;

    }

    //获取开始的索引
    public int getOffset(){
        return (this.currentPage-1)* this.pageSize;
    }
}

构造函数说明:
(1)当前端没有传来页码和该页的条数时,默认使用该类的缺省值
(2)当前端只传来页码而没有该页的条数时,默认使用每页10条数据。
(3)当前端传来页码和该页的条数时,进行逻辑处理求offset。

Controller、Service、传参PageRequest类:
在这里插入图片描述

3.2 Controller层

BookInfoController 类的getBookInfoListByPage方法:

@Slf4j
@RequestMapping("/book")
@RestController
public class BookInfoController {

    @Autowired
    private BookInfoService bookInfoService;

    // 手动设置拦截用户
    @RequestMapping("/getBookInfoListByPage")
    public Result getBookInfoListByPage(PageRequest pageRequest, HttpSession session){

        log.info("Controller被调用");

        //验证是否认证
        UserInfo userInfo = (UserInfo)session.getAttribute(Constants.SESSION_USER_KEY);
        if(userInfo==null){

            Result result = new Result();
            result.setStatus(ResultStatus.UNLOGIN);
            return  result;

        }else if(userInfo.getId()<0){
            Result result = new Result();
            result.setStatus(ResultStatus.UNLOGIN);
        }


        // 参数校验
        if(pageRequest.getPageSize()<1||pageRequest.getCurrentPage()<=0){

            Result result = new Result();
            result.setStatus(ResultStatus.FIAL);
            result.setErrorMessage("参数验证失败");

            return result;
        }

        PageResult<BookInfo> pageResult = null;

        try{
            pageResult = bookInfoService.getBookInfoListByPage(pageRequest);
        }catch(Exception e){
            log.error("查询翻页信息错误:" + e);
        }

//        Result result = new Result();
//        result.setStatus(ResultStatus.SUCCESS);
//        result.setData(pageResult);
//
//        return result;

        return Result.success(pageResult);
    }
}

说明:

(1)验证是否已认证:如果没有该代码,在浏览器中直接诶搜索127.0.0.1:8080/book/getBookInfoListByPage(未登录)也会出现图书列表,这是不符合安全设计的。获取session中的对应的用户对象,并检查该用户是否合规。

(2)参数校验:为了高内聚低耦合,封装了一个Result类,Result类中设置的有常用的属性。

(3)页面的结果:为了高内聚低耦合,封装了一个PageResult类,PageResult类中设置的有常用的页面属性。

2.3 PageResult 和 Result

2.3.1 PageResult

如果不设计PageResult类,获取该页的内容后,需要返回前端三个属性:
(1)total(该页数据的总条数);
(2)bookInfoList(该页的数据);
(3)pageRequest(前端的请求内容)。

后端想要一次性返回给前段上述三个属性使用类封装起来是最好的办法,也实现了高内聚低耦合的设计。

PageResult类:

@Data
public class PageResult<T> {

    //当前页数据的总条数
    private int total;

    //当前页的数据
    private List<T> bookInfoList;

    private PageRequest pageRequest;

    public PageResult(int count,List<T> bookInfoList, PageRequest pageRequest){
        this.total = count;
        this.bookInfoList = bookInfoList;
        this.pageRequest = pageRequest;
    }
}

为了实现了高内聚低耦合的设计,PageResult类设计为模板类;在创建构造函数中设计赋值。

Controller和Service使用PageResult对象:
在这里插入图片描述

2.3.2 Result

使用Result类创建的对象可以作为后端返回给前端的中间对象,PageResult类包含返回给前端数据的常用属性。

Result类:

public class Result {
    private ResultStatus status;

    private String ErrorMessage;

    private Object data;


    public static Result success(Object data){
        Result result  = new Result();
        result.setStatus(ResultStatus.SUCCESS);

        // 赋值返回的数据
        result.data = data;

        return result;
    }


    public ResultStatus getStatus() {
        return status;
    }

    public void setStatus(ResultStatus status) {
        this.status = status;
    }

    public String getErrorMessage() {
        return ErrorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        ErrorMessage = errorMessage;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

说明:

(1)Object 是Java中所有类的根类(基类),使用它可以让 data 字段存储​​任意类型的数据​​

(2)status是枚举类ResultStatus 的对象,一共有三个状态:

200:成功–SUCCESS
-1:用户未登录–UNLOGIN
-2:异常或检验失败–FAIL

public enum ResultStatus {
    SUCCESS(200),
    UNLOGIN(-1),
    FIAL(-2);

    private Integer status;

    ResultStatus(Integer Status){
        this.status=Status;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }
}

2.4 Service 层

Service层是处理主要业务逻辑的,直接调用Mapper层

@Slf4j
@Service
public class BookInfoService {

    @Autowired
    private BookInfoMapper bookInfoMapper;

    public PageResult<BookInfo> getBookInfoListByPage(PageRequest pageRequest) {
        if(pageRequest==null){
            return null;
        }

        //获取表中数据的总数
        Integer count = bookInfoMapper.queryBookInfoCount();

        //获取该页的数据
        List<BookInfo> bookInfoList = bookInfoMapper.queryBookInfoByPage(pageRequest);

        //根据status 修改 statusCN
        for(BookInfo it : bookInfoList){

            // 使用枚举类设置图书的状态
            it.setStatusCN(BookInfoStatusEnum.getNameByCode(it.getStatus()).getName());
//            if(it.getStatus()==0){
//                it.setStatusCN("无效");
//            } else if(it.getStatus()==1){
//                it.setStatusCN("可借阅");
//            }else{
//                it.setStatusCN("不可借阅");
//            }
        }

        // 创建PageResult对象返回给Controller
        return new PageResult<BookInfo>(count,bookInfoList,pageRequest);

    }
}

说明:

(1)bookInfoMapper.queryBookInfoCount():获取数据的总条数

(2)queryBookInfoByPage(pageRequest):获取该页的数据

(3)it.setStatusCN(BookInfoStatusEnum.getNameByCode(it.getStatus()).getName()):BookInfoStatusEnum是一个枚举类,该枚举类设置的有图书的状态:

public enum BookInfoStatusEnum {
    DELETED(0,"已经删除"),
    NORMALL(1,"允许借阅"),
    FORBIDDEN(2,"禁止借阅");

    public static BookInfoStatusEnum getNameByCode(int code){
        switch(code) {
            case 0: return BookInfoStatusEnum.DELETED;
            case 1: return BookInfoStatusEnum.NORMALL;
            case 2: return BookInfoStatusEnum.FORBIDDEN;
            default:
                return BookInfoStatusEnum.FORBIDDEN;
        }
    }


    private int code;
    private String name;

	//构造函数
    BookInfoStatusEnum(int code, String name){
        this.code= code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

枚举类中的方法getNameByCode是一个静态方法,接收的参数是整型(方便BookInfo的status属性传参),方法中设置switch–case(多条件分支控制​​的语句),根据传来的参数创建BookInfoStatusEnum对象。

2.5 Mapper层

Mapper直访问数据库,该功能下有两个主要的方法:

@Mapper
public interface BookInfoMapper {


    //每页的数据
    @Select("select id,book_name,author,count,price,publish,status," +
            "create_time,update_time from book_info "+
            "where status !=0 order by id asc limit #{offset},#{pageSize} "
    )
    List<BookInfo> queryBookInfoByPage(PageRequest pageRequest);


    //数据的总条数
    @Select("select count(*) from book_info where status!=0;")
    Integer queryBookInfoCount();

说明:

(1)queryBookInfoByPage方法主要使用关键字limit来进行分页查询,offset是数据的开始id,pageSize是数据条数的数量。

(2)queryBookInfoCount方法用于查询数据的总条数。

4. 前端代码

book_list.html文件:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书列表展示</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">

    <link rel="stylesheet" href="css/list.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <script src="js/jq-paginator.js"></script>

</head>

<body>
    <div class="bookContainer">
        <h2>图书列表展示</h2>
        <div class="navbar-justify-between">
            <div>
                <button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
                <button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
            </div>
        </div>

        <table>
            <thead>
                <tr>
                    <td>选择</td>
                    <td class="width100">图书ID</td>
                    <td>书名</td>
                    <td>作者</td>
                    <td>数量</td>
                    <td>定价</td>
                    <td>出版社</td>
                    <td>状态</td>
                    <td class="width200">操作</td>
                </tr>
            </thead>
            <tbody>


            </tbody>
        </table>

        <div class="demo">
            <ul id="pageContainer" class="pagination justify-content-center"></ul>
        </div>
        <script>

            getBookList();
            function getBookList() {
                $.ajax({
                    //                                   获取参数
                    url:"/book/getBookInfoListByPage"+ location.search,
                    type:"get",

                    success:function(result){

                        if(result.status == "FAIL"){
                            location.href = "login.html";//
                        }

                        if(result.status == "UNLOGIN"){
                            location.href = "login.html";//
                        }

                        var finalHtml="";

                        result = result.data;//

                        //加载列表
                        for(var book of result.bookInfoList){
                            //根据每一条记录去拼接,拼成一个<tr>内容</tr>
                            finalHtml += '<tr>'
                            finalHtml += '<td><input type="checkbox" name="selectBook" value="'+book.id+'" id="selectBook" class="book-select"></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>'+book.statusCN+'</td>'
                            finalHtml += '<td><div class="op">'
                            finalHtml += '<a href="book_update.html?bookId='+book.id+'">修改</a>'
                            finalHtml += '<a href="javascript:void(0)" onclick="deleteBook('+book.id+')">删除</a>'
                            finalHtml += '</div></td></tr>'
                        }
                        //展示
                        console.log(finalHtml);

                        //放到tbody中
                        $("tbody").html(finalHtml)


                        //翻页信息
                        $("#pageContainer").jqPaginator({
                            totalCounts: result.total, //总记录数
                            pageSize: result.pageRequest.pageSize,    //每页的个数
                            visiblePages: 5, //可视页数
                            currentPage: result.pageRequest.currentPage,  //当前页码
                            first: '<li class="page-item"><a class="page-link">首页</a></li>',
                            prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
                            next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
                            last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
                            page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
                            //页面初始化和页码点击时都会执行
                            onPageChange: function (page, type) {
                                console.log("第" + page + "页, 类型:" + type);
                                if(type=="change"){
                                    location.href="book_list.html?currentPage="+page; //使用后端默认设置的每页数据量
                                }

                                //跳转
                                // location.href="book_list.html?currentPage="+page;
                            }
                        });
                    }
                });

            }


            function deleteBook(id) {
                var isDelete = confirm("确认删除?");
                if (isDelete) {
                    //删除图书
                    $.ajax({
                      //..
                    });

                }
            }
            function batchDelete() {
                var isDelete = confirm("确认批量删除?");
                if (isDelete) {
                    //获取复选框的id
                    var ids = [];
                    $("input:checkbox[name='selectBook']:checked").each(function () {
                        ids.push($(this).val());
                    });

                    //发送请求,批量删除
                    $.ajax({
                       //..
                    });

                }
            }

        </script>
    </div>
</body>

</html>

ajax说明:

  1. 处理请求结果​
if (result.status == "FAIL" || result.status == "UNLOGIN") {
    location.href = "login.html"; // 状态异常时跳转到登录页
}

if(result.status == "UNLOGIN"){
     location.href = "login.html";//未登录时跳转到登录页
}
  1. 动态生成表格行​
    遍历 result.bookInfoList 中的每本图书,生成包含复选框、图书信息和操作按钮的表格行,把每个图书信息拼接一起。
var finalHtml = "";
result = result.data; // 提取核心数据(假设 result.data 包含 bookInfoList 和 total)

for (var book of result.bookInfoList) {
    finalHtml += '<tr>'
        + '<td><input type="checkbox" name="selectBook" value="' + book.id + '" class="book-select"></td>'
        + '<td>' + book.id + '</td>'
        + '<td>' + book.bookName + '</td>'
        + '<td>' + book.author + '</td>'
        + '<td>' + book.count + '</td>'
        + '<td>' + book.price + '</td>'
        + '<td>' + book.publish + '</td>'
        + '<td>' + book.statusCN + '</td>'
        + '<td><div class="op">'
            + '<a href="book_update.html?bookId=' + book.id + '">修改</a>'
            + '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')">删除</a>'
        + '</div></td></tr>';
}

$("tbody").html(finalHtml); // 将拼接的 HTML 插入表格
  1. 初始化分页控件 (jqPaginator)​
$("#pageContainer").jqPaginator({
    totalCounts: result.total,             // 总记录数
    pageSize: result.pageRequest.pageSize, // 每页显示数量
    visiblePages: 5,                       // 显示的分页按钮数
    currentPage: result.pageRequest.currentPage, // 当前页码
    // 分页按钮模板
    first: '<li class="page-item"><a class="page-link">首页</a></li>',
    prev: '<li class="page-item"><a class="page-link">上一页</a></li>',
    next: '<li class="page-item"><a class="page-link">下一页</a></li>',
    last: '<li class="page-item"><a class="page-link">末页</a></li>',
    page: '<li class="page-item"><a class="page-link">{{page}}</a></li>',
    // 页码变化回调
    onPageChange: function (page, type) {
        if (type == "change") { // 仅在用户点击时跳转
            location.href = "book_list.html?currentPage=" + page;
        }
    }
});

分页参数​​依赖后端返回的 total(总记录数)、pageRequest.pageSize(每页大小)、pageRequest.currentPage(当前页)。当用户点击分页按钮(类型为 “change”)时,通过修改 URL 的 currentPage 参数重新加载页面。

5.结语

本文系统讲解了基于 Spring Boot 和 MyBatis 的分页查询功能实现方案,从前端交互到数据库查询构建了完整的技术链路。通过 ​​模块化封装​​ 与 ​​动态参数处理​​,实现了高复用性、易维护的分页架构,为数据密集型系统的开发提供了标准化解决方案。

​​核心价值​​

  1. ​​分层解耦设计​​
    通过 PageRequest 参数封装、PageResult 分页结果包装、Result 统一响应体,实现前后端数据流的规范化传递。

  2. 高效分页机制​​
    基于 MySQL 的 LIMIT 分页语法,结合后端动态计算偏移量,有效平衡性能与开发效率。

  3. 安全与健壮性​​
    参数校验、登录态拦截、异常捕获三重机制保障系统稳定性,避免非法请求与空指针异常。

  4. 前端交互友好​​
    整合 jqPaginator 分页控件,实现页码动态渲染与无刷新跳转,提升用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

养生:为健康生活添彩

养生是对生活的热爱&#xff0c;是为健康生活注入活力的良方。从饮食、运动到生活习惯&#xff0c;每一个方面都能让我们离健康更近一步。以下是一些实用的养生之道&#xff0c;助你开启健康生活的新旅程。 饮食养生&#xff1a;营养均衡&#xff0c;健康基石 合理的饮食是养…

服务器综合实验(实战详解)

该文章的目录部分 实验内容 实验完成步骤 虚拟机准备 配置两个虚拟机的本地仓库 虚拟机A&#xff1a; 虚拟机B&#xff1a; 配置SSH公钥互信 虚拟机A&#xff1a; ​编辑 虚拟机B&#xff1a; 提供基于bind的DNS服务 虚拟机A&#xff1a; 项目需求1&#xff1a; …

VSCode-插件:codegeex:ai coding assistant / 清华智普 AI 插件

一、官网 https://codegeex.cn/ 二、vscode 安装插件 点击安装即可&#xff0c;无需复杂操作&#xff0c;国内软件&#xff0c;无需科学上网&#xff0c;非常友好 三、智能注释 输入 // 或者 空格---后边自动出现注释信息&#xff0c;&#xff0c;按下 Tab 键&#xff0c;进…

SlideLoss与FocalLoss在YOLOv8分类损失中的应用及性能分析

文章目录 一、引言二、YOLOv8 损失函数概述三、SlideLoss 详解&#xff08;一&#xff09;SlideLoss 的原理&#xff08;二&#xff09;SlideLoss 的代码实现 四、FocalLoss 分类损失函数详解&#xff08;一&#xff09;FocalLoss 的原理&#xff08;二&#xff09;FocalLoss 的…

OpenCv实战笔记(4)基于opencv实现ORB特征匹配检测

一、原理作用 ORB 原理&#xff08;Oriented FAST and Rotated BRIEF&#xff09;&#xff1a; 特征点检测&#xff1a;使用 FAST 算法检测角点&#xff08;关键点&#xff09;。 方向计算&#xff1a;为每个关键点分配主方向&#xff0c;增强旋转不变性。 特征描述&#xff1a…

深入解析路由策略:从流量控制到策略实施

一、网络流量双平面解析 在路由策略的设计中&#xff0c;必须明确区分两个关键平面&#xff1a; 1. 控制层面&#xff08;Control Plane&#xff09; ​​定义​​&#xff1a;路由协议传递路由信息形成的逻辑平面&#xff08;如OSPF的LSA、RIP的Response报文&#xff09;​…

FHE 之 面向小白的引导(Bootstrapping)

1. 引言 FHE初学者和工程师常会讨论的一个问题是&#xff1b; “什么是引导&#xff08;bootstrapping&#xff09;&#xff1f;” 从理论角度看&#xff0c;这个问题的答案很简单&#xff1a; 引导就是套用 Gentry 提出的思想——在加密状态下同态地执行解密操作&#xff…

51单片机入门教程——AT24C02数据存储

前言 本教程基于B站江协科技课程进行个人学习整理&#xff0c;专为拥有C语言基础的零基础入门51单片机新手设计。既帮助解决因时间差导致的设备迭代调试难题&#xff0c;也助力新手快速掌握51单片机核心知识&#xff0c;实现从C语言理论到单片机实践应用的高效过渡 。 目录 …

M0的基础篇之PWM学习

一、困惑 上一节课就是单纯的之配置了一个基础的定时器进行计数&#xff0c;计到一定的数值也就是到了一定的时间就进入中断&#xff0c;执行中断里面的任务&#xff0c;也就是一个最基础的定时的功能 这一节课的定时器产生了一个pwm波。也就是我们可以改变里面高电平的持续时间…

Python----神经网络(基于AlexNet的猫狗分类项目)

一、基于AlexNet的猫狗分类 1.1、项目背景 猫和狗是我们生活中最常见的宠物&#xff0c;它们的图像数据大量存在于互联网上。对此进行分类不仅可以帮助开发自动化宠物识别应用&#xff0c;也可以应用于更广泛的计算机视觉领域。例如&#xff0c;训练良好的模型可以支持流浪动物…

荣耀A8互动娱乐组件部署实录(第1部分:服务端环境搭建)

作者&#xff1a;一位被“只支持安卓”的前端劝退过三次的技术人 前言 这一套组件我拆包已经不止一遍了&#xff0c;老实讲&#xff0c;不支持 iOS 是遗憾&#xff0c;但对于研究 UI 动态加载、资源分离结构和整体架构来说&#xff0c;A8 的这套服务还算完整&#xff0c;服务器…

基于Python Flask的深度学习电影评论情感分析可视化系统(2.0升级版,附源码)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

计算机学习路线与编程语言选择(信息差)

——授人以鱼不如授人以渔 计算机学习公式&#xff1a;1/3科班思维 1/3路线选择 1/3工程能力 好工作随便找&#xff08;来自B站小毛毛熊&#xff09; 本文主要是路线选择&#xff01;&#xff01;&#xff01;下面开始吧。 面向岗位学习&#xff01;到招聘网站看看有哪些…

【redis】redis 手动切换主从

场景一&#xff1a; 测试需要&#xff0c;需要手动切换主从 在redis节点&#xff1a; $ redis-cli -h xx.xx.xx.xx -p XX -a XX shutdown 不要直接关闭redis进程&#xff0c;使用 shutdown &#xff0c;能在进程关闭前持久化内存中的数据 待主从切换完毕后&#xff1…

第三节:Vben Admin 最新 v5.0 对接后端登录接口(下)

文章目录 前言一、处理请求头Authorization二、/auth/user/info 接口前端接口后端接口三、/auth/codes 接口1.前端2.后端四、测试接口前言 上一节内容,实现了登录的/auth/login 接口,但是登陆没有完成,还需要完成下面两个接口。才能完成登录。 一、处理请求头Authorizatio…

爬虫学习————开始

&#x1f33f;自动化的思想 任何领域的发展原因————“不断追求生产方式的改革&#xff0c;即使得付出与耗费精力越来愈少&#xff0c;而收获最大化”。由此&#xff0c;创造出方法和设备来提升效率。 如新闻的5W原则直接让思考过程规范化、流程化。或者前端框架/后端轮子的…

Ubuntu18.04搭建samda服务器

一.什么是Samba服务器&#xff1f; Samba服务器是一种基于开源协议实现的网络共享服务软件&#xff0c;主要用于在不同操作系统&#xff08;如Windows、Linux、Unix&#xff09;之间实现文件和打印机共享功能。其核心目标是解决跨平台资源共享的兼容性问题&#xff0c;尤其是在…

2025-05-10-FFmepg库裁切有水印的视频

裁后 代码 import subprocess# 文件路径 input_video_path "bg_video.mp4" output_video_path "output_video_cropped.mp4"# 裁剪视频下方的水印 def crop_video(input_video_path, output_video_path, crop_height):# 获取视频的分辨率def get_video…

opencv+opencv_contrib+cuda和VS2022编译

本文介绍使用OpenCV和OpenCV_Contrib源码及Cuda进行编译的过程&#xff0c;编译过程中会用到OpenCV、OpenCV_Contrib、CUDA Toolkit、cuDNN、Cmake、VS2022等工具&#xff0c;最终编译OpenCV的Cuda版本。 一、OpenCV下载地址 OpenCV官网下载地址:https://opencv.org/releases…

网工实验——OSPF配置

网络拓扑图 配置 1.为每个路由器配置接口&#xff08;略&#xff09;&#xff08;详细见RIP实验&#xff09; 2.配置OSPF AR1 [AR1]ospf [AR1-ospf-1]area 1 [AR1-ospf-1-area-0.0.0.1]network 172.16.1.1 0.0.0.0 #精确配置网络&#xff0c;也可以像下面那条命令那样配置 …