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/getListByPagecurrentPage=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>//这里的内容我们用findHtml变量拼接并传送到这个标签里了</tbody>
我们写在ajax中使用findHtml变量进行拼接。并用如下方法传送到这个标签中。
$("tbody").html(findHtml); //塞到tbody这个标签里面
success: function (result) {var books = result.records;console.log(books); //如果前端没有报错,那么我们打印日志。观察后端返回结果对不对var findHtml = ""; //用这个变量来拼接HTMLfor (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/queryBookByIdbookId=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_infoset status = 0where id in<foreach collection="ids" open="(" close=")" item="id" separator=",">#{id}</foreach></update>
4.3后端校验
后端操作成功
4.4实现前端代码
function batchDelete() {var isDelete = confirm("确认批量删除?");if (isDelete) {//获取复选框的idvar 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整体测试
测试成功!!!!
五、强制登录
这个功能的实现我们下一篇文章再讲哦!!!!
到这里其实这个图书管理系统的功能就基本实现完成了。
不过对于这个图书管理系统。
我们没有进行登录也可以进行操作。
因此我们下一篇文章会详细讲解强制登录功能。
并且后续会讲到统一功能!!!!!!!!!!!!!!!
相关文章:
21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)(非强制登录版本完结)>
PS: 开闭原则 定义和背景 开闭原则(Open-Closed Principle, OCP),也称为开放封闭原则,是面向对象设计中的一个基本原则。该原则强调软件中的模块、类或函数应该对扩展开放,对修改封闭。这意味着一个软件实体…...
MySQL日志体系的深度解析:功能与差异
优质博文:IT-BLOG-CN 一、binlog binlog记录数据库表结构和表数据变更,比如update/delete/insert/truncate/create,它不会记录select。存储着每条变更的SQL语句和XID事务Id等等。binlog日志文件如下: [root192.168.10.11]# mysq…...
电商项目-数据同步解决方案(四)商品下架同步更新ES索引库数据
商品下架索引库删除数据 一、 需求分析和业务逻辑 商品下架后将商品从索引库中移除。 主要应用技术有: 消息队列-RabbitMQ ,分布式搜索引擎-ElasticSearch,Eureka,Canal,Feign远程调用 (1)在…...
Kafka
目录 一、什么是Kafka 核心组件 特性 使用场景 安装与配置 二、Kafka的使用 安装 ZooKeeper 和 Kafka 安装 ZooKeeper 安装 Kafka 配置 ZooKeeper 和 Kafka 配置 ZooKeeper 配置 Kafka 启动 ZooKeeper 和 Kafka 创建 Topic 编写生产者代码 编写消费者代码 运行…...
SAP SD学习笔记22 - VF04,VF06,VF24 等一括请求处理
上一篇学习了请求传票(发票)的拷贝管理。 SAP SD学习笔记21 - 请求传票的数据流(拷贝管理)-CSDN博客 本章继续学习 SAP SD的内容。 目录 1,VF04 - 一括请求处理(开票到期清单) 2,…...
JR-RLAA系20路模拟音频多功能编码器
JR-RLAA系20路模拟音频多功能编码器 产品特色 (1)工业级19英寸标准设备,内置双电源 (2)内嵌Web Server,支持远程Web页面登陆后的统一配置操作 (3)支持20路音频输入 (4)支持Dolby Digital(AC-3) ,MPEG-2,AAC-LC/HE-AAC&#x…...
数据结构复习 (二叉查找树,高度平衡树AVL)
1.二叉查找树: 为了更好的实现动态的查找(可以插入/删除),并且不超过logn的时间下达成目的 定义: 二叉查找树(亦称二叉搜索树、二叉排序树)是一棵二叉树,其各结点关键词互异,且中根序列按其关键词递增排列。 等价描述: 二叉查找…...
深入浅出梯度下降与反向传播
文章目录 1. 前言2. 基本概念2.1 一元函数的导数2.2 偏导数2.3 方向导数2.4 梯度2.5 均方误差 3. 梯度下降3.1 梯度下降的公式3.2 梯度下降的类型(优化器) 4. 反向传播4.1 反向传播的基本步骤4.2 反向传播的数学推导 5. 实战5.1 手动求导5.2 自动求导5.3…...
PLC(01)
一.职业规划 电路----------------->电工------------------>电气-------------------plc---------------------DCS--------------------> 机器人 二.交流电直流电的概念 1.交流电AC alternating current 大小方向随时间发生周期性变化 2.直流电 Direct current…...
如何通过本地部署的DIFY辅助学习算法(PS可以辅助帮你学习任何想学习的资料)
如何通过本地部署的DIFY辅助学习算法(PS可以辅助帮你学习任何想学习的资料 一 提升知识库的大小容量1.1 调大知识库的基础配置修改.env文件1.2 通过docker compose 重启加载最新配置1.3 重新上传知识库 二 搭建算法知识库的学习助手2.1 text embedding 模型对比2.1.1 如何选择合…...
深入探讨服务器虚拟化:架构、技术与应用
1. 引言 在现代IT基础设施中,服务器虚拟化已成为一种不可或缺的技术。它不仅提高了资源利用率,还增强了系统的灵活性和可管理性。随着企业对高效、灵活和可扩展IT环境的需求不断增加,服务器虚拟化技术的应用愈发广泛。本文将深入探讨服务器虚…...
C++笔记之尾后迭代器
C笔记之尾后迭代器 code review! 参考笔记 1.C笔记之尾后迭代器 2.C笔记之迭代器失效问题处理 在C中,尾后迭代器(通常称为 past-the-end iterator)是指指向容器中最后一个元素之后的位置的迭代器。它并不指向任何有效的元素,而是…...
2024年总结【第五年了】
2024年总结 北国绕院扫雪,南方围炉烹茶,且饮一杯无? 执笔温暖不曾起舞日子里的点点滴滴,誊写一段回忆,还以光阴一段副本。 那么你要听一支新故事吗?第五年总结的片碎。 衣单天寒,走趟流星孤骑…...
EasyExcel(环境搭建以及常用写入操作)
文章目录 EasyExcel环境搭建1.创建模块 easyexcel-demo2.引入依赖3.启动类创建 EasyExcel写1.最简单的写入1.模板2.方法3.结果 Write01.xlsx 2.指定字段不写入Excel1.模板2.方法3.结果 Write02.xlsx 3.指定字段写入excel1.模板2.方法3.结果 Write03.xlsx 4.按照index顺序写入ex…...
JVM类加载器
什么是类加载器 类加载器(ClassLoader)是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。 类加载器只参与加载过程中的字节码获取并加载到内存这一部分 类加载器的分类 类加载器分为两类,一类是Java代码中实现的࿰…...
druid连接池参数配置
最近发现生产环境经常有数据库连接超时的问题,排查发现是druid连接池参数设置不合理导致 总结问题如下: 为了防止僵尸连接,k8s ipvs做了连接超时限制,如果TCP连接闲置超过900s(15分钟),客户端再尝试通过这个连接去发起…...
【机器学习】Kaggle实战信用卡反欺诈预测(场景解析、数据预处理、特征工程、模型训练、模型评估与优化)
构建信用卡反欺诈预测模型 建模思路 本项目需解决的问题 本项目通过利用信用卡的历史交易数据,进行机器学习,构建信用卡反欺诈预测模型,提前发现客户信用卡被盗刷的事件。 项目背景 数据集包含由欧洲持卡人于2013年9月使用信用卡进行交的…...
Linux(Ubuntu)下ESP-IDF下载与安装完整流程(2)
接前一篇文章:Linux(Ubuntu)下ESP-IDF下载与安装完整流程(1) 本文主要看参考官网说明,如下: 快速入门 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 Linux 和 macOS 平台工具链的标准设置 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 一、安装准备 1. Linux用...
SpringBoot3 快速启动框架
文章目录 1 SpringBoot3 介绍 1.1 SpringBoot3 简介1.2 快速入门1.3 入门总结 2 SpringBoot3 配置文件 2.1 统一配置管理概述2.2 属性配置文件使用2.3 YAML配置文件使用2.4 批量配置文件注入2.5 多环境配置和使用 3 SpringBoot 整合 springMVC 3.1 实现过程3.2 web相关配置3.3…...
Enum枚举类,静态常量类,静态类的区别
Enum枚举类,静态常量类,静态类的区别 Enum枚举类静态常量类静态类Enum枚举类,静态常量类,静态类的区别 Enum枚举类 Enum枚举类的结构组成和用法使用可以查阅 Enum枚举类与静态变量和静态数组的区别 静态常量类 public class St…...
解锁专利世界的钥匙 ——famiwei 网
在知识经济的时代,专利作为创新成果的重要体现,无论是对于企业、科研人员乃至整个社会的发展都具有举足轻重的意义。而在众多的专利网站中,famiwei 网为用户提供了一个全面、精准且高效的专利信息交流与服务的舞台。 一、卓越功能,开启专利探索之门 famiwei 网拥有一套强大的专…...
金融租赁系统的创新与发展推动行业效率提升
金融租赁系统的技术升级与创新 在当今快速发展的金融市场中,金融租赁系统的技术升级与创新充满了无限可能。想象一下,传统的租赁方式就像一位沉闷的老师,而新兴技术就如同一位活泼的学生,不断追求新鲜事物。通过自动化、人工智能…...
SQL-Server链接服务器访问Oracle数据
SQL Server 链接服务器访问 Oracle 离线安装 .NET Framework 3.5 方法一:使用 NetFx3.cab 文件 下载 NetFx3.cab 文件,并将其放置在 Windows 10 系统盘的 C:Windows 文件夹中。 以管理员身份运行命令提示符,输入以下命令并回车: …...
Sonic:开源Go语言开发的高性能博客平台
Sonic:一个用Go语言开发的高性能博客平台 简介 Sonic,一个以其速度如声速般快速而命名的博客平台,是一个用Go语言开发的高性能博客系统。正如其名字所暗示的,Sonic旨在提供一个简单而强大的博客解决方案。这个项目受到了Halo项目…...
【react】常见的性能优化 1
目录 常见的 React 性能优化手段 1. 使用 useMemo 和 useCallback 缓存数据和函数 2. 使用 React.memo 缓存组件 3. 组件懒加载 4. 合理使用 key 5. 在组件销毁时清除定时器/事件 6. 使用 Suspense 和 Lazy 拆分组件 7. 使用 Fragment 避免额外标记 8. 避免使用内联函…...
SpringCloud源码-openFeign
LoadBalancer默认只有nacos服务发现器 openFeign与springcloud loadbalancer的结合点...
QLabel添加点击处理
在QLabel中添加点击事件有三种方式,分别是 使用LinkActivated信号连接槽函数(有缺限)注册事件分发器eventFilter创建类重写鼠标事件 1. 使用LinkActivated信号 QLabel类中有LinkActivated信号,是当标签中的链接被点击的时候触发…...
Markdown表格的使用
Markdown表格的使用 前言语法详解定义表格设定表格列内容的对齐方式 使用场景及实例小结其他文章快来试试吧 Markdown表格的使用👈点击这里也可查看 前言 表格通常作为一种布局的形式,用于结构化的数据展示。 Markdown表格包含三个部分:表头…...
时间序列预测算法介绍
时间序列预测是根据时间序列数据的历史变化规律,对未来数据进行预测的方法。在给定的代码中,使用的是自回归(AR)模型中的AR(4)模型来预测光伏功率。以下将详细解释这种算法: 1. 自回归模型(AR模型…...
加密流量TLS1.2 和TLS1.3的握手区别
加密流量TLS1.2 和TLS1.3的握手区别 TLS1.2 握手均是明文 1)Client Hello 2)Server Hello 3)Certificate TLS1.3 握手中Client Hello是明文,而Server Hello中Extensions以及后面的握手信息不可见 1)Client Hello…...
MySQL数据库——主从复制
本文详细介绍 MySQL的主从复制,从原理到配置再到同步过程。 文章目录 简介核心组件主从复制的原理作用主从复制的线程模型主从复制的模式形式复制的方式设计复制机制主从复制的配置步骤优化和改进总结 简介 MySQL 主从复制(Replication)是一…...
详细说明嵌入式linux中bootcmd与bootargs差异
bootcmd 和 bootargs 是在嵌入式系统开发,特别是基于U-Boot(一个广泛应用的开源引导加载程序)环境中常见的两个重要参数,它们的区别如下: 功能用途 bootcmd: 定义:bootcmd 是U-Boot中的一个环…...
【UE5】UnrealEngine源码构建2:windows构建unreal engine 5.3.2
参考大神知乎的文章:UE5 小白也能看懂的源码编译指南 据说会耗费400G的空间。 代码本身并不大,可能是依赖特别多,毕竟看起来UE啥都能干,核心还是c++的, 【UE5】UnrealEngine源码构建1:tag为5.3.2源码clone 本着好奇+ 学习的态度,想着也许有机会能更为深入的熟悉UE的机制…...
【YOLO算法改进】ALSS-YOLO:无人机热红外图像|野生动物小目标检测
目录 论文信息 论文创新点 1.自适应轻量通道分割和洗牌(ALSS)模块 2.轻量坐标注意力(LCA)模块 3.单通道聚焦模块 4.FineSIOU损失函数 摘要 架构设计 轻量高效网络架构 - ALSS模块 LCA模块 单通道聚焦模块 损失函数优…...
时间序列预测算法---LSTM
文章目录 一、前言1.1、深度学习时间序列一般是几维数据?每个维度的名字是什么?通常代表什么含义?1.2、为什么机器学习/深度学习算法无法处理时间序列数据?1.3、RNN(循环神经网络)处理时间序列数据的思路?1.4、RNN存在哪些问题?…...
【QT】:QT图形化界面概述
Qt背景介绍 1.1 什么是Qt Qt 是⼀个跨平台的C图形⽤⼾界⾯应⽤程序框架。它为应⽤程序开发者提供了建⽴艺术级图形 界⾯所需的所有功能。它是完全⾯向对象的,很容易扩展。Qt为开发者提供了⼀种基于组件的开发模 式,开发者可以通过简单的拖拽和组合来实现…...
[论文笔记]Representation Learning with Contrastive Predictive Coding
引言 今天带来论文 Representation Learning with Contrastive Predictive Coding的笔记。 提出了一种通用的无监督学习方法从高维数据中提取有用表示,称为对比预测编码(Contrastive Predictive Coding,CPC)。使用了一种概率对比损失, 通过使用负采样使…...
Redis相关
Redis相关 什么是redis?redis可以干什么? Redis是一个c语言编写的nosql数据库(不仅仅是sql,泛指非关系型数据库,一般把非关系型数据库称为nosql数据库),数据在内存中以键值对的形式存储,读写速度快,提供数据持久化方式. 常常被广泛应用到做缓存 Redis使用场景 1.缓存 2…...
【优选算法】Binary-Blade:二分查找的算法刃(上)
文章目录 1.概念解析2.二分查找的简单模版3.二分查找的进阶模版4.x的平方根5.搜索插入位置希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 本篇是优选算法之二分查找算法,该算法是一种高效的在有序数组中查找特定元素的搜索算法 1.概…...
Docker--Docker Network(网络)
Docker Network(网络)是Docker容器之间和容器与外部网络之间的通信和连接的一种机制。以下是对Docker Network的详细解释: 一、Docker网络的重要性 Docker容器网络是为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作…...
转化率是衡量网页设计的一个重要指标,请问如何做?
AARRR是互联网产品运营中一个非常重要的模型,这些模型的每一个步骤都涉及到转化率问题,那么AARRR是是什么呢?转化漏斗是什么吗?转化率为什么重要?设计师在做网页设计的时候,如何提升转化率呢?本…...
运维工具之syncthing工具的安装和使用
一、syncthing工具简介 Syncthing是一款开源的文件同步工具,采用Go语言编写。它支持在多个操作系统上运行,包括Windows、macOS和Linux,以及BSD、Solaris和Android等。以下是对这款软件的详细介绍,主要功能: 实时文件同…...
国产数据库-崖山使用介绍
本文档基于崖山数据库23.3 个人版本,单机(主备)部署模式的情况下的使用介绍。 数据库实例状态: NOMOUNT:仅读取参数文件,不加载数据库 MOUNT:读取控制文件,加载数据库ÿ…...
primevue的<Menu>组件
1.使用场景 2.代码 1.给你的menu组件起个引用名 2.<Menu>组件需要一个MenuItem[] 3.你要知道MenuItem[ ]的特殊的数据格式,就像TreeNode[ ]一样,数据格式不对是不渲染的。。。。 常用的属性就这几种,js语言和java不一样,J…...
【玩转23种Java设计模式】行为型模式篇:备忘录模式
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 汇总目录链接&…...
便捷饭店点餐小程序的设计与实现ssm+论文源码调试讲解
第4章 系统设计 一个成功设计的系统在内容上必定是丰富的,在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值,吸引更多的访问者访问系统,以及让来访用户可以花费更多时间停留在系统上,则表明该系统设计得比较专…...
微信小程序Uniapp
使用命令行创建项目(vuets) npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project然后用HBX打开项目 再安装依赖 npm i 再运行开发版本,生成dist目录 pnpm dev:mp-weixin 注意要设置APPid 再用微信小程序打开...
Android GameActivity(NativeActivity)读写文件
最近研究native android相关内容,其中最棘手的就是文件读写问题,最主要的是相关的文档很少。这里写下我所知道的方法。 由于本人使用的是Android14[arm64-v8a]版本的设备,能访问的路径相当有限,如果想要访问更多的路径,就不得不申…...
《计算机网络A》单选题-复习题库解析-2
目录 51、下列关于以太网网卡地址特点的说法中,不正确的是( )。 52、当一个Web Browser向一个使用标准服务器端口的Web Server提出请求时,那么在服务返回的响应包中,所使用的源端口是( ࿰…...
GPU 进阶笔记(二):华为昇腾 910B GPU
大家读完觉得有意义记得关注和点赞!!! 1 术语 1.1 与 NVIDIA 术语对应关系1.2 缩写2 产品与机器 2.1 GPU 产品2.2 训练机器 底座 CPU功耗操作系统2.3 性能3 实探:鲲鹏底座 8*910B GPU 主机 3.1 CPU3.2 网卡和网络3.3 GPU 信息 3.3…...