20.<Spring图书管理系统①(登录+添加图书)>
PS:关于接口定义
接口定义,通常由服务器提供方来定义。
1.路径:自己定义
2.参数:根据需求考虑,我们这个接口功能完成需要哪些信息。
3.返回结果:考虑我们能为对方提供什么。站在对方角度考虑。
我们使用到的技术:
前端:”是自己在网上找的代码
后端
- IDEA
- Maven
- MySQL+Mybatis
- SSM
实现的功能:
- 用户登录
- 添加图书
- 显示图书列表
- 更新图书
- 删除图书
- 批量删除图书
- 强制登录
- 引入统一功能
做这个管理系统,首先我们需要考虑到什么呢?
第一步建立数据库
比如登录、用户要输入 用户名 和 密码。
因此对于数据库。我们需要一张用户表。用来存储用户名和密码。
还需要配置数据库 & 日志文件
搞完数据库相关的。就要写代码了。
第二步创建实体类
我们需要根据数据库字段创建一些实体类。
第三步实现用户登录功能
第四步实现添加图书功能
第五步实现显示图书列表功能
第六步实现更新图书功能
第七步实现删除图书功能
第八步实现批量删除图书
第九步实现强制登录
第十步加上统一功能
预览整体项目
首页
登录进去
可以进行翻页
添加图书
批量删除
修改图书
删除图书
一、建立数据库
1.1配置数据库 & 日志
server: #端口号配置port: 1208
spring:datasource: # 数据库连接配置url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 12345678driver-class-name: com.mysql.cj.jdbc.Drivermybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印 MyBatis?志map-underscore-to-camel-case: true #配置驼峰?动转换mapper-locations: classpath:mapper/**Mapper.xml # 配置mybatis xml的?件路径,在resources/mapper创建所有表的xml?件# classpath对应resources这个目录,接下来说明在mapper这个文件夹下面,以Mapper.xml结束的都可以被加载# 设置?志?件的?件名
logging:file:name: spring-book.log
我们新建一个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` ), --将 id 列设置为主键,保证每条记录唯一UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC )
--指定了索引的列以及排序方式。在此例中,user_name 列按照升序(ASC)排序。
--默认是升序,因此这里 ASC 是可选的。
) ENGINE = INNODB --设置存储引擎为 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, '?主与建设出版社');
下面是我们建好后的用户表
图书表
二、创建实体类
2.1 用户实体类UserInfo实体类
package com.qiyangyang.springbook.demos.model;import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {private Integer id;private String userName;private String password;private Integer delete_flag;private Date createTime;private Date updateTime;
}
2.2 图书实体类 BookInfo实体类
package com.qiyangyang.springbook.demos.model;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer count;private BigDecimal price;private String publish;private Integer status;//1-可借阅 2-不可借阅 0-已删除private String stateCN;//根据book状态设置描述private Date createTime;private Date updateTime;
}
三、实现用户登录接口
3.1约定前后端交互接口
[请求]
/user/login
Content-Type: application/x-www-form-urlencoded; charset=UTF-8[参数]
name=zhangsan&password=123456[响应]
true //账号密码验证正确, 否则返回false
浏览器给服务器发送 /user/login 这样的 HTTP 请求, 服务器给浏览器返回了一个Boolean类型 的数据.返回true,表示账号密码验证正确
3.2实现(后端)服务器代码
3.2.1控制层
从数据库查询用户名和密码,如果可以查到并且密码一致,就认为登录成功。
创建UserController
package com.qiyangyang.springbook.demos.controller;import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
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;
import javax.servlet.http.HttpSession;@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/login")public boolean login(String userName, String password, HttpSession session){/*** 校验参数*/if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}//判断用户输入的密码和用户输入的密码是否一致//我们需要查询数据库,得到数据库的密码UserInfo userInfo = userService.queryByName(userName);if(userInfo == null){//用户不存在return false;}if(password.equals(userInfo.getPassword())){//将密码置为空,不置为空也可以,因为Session是在服务器上的数据,客户端也看不到//session也是占内存的因此,不需要的不存。/*** 如果密码正确* 存Session*///由于密码信息是没用的,用不到。我们设置成空。不设置成空也行,因为存在服务器。客户端是看不到的userInfo.setPassword("");session.setAttribute("user_session",userInfo);return true;}return false;}
}
/**
package com.qiyangyang.springbook.demos.controller;import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
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;
import javax.servlet.http.HttpSession;@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/login")public boolean login(String userName, String password, HttpSession session){/*** 校验参数*/if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}//判断用户输入的密码和用户输入的密码是否一致//我们需要查询数据库,得到数据库的密码UserInfo userInfo = userService.queryByName(userName);if(userInfo == null){//用户不存在return false;}if(password.equals(userInfo.getPassword())){//将密码置为空,不置为空也可以,因为Session是在服务器上的数据,客户端也看不到//session也是占内存的因此,不需要的不存。/*** 如果密码正确* 存Session*///由于密码信息是没用的,用不到。我们设置成空。不设置成空也行,因为存在服务器。客户端是看不到的userInfo.setPassword("");session.setAttribute("user_session",userInfo);return true;}return false;}
}
/*** HttpSession session* 存的是根据SessionId获取的Session对象,每一个sessionId对应一个session对象。* 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。* SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。**/**/
问题1:每次我们存的Session都一样。后面用户。存的Session会覆盖前面用户的Session吗?
答:同一个用户会覆盖,不同用户,不同客户端不会覆盖。
Session表示的是会话,对话。是有来有回的,而且是多个回合。
* HttpSession session
* 存的是根据SessionId获取的Session对象,每一个sessionId对应一个session对象。
* 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。
* SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。
问题2:如果多个客户端同时访问,需不需要加多线程?
答:不需要,因为我们没有使用多线程。
请求的隔离框架已经帮我们做了。因此不考虑多线程。
什么时候才去做多线程呢,比如程序里面用到了线程池。才考虑多线程。每个用户进来login函数。信息存放在栈里面,栈是线程私有的。堆是线程公有的。这些成员变量存储在栈里面,因此每个用户的信息之间没有关系。分别对应不同的对象。
在我们需要进行优化的时候考虑多线程。比如要查询两次数据。第一次得到了密码,可以因为业务需要还要查询一次。这时候串行查询觉得太慢了。这时候考虑多线程。就可以进行并行查询。加了多线程我们就要考虑线程安全的情况。代码里用到多线程,才考虑多线程。
校验密码我们推荐在业务逻辑层来写,由于这里比较简单。我们就写在Controller中
3.2.2 业务层
创建UserService
package com.qiyangyang.springbook.demos.service;import com.qiyangyang.springbook.demos.mapper.UserInfoMapper;
import com.qiyangyang.springbook.demos.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;/*** 从数据库中查询用户信息* @param userName* @return*/public UserInfo queryByName(String userName){return userInfoMapper.queryByName(userName);}
}
3.2.3数据层
创建UserInfoMapper
package com.qiyangyang.springbook.demos.mapper;import com.qiyangyang.springbook.demos.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface UserInfoMapper {@Select("select * from user_info where delete_flag = 0 and user_name=#{userName}")UserInfo queryByName(String userName);}
3.3后端校验
使用Postman校验。多次实验发现,校验成功。然后我们再去写前端的代码。
3.4实现前端代码
3.4.1 ajax 部分
<script src="js/jquery.min.js"></script><script>function login() {$.ajax({type:"post",url:"/user/login",data:{userName:$("#userName").val(),password:$("#password").val()},success:function (result) {if(result===true){//验证成功location.href = "book_list.html";}else {alert("登录失败,用户名不存在或密码错误!");}}});}</script>
3.4.2完整前端登录代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="css/bootstrap.min.css"><link rel="stylesheet" href="css/login.css"><script type="text/javascript" src="js/jquery.min.js"></script>
</head><body><div class="container-login"><div class="container-pic"><img src="pic/computer.png" width="350px"></div><div class="login-dialog"><h3>登陆</h3><div class="row"><span>用户名</span><input type="text" name="userName" id="userName" class="form-control"></div><div class="row"><span>密码</span><input type="password" name="password" id="password" class="form-control"></div><div class="row"><button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button></div></div></div><script src="js/jquery.min.js"></script><script>function login() {$.ajax({type:"post",url:"/user/login",data:{userName:$("#userName").val(),password:$("#password").val()},success:function (result) {if(result===true){//验证成功location.href = "book_list.html";}else {alert("登录失败,用户名不存在或密码错误!");}}});}</script>
</body></html>
3.5完整校验前后端交互
输入正确用户名和密码
成功登录,并且跳转到图书目录页面。
输入错误用户名和密码。登录失败。弹框显示用户名不存在或密码错误。
四、实现添加图书接口
4.1约定前后端交互
[请求]
/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表单的形式来提交数据。服务器返回处理结果。返回“”表示图书添加成功。否则,返回失败信息。
4.2实现(后端)服务器代码
4.2.1控制层
创建BookController类
@Slf4j
@RestController
@RequestMapping("book")
public class BookController {@Autowiredprivate BookService bookService;@RequestMapping("/addBook")public String addBook(BookInfo bookInfo){log.info("添加图书,bookInfo:{}",bookInfo);/*** 参数校验*/if(!StringUtils.hasLength(bookInfo.getBookName())|| !StringUtils.hasLength(bookInfo.getAuthor())|| !StringUtils.hasLength(bookInfo.getPublish())|| bookInfo.getCount() <=0|| bookInfo.getPrice()==null){return "参数错误";}/*** 添加图书*//*** 出现错误比如参数错误。添加过程出现异常,因为MySQL会出现一些异常* 我们使用try/catch来捕获。*/try {bookService.insertBook(bookInfo);}catch (Exception a){return "内部发生错误,请联系管理员";}/*** 返回成功添加吐过表示图书插入成功。*/return "成功添加图书";}
}
4.2.2 业务层
创建BookService类
@Service
public class BookService {@Autowiredprivate BookInfoMapper bookInfoMapper;public Integer insertBook(BookInfo bookInfo){return bookInfoMapper.insertBook(bookInfo);}
}
4.2.3 数据层
创建BookInfoMapper
@Mapper
public interface BookInfoMapper {@Insert("insert into book_info(book_name,author,count,price,publish) " +"values (#{bookName},#{author},#{count},#{price},#{publish})")Integer insertBook(BookInfo bookInfo);
}
4.3后端测试
填写正确数据,返回成功添加图书
填写错误数据,返回参数错误
小bug(后端服务器问题)
count 和 price为字符串时,会报400错误。请求参数类型不匹配。
日志显示在绑定
bookInfo
对象时出现了类型转换错误:
count
字段:后端定义count
应为Integer
,但接收到的值是"五大"
(字符串)。price
字段:后端定义price
应为BigDecimal
,但接收到的值是"带娃"
(字符串)。因为这些值无法转换成期望的数值类型,所以 Spring 在尝试绑定请求参数时抛出了
BindException
,并返回HTTP 400
错误,表示请求的格式或内容无效。
4…4实现前端代码
4.4.1 form表单 和 ajax 部分
form表单
我们可以把提交的数据写成一个form表单。
form表单 Id 在前端显示页面并没有什么作用。主要是搭配后端来进行前后端交互。
整个表单内容需要提交的话,我们可以借助form标签来提交整个表单
data: $("#addBook").serialize(), //序列化
//这个函数会把整个表单的所有的input框…等等输入的项目都会提交
提交的结构是以key : value 键值对的形式提交
key就是name
value就是输入的值。
<form id="addBook"><div class="form-group"><label for="bookName">图书名称:</label><inputtype="text"class="form-control"placeholder="请输入图书名称"id="bookName"name="bookName"/></div>
<form id="addBook"> <div class="form-group"><label for="bookName">图书名称:</label><input type="text" class="form-control" placeholder="请输入图书名称" id="bookName" name="bookName"></div><div class="form-group"><label for="bookAuthor">图书作者</label><input type="text" class="form-control" placeholder="请输入图书作者" id="bookAuthor" name="author" /></div><div class="form-group"><label for="bookStock">图书库存</label><input type="text" class="form-control" placeholder="请输入图书库存" id="bookStock" name="count"/></div><div class="form-group"><label for="bookPrice">图书定价:</label><input type="number" class="form-control" placeholder="请输入价格" id="bookPrice" name="price"></div><div class="form-group"><label for="bookPublisher">出版社</label><input type="text" id="bookPublisher" class="form-control" placeholder="请输入图书出版社" name="publish" /></div><div class="form-group"><label for="bookStatus">图书状态</label><select class="custom-select" id="bookStatus" name="status"><option value="1" selected>可借阅</option><option value="2">不可借阅</option></select></div><div class="form-group" style="text-align: right"><button type="button" class="btn btn-info btn-lg" onclick="add()">确定</button><button type="button" class="btn btn-secondary btn-lg" onclick="javascript:history.back()">返回</button></div></form>
ajax部分
<script type="text/javascript" src="js/jquery.min.js"></script><script>function add() {$.ajax({type:"post",url:"/book/addBook",
//整个表单内容需要提交的话,我们可以借助form标签来提交整个表单,搭配后端做一些交互来使用的。data: $("#addBook").serialize(),//序列化
//这个函数会把整个表单的所有的input框..等等输入的项目都会提交success:function (result) {if(result === "成功添加图书"){alert("添加成功");location.href = "book_list.html";}else {alert(result);}}});}</script>
4.4.2完整前端添加图书代码
<!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/add.css" /></head><body><div class="container"><div class="form-inline"><h2 style="text-align: left; margin-left: 10px"><svgxmlns="http://www.w3.org/2000/svg"width="40"fill="#17a2b8"class="bi bi-book-half"viewBox="0 0 16 16"><pathd="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z"/></svg><span>添加图书</span></h2></div><form id="addBook"><div class="form-group"><label for="bookName">图书名称:</label><inputtype="text"class="form-control"placeholder="请输入图书名称"id="bookName"name="bookName"/></div><div class="form-group"><label for="bookAuthor">图书作者</label><inputtype="text"class="form-control"placeholder="请输入图书作者"id="bookAuthor"name="author"/></div><div class="form-group"><label for="bookStock">图书库存</label><inputtype="text"class="form-control"placeholder="请输入图书库存"id="bookStock"name="count"/></div><div class="form-group"><label for="bookPrice">图书定价:</label><inputtype="number"class="form-control"placeholder="请输入价格"id="bookPrice"name="price"/></div><div class="form-group"><label for="bookPublisher">出版社</label><inputtype="text"id="bookPublisher"class="form-control"placeholder="请输入图书出版社"name="publish"/></div><div class="form-group"><label for="bookStatus">图书状态</label><select class="custom-select" id="bookStatus" name="status"><option value="1" selected>可借阅</option><option value="2">不可借阅</option></select></div><div class="form-group" style="text-align: right"><button type="button" class="btn btn-info btn-lg" onclick="add()">确定</button><buttontype="button"class="btn btn-secondary btn-lg"onclick="javascript:history.back()">返回</button></div></form></div><script type="text/javascript" src="js/jquery.min.js"></script><script>function add() {$.ajax({type: "post",url: "/book/addBook",//整个表单内容需要提交的话,我们可以借助form标签来提交整个表单,搭配后端做一些交互来使用的。data: $("#addBook").serialize(), //序列化//这个函数会把整个表单的所有的input框..等等输入的项目都会提交success: function (result) {if (result === "成功添加图书") {alert("添加成功");location.href = "book_list.html";} else {alert(result);}},});}</script></body>
</html>
4.5完整校验前后端交互
输入正确数据
成功添加到我们的数据库中。
输入错误数据。
弹框提示输入参数错误!
本篇内容已经很多。
后续内容在下一篇文章中!
相关文章:

20.<Spring图书管理系统①(登录+添加图书)>
PS:关于接口定义 接口定义,通常由服务器提供方来定义。 1.路径:自己定义 2.参数:根据需求考虑,我们这个接口功能完成需要哪些信息。 3.返回结果:考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…...

关于图像锐化的一份介绍
在这篇文章中,我将介绍有关图像锐化有关的知识,具体包括锐化的简单介绍、一阶锐化与二阶锐化等方面内容。 一、锐化 1.1 概念 锐化(sharpening)就是指将图象中灰度差增大的方法,一次来增强物体的轮廓与边缘。因为发…...

Django开发入门 – 0.Django基本介绍
Django开发入门 – 0.Django基本介绍 A Brief Introduction to django By JacksonML 1. Django简介 1) 什么是Django? 依据其官网的一段解释: Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. …...

多智能体协作架构模式:驱动传统公司向AI智能公司转型
前言 在数字化浪潮的席卷下,传统公司的运营模式正面临着前所未有的挑战。随着市场竞争的日益激烈,客户需求的快速变化以及业务复杂度的不断攀升,传统公司在缺乏 AI 技术支撑的情况下,暴露出诸多痛点。在决策层面,由于…...

CentOS服务器部署Docker+Jenkins持续集成环境
一、准备工作 一台运行 CentOS 的服务器,确保有足够的磁盘空间、内存资源,并且网络连接稳定。建议使用 CentOS 7 或更高版本,本文以 CentOS 7 为例进行讲解。 拥有服务器的 root 权限,因为后续安装软件包、配置环境等操作需要较…...

【prompt实战】AI +OCR技术结合ChatGPT能力项目实践(BOL提单识别提取专家)
本文原创作者:姚瑞南 AI-agent 大模型运营专家,先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗;多年人工智能行业智能产品运营及大模型落地经验,拥有AI外呼方向国家专利与PMP项目管理证书。(转载需经授权) 目录 1. 需求背景 2. 目标 3. BOL通用处理逻辑…...

【Android】Android开发应用如何开启任务栏消息通知
Android开发应用如何开启任务栏消息通知 1. 获取通知权限2.编写通知工具类3. 进行任务栏消息通知 1. 获取通知权限 在 AndroidManifest.xml 里加上权限配置,如下。 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android…...

上传文件报错:the request was rejected because no multipart boundary was found
后端使用的springboot的MultipartFile上传文件,接口使用apifox调试过没有问题,但前端调接口报错。前端使用了fetch发送formData数据。 the request was rejected because no multipart boundary was found 前端使用的请求头是 multipart/form-data 没有…...

大模型—Dify本地化部署实战
Dify本地化部署实战 系统要求 安装 Dify 之前, 请确保你的机器已满足最低安装要求: CPU >= 2 CoreRAM >= 4 GiB本地部署 开始前先简单介绍下部署Dify需要用到的组件,稍微有点多,但放心,有Docker你怕啥? 关系数据库:postgres缓存:Redis向量数据库:支持weaviate…...

功能架构元模型
功能架构的元模型是对功能架构进行描述和建模的基础框架,它有助于统一不同团队对系统的理解,并为系统的设计和开发提供一致的标准和规范。虽然具体的元模型可能因不同的应用领域和特定需求而有所差异,但一般来说,功能架构的元模型可以涵盖以下几个方面: 组件/模块元模型:…...

常用工具类——Collections集合框架
常用工具类——Collections集合框架 Collections 是 JDK 提供的一个工具类,提供了一系列静态方法,分类来复习! 1.排序操作 reverse(List list) :反转顺序shuffle(List list) : 洗牌,将顺序打乱sort(List list) &…...

e2studio开发RA2E1(9)----定时器GPT配置输入捕获
e2studio开发RA2E1.9--定时器GPT配置输入捕获 概述视频教学样品申请硬件准备参考程序源码下载选择计时器时钟源UART配置UART属性配置设置e2studio堆栈e2studio的重定向printf设置R_SCI_UART_Open()函数原型回调函数user_uart_callback ()printf输出重定向到串口定时器输入捕获配…...

25/2/7 <机器人基础>雅可比矩阵计算 雅可比伪逆
雅可比矩阵计算 雅可比矩阵的定义 假设我们有一个简单的两个关节的平面机器人臂,其末端执行器的位置可以表示为: 其中: L1 和 L2 是机器人臂的长度。θ1 和 θ2是关节的角度。 计算雅可比矩阵 雅可比矩阵 JJ 的定义是将关节速度与末…...

网络爬虫js逆向之异步栈跟栈案例
【注意!!!】 前言: 1. 本章主要讲解js逆向之异步栈跟栈的知识(通过单步执行调试) 2. 使用关键字搜定位加密入口 3. 本专栏通过多篇文章【文字案例】的形式系统化进行描述 4. 本文章全文进行了脱敏处理 5. 详…...

使用Ollama本地部署deepseek
1、下载安装Ollama 前往下载页面 https://ollama.com/download下载好安装包,如同安装软件一样,直接安装即可 win中默认为C盘,如果需要修改到其他盘,查找具体教程 运行list命令,检查是否安装成功 2、修改模型下载的…...

Rust错误处理:从灭火器到核按钮的生存指南
开篇:错误处理的生存哲学 在Rust的平行宇宙里,错误分为两种人格: panic! → 核按钮💣(不可恢复,全系统警报)Result → 灭火器🧯(可控制,局部处理࿰…...

Golang:Go 1.23 版本新特性介绍
流行的编程语言Go已经发布了1.23版本,带来了许多改进、优化和新特性。在Go 1.22发布六个月后,这次更新增强了工具链、运行时和库,同时保持了向后兼容性。 Go 1.23 的新增特性主要包括语言特性、工具链改进、标准库更新等方面,以下…...

电脑运行黑屏是什么原因?原因及解决方法
电脑运行黑屏是指电脑在正常开机或使用过程中,突然出现屏幕变黑,无法显示任何内容的现象。这种现象可能会给用户带来很多不便,甚至造成数据丢失或硬件损坏。那么,电脑运行黑屏是什么原因呢?下面我们将分析几种可能的原…...

redis之AOF持久化过程
流程图 在redis.conf文件中配置appendonly为yes则开启aof持久化机制 #开启aof持久化,默认关闭为no appendonly no也可以在命令行开启 aof刷盘策略 #每个写操作都会同步刷盘。 appendfsync always #执行命令后先放入aof缓冲区,每秒钟将缓冲区数据刷盘…...

Elasticsearch:向量搜索的快速介绍
作者:来自 Elastic Valentin Crettaz 本文是三篇系列文章中的第一篇,将深入探讨向量搜索(也称为语义搜索)的复杂性,以及它在 Elasticsearch 中的实现方式。 本文是三篇系列文章中的第一篇,将深入探讨向量搜…...

Docker在安装时遇到的问题(第一部分)
一、在用docker-config-manager安装yum源时出现错误 [rootlocalhost ~]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 已加载插件:fastestmirror, langpacks adding repo from: https://download.docker.com/linux/ce…...

使用 OpenGL ES 在 iOS 上渲染一个四边形:从基础到实现
使用 OpenGL ES 在 iOS 上渲染一个四边形:从基础到实现 在 iOS 开发中,OpenGL ES 是一个强大的工具,用于实现高性能的 2D 和 3D 图形渲染。本文将详细分析一段完整的代码,展示如何使用 OpenGL ES 在 iOS 上渲染一个简单的四边形。我们将从代码的结构、关键模块、着色器的实…...
Spring Boot 2 快速教程:WebFlux处理流程(五)
WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤: 第一步:发起请求到前端控制器(DispatcherServlet) 第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找) 匹配条件包括…...

Vue 鼠标事件合集,关于鼠标右键的处理方法(改写鼠标右键方法、自定义鼠标右键)
鼠标事件使用 mousedown"canvasDown($event)"按下事件合集 click 点击某个对象时触发 mousedown 鼠标按钮被按下时触发 mouseup 鼠标按钮被松开时触发 mouseleave 当鼠标指针移出元素时触发 dblclick 双击时触发 mousemove 鼠标移动时触发,…...

两种交换排序算法--冒泡,快速
目录 1.冒泡排序原理 2.快速排序原理 3.冒泡代码实现 4.快速排序代码实现 1.冒泡排序原理 冒泡排序(Bubble Sort)是一种简单的排序算法,基本思想是通过反复交换相邻的元素,直到整个序列有序。它的名字来源于较大的元素像气泡…...

语音交友app系统源码功能及技术研发流程剖析
语音交友App的核心功能包括语音聊天、语音房间、社交互动等,开发流程涵盖需求分析、技术选型、前后端开发、实时通信集成、测试优化、部署上线及运营维护。 一、语音交友App的大概功能 1. 语音聊天 一对一聊天:用户可与好友进行私密语音通话。 群组语音…...

零基础Vue入门7——状态管理Pinia
本节重点: pinia是什么pinia怎么用 pinia是什么 vue中组件间的数据传递: app.config.globalProperties:能够被应用内所有组件实例访问到的全局属性的对象props:父传子用provide:父传后代用 想象下有咩有哪些数据存储…...

Bash (Bourne-Again Shell)、Zsh (Z Shell)
文章目录 1. 历史背景2. 主要区别3. 功能对比自动补全插件和主题路径扩展提示符定制 4. 性能5. 使用场景6. 如何切换 Shell7. 总结 以下是 Bash 和 Zsh 之间的主要区别,列成表格方便对比: 特性BashZsh默认Shell大多数Linux发行版默认ShellmacOS默认She…...

Android studio 创建aar包给Unity使用
1、aar 是什么? 和 Jar有什么区别 aar 和 jar包 都是压缩包,可以使用压缩软件打开 jar包 用于封装 Java 类及其相关资源 aar 文件是专门为 Android 平台设计的 ,可以包含Android的专有内容,比如AndroidManifest.xml 文件 &#…...

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求
DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法,通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力,其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们如何通过纯强化学习来增强 LLM 解决复杂问题的能力,而无…...