【个人博客系统网站】注册与登录 · 加盐加密验密算法 · 上传头像
【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这块是一个偏向于概念模…...
【业务功能篇102】springboot+mybatisPlus分页查询,统一返回封装规范
业务场景: 随着业务代码量增多,很多接口查询的分页写法各种各样,为了使项目工程代码易于维护,我们统一规范,相对没有那么复杂的接口,我们统一都在java的service实现类中,去完成分页查询的接口逻…...
中国手机新进程:折叠屏出海的荣耀,5G中回归的华为
最近,“华为5G回归”“自研麒麟芯片回归”的消息引爆网络。网友开心庆贺之余,也纷纷猜测,华为强势归来,哪家友商最慌? “华为的回归,让竞争充满了更多的可能性和更多的魅力”,与华为渊源颇深的…...
安装RabbitMQ的各种问题(包括已注册成windows服务后,再次重新安装,删除服务重新注册遇到的问题)
一、安装Erlang(傻瓜式安装) 安装完成之后,配置环境变量: 1.新建系统变量名为:ERLANG_HOME 变量值为erlang安装地址 2. 双击系统变量path,点击“新建”,将%ERLANG_HOME%\bin加入到path中。 …...
多线程与高并发——并发编程(6)
文章目录 六、并发集合1 ConcurrentHashMap1.1 存储结构1.2 存储操作1.2.1 put方法1.2.2 putVal方法-散列算法1.2.3 putVal方法-添加数据到数组&初始化数组1.2.4 putVal方法-添加数据到链表1.3 扩容操作1.3.1 treeifyBin方法触发扩容1.3.2 tryPresize方法-针对putAll的初始…...
Elasticsearch——Docker单机部署安装
文章目录 1 简介2 Docker安装与配置2.1 安装Docker2.2 配置Docker镜像加速器2.3 调整Docker资源限制 3 准备Elasticsearch Docker镜像3.1 下载Elasticsearch镜像3.2 自定义镜像配置3.3执行Docker Compose 4 运行Elasticsearch容器4.1 创建Elasticsearch容器4.2 修改配置文件4.3…...
基于AHP模型指标权重分析python整理
一 背景介绍 日常会有很多定量分析的场景,然而也会有一些定性分析的场景针对定性分析的场景,预测者只能通过主观判断分析能力来推断事物的性质和发展趋势然而针对个人的直觉和虽然能够有一定的协助判断效果,但是很难量化到指标做后期的复用 …...
用python实现基本数据结构【02/4】
*说明 如果需要用到这些知识却没有掌握,则会让人感到沮丧,也可能导致面试被拒。无论是花几天时间“突击”,还是利用零碎的时间持续学习,在数据结构上下点功夫都是值得的。那么Python 中有哪些数据结构呢?列表、字典、集…...
蓝牙Mesh专有DFU
蓝牙Mesh专有DFU Mesh专有DFU协议介绍特征DFU模式和类型角色并发传输混合设备的网络传输速率后台操作传输分区内存映射安全DFU固件IDApplication firmware IDSoftDevice firmware IDBootloader firmware ID 设备页面格式内容 Mesh专有DFU协议介绍 设备固件更新(Device Firmwar…...
浅谈综合管廊智慧运维管理平台应用研究
贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要:为提升综合管廊运维管理水平,实现管理的数字化转型,采用综合监测系统、BIMGIS 可视化系统、智能机器人巡检、结构安全监测等技术,搭建实时监控、应急管理、数据分析等多功能…...
Httpservletrequest与Httpservletresponse
目录 一、Httpservletrequest 1.1什么是Httpservletrequest 1.2Httpservletrequest中的方法 二、Httpservletresponse 1.1什么是Httpservletresponse 1.2Httpservletresponse的方法 一、Httpservletrequest 1.1什么是Httpservletrequest HttpServletRequest(…...
系部网站开发计划/全面落实疫情防控优化措施
走进异步编程的世界 - 在 GUI 中执行异步操作 【博主】反骨仔 【原文地址】http://www.cnblogs.com/liqingwen/p/5877042.html 序 这是继《开始接触 async/await 异步编程》、《走进异步编程的世界 - 剖析异步方法》后的第三篇。主要介绍在 WinForm 中如何执行异步操作。 目…...
网站大图轮播/南宁网站推广排名
题目 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印 ************ *****所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小…...
连云港营销型网站建设/前端seo优化
Chapter27:参数方程和极坐标27.参数方程和极坐标27.1 参数方程27.1.1 参数方程的导数27.1.2 参数定义的曲线长度27.1.3 参数化曲线的旋转体表面积27.2 极坐标27.2.1 极坐标与笛卡尔坐标互换27.2.2 极坐标中画曲线常见的极坐标曲线27.2.3 求极坐标曲线的切线27.2.4 求…...
wordpress 别名插件/策划网络营销活动
资源寻找 综合导航- 阿虚同学http://axutongxue.com/ 好网站不私藏https://www.207788.xyz/ 网站导航 爱达杂货铺https://adzhp.cn/ 书签地球https://www.bookmarkearth.com/ 不死鸟https://iao.su/- iMyShare 工具资源导航-https://imyshare.com/ LKS的网站推荐:…...
b2b信息发布网站大全/公众号软文怎么写
函数式接口:只有一个方法的接口 FunctionalInterface public interface Runnable {public abstract void run(); }超级多的FunctionalInterface 可以简化编程模型,在新版本的框架底层大量应用,foreach(消费者类的函数式接口&…...
做旅行的网站/正规网站优化推广
近日没啥事情,研究了一下 everything、光速搜索原理。花了一个礼拜时间,终于搞定。 废话不多说,直接上代码: [delphi] view plaincopy unit uMFTSearchFile; { dbyoungsina.com 2018-04-23 } interface uses Windows, …...