《JavaEE进阶》----21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)>

PS:

开闭原则

定义和背景‌
‌开闭原则(Open-Closed Principle, OCP)‌,也称为开放封闭原则,是面向对象设计中的一个基本原则。该原则强调软件中的模块、类或函数应该对扩展开放,对修改封闭。这意味着一个软件实体应该在不修改现有代码的基础上,能够适应新的变化和需求。

核心思想
开闭原则的核心思想是:

  • ‌对扩展开放‌:当新的需求或变化出现时,可以通过扩展现有代码来适应新的情况,而不是修改现有的代码。
  • ‌对修改封闭‌:一旦类或模块设计完成,就应该能够独立完成其工作,不再对其进行任何修改。(能够兼容之前的版本)

针对先上线的程序而言

比如后端接口从A改成了B。(前端接口也要修改)

如果后端先上线:前端调用就会出错,找不到A接口

如果前端先上线,前端调用依然会报错,找不到B接口。因为此时后端还没上线。

正确的做法:后端对之前的接口进行兼容,如果兼容则同时存在A和B接口

实现方式
实现开闭原则的方式主要包括:

  • ‌抽象编程‌:通过面向对象的继承和多态机制,实现对抽象体的继承和方法的覆写,从而实现新的扩展方法。
  • ‌依赖抽象‌:类依赖于固定的抽象,而不是具体的实现,这样可以保证类的稳定性。

相关设计原则
开闭原则与其他设计原则密切相关,包括:

  • ‌里氏替换原则‌:子类对象能够替代父类对象出现的地方,并且保证原有逻辑行为不变。
  • ‌接口隔离原则‌:接口调用方和使用者只关心自己相关的接口,不依赖于不需要的接口。
  • ‌依赖反转原则‌:高模块不直接依赖低模块,而是通过抽象来互相依赖。
  • ‌单一职责原则‌:一个类或模块只负责完成一个职责或功能。

 一、图书列表展示功能

1.1 实现分页功能

提到展示图书列表,就不得不提到分页了

分页时,数据是如何展示的呢

第1页:显示1-10 条的数据

第2页:显示11-20 条的数据

第3页:显示 21-30 条的数据

以此类推...

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

select * from book_info where status <> 0 limit 0,10;
select * from book_info where status <> 0 limit 10,10;
select * from book_info where status <> 0 limit 20,10;

我们发现只有开始索引在改变。每页显示的条数是固定的。

开始索引的计算公式:开始索引 = (当前页码 - 1) * 每页显示条数。

因此:

1.前端发起查询请求时,需要向服务器端传递的参数。

currentPage 当前页码 :默认值为1

pageSize 每页显示条数 默认值为10

注:

为了项目更好的扩展性,通常不设置固定值,而是是以参数的形式来进行传递

扩展性: 软件系统具备面对未来需求变化而进行扩展的能力。 比如当前需求一页显示10条,后期需求改为一页显示20条,

后端代码不需要任何修改。

2. 后端响应时,需要响应给前端的数据。

records :所查询到的数据列表(存储到List集合中)

count :总记录数(用于告诉前端显示多少页,

显示页数为:(count + pageSize -1)/pageSize

翻页请求和响应部分, 我们通常封装在两个对象中

1.1.1 翻页请求对象PageRequest

创建PageRequest

前端进行请求

1.会请求当前页 和 每页显示的个数。

2.由上面两个数据计算出offset,用作参数传递给SQL语句

package com.qiyangyang.springbook.demos.model;
import lombok.Data;
@Data
public class PageRequest {
    private Integer currentPage = 1;//当前页
    private Integer pageSize = 10;//每页显示个数
    private Integer offset;
    /**
     * 从多少条记录开始查询
     * @return
     */
    public Integer getOffset() {
        return (currentPage-1) * pageSize;
    }
}

1.1.2  翻页响应对象

package com.qiyangyang.springbook.demos.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * 定义一个泛型类,就是,这个地方不定义具体类型
 * 我们在进行对象的生成的时候,它才有具体的类型。
 * @param <T>
 */
//上面两个注解用来创建构造方法
@AllArgsConstructor
@NoArgsConstructor
@Data
public class PageResult<T> {
    /**
     * 返回的结果也是一个泛型
     * 不定义具体类型,在对象的创建才会有具体类型
     */
    private List<T> records; //当前页数据
    private Integer count; //所有记录数
    private PageRequest pageRequest; //小驼峰,用来返回给前端当前页数
    // 这里将整个对象告诉result。用来给前端获取多少页

}

返回结果中, 使用泛型来定义记录的类型

后端定义参数。

offset(起始序号)和limit(显示多少条)

 MySQL语句

 前端根据总记录数,来显示分了多少页。

1.2使用枚举来处理status/stateCN字段。 (可借阅/不可借阅)

1.创建enums文件夹

2.创建BookStatusEnums类

package com.qiyangyang.springbook.demos.enums;

/**
 * 枚举类
 * 可以列举出来的,是一个有限的个数,我们将他们定义成枚举类
 * 方便定义类似
 * 根据状态设置描述
 *             if(bookInfo.getStatus() == 1){
 *                 bookInfo.setStateCN("可借阅");
 *             } else if (bookInfo.getStatus() == 2) {
 *                 bookInfo.setStateCN("不可借阅");
 *             }else {
 *                 bookInfo.setStateCN("无效");
 *             }
 */
public enum BookStatusEnums {
    DELETE(0,"无效"), //删除
    NORMAL(1,"可借阅"), //有效的
    FORBIDDEN(2,"不可借阅"), //禁止
    ;
    private int code;
    private String desc;

    BookStatusEnums(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    /**
     * 我们将这个封装成一个方法
     * 根据code获取描述
     *
     * @return
     */
    public static  BookStatusEnums getDescByCode(int code){
        switch (code){
            case 0: return BookStatusEnums.DELETE;
            case 1: return BookStatusEnums.NORMAL;
            case 2: return BookStatusEnums.FORBIDDEN;
        }
        return BookStatusEnums.DELETE;
    }
    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }
}

稍后在业务层我们会对这个方法进行调用

1.3约定前后端交互接口

接口定义:

url:/book/getListByPage?currentPage=1

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

参数:

当前页数

返回结果:

当前页的数据+总记录数(决定前端显示多少页数)

我们约定,浏览器给服务器发送一个

/book/getListByPage 这样的 HTTP 请求,

通过 currentPage 参数告诉服务器,当前请求为第几页的数据,

后端根据请求参数,返回对应页的数据

第一页可以不传参数, currentPage默认值为1。

1.4实现服务器代码

1.4.1控制层:

完善 BookController

    @RequestMapping("getListByPage")
    public PageResult<BookInfo> getListByPage(PageRequest pageRequest){
        log.info("查询列表信息,pageRequest:{}",pageRequest);
        if(pageRequest.getCurrentPage()< 1){
            return null;
        }//这里返回null。会导致前端不知道是没有数据为null。还是当前页错误返回null
        //先不管,后续改进
        /**
         * 通过Service来去调用数据库
         */
        return bookService.getListByPage(pageRequest);
    }

1.4.2 业务层 :

完善 BookService

    public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {
        /**
         * 1.查询记录的总数
         * 2.查询当前页的数据
         */
        Integer count = bookInfoMapper.count();
        //bookInfos来接收查询到的数据
        List<BookInfo> bookInfos = bookInfoMapper.queryListByPage(pageRequest);

        for(BookInfo bookInfo : bookInfos){
            /**
             * 根据book状态设置描述(stateCN)
             */                    
        bookInfo.setStateCN(BookStatusEnums.getDescByCode(bookInfo.getStatus()).getDesc());
        }

        return new PageResult<>(bookInfos,count);
    }

1.4.3 数据层 :

完善 BookInfoMapper

    /**
     * 查询总数
     * @return
     */
    //count(1):返回满足条件的记录数(即行数)。count(1) 和 count(*) 基本等效,都是用于统计记录数。
    @Select(("select count(1) from book_info where status <> 0"))
    Integer count();

    //希望把新添加的图书放到下面,因此order by id desc降序。

    @Select("select * from book_info where status <> 0 order by id desc limit #{offset},#{pageSize}")
    List<BookInfo> queryListByPage(PageRequest pageRequest);

 1.5校验后端

不用传参也行,因为我们默认currentPage 为1。且pageSize为5。

我们发现返回正确。

总记录数也返回正确。为46。

我们发现后端接口没有问题。

 1.6实现前端代码

1.6.1显示图书数据的内容

将前端<tbody>标签中的内容,也就是

        <tbody>
          //这里的内容我们用findHtml变量拼接并传送到这个标签里了

        </tbody>

我们写在ajax中使用findHtml变量进行拼接。并用如下方法传送到这个标签中。

$("tbody").html(findHtml); //塞到tbody这个标签里面
            success: function (result) {
              var books = result.records;
              console.log(books); //如果前端没有报错,那么我们打印日志。观察后端返回结果对不对
              var findHtml = "";  //用这个变量来拼接HTML
              for (var book of books) {
                //拼接html。假如后端返回10个tr那么直接for循环拼接在这里面。findHtml
                //我们用单引号拼接,因为里面有双引号
                findHtml += '<tr>';
                findHtml += '<td><input type="checkbox" name="selectBook" value="' +book.id +'" id="selectBook" class="book-select"></td>';
                findHtml += "<td>" + book.id + "</td>";
                findHtml += "<td>" + book.bookName + "</td>";
                findHtml += "<td>" + book.author + "</td>";
                findHtml += "<td>" + book.count + "</td>";
                findHtml += "<td>" + book.price + "</td>";
                findHtml += "<td>" + book.publish + "</td>";
                findHtml += "<td>" + book.stateCN + "</td>";
                findHtml += "<td>";
                findHtml += '<div class="op">';
                findHtml +=
                  '<a href="book_update.html?bookId=' + book.id + '">修改</a>';
                findHtml +=
                  '<a href="javascript:void(0)" onclick="deleteBook('+book.id +')">删除</a>';
                findHtml += "</div>";
                findHtml += "</td>";
                findHtml += "</tr>";
              }
              $("tbody").html(findHtml); //塞到tbody这个标签里面


​

 1.6.2处理翻页信息

我们需要在前端head标签中引入jquery 和 paginator

相当于引入插件

    <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>
      <div class="demo">
        <ul id="pageContainer" class="pagination justify-content-center"></ul>
      </div>
              //处理翻页信息
                console.log(result);
                console.log(result.pageRequest);
              //翻页信息
              $("#pageContainer").jqPaginator({
                totalCounts: result.count, //总记录数
                pageSize: 10, //每页的个数
                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;
                  }
                },
              });

1.7校验前后端

成功实现图书列表显示以及翻页功能。

二、修改图书列表功能

2.1约定前后端交互接口

1.进入修改页面,需要显示当前 Id 图书的信息

[请求]

/book/queryBookById?bookId=25

[参数] 

bookId

[响应]

{

"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,获取当前图书的信息

2.点击修改按钮,修改图书信息

[请求]

/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

[响应] true/false

我们约定,

浏览器给服务器发送一个 /book/updateBook 这样的HTTP请求,

form表单的形式来 提交数据

服务器返回处理结果,

返回"修改成功"修改图书成功,否则,返回失败信息.

2.2实现服务器端代码

2.2.1控制层:

    @RequestMapping("/queryBookById")
    public BookInfo queryBookById(Integer bookId){
        log.info("查询图书信息,bookId:"+bookId);
        if(bookId == null || bookId<=0){
            return new BookInfo();
        }
        return bookService.queryBookById(bookId);
    }
    @RequestMapping("/updateBook")
    //先使用boolean类型返回。后续我们还会再进行完善。
    public boolean upDateBook(BookInfo bookInfo){
        log.info("修改图书信息, updateBook{}:",bookInfo);
        if(!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || !StringUtils.hasLength(bookInfo.getPublish())
                || bookInfo.getCount() <=0
                || bookInfo.getPrice()==null){
            return false;
        }
        try {
            Integer result = bookService.updateBook(bookInfo);
            if(result <= 0){
                return false;
            }
        }catch (Exception e){
            log.error("更新图书失败");
            return false;
        }
        return true;
    }

2.2.2 业务层 :

    public BookInfo queryBookById(Integer bookId) {
        return bookInfoMapper.queryBookById(bookId);
    }

    public Integer updateBook(BookInfo bookInfo) {
        return bookInfoMapper.updateBook(bookInfo);
    }

2.2.3 数据层 :

    /**
     * 根据Id查询图书信息
     * @param id
     * @return
     */
    @Select("select * from book_info where status <> 0 and  id = #{id}")
    BookInfo queryBookById(Integer id);

    /**
     * 根据Id修改图书信息
     */
    Integer updateBook(BookInfo bookInfo);

根据 Id 修改图书信息 我们使用的是XML方式实现的SQL

<?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.qiyangyang.springbook.demos.mapper.BookInfoMapper">
    <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>

2.3校验后端

我发现这个接口都校验成功。

2.3.1校验queryBookById接口 

2.3.2校验updateBook接口 

 

修改成功!

2.4实现前端代码

注意:前端传递数据的时候记得加上id。

    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script>
        //查询当前ID图书
        $.ajax({
            type: "get",
            url: "book/queryBookById"+location.search,
            success:function(book){
                if(book!=null){
                    $("#bookId").val(book.id);
                    $("#bookName").val(book.bookName);
                    $("#bookAuthor").val(book.author);
                    $("#bookStock").val(book.count);
                    $("#bookPrice").val(book.price);
                    $("#bookPublisher").val(book.publish);
                    $("#bookStatus").val(book.status);
                }
            }
        });
        //更新当前Id图书
        function update() {
            $.ajax({
                type: "get",
                url: "/book/updateBook",
                data:$("#updateBook").serialize(),//提交整个表单
                success:function(result){
                    if(result == true){
                        alert("更新成功");
                        location.href = "book_list.html"
                    }else{
                        alert("更新失败");
                    }
                }
                
            });
        }
    </script>

2.5整体测试

比如我们要将图书ID为135的图书

作者 修改为 洋洋

数量 修改为 888

价格 修改为 666

出版社 修改为 人民出版社

可借阅 修改为 不可借阅

修改成功!!!!! 

三、逻辑删除图书

删除图书分为

逻辑删除(update):

从逻辑上进行删除,数据并没有真实删除

物理删除(delete语句):

数据真实删除。

但数据并没有真实清空,只是数据库上看不到了。

硬件存储上还是存在的

删除并归档(操作交为复杂):insert into... select....语句

1.删除(delete or update)

2.归档(把已经删除的数据存储下来)

3.1约定前后端交互接口

逻辑删除的话,

依然是更新逻辑,我们可以直接使用修改图书的接口

[请求]

/book/updateBook

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

[参数]

id=1&status=0

[响应]

true / false

3.2实现服务器代码

3.2.1控制层:

由于我们在upadate接口中只需要传递 id 和 status 两个参数。

因此我们需要修改控制层中的校验参数的步骤

    @RequestMapping("/updateBook")
    //先使用boolean类型返回。后续我们还会再进行完善。
    public boolean upDateBook(BookInfo bookInfo){
        log.info("修改图书信息, updateBook{}:",bookInfo);
        if(!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || !StringUtils.hasLength(bookInfo.getPublish())
                || bookInfo.getCount() <=0
                || bookInfo.getPrice()==null){
            return false;
        }
        try {
            Integer result = bookService.updateBook(bookInfo);
            if(result <= 0){
                return false;
            }
        }catch (Exception e){
            log.error("更新图书失败");
            return false;
        }
        return true;
    }

修改为

    @RequestMapping("/updateBook")
    //先使用boolean类型返回。后续我们还会再进行完善。
    public boolean updateBook(BookInfo bookInfo){
        log.info("修改图书信息, updateBook{}:",bookInfo);
        if(bookInfo.getId()<0){
            return false;
        }
        try {
            Integer result = bookService.updateBook(bookInfo);
            if(result <= 0){
                return false;
            }
        }catch (Exception e){
            log.error("更新图书失败");
            return false;
        }
        return true;
    }

3.2.2 业务层 :

同之前的updateBook一样

    public Integer updateBook(BookInfo bookInfo) {
        return bookInfoMapper.updateBook(bookInfo);
    }

3.2.3 数据层 :

同之前的update一样

    /**
     * 根据Id修改图书信息
     */
    Integer updateBook(BookInfo bookInfo);
    <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>

校验后端接口 

 

134号图书 status 成功修改为0 

 

3.3实现前端代码

        function deleteBook(id) {
            //删除图书
          var isDelete = confirm("确认删除?");
          if (isDelete) {
            $.ajax({
              type: "post",
              url: "/book/updateBook",
              data:{
                id: id,
                status: 0
              },
              success:function(result){
                if(result == true){
                  alert("删除成功");
                  location.href = "book_list.html";
                }
              }
            });
          }
        }

3.4整体校验

删除132号图书三体

成功删除!!!!!!!!!!! 

 四、批量逻辑删除

4.1定义前后端交互接口

请求:

/book/batchDeleteBook

参数:

响应:

true/false

4.2实现服务器端代码

4.2.1控制层:

注意加上:注解@RequestParam

    @RequestMapping("/batchDelete")
    public boolean batchDelete(@RequestParam List<Integer> ids){
        log.info("批量删除数据,ids:{}",ids);
        try {
            Integer result = bookService.batchDelete(ids);
            if(result <= 0){
                return false;
            }
        }catch (Exception e){
            log.info("批量删除失败,id:{},e:{}", ids, e);
            return false;
        }
        return true;
    }

4.2.2 业务层 :

    public Integer batchDelete(List<Integer> ids) {
        return bookInfoMapper.batchDelete(ids);
    }

4.2.3 数据层 :

注意加上注解:

@Param("ids")

    Integer batchDelete(@Param("ids") List<Integer> ids);
    <update id="batchDelete">
        update book_info
        set status = 0
        where id in
        <foreach collection="ids" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </update>

4.3后端校验

后端操作成功

4.4实现前端代码 

        function batchDelete() {
          var isDelete = confirm("确认批量删除?");
          if (isDelete) {
            //获取复选框的id
            var ids = [];
            $("input:checkbox[name='selectBook']:checked").each(function () {
              ids.push($(this).val());
            });
            console.log(ids);
            $.ajax({
              type: "post",
              url: "/book/batchDelete?ids="+ids,
              success:function(result){
                if(result == true){
                  alert("批量删除成功");
                  location.href = "book_list.html";
                }else{
                  alert("删除失败,请联系管理员!");
                }
              }
            });
          }
        }

4.5整体测试

测试成功!!!!

五、强制登录

这个功能的实现我们下一篇文章再讲哦!!!!

到这里其实这个图书管理系统的功能就基本实现完成了。

不过对于这个图书管理系统。

我们没有进行登录也可以进行操作。

因此我们下一篇文章会详细讲解强制登录功能。

并且后续会讲到统一功能!!!!!!!!!!!!!!! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter错误: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared

前言 今天要做蓝牙通信的功能&#xff0c;我使用了flutter_reactive_ble这个库&#xff0c;但是在运行的时候发现一下错误 Launching lib/main.dart on AQM AL10 in debug mode... /Users/macbook/Desktop/test/flutter/my_app/android/app/src/debug/AndroidManifest.xml Err…

【C++滑动窗口】1297. 子串的最大出现次数|1748

本文涉及的基础知识点 C算法&#xff1a;滑动窗口及双指针总结 固定长度滑动窗口 LeetCode1297. 子串的最大出现次数 给你一个字符串 s &#xff0c;请你返回满足以下条件且出现次数最大的 任意 子串的出现次数&#xff1a; 子串中不同字母的数目必须小于等于 maxLetters 。…

信息宣传投稿栽跟头不可怕,关键是你要能再站起来

在繁忙的市郊,一家的事业基层单位,这里汇聚了各路英才,每个科室都有自己的专长。然而,有一项任务,让这些精英们头疼不已——单位信息宣传投稿。 起初,大家对这项任务并不以为然,以为不过是小菜一碟。李科长甚至开玩笑说:“不就是写篇文章,投个稿嘛,我们这些笔杆子还怕这个?”…

[极客大挑战 2019]PHP 1

[极客大挑战 2019]PHP 1 审题 猜测备份在www.zip中&#xff0c;输入下载文件。 知识点 反序列化 解题 查看代码 看到index.php中包含了class.php,直接看class.php中的代码 查看条件 当usernameadmin&#xff0c;password100时输出flag 构造反序列化 输入select中&#…

【初阶数据结构与算法】线性表之单链表的定义与实现

文章目录 一、单链表的概念与结构1.单链表的概念2.单链表的节点3.链表的性质 二、单链表的实现1.结构准备2.链表的打印和节点申请打印函数节点申请函数 3.链表的头插和尾插头插函数尾插函数 4.链表的头删和尾删头删函数尾删函数 5.查找指定节点6.指定节点位置的删除和插入删除指…

SCNU习题 总结与复习

1. P1:构建最大二叉树 【分治】 重点 构树函数需要注意的点&#xff1b; 前序遍历需要注意&#xff0c;本题的输出有点特点。若一个结点无左子&#xff0c;无右子就不再下去遍历&#xff1b; 其他情况都要下去遍历&#xff1b; 2. P2 寻找多数【分治】 没啥&#xff0c;注意…

代码随想录-栈和队列-用栈实现队列

问题描述 题目描述中有说不存在空栈的pop和peek&#xff0c;所以无需判断这个 解析 重点在于思路&#xff0c;代码白给。 要用栈实现队列&#xff0c;肯定是两个栈才可以。一个做入队操作&#xff0c;一个做出队操作。 首先入队简单&#xff0c;往栈里加就完事了。 出队复…

Scrapy框架:Python爬虫开发快速入门与初试

在众多编程语言中&#xff0c;Python以其简洁的语法和强大的库支持&#xff0c;成为了编写爬虫的首选语言。而在Python的爬虫库中&#xff0c;Scrapy框架无疑是其中的佼佼者。Scrapy是一个开源的、基于Python的爬虫框架&#xff0c;它提供了一套完整的工具和功能&#xff0c;使…

三菱QD77MS定位模块速度限制功能

“速度限制功能”是控制中的指令速度超过“速度限制值”的情况下&#xff0c;将指令速度限制在“速度限制值”的设置范围内的功能。 [1]速度限制功能与各控制的关系 速度限制功能”与各控制的关系如下所示。 [3]速度限制功能的设置方法 使用“速度限制功能”时&#xff0c;在如…

LeetCode【0002】两数相加

本文目录 1 中文题目2 求解思路2.1 基础解法&#xff1a; 递归解法2.2 最优解法&#xff1a;迭代法 3 题目总结 1 中文题目 给你两个非空的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照逆序的方式存储的&#xff0c;并且每个节点只能存储一位数字。请将两个数相…

鸿蒙进阶-属性动画

hello大家好啊&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习鸿蒙中的动画属性。 先来说说动画~ 属性值的变化&#xff0c;通常会引发 UI 的变化,结合动画可以让这个变化过程【更为流畅】&#xff0c;反之这个过程将在一瞬间完成&#xff0c;用户体验不好&#xff…

工业相机常用功能之白平衡及C++代码分享

目录 1、白平衡的概念解析 2、相机白平衡参数及操作 2.1 相机白平衡参数 2.2 自动白平衡操作 2.3 手动白平衡操作流程 3、C++ 代码从XML读取参数及设置相机参数 3.1 读取XML 3.2 C++代码,从XML读取参数 3.3 给相机设置参数 1、白平衡的概念解析 白平衡(White Balance)…

语音识别ic赋能烤箱,离线对话操控,引领智能厨房新体验

一、智能烤箱产品的行业背景 随着科技的飞速发展&#xff0c;智能家居已经成为现代家庭的新宠。智能烤箱作为智能家居的重要组成部分&#xff0c;正逐渐从高端市场走向普通家庭。消费者对于烤箱的需求不再仅仅局限于基本的烘焙功能&#xff0c;而是更加注重其智能化、便捷化和…

智能合约在供应链金融中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 引言 智能合约概述 定义与原理 发展…

书生大模型实战营-玩转HF/魔搭社区闯关任务

通过Github Codespace下载InternLM模型并运行 本篇博客是记录《书生大模型实战营第四期-玩转HF/魔搭/魔乐》章节的闯关任务从HF上下载模型文件&#xff0c;对实战营感兴趣的小伙伴也可以扫码报名哦。 一、通过模版创建Codespace环境 访问codespace 点击Jupyter Notebook 模版…

多维视角下的知识管理:Spring Boot应用

2 开发技术 2.1 VUE框架 Vue.js&#xff08;读音 /vjuː/, 类似于 view&#xff09; 是一套构建用户界面的渐进式框架。 Vue 只关注视图层&#xff0c; 采用自底向上增量开发的设计。 Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 2.2 Mysql数据库 …

【hdfs】【hbase】【大数据技术基础】实践二 HBase Java API编程

实践二 HBase Java API编程 为什么可以写命令还要编写程序&#xff1f;自动化批量处理&#xff1f; 尽管我们可以通过HBase的shell命令行工具进行数据操作&#xff0c;但在实际的生产环境中&#xff0c;为了提高效率和实现自动化处理&#xff0c;我们通常需要编写程序来与HBa…

【Pikachu靶场:XSS系列】xss之过滤,xss之htmlspecialchars,xss之herf输出,xss之js输出通关啦

一、xss之过滤 <svg onloadalert("过关啦")> 二、xss之htmlspecialchars javascript:alert(123) 原理&#xff1a;输入测试文本为herf的属性值和内容值&#xff0c;所以转换思路直接变为js代码OK了 三、xss之href输出 JavaScript:alert(假客套) 原理&#x…

【数据分享】1901-2023年我国省市县镇四级的逐年降水数据(免费获取/Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月降水栅格数据和Shp和Excel格式的省市县四级逐月降水数据&#xff0c;原始的逐月降水栅格数据来源于彭守璋学者在国家青藏高原科学数据中心平台上分享的数据&#xff01;基于逐月数据我们采用求年累计值的方法得到逐年降水栅格数据&#…

Istio Gateway发布服务

1. Istio Gateway发布服务 在集群中部署一个 tomcat 应用程序。然后将部署一个 Gateway 资源和一个与 Gateway 绑定的 VirtualService&#xff0c;以便在外部 IP 地址上公开该应用程序。 1.1 部署 Gateway 资源 vim ingressgateway.yaml --- apiVersion: networking.istio.…