ruoyi框架使用自定义用户表登录
背景
有的时候我们做框架升级或改造的时候,需要用到原来的部分表,比如只是用ruoyi的框架,然后登录的用户逻辑还是想用自己的表,那么接下来这边文章将介绍修改逻辑。
修改教程
1、SysLoginController.java
大家找到这个login方法,这是controller的入口。
/*** 登录方法* * @param loginBody 登录信息* @return 结果*/@PostMapping("/login")public AjaxResult login(@RequestBody LoginBody loginBody){// 退出接口查看LogoutSuccessHandlerImpl.onLogoutSuccessAjaxResult ajax = AjaxResult.success();// 生成令牌,修改这个map返回自己的表的用户对象。// 如果这里不处理其余的逻辑就不需要修改,因为我这里要手动写入自己的日志Map<String, Object> map = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),loginBody.getUuid());LoginUser loginUser = (LoginUser)map.get("loginUser");loginUser.setLanguage(loginBody.getLanguage());bsOperateLogV2Service.createLoginLog(String.valueOf(loginUser.getUserId()),loginUser.getUsername(),1,String.valueOf(loginUser.getDeptId()));ajax.put(Constants.TOKEN, map.get("token"));return ajax;}
2、SysLoginService.java
这里有一些验证,比如验证码,用户是否存在等,大家点击进入到loginPreCheck方法中,把查询用户修改为自己的表查询,然后把没有用的逻辑注释掉。
/*** 登录验证* * @param username 用户名* @param password 密码* @param code 验证码* @param uuid 唯一标识* @return 结果*/public Map<String, Object> login(String username, String password, String code, String uuid){// 验证码校验validateCaptcha(username, code, uuid);// 登录前置校验loginPreCheck(username, password);// 用户验证Authentication authentication = null;try{UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);AuthenticationContextHolder.setContext(authenticationToken);// 该方法会去调用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(authenticationToken);}catch (Exception e){if (e instanceof BadCredentialsException){//AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));throw new UserPasswordNotMatchException();}else{//AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));throw new ServiceException(e.getMessage());}}finally{AuthenticationContextHolder.clearContext();}//AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));LoginUser loginUser = (LoginUser) authentication.getPrincipal();//recordLoginInfo(loginUser.getUserId());Map<String, Object> map = new HashMap<>();map.put("token",tokenService.createToken(loginUser));map.put("loginUser",loginUser);// 生成tokenreturn map;}/*** 登录前置校验* @param username 用户名* @param password 用户密码*/public void loginPreCheck(String username, String password){// 用户名或密码为空 错误if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));throw new UserNotExistsException();}// 密码如果不在指定范围内 错误
// if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
// || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
// {
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
// throw new UserPasswordNotMatchException();
// }
// // 用户名不在指定范围内 错误
// if (username.length() < UserConstants.USERNAME_MIN_LENGTH
// || username.length() > UserConstants.USERNAME_MAX_LENGTH)
// {
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
// throw new UserPasswordNotMatchException();
// }
// // IP黑名单校验
// String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
// if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
// {
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
// throw new BlackListException();
// }}
3、loadUserByUsername方法
大家找到UserDetailsServiceImpl.loadUserByUsername方法,这是核心。
@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
// 这是自己的页面输入的密码,没有加密,比如123456String inputPassword = usernamePasswordAuthenticationToken.getCredentials().toString();// 这里是自定义的表查询,用户和密码验证,如果还有其他的验证都可以在这里进行添加LambdaQueryWrapper wrapper = new LambdaQueryWrapper<BladeUserV2DO>().eq(BladeUserV2DO::getAccount,username)//PasswordUtil是自己的加密工具,你用什么加密就保持原来的就行.eq(BladeUserV2DO::getPassword, PasswordUtil.encrypt(inputPassword)).eq(BladeUserV2DO::getIsDeleted,0);// 这里写自己的登录验证逻辑BladeUserV2DO bladeUserV2DO = bladeUserV2Mapper.selectOne(wrapper);
// SysUser user = userService.selectUserByUserName(username);if (StringUtils.isNull(bladeUserV2DO)){log.info("登录用户:{} 不存在.", username);throw new UserPasswordNotMatchException();}BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();// 这里一定要把加密后的密码放进去,后面的验证中会一直用这个密码// 这个是123456加密后的密码,这里给框架都是完全通过的密码,// 因为我们在方法开始的时候自己进行密码验证,能走到这里都是验证通过的bladeUserV2DO.setPassword(passwordEncoder.encode(inputPassword));passwordService.validate(bladeUserV2DO);return createLoginUser(bladeUserV2DO);}public UserDetails createLoginUser(BladeUserV2DO bladeUserV2DO){BladeUserRespVo bladeUserRespVo = bladeUserV2Mapper.getBladeUserInfo(bladeUserV2DO.getId());SysUser user = new SysUser();user.setUserId(bladeUserV2DO.getId());user.setDeptId(0L);if(StringUtils.isNotEmpty(bladeUserV2DO.getDeptId())){user.setDeptId(Long.parseLong(bladeUserV2DO.getDeptId()));}user.setEmail(bladeUserV2DO.getEmail());user.setDelFlag("0");user.setNickName(bladeUserV2DO.getRealName());user.setUserName(bladeUserV2DO.getAccount());user.setPhonenumber(bladeUserV2DO.getPhone());user.setCreateTime(bladeUserV2DO.getCreateTime());user.setRoleId(0L);// 必须复制加密后的密码,后续框架一直在验证// 上面已经把123456对应的加密字符串保存进来,这里直接复制进去// 后续的框架一直在验证user.setPassword(bladeUserV2DO.getPassword());if(StringUtils.isNotEmpty(bladeUserV2DO.getRoleId())){user.setRoleId(Long.parseLong(bladeUserV2DO.getRoleId()));}user.setSex(bladeUserV2DO.getSex()+"");// LoginUser直接修改代码,把自己需要添加的字段都写进去,生成对应的set和get方法就行return new LoginUser(user.getUserId(), user.getDeptId(),user, permissionService.getMenuPermission(user),bladeUserRespVo.getIsSuperAdmin(),bladeUserRespVo.getIsAdmin(),bladeUserV2DO.getAccount());}public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions,int isSuperAdmin,int isAdmin, String account){this.userId = userId;this.deptId = deptId;this.user = user;this.permissions = permissions;//增加自己的字段this.isSuperAdmin = isSuperAdmin;this.isAdmin = isAdmin;this.account = account;}
4、SysPasswordService.java
这里的validate方法中,把没有用的逻辑注释掉。
/*** 登录账户密码错误次数缓存键名* * @param username 用户名* @return 缓存键key*/private String getCacheKey(String username){return CacheConstants.PWD_ERR_CNT_KEY + username;}public void validate(BladeUserV2DO bladeUserV2DO){Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();String username = usernamePasswordAuthenticationToken.getName();String password = usernamePasswordAuthenticationToken.getCredentials().toString();
// Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
//
// if (retryCount == null)
// {
// retryCount = 0;
// }
//
// if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
// {
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
// MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime)));
// throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
// }if (!matches(bladeUserV2DO, password)){
// retryCount = retryCount + 1;
// AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
// MessageUtils.message("user.password.retry.limit.count", retryCount)));
// redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);throw new UserPasswordNotMatchException();}else{clearLoginRecordCache(username);}}
5、PasswordUtil.java
如果你用的md5加密就不需要我的这个工具类
package com.ruoyi.common.utils;import jodd.util.StringUtil;
import org.apache.commons.codec.Charsets;
import org.springframework.lang.Nullable;
import org.springframework.util.DigestUtils;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;public class PasswordUtil extends DigestUtils {private static final char[] HEX_CODE = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};public PasswordUtil() {}public static String md5Hex(final String data) {return DigestUtils.md5DigestAsHex(data.getBytes(Charsets.UTF_8));}public static String md5Hex(final byte[] bytes) {return DigestUtils.md5DigestAsHex(bytes);}public static String sha1Hex(String data) {return sha1Hex(data.getBytes(Charsets.UTF_8));}public static String sha1Hex(final byte[] bytes) {return digestHex("SHA-1", bytes);}public static String sha224Hex(String data) {return sha224Hex(data.getBytes(Charsets.UTF_8));}public static String sha224Hex(final byte[] bytes) {return digestHex("SHA-224", bytes);}public static String sha256Hex(String data) {return sha256Hex(data.getBytes(Charsets.UTF_8));}public static String sha256Hex(final byte[] bytes) {return digestHex("SHA-256", bytes);}public static String sha384Hex(String data) {return sha384Hex(data.getBytes(Charsets.UTF_8));}public static String sha384Hex(final byte[] bytes) {return digestHex("SHA-384", bytes);}public static String sha512Hex(String data) {return sha512Hex(data.getBytes(Charsets.UTF_8));}public static String sha512Hex(final byte[] bytes) {return digestHex("SHA-512", bytes);}public static String digestHex(String algorithm, byte[] bytes) {try {MessageDigest md = MessageDigest.getInstance(algorithm);return encodeHex(md.digest(bytes));} catch (NoSuchAlgorithmException var3) {var3.printStackTrace();}return null;}public static String hmacMd5Hex(String data, String key) {return hmacMd5Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacMd5Hex(final byte[] bytes, String key) {return digestHMacHex("HmacMD5", bytes, key);}public static String hmacSha1Hex(String data, String key) {return hmacSha1Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacSha1Hex(final byte[] bytes, String key) {return digestHMacHex("HmacSHA1", bytes, key);}public static String hmacSha224Hex(String data, String key) {return hmacSha224Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacSha224Hex(final byte[] bytes, String key) {return digestHMacHex("HmacSHA224", bytes, key);}public static byte[] hmacSha256(String data, String key) {return hmacSha256(data.getBytes(Charsets.UTF_8), key);}public static byte[] hmacSha256(final byte[] bytes, String key) {return digestHMac("HmacSHA256", bytes, key);}public static String hmacSha256Hex(String data, String key) {return hmacSha256Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacSha256Hex(final byte[] bytes, String key) {return digestHMacHex("HmacSHA256", bytes, key);}public static String hmacSha384Hex(String data, String key) {return hmacSha384Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacSha384Hex(final byte[] bytes, String key) {return digestHMacHex("HmacSHA384", bytes, key);}public static String hmacSha512Hex(String data, String key) {return hmacSha512Hex(data.getBytes(Charsets.UTF_8), key);}public static String hmacSha512Hex(final byte[] bytes, String key) {return digestHMacHex("HmacSHA512", bytes, key);}public static String digestHMacHex(String algorithm, final byte[] bytes, String key) {SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(Charsets.UTF_8), algorithm);try {Mac mac = Mac.getInstance(secretKey.getAlgorithm());mac.init(secretKey);return encodeHex(mac.doFinal(bytes));} catch (InvalidKeyException | NoSuchAlgorithmException var5) {var5.printStackTrace();}return null;}public static byte[] digestHMac(String algorithm, final byte[] bytes, String key) {SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(Charsets.UTF_8), algorithm);try {Mac mac = Mac.getInstance(secretKey.getAlgorithm());mac.init(secretKey);return mac.doFinal(bytes);} catch (InvalidKeyException | NoSuchAlgorithmException var5) {var5.printStackTrace();}return null;}public static String encodeHex(byte[] bytes) {StringBuilder r = new StringBuilder(bytes.length * 2);byte[] var2 = bytes;int var3 = bytes.length;for(int var4 = 0; var4 < var3; ++var4) {byte b = var2[var4];r.append(HEX_CODE[b >> 4 & 15]);r.append(HEX_CODE[b & 15]);}return r.toString();}public static boolean slowEquals(@Nullable String a, @Nullable String b) {return a != null && b != null ? slowEquals(a.getBytes(Charsets.UTF_8), b.getBytes(Charsets.UTF_8)) : false;}public static boolean slowEquals(@Nullable byte[] a, @Nullable byte[] b) {if (a != null && b != null) {if (a.length != b.length) {return false;} else {int diff = a.length ^ b.length;for(int i = 0; i < a.length; ++i) {diff |= a[i] ^ b[i];}return diff == 0;}} else {return false;}}public static String hex(String data) {return StringUtil.isBlank(data) ? "" : sha1Hex(data);}public static String encrypt(String data) {return StringUtil.isBlank(data) ? "" : sha1Hex(md5Hex(data));}
}
6、完结
相关文章:
ruoyi框架使用自定义用户表登录
背景 有的时候我们做框架升级或改造的时候,需要用到原来的部分表,比如只是用ruoyi的框架,然后登录的用户逻辑还是想用自己的表,那么接下来这边文章将介绍修改逻辑。 修改教程 1、SysLoginController.java 大家找到这个login方…...

计算机视觉与深度学习-卷积神经网络-卷积图像去噪边缘提取-卷积-[北邮鲁鹏]
目录标题 参考学习链接卷积的定义卷积的性质叠加性平移不变性交换律结合律分配律标量 边界填充边界填充方法 - 常数填充最常用常数填充零填充(zero padding)拉伸镜像 卷积示例单位脉冲核无变化平移平滑锐化 卷积核平均卷积核高斯卷积核高斯卷积核定义高斯…...

JS手动实现发布者-订阅者模式
发布-订阅模式是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。具体过程是:订阅者把自己想订阅的事件注册到调度中心,当发布者更新该事件时通知调度中心,由调度中…...
【含面试题】MySQL死锁日志分析与解决的Java代码实现
AI绘画关于SD,MJ,GPT,SDXL百科全书 面试题分享点我直达 2023Python面试题 2023最新面试合集链接 2023大厂面试题PDF 面试题PDF版本 java、python面试题 项目实战:AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI…...

解决方案:TSINGSEE青犀+智能分析网关助力智慧仓储智能化监管
为全面保障物流仓储的安全性与完整性,解决仓库管理难题,优化物流仓储方式,提升仓储效率,降低人工成本,旭帆科技推出智慧仓储AI视频智能分析方案,利用物联网、大数据、云计算等技术,对仓储管理进…...

进程间通信
#include <unistd.h> int pipe(int pipefd[2]); 功能:创建一个匿名管道,用于进程间通信 参数: -int pipefd[2]:传出参数 pipefd[0]对应的是管道的读端 pipefd[0]对应的是管道的写端 返回值: 成功返回0,失败返回-…...

Ubuntu 22.04.3 LTS安装
最近换电脑了,准备重新装一下ubuntu。多年前装过ubuntu很老的版本,现在发现官网最新的LTS版本是 Ubuntu 22.04.3 LTS 版本。那重新装的话,肯定装最新的版本了。这里我记录下自己的安装过程,作为以后的笔记查看。 我的环境&#x…...

记一次manjaro-i3系统sogoupinying候选词无法正常显示中文(变方框了)问题解决方案
记一次manjaro-i3系统sogoupinying候选词无法正常显示中文(变方框了)问题解决方案 前言解决方案 前言 今天早上发现公司电脑显卡驱动好像坏了,各种折腾完了干脆把系统搞黑屏无法开机了,时间有限懒再修了,于是重装了系…...

Lua学习笔记:词法分析
前言 本篇在讲什么 Lua的词法分析 本篇需要什么 对Lua语法有简单认知 对C语法有简单认知 依赖Visual Studio工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ 👉 ♠ 一级标题…...

flask服务鉴权
基本认证(Basic Authentication): 这是一种简单的鉴权方式,需要客户端发送用户名和密码,服务器验证后允许或拒绝访问。可以使用 Flask-BasicAuth 扩展来实现。首先,安装扩展: pip install Fla…...

【2023华为杯B题】DFT类矩阵的整数分解逼近(思路及代码下载)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

基于微信小程序的校园生活管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言运行环境学生微信端的主要功能有:管理员的主要功能有:具体实现截图视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝1…...

SQL server 创建存储过程
SQL Server如何创建存储过程 存储过程: 可以理解为完成特定功能的一组 SQL 语句集,存储在数据库中,经过第一次编译,之后的运行不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数…...

一文了解亚马逊云科技适用于 Amazon Lightsail 的托管数据库
Amazon Lightsail 是亚马逊云科技提供的一种易上手使用、月度价格经济实惠,并包括了计算实例、容器、存储、数据库的虚拟专用服务器。在创建时可以进行业务蓝图选择,可选择包含多种操作系统(Linux/Windows 等)或操作系统加上典型应…...
【antd Col】奇怪的TypeError: Cannot read properties of undefined (reading ‘then‘)
现象 修改antd的Col组件的layouts属性为span后,并通过监听resize事件对span列宽进行动态变化时,报错TypeError: Cannot read properties of undefined (reading ‘then‘)。 补充示例一 由于我使用了飞冰ice.js,且在以下过程中写了如下语句…...
requests处理 multipart/form-data 请求以及 boundary值问题
requests处理 multipart/form-data 请求以及 boundary值问题 前言1. 请求需要携带本地资源2. 请求需要携带json3. 总结 前言 关于 Content-type: multipart/form-data可以看一下这篇文章, 分析特别详细 HTTP协议之multipart/form-data请求分析 put和post区别不大, 只是上传资…...

FBX文件结构解读【文本格式】
FBX 格式几乎受到所有 3D 引擎的支持,是 Autodesk 开发的 3D 模型的专有格式。它支持顶点、索引、法线、UV坐标、材质和动画。 FBX还支持许多其他类型的信息,但它们对游戏引擎几乎没有用处。 推荐:用 NSDT编辑器 快速搭建可编程3D场景 有两种…...

JS基础语法
JS是一门面向对象的编程语言,运行在客户端的脚本语言,可以基于Node.js进行服务器端编程 JS的作用: 表单动态校验网页特效服务端开发 浏览器执行JS: 浏览器分为两部分:渲染引擎和JS引擎 渲染引擎用来解析HTML和CSS,…...

【Zabbix监控一】zabbix的原理与安装
利用一个优秀的监控软件,我们可以: ●通过一个友好的界面进行浏览整个网站所有的服务器状态 ●可以在 Web 前端方便的查看监控数据 ●可以回溯寻找事故发生时系统的问题和报警情况 总结:zabbix主要功能 监控,cpu负载,内存使用&a…...

图的十字链表存储结构
1.其实就是邻接表和逆邻接表的结合,说明白点,就是用箭头表示出弧头,弧尾,以及他们之间的关系 2.顶点结构 3.弧结构 3.这样根据上面的结点十字链表结构就很好分析了...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...