【个人博客系统网站】注册与登录 · 加盐加密验密算法 · 上传头像
【JavaEE】进阶 · 个人博客系统(3)
文章目录
- 【JavaEE】进阶 · 个人博客系统(3)
- 1. 加盐加密验密算法原理
- 1.1 md5加密
- 1.2 md5验密
- 1.3 md5缺漏
- 1.4 加盐加密
- 1.5 后端的盐值拼接约定
- 1.6 代码实现
- 1.6.1 加密
- 1.6.2 验密
- 1.6.3 测试
- 2. 博客注册页
- 2.1 上传头像
- 2.1.1 期待效果
- 2.1.2 约定前后端交互接口
- 2.1.3 后端代码
- 2.1.4 前端代码
- 2.1.5 测试
- 2.2 注册
- 2.2.1 期待效果
- 2.2.2 约定前后端交互接口
- 2.2.3 后端代码
- 2.2.4 前端代码
- 2.2.5 测试
- 3. 博客登录页
- 3.1 期待效果
- 3.2 失焦更新头像
- 3.2.1 约定前后端交互接口
- 3.2.2 后端代码
- 3.2.3 前端代码
- 3.2.4 测试
- 3.3 处理url 以及 注册页面跳转
- 3.3.1 通过key,获取url中的value
- 3.3.2 将username赋值给用户名输入框
- 3.3.3 注册页面跳转
- 3.3.4 测试
- 3.4 登录功能
- 3.4.1 约定前后端交互接口
- 3.4.2 后端代码
- 3.4.3 前端代码
- 3.4.4 测试
【JavaEE】进阶 · 个人博客系统(3)
本文章正式进行前后端交互了!
还是一样的老套路:
- 根据期待效果约定前后端交互接口
- 后端代码
- 三板斧:校验,处理请求,返回响应
- 前端代码
- 三板斧:校验,发送请求,处理响应
先写后端还是先写前端,个人习惯问题~
大方向就是那三板斧,具体按具体改动~
1. 加盐加密验密算法原理
1.1 md5加密
我们原本通过md5进行加密,这是一个不可逆的加密:
在这里插入图片描述](https://img-blog.csdnimg.cn/dbcab6e1574148c0ab41849ba13fc77b.gif)
原理就是通过password生成一个 一一对应 的固定长度的加密密码
1.2 md5验密
为什么不说是解密的,因为这个是一个不可逆的过程,也就是说,如果后端用md5加密后,是无法获取到原密码的,除非你使用“逆天的暴力枚举”
而一个固定的password,生成的是一个固定的加密密码!
这个也是常识,因为我们几乎在任何场景下,都没有遇到过,找回密码是返回原密码的,一般都是通过一些手段验证你的信息,进行修改密码的操作~
所以,后端能做的就是“验证密码”
因为一个固定的password,生成的是一个固定的加密密码!
所以如果密码是正确的话,生成的加密密码也是正确对应的上的!
1.3 md5缺漏
没错,不良用户/黑客,可以通过“逆天的暴力枚举”,也就是他们总结出来的“彩虹表”:
- 这个表,记录了很多很多字符串的加密密码,这样如果攻破了数据库的话,这些用户的密码就会被破解出来!
1.4 加盐加密
加盐,这里是比较形象的说法,也就是加点料,让加密密码无规律:
- 生成一个全球不重复的随机的盐值
- 盐值 + 原密码,进行md5加密,获取加密密码
- 将盐值 + 加密密码保存到数据库
而这个盐值,可见就是UUID!
- 因此,同样的原密码,由于UUID不会重复和md5加密的一一对应,生成的加密密码是不一样的~
- UUID和md5都是用不完的,底层不需要理解,坐享其成即可,不要杞人忧天~
这个算法逻辑上是破解的了的:
- 攻破数据库后,获取一个杂合密码
- 破解出盐值和加密密码(不良用户不知道这个盐值 + 加密码是咋组合的)
- 用彩虹表破解加密密码,获取原生组合,破解出原密码
- 不良用户不知道这个盐值 + 原密码是咋组合的
- 很难映射出这么“主观性这么强,随机性这么强”的原生组合
从逻辑分析上可以看出,破解难度和成本高出的倍数是不能计量的,“逆宇宙级枚举”
但是世界上没有完全的安全,只有你想不到的破解方法,和他们考虑成本是否要进行破解!
补充:加密过程后端是不会记录下来的,这里黑客破解的是持久化的数据
1.5 后端的盐值拼接约定
- 盐值跟原密码直接拼接,生成的加密密码
- 盐值跟加密密码以:
[salt]$[plus password]
格式拼接- 这样方便获取盐值
1.6 代码实现
1.6.1 加密
创建一个用户相关的工具类:UserUtils
public class UserUtils {public static String encrypt(String password) {// 1. 获取盐值String salt = UUID.randomUUID().toString();// 2. md5加密String plusPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));// 3. 将盐值和加密密码组合返回return salt + "$" + plusPassword;}
}
1.6.2 验密
根据加密原理推算:
验密就是根据数据库里的组合密码:
- 获取到[盐值]和[正确的加密密码]
- [盐值]拼接[待验证的密码],生成[待验证的加密密码]
- 对比[正确的加密密码]和[待验证的加密密码]
根据md5的一一对应,如果对应的上,那就是正确的密码
public static boolean confirm(String password, String dbPassword) {// 1. 获取到[盐值]和[正确的加密密码]String[] group = dbPassword.split("\\$"); // 在split函数的参数字符串里,这个$有特殊含义,需要转义一下// 2. md5加密String plusPassword = DigestUtils.md5DigestAsHex((group[0] + password).getBytes(StandardCharsets.UTF_8));// 3. 对比return group[1].equals(plusPassword);
}
参数校验调用这些方法之前就确认过了,不必重复~
- dbPassword必然是正确样式的数据,否则之前就不会添加成功,获取不到也更不会调用这个方法~
1.6.3 测试
public static void main(String[] args) {String password = "abcd";String dbPassword1 = encrypt(password);boolean conf1 = confirm(password, dbPassword1);String dbPassword2 = encrypt(password);boolean conf2 = confirm(password, dbPassword2);System.out.println(password);System.out.println(dbPassword1);System.out.println(conf1);System.out.println(dbPassword2);System.out.println(conf2);
}
结果:
补充:UUID的-
建议去除,我的数据库是65位的组合密码,所以得去掉:
- 这样UUID就是十六进制的三十二位数了
public static String encrypt(String password) {// 1. 获取盐值String salt = UUID.randomUUID().toString().replace("-", "");// 2. md5加密String plusPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));// 3. 将盐值和加密密码组合返回return salt + "$" + plusPassword;
}
2. 博客注册页
2.1 上传头像
2.1.1 期待效果
之前用的是form表单上传文件,现在我们用Ajax上传文件,这样我们就不会被强制跳转且可以获取传递回来的文件名,更新其显示!
2.1.2 约定前后端交互接口
后端:
- /user/picture
- 接受请求中的文件,项目外的D:/blog_userImage目录下
- 不用导致项目空间占用太大
- 应该是项目,映射指向机器的某一个位置的资源
- 返回文件名(包装成的CommonResult对象)
前端:
- /user/picture
- multipart/form-data
- post
- body:文件按钮上传的文件
2.1.3 后端代码
- 工具类ImageUtils,通过getImageUniquePath方法,可获取文件保存路径
public class ImageUtils {public static String getImageUniquePath(String originName) {String path = "blog_userImage/";// 获取唯一idString id = UUID.randomUUID().toString();//获取文件后缀String suffix = originName.substring(originName.lastIndexOf("."));//拼接path += id + suffix;return path;}
}
- controller层,处理请求,调用service层进行数据持久化
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/picture")public CommonResult picture(@RequestPart("myfile")MultipartFile file) throws IOException {if(file == null) {return CommonResult.fail(-1, "上传文件失败");}//获取文件保存路径String path = ImageUtils.getImageUniquePath(file.getOriginalFilename());//通过文件保存路径,将文件进行保存userService.loadImage(file, path);//返回文件名(包装成统一对象)return CommonResult.success(path);}}
- service层,进行数据持久化
@Service
@Slf4j
public class UserService {public void loadImage(MultipartFile file, String path) {log.info("保存成功:" + path);//保存成功日志//保存文件try {file.transferTo(new File("D:/" + path));//spring mvc是可以直接throws异常的,框架内部/异常处理器有处理,但是多级调用,耦合度有点高} catch (IOException e) {e.printStackTrace();}}
}
- 配置静态资源映射
对于新增的文件:
- 我们的网站能够访问到我们自己的静态资源是因为我们在运行的时候,将这些打包到target里面了,而新增的文件只是在我们开发的时候的路径下,并没有立即加载到target里
- 绝对路径也是一样,无论你保存到项目里,还是保存到项目外,都没有加载到target里面,我们也无法手动写入target
而我们的网站,浏览器考虑到安全性,是不能直接访问不在项目target里的静态资源的
而我们spring boot项目与普通maven项目不同,spring boot项目修改静态资源,例如html/css/js等等,必须保存并重启服务器才能更新~
所以我们需要进行,静态资源的映射!
@Configuration
public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {/*** 配置静态访问资源* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/blog_userImage/**").addResourceLocations("file:D:/blog_userImage/");}}
含义就是,将“file:D:/blog_userImage/”路径下的静态资源,映射成“/blog_userImage/**”
- 通过
localhost:8080/blog_userImage/**
,就可以访问~
并且,访问服务器的路由以这个为准,拦截器配置:
目录结构:
2.1.4 前端代码
<div id="fileImage"><inputid="i"type="button"value="请上传头像"onclick="putImage();"/><input id="f_file" type="file" name="file" style="display: none" />
</div>
putImage(点击普通按钮触发file按钮):
function putImage() {javascript: jQuery("input[name='file']").click();
}
file按钮上传成功触发的事件(发送请求):
- 固定搭配,无需多问~
jQuery("#f_file").change(function (e) {// 获取选中的文件var file = e.target.files[0];// 创建一个 FormData 对象var formData = new FormData();formData.append("myfile", file);// 用 Ajax 向服务器发送文件jQuery.ajax({url: "/user/picture",type: "POST",data: formData,processData: false, // 告诉 jQuery 不要处理发送的数据contentType: false, // 告诉 jQuery 不要设置 Content-Type 请求头success: function (res) {if (res.code === 200) {//修改图像var url = "url(" + res.data + ")";jQuery("#i").css("background-image", url);jQuery("#i").val("");} else {console.log("上传失败: " + res.msg);}},error: function () {console.log("上传失败,请重试!");},});
});
2.1.5 测试
2.2 注册
2.2.1 期待效果
输入必选项:昵称,密码,确认密码
- 确认密码在发送之前进行验证,因为没有确认密码这个字段,也没有必要,这个不需要多说
代码仓库以及头像为非必选
- 注册成功后,弹框提示自动生成的用户名,跳转到登录页面,并帮助用户填写用户名
而在后端:
- 生成一个加密密码
- 生成一个用户名
2.2.2 约定前后端交互接口
后端:
- /user/register
- 返回受影响行数,以及用户名
前端:
- body:image,name,password,git
- post,json,/user/register
2.2.3 后端代码
- UserUtils的获取用户名的方法
public static String getUsername() {// 获取当前时间戳long timestamp = System.currentTimeMillis();// 生成随机数Random random = new Random();int randomNumber = random.nextInt(100);// 结合时间戳和随机数生成唯一标识符String identifier = String.valueOf(timestamp) + String.valueOf(randomNumber);return identifier;
}
不适用UUID是因为UUID太长了,没啥规律,带字母,而这里我用的是当前时间戳 + 100以内的随机数组成的15位十进制数
如果恶意注册,用户名才可能重复,由于有unique约束,所以会添加失败,受影响行数返回0~
- controller层
@RequestMapping("register")
public CommonResult register(@RequestBody UserInfo userInfo) {// 1. 校验参数if(userInfo == null || !StringUtils.hasLength(userInfo.getName())|| !StringUtils.hasLength(userInfo.getPassword())) {return CommonResult.fail(-1, "非法参数");}// 2. 生成一个用户名String username = UserUtils.getUsername();userInfo.setUsername(username);// 3. 加密userInfo.setPassword(UserUtils.encrypt(userInfo.getPassword()));// 4. 请求service的添加数据库操作int rows = userService.register(userInfo);// 5. 执行结果返回Map<String, Object> map = new HashMap<>();map.put("rows", rows);map.put("username", username);return CommonResult.success(map);
}
补充:
判断字符串为空字符串/null,是的话,返回false
- mapper层
实现:
- 由于我需要用到标签,所以注解的方式不太方便,我用xml去实现
<?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.example.demo.mapper.UserMapper"></mapper>
register实现(非必选项的判断):
<insert id="register">insert into userinfo (username,name,<if test="photo != null">photo,</if><if test="git != null">git,</if>password) values (#{username},#{name},<if test="photo != null">#{photo},</if><if test="git != null">#{git},</if>#{password})
</insert>
- service层
@Autowired
private UserMapper userMapper;
public int register(UserInfo userInfo) {return userMapper.register(userInfo);
}
- 拦截器配置
2.2.4 前端代码
- 用户名不能全为空,并且上传时空白符会被去除掉
- 密码不能全为空,并且上传时空白符会被去除掉
实现:
function register() {var name = jQuery("#username");var password = jQuery("#password");var judge_password = jQuery("#judge_password");var photo = jQuery("#i").css("background-image").replace("url(", "").replace(")", "").replace("\"", "").replace("\"", "");//去掉两个引号var git = jQuery("#git");// 1. 非空校验if (name.val().trim() == "") {alert("请输入昵称!");name.focus();return false;}if (password.val().trim() == "") {alert("请输入密码!");password.focus();return false;}if (judge_password.val().trim() == "") {alert("请输入密码!");judge_password.focus();return false;}if (password.val() != judge_password.val()) {alert("两次输入密码不一致!");return false;}// 2. 发送请求jQuery.ajax({url: "/user/register",method: "POST",contentType: "application/json; charset=utf8",data: JSON.stringify({name: name.val().trim(),password: password.val().trim(),photo: photo,git: git.val(),}),// 3. 处理响应success: function (body) {if (body.code == 200 && body.data.rows == 1) {alert("注册成功,请记住你的用户名:" + body.data.username + " !");location.href = "blog_login.html?username=" + body.data.username;} else {alert("注册失败:" + data.msg);}},});
}
2.2.5 测试
在这里插入图片描述
3. 博客登录页
3.1 期待效果
- 用户名输入框聚焦到失焦的时候发送请求给后端,尝试获取用户头像
- 根据querystring,如果有用户名将用户名进行赋值,两个输入框都输入值后才能发送登录请求,后端对数据进行校验
- 点击注册按钮,跳转到注册页
3.2 失焦更新头像
3.2.1 约定前后端交互接口
后端:
- /user/get_photo
- 返回头像名
前端:
- /user/get_photo
- 用户名
- json
3.2.2 后端代码
- controller层
@RequestMapping("/get_photo")
public CommonResult getPhoto(@RequestBody UserInfo user) {String username = user.getUsername();UserInfo userInfo = userService.getUserByUsername(username);return userInfo != null ? CommonResult.success(userInfo.getPhoto()) : CommonResult.fail(-1, "没有此用户");
}
- service层
public UserInfo getUserByUsername(String username) {return userMapper.selectByUsername(username);
}
- mapper层
@Select("select * from userinfo where username = #{username}")
UserInfo selectByUsername(@Param("username") String username);
- 拦截器配置
.excludePathPatterns("/user/get_photo")
3.2.3 前端代码
给用户名输入框一个失焦事件:
jQuery("#username").blur(function () {var username = jQuery("#username");if (username.val().trim() != "") {jQuery.ajax({url: "/user/get_photo",method: "post",contentType: "application/json; charset=utf8",data: JSON.stringify({username: username.val().trim(),}),success: function (body) {if (body.code == 200 && body.data != "") {var img = "url(" + body.data + ")";jQuery("#i").css("background-image", img);} else {jQuery("#i").css("background-image","url(blog_userImage/avatar.png)");}},});}
});
3.2.4 测试
3.3 处理url 以及 注册页面跳转
3.3.1 通过key,获取url中的value
<script src="js/url_handler.js"></script>
// 根据 key 获取 url 中对应的 value
function getParamValue(key){// 1.得到当前url的参数部分var params = location.search;// 2.去除“?”if(params.indexOf("?")>=0){params = params.substring(1);// 3.根据“&”将参数分割成多个数组var paramArray = params.split("&");// 4.循环对比 key,并返回查询的 valueif(paramArray.length>=1){for(var i=0;i<paramArray.length;i++){// key=valuevar item = paramArray[i].split("=");if(item[0]==key){return item[1];}}}}return null;
}
3.3.2 将username赋值给用户名输入框
jQuery("#username").val(getParamValue("username"));
jQuery("#username").focus();
3.3.3 注册页面跳转
3.3.4 测试
3.4 登录功能
3.4.1 约定前后端交互接口
后端:
- /user/login
- 返回 true / false
前端:
- /user/login
- 用户名,密码,json,post
- true:跳转到所有人的博客列表页;false:弹窗提示
3.4.2 后端代码
- controller层
@RequestMapping("/login")
public CommonResult login(@RequestBody UserInfo userInfo, HttpServletRequest request) {//1. 参数校验if(userInfo.getUsername() == null || !StringUtils.hasLength(userInfo.getUsername())|| userInfo.getPassword() == null || !StringUtils.hasLength(userInfo.getPassword())) {return CommonResult.fail(-1, "非法参数!");}//2. 根据用户名查询对象UserInfo user = userService.getUserByUsername(userInfo.getUsername());if(user == null || user.getId() == 0) {return CommonResult.fail(-2, "用户名或者密码错误!");}//3. 验证密码(左边待测,右边数据库查出来的)if(!UserUtils.confirm(userInfo.getPassword(), user.getPassword())) {return CommonResult.fail(-2, "用户名或者密码错误!");}//4. 比较成功,将对象存储到session中SessionUtils.setUser(request, user);//5. 返回结果return CommonResult.success("登录成功");
}
- 拦截器配置
.excludePathPatterns("/user/login")
3.4.3 前端代码
function login() {var username = jQuery("#username");var password = jQuery("#password");// 1. 非空校验if (username.val().trim() == "") {alert("请输入昵称!");username.focus();return false;}if (password.val().trim() == "") {alert("请输入密码!");password.focus();return false;}// 2. 发送请求jQuery.ajax({url: "/user/login",method: "POST",contentType: "application/json; charset=utf8",data: JSON.stringify({username: username.val().trim(),password: password.val().trim(),}),// 3. 处理响应success: function (body) {if (body.code == 200) {alert("登录成功!");location.href = "blog_lists.html";} else {alert("登录失败:" + body.msg);}},});
}
3.4.4 测试
可以访问需要登录校验的页面:
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆!代码:myblog_system · 游离态/马拉圈2023年9月 - 码云 - 开源中国 (gitee.com)
相关文章:

【个人博客系统网站】注册与登录 · 加盐加密验密算法 · 上传头像
【JavaEE】进阶 个人博客系统(3) 文章目录 【JavaEE】进阶 个人博客系统(3)1. 加盐加密验密算法原理1.1 md5加密1.2 md5验密1.3 md5缺漏1.4 加盐加密1.5 后端的盐值拼接约定1.6 代码实现1.6.1 加密1.6.2 验密1.6.3 测试 2. 博客…...

[H5动画制作系列] Sprite及Text Demo
参考代码: sprite.js: var canvas, stage, container; canvas document.getElementById("mainView"); function init() {stage new createjs.Stage(canvas);createjs.Touch.enable(stage);var loader new createjs.LoadQueue(false);loader.addEventListener(&q…...
目标检测YOLO实战应用案例100讲-毫米波辐射图像去模糊重建与目标检测
目录 前言 毫米波辐射图像去模糊重建研究现状 基于传统算法的图像去模糊重建...
Android10 SystemUI系列(一)概述
一、前言 由于笔者之前负责过SystemUI,之前没有抽空把很多东西整理出来,趁着最近不太忙,就慢慢动手梳理一下,顺便把自己遇到的问题也整理一下,当然自己之前主要看的是android11 之后的源码。这次主要是Android10 的源码,当然原理大差不差,也算是自己沉淀一下了 二、Sy…...

SpringMVC的常用注解,参数传递以及页面跳转的使用
目录 slf4j 常用注解 RequestMapping RequestParam RequestBody PathVariable 参数传递 首先在pom.xml配置文件中导入SLF4J的依赖 基础类型String 复杂类型 RequestParam PathVariable RequestBody 增删改查 返回值 void返回值 String返回值 modelString …...

Java“牵手”易贝商品列表数据,关键词搜索易贝商品数据接口,易贝API申请指南
ebay商城是一个网上购物平台,售卖各类商品,包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取ebay商品列表和商品详情页面数据,您可以通过开放平台的接口或者直接访问ebay商城的网页来获取商品详情信息。以下是两种常用方法的介绍&…...

java中HashMap如何根据value的值去获取key是多少
在Java中,HashMap是一种基于键值对存储数据的数据结构。HashMap并没有直接提供根据value获取key的方法。但你可以通过遍历HashMap的entrySet,找到对应的value,然后获取其对应的key。 以下是一个示例代码: public <K, V> K…...
Python|OpenCV-色彩空间之RGB轨迹调试板(5)
前言 本文是该专栏的第5篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 通常情况下,在处理图像需求的时候,需要掌握多个色彩空间的知识点。现实中,我们肉眼可以看到多种颜色,色彩是人的眼睛对于不同频率的光线的不同感受,其既是客观存在的,也是主观感知的。…...

安全生产:CVE-2020-11022/CVE-2020-11023漏洞解析
文章目录 一、前言二、漏洞原理三、修复方案3.1 升级jQuery3.2 1.x 升级至 3.x 需要考虑的问题3.2.1 table表格元素自动添加tbody3.2.2 方法变更 3.3 jquery migrate是什么 四、拓展阅读 一、前言 代码安全扫描阶段,前端资源审计发现jQuery版本过低导致生产系统存在…...

手写Spring:第17章-通过三级缓存解决循环依赖
文章目录 一、目标:通过三级缓存解决循环依赖二、设计:通过三级缓存解决循环依赖2.1 通过三级缓存解决循环依赖2.2 尝试使用一级缓存解决循环依赖 三、实现:通过三级缓存解决循环依赖3.1 工程结构3.2 通过三级缓存解决循环依赖类图3.3 设置三…...

C#使用proto
写多了go代码,被go mod tidy惯坏了,还以为全天下的都很好用呢,结果发现并不是这样。尤其是项目组的proto还是又封了个工具直接就能跑得,导致以为没那么复杂的事情变得复杂了起来。是有两套生成的规则,时间有点晚&#…...
Java基础知识面试题(一)(英语答案)
加油 前言Java中的基本数据类型包括以下几种:String和StringBuilder的区别是什么?什么是面向对象编程(OOP)?如何在Java中创建一个类?什么是继承?如何在Java中实现继承?什么是多态性?如何在Java中实现多态性?什么是封装和继承?什么是接口(Interface)?如何在Java中…...

基于csv数据建立线性回归模型并预测进行评估模型表现案例实现
一、数据处理 1.加载csv数据进行查看 import pandas as pd data pd.read_csv("generated_data.csv") print(data)2.将上述数据的x和y进行分离开,便于后续进行坐标建立 x data.loc[:,x] y data.loc[:,y] print(x,y)3.先使用matplotlib进行显示数据 …...

MySQL学习问题记录
文章目录 MySQL学习问题记录1、查询记录自动根据id排序? MySQL学习问题记录 1、查询记录自动根据id排序? step1:建表 表项信息: 写入数据顺序id为10 2 7 1。查寻时返回记录顺序为1 2 7 10? 更新一条数据后仍然按照…...

YMatrix 5.0 与天翼云完成产品兼容性认证
近日,北京四维纵横数据技术有限公司与天翼云宣布完成产品兼容性认证。经过双方严格的测试验证,超融合数据库 YMatrix 5.0 与天翼云兼容性良好,可基于天翼云稳定运行。 数据库系统作为基础软件的核心,自主可控势在必行。在此背景下…...
蓝桥杯官网练习题(旋转)
题目描述 图片旋转是对图片最简单的处理方式之一,在本题中,你需要对图片顺时针旋转 90 度。 我们用一个 nm 的二维数组来表示一个图片,例如下面给出一个 34 的 图片的例子: 1 3 5 7 9 8 7 6 3 5 9 7 这个图片顺时针旋转 90 …...
Jtti:Linux如何开机启动bootstrap
在Linux中,"bootstrap"通常不是一个单独的启动项,而是指引导过程的一部分。引导过程涉及到启动引导加载程序,加载内核,初始化系统并启动各种服务。启动过程中不会直接启动"bootstrap",而是通过引导…...
qt之事件循环与线程的关系
先说重点,先了解几个重要的概念, 事件调度器,该调度器的具体实现与操作系统相关,不同的操作系统具有不同的实现,例如linux系统下该调度器的实现为QEventDispatcherUNIX,而window下的他们的实现为QEventDis…...

Python 变量的定义和数据类型的转换
变量 变量的定义 基本语法:变量名 值 变量名是给对象贴一个用于访问的标签,给对象绑定名字的过程也称为赋值,赋值符号 “” 变量名自定义,要满足标识符命名规则。 Python中,不需要事先声明变量名及其类型ÿ…...
Android Java JVM常见问答分析与总结
一、JVM是什么 JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 JVM的重要性 JVM这块是一个偏向于概念模…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...