JAVA集成强密码校验

news2024/11/17 12:49:34

JAVA集成强密码校验

    • 1 : 背景
    • 2 : 代码设计编写
      • 2.1 : 引入规则配置
      • 2.2 : 密码校验工具类
    • 3 : 验证
    • 4 : 相关链接

1 : 背景

最近系统需要做用户密码升级,增加强密码校验,密码长度,复杂度等等,所以整理了一份通用的密码复杂度控制代码。
目的:实现一套拿来即用的密码验证功能,可灵活配置,随意挑选规则。需实现可复用性,可迁移性等。

1、引入密码等级概念。
即框定规则,等级数为满足规则的数量,这样等级越高,规则越复杂。
但缺点为不可控,故放弃次方式。
2、仅引入密码开关,密码规则概念。
密码开关做总控,密码规则开关做细分管控,方便随意搭配密码规则。

2 : 代码设计编写

2.1 : 引入规则配置

1、密码检测总控开关
2、密码长度控制开关
3、数字、小写字母、大写字母、特殊符号控制开关
4、键盘横向连续检测开关,如qwer等
5、键盘斜向连续检测开关
6、逻辑位置连续检测开关,如1234、abcd等
7、相邻字符相同检测开关,如aaaa、1111、####等
8、自定义密码检测开关,如固定字符等
由此引入yml配置如下
application.yml

server:
  port: 8080
  servlet:
    context-path: /project

password:
  #密码检测总控开关
  passwordCheckSwitch: true
  #密码长度控制开关
  checkPasswordLength: true
  limitPasswordMinLength: 8
  limitPasswordMaxLength: 20
  #数字、小写字母、大写字母、特殊符号控制开关
  checkContainDigit: true
  checkContainUpperLowerCase: false
  checkContainLowerCase: true
  checkContainUpperCase: true
  checkContainSpecialChar: false
  defaultSpecialChar: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
  #键盘横向连续检测开关,如qwer等
  checkHorizontalKeySequential: false
  limitHorizontalKeyNumber: 3
  #键盘斜向连续检测开关
  checkSlopeKeySequential: false
  limitSlopeKeyNumber: 3
  #逻辑位置连续检测开关,如1234、abcd等
  checkLogicSequential: false
  limitLogicNumber: 3
  #相邻字符相同检测开关,如aaaa、1111、####等
  checkSequentialCharSame: false
  limitSequentialCharNumber: 3
  #自定义密码检测开关,如固定字符等
  checkCustomPasswordArray: true

引入自定义密码文件:password.txt

123456
123456789
1234567890
1234561314
admin1234
test1234
123abc

以上配置引入,在代码中如何注入,可参考文末链接。

对应配置类 PasswordConfigBean.java

package com.bean;

import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;

@Component
public class PasswordConfigBean {
    //开关->开
    public final static String PASS_WORD_STATUS_TRUE = "true";
    //开关->关
    public final static String PASS_WORD_STATUS_FALSE = "false";

    //密码检测开关
    public static volatile String PASS_WORD_CHECK_SWITCH;
    //是否检测密码口令长度标识
    public static volatile String CHECK_PASSWORD_LENGTH;
    //密码最小长度
    public static volatile String LIMIT_PASSWORD_MIN_LENGTH;
    //密码最大长度
    public static volatile String LIMIT_PASSWORD_MAX_LENGTH;
    //是否包含数字
    public static volatile String CHECK_CONTAIN_DIGIT;
    //是否区分大小写
    public static volatile String CHECK_CONTAIN_UPPER_LOWER_CASE;
    //是否包含小写字母
    public static volatile String CHECK_CONTAIN_LOWER_CASE;
    //是否包含大写字母
    public static volatile String CHECK_CONTAIN_UPPER_CASE;
    //是否包含特殊符号
    public static volatile String CHECK_CONTAIN_SPECIAL_CHAR;
    //特殊符号集合
    public static volatile String DEFAULT_SPECIAL_CHAR;
    //是否检测键盘按键横向连续
    public static volatile String CHECK_HORIZONTAL_KEY_SEQUENTIAL;
    //键盘物理位置横向不允许最小的连续个数
    public static volatile String LIMIT_HORIZONTAL_KEY_NUMBER;
    //是否检测键盘按键斜向连续
    public static volatile String CHECK_SLOPE_KEY_SEQUENTIAL;
    //键盘物理位置斜向不允许最小的连续个数
    public static volatile String LIMIT_SLOPE_KEY_NUMBER;
    //是否检测逻辑位置连续
    public static volatile String CHECK_LOGIC_SEQUENTIAL;
    //密码口令中字符在逻辑位置上不允许最小的连续个数
    public static volatile String LIMIT_LOGIC_NUMBER;
    //是否检测连续字符相同
    public static volatile String CHECK_SEQUENTIAL_CHAR_SAME;
    //密码口令中相同字符不允许最小的连续个数
    public static volatile String LIMIT_SEQUENTIAL_CHAR_NUMBER;
    //是否校验自定义密码集合
    public static volatile String CHECK_CUSTOM_PASSWORD_ARRAY;
    //自定义密码集合
    public static volatile List<String> CUSTOM_PASSWORD_ARRAY = new ArrayList<>();
    //键盘横向方向规则
    public static volatile String[] KEYBOARD_HORIZONTAL_ARR = {"01234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"};
    //键盘斜线方向规则
    public static volatile String[] KEYBOARD_SLOPE_ARR = {
            "1qaz", "2wsx", "3edc", "4rfv", "5tgb", "6yhn", "7ujm", "8ik,", "9ol.", "0p;/", "=[;.", "-pl,", "0okm", "9ijn", "8uhb", "7ygv", "6tfc", "5rdx", "4esz",
            "!QAZ", "@WSX", "#EDC", "$RFV", "%TGB", "^YHN", "&UJM", "*IK<", "(OL>", ")P:?", "+{:>", "_PL<", ")OKM", "(IJN", "*UHB", "&YGV", "^TFC", "%RDX", "$ESZ"
    };

}

对应配置类 PasswordConfigBeanSet.java

package com.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;

@Component
public class PasswordConfigBeanSet {
    @Value("${password.passwordCheckSwitch}")
    public static void setPasswordCheckSwitch(String passwordCheckSwitch) {
        PasswordConfigBean.PASS_WORD_CHECK_SWITCH = passwordCheckSwitch;
    }
    @Value("${password.checkPasswordLength}")
    private static void setCheckPasswordLength(String checkPasswordLength) {
        PasswordConfigBean.CHECK_PASSWORD_LENGTH = checkPasswordLength;
    }
    @Value("${password.limitPasswordMinLength}")
    private void setLimitPasswordMinLength(String limitPasswordMinLength) {
        PasswordConfigBean.LIMIT_PASSWORD_MIN_LENGTH = limitPasswordMinLength;
    }
    @Value("${password.limitPasswordMaxLength}")
    private void setLimitPasswordMaxLength(String limitPasswordMaxLength) {
        PasswordConfigBean.LIMIT_PASSWORD_MAX_LENGTH = limitPasswordMaxLength;
    }
    @Value("${password.checkContainDigit}")
    private void setCheckContainDigit(String checkContainDigit) {
        PasswordConfigBean.CHECK_CONTAIN_DIGIT = checkContainDigit;
    }
    @Value("${password.checkContainUpperLowerCase}")
    private void setCheckContainUpperLowerCase(String checkContainUpperLowerCase) {
        PasswordConfigBean.CHECK_CONTAIN_UPPER_LOWER_CASE = checkContainUpperLowerCase;
    }
    @Value("${password.checkContainLowerCase}")
    private void setCheckContainLowerCase(String checkContainLowerCase) {
        PasswordConfigBean.CHECK_CONTAIN_LOWER_CASE = checkContainLowerCase;
    }
    @Value("${password.checkContainUpperCase}")
    private void setCheckContainUpperCase(String checkContainUpperCase) {
        PasswordConfigBean.CHECK_CONTAIN_UPPER_CASE = checkContainUpperCase;
    }
    @Value("${password.checkContainSpecialChar}")
    private void setCheckContainSpecialChar(String checkContainSpecialChar) {
        PasswordConfigBean.CHECK_CONTAIN_SPECIAL_CHAR = checkContainSpecialChar;
    }
    @Value("${password.defaultSpecialChar}")
    private void setDefaultSpecialChar(String defaultSpecialChar) {
        PasswordConfigBean.DEFAULT_SPECIAL_CHAR = defaultSpecialChar;
    }
    @Value("${password.checkHorizontalKeySequential}")
    private void setCheckHorizontalKeySequential(String checkHorizontalKeySequential) {
        PasswordConfigBean.CHECK_HORIZONTAL_KEY_SEQUENTIAL = checkHorizontalKeySequential;
    }
    @Value("${password.limitHorizontalKeyNumber}")
    private void setLimitHorizontalKeyNumber(String limitHorizontalKeyNumber) {
        PasswordConfigBean.LIMIT_HORIZONTAL_KEY_NUMBER = limitHorizontalKeyNumber;
    }
    @Value("${password.checkSlopeKeySequential}")
    private void setCheckSlopeKeySequential(String checkSlopeKeySequential) {
        PasswordConfigBean.CHECK_SLOPE_KEY_SEQUENTIAL = checkSlopeKeySequential;
    }
    @Value("${password.limitSlopeKeyNumber}")
    private void setLimitSlopeKeyNumber(String limitSlopeKeyNumber) {
        PasswordConfigBean.LIMIT_SLOPE_KEY_NUMBER = limitSlopeKeyNumber;
    }
    @Value("${password.checkLogicSequential}")
    private void setCheckLogicSequential(String checkLogicSequential) {
        PasswordConfigBean.CHECK_LOGIC_SEQUENTIAL = checkLogicSequential;
    }
    @Value("${password.limitLogicNumber}")
    private void setLimitLogicNumber(String limitLogicNumber) {
        PasswordConfigBean.LIMIT_LOGIC_NUMBER = limitLogicNumber;
    }
    @Value("${password.checkSequentialCharSame}")
    private void setCheckSequentialCharSame(String checkSequentialCharSame) {
        PasswordConfigBean.CHECK_SEQUENTIAL_CHAR_SAME = checkSequentialCharSame;
    }
    @Value("${password.limitSequentialCharNumber}")
    private void setLimitSequentialCharNumber(String limitSequentialCharNumber) {
        PasswordConfigBean.LIMIT_SEQUENTIAL_CHAR_NUMBER = limitSequentialCharNumber;
    }
    @Value("${password.checkCustomPasswordArray}")
    private void setCheckCustomPasswordArray(String checkCustomPasswordArray) {
        PasswordConfigBean.CHECK_CUSTOM_PASSWORD_ARRAY = checkCustomPasswordArray;
        if("true".equals(checkCustomPasswordArray)){
            loadCustomPasswordArray();
        }
    }

    //加载自定义密码
    private static void loadCustomPasswordArray() {
        BufferedReader bufferedReader = null;
        ClassPathResource classPathResource = new ClassPathResource("password.txt");
        try (InputStream inputStream = classPathResource.getInputStream();
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream);){
            bufferedReader = new BufferedReader(inputStreamReader);
            String line;
            while(null != (line = bufferedReader.readLine())) {
                PasswordConfigBean.CUSTOM_PASSWORD_ARRAY.add(line);
            }
        } catch (IOException var5) {
            PasswordConfigBean.CUSTOM_PASSWORD_ARRAY.addAll(Arrays.asList(("123456,Qwer,111111,123456789,test1234").split(",")));
        }
    }
}

2.2 : 密码校验工具类

PasswordCheckUtil.java

package com.utils;

import com.bean.PasswordConfigBean;
import java.util.Iterator;

public class PasswordCheckUtil {

    public static boolean checkPassword(String password) {
        if (password == null || "".equals(password)) {
            return false;
        }
        //密码校验总开关
        if (PasswordConfigBean.PASS_WORD_STATUS_FALSE.equals(PasswordConfigBean.PASS_WORD_CHECK_SWITCH)){
            return true;
        }
        //是否在自定义集合中
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CUSTOM_PASSWORD_ARRAY) && checkCustomPasswordArray(password)){
            return false;
        }
        //检测长度
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_PASSWORD_LENGTH) && !checkPasswordLength(password, PasswordConfigBean.LIMIT_PASSWORD_MAX_LENGTH, PasswordConfigBean.LIMIT_PASSWORD_MIN_LENGTH)){
            return false;
        }
        //检测包含数字
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_DIGIT) && !password.matches("(.*[0-9].*)")){
            return false;
        }
        //检测包含字母(区分大小写)
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_UPPER_LOWER_CASE)){
            //检测包含小写字母
            if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_LOWER_CASE) && !password.matches("(.*[a-z].*)")){
                return false;
            }
            //检测包含大写字母
            if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_UPPER_CASE) && !password.matches("(.*[A-Z].*)")){
                return false;
            }
        } else {
            if (!checkContainCase(password)) {
                return false;
            }
        }
        //检测包含特殊符号
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_SPECIAL_CHAR) && !password.matches("(.*[`~!@#$%^&*()+=|{}':;',//[//].<>/?].*)")){
            return false;
        }
        //检测键盘横向连续
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_HORIZONTAL_KEY_SEQUENTIAL) && checkLateralKeyboardSite(password)){
            return false;
        }
        //检测键盘斜向连续
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_SLOPE_KEY_SEQUENTIAL) && checkKeyboardSlantSite(password)){
            return false;
        }
        //检测逻辑位置连续
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_LOGIC_SEQUENTIAL) && checkSequentialChars(password)){
            return false;
        }
        //检测相邻字符是否相同
        if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_SEQUENTIAL_CHAR_SAME) && checkSequentialSameChars(password)){
            return false;
        }
        return true;
    }

    public static boolean checkPasswordForUpdate(String password) {
        if (password == null || "".equals(password)) return false;
        if (!checkPasswordLength(password, "", "8")) return false;
        if (!password.matches("(.*[0-9].*)")) return false;
        if (!password.matches("(.*[a-z].*)")) return false;
        if (!password.matches("(.*[A-Z].*)")) return false;
        return true;
    }

    public static boolean checkCustomPasswordArray(String password) {
        Iterator iterator = PasswordConfigBean.CUSTOM_PASSWORD_ARRAY.iterator();
        while(iterator.hasNext()) {
            if(password.equals(iterator.next())) {
                return true;
            }
        }
        return false;
    }

    public static boolean checkPasswordLength(String password, String max, String min) {
        boolean flag = false;
        if("".equals(max)) {
            if (password.length() >= Integer.parseInt(min)) {
                flag = true;
            }
        } else {
            if (password.length() >= Integer.parseInt(min) && password.length() <= Integer.parseInt(max)) {
                flag = true;
            }
        }
        return flag;
    }

    public static boolean checkContainDigit(String password) {
        boolean flag = false;
        char[] charArray = password.toCharArray();
        int numberCount = 0;
        for (char c : charArray) {
            if (Character.isDigit(c)) numberCount++;
        }
        if (numberCount >= 1) flag = true;
        return flag;
    }

    public static boolean checkContainCase(String password) {
        boolean flag = false;
        char[] charArray = password.toCharArray();
        int charCount = 0;
        for (char c : charArray) {
            if (Character.isLetter(c)) charCount++;
        }
        if (charCount >= 1) flag = true;
        return flag;
    }

    public static boolean checkContainLowerCase(String password) {
        boolean flag = false;
        char[] charArray = password.toCharArray();
        int charCount = 0;
        for (char c : charArray) {
            if (Character.isLowerCase(c)) charCount++;
        }
        if (charCount >= 1) flag = true;
        return flag;
    }

    public static boolean checkContainUpperCase(String password) {
        boolean flag = false;
        char[] charArray = password.toCharArray();
        int charCount = 0;
        for (char c : charArray) {
            if (Character.isUpperCase(c)) charCount++;
        }
        if (charCount >= 1) flag = true;
        return flag;
    }

    public static boolean checkContainSpecialChar(String password) {
        boolean flag = false;
        char[] charArray = password.toCharArray();
        int specialCount = 0;
        for (char c : charArray) {
            if (PasswordConfigBean.DEFAULT_SPECIAL_CHAR.indexOf(c) != -1) specialCount++;
        }
        if (specialCount >= 1) flag = true;
        return flag;
    }

    public static boolean checkLateralKeyboardSite(String password) {
        //将所有输入字符转为小写
        String lowerCasePassword = password.toLowerCase();
        //键盘横向规则检测
        int arrLength = PasswordConfigBean.KEYBOARD_HORIZONTAL_ARR.length;
        int limitNumKey = Integer.parseInt(PasswordConfigBean.LIMIT_HORIZONTAL_KEY_NUMBER) ;
        for (int i = 0; i + limitNumKey <= lowerCasePassword.length(); i++) {
            String str = lowerCasePassword.substring(i, i+limitNumKey);
            String distinguishStr = password.substring(i, i+limitNumKey);
            String revOrderStr = null;
            for (int j = 0; j < arrLength; j++) {
                String configStr = PasswordConfigBean.KEYBOARD_HORIZONTAL_ARR[j];
                revOrderStr = new StringBuffer(PasswordConfigBean.KEYBOARD_HORIZONTAL_ARR[j]).reverse().toString();
                //检测包含字母(区分大小写)
                if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_UPPER_LOWER_CASE)) {
                    //考虑 大写键盘匹配的情况
                    String UpperStr = PasswordConfigBean.KEYBOARD_HORIZONTAL_ARR[j].toUpperCase();
                    if(configStr.contains(distinguishStr) || UpperStr.contains(distinguishStr)) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    String revUpperStr = new StringBuffer(UpperStr).reverse().toString();
                    if(revOrderStr.contains(distinguishStr) || revUpperStr.contains(distinguishStr)) {
                        return true;
                    }
                } else {
                    if(configStr.contains(str)) return true;
                    //考虑逆序输入情况下 连续输入
                    if(revOrderStr.contains(str)) return true;
                }
            }
        }
        return false;
    }

    public static boolean checkKeyboardSlantSite(String password) {
        //将所有输入字符转为小写
        String lowerCasePassword = password.toLowerCase();
        //键盘斜线方向规则检测
        int arrLength = PasswordConfigBean.KEYBOARD_SLOPE_ARR.length;
        int limitNumKey = Integer.parseInt(PasswordConfigBean.LIMIT_SLOPE_KEY_NUMBER);
        for (int i = 0; i + limitNumKey <= lowerCasePassword.length(); i++) {
            String str = lowerCasePassword.substring(i, i + limitNumKey);
            String distinguishStr = password.substring(i, i + limitNumKey);
            String revOrderStr = null;
            for (int j = 0; j < arrLength; j++) {
                String configStr = PasswordConfigBean.KEYBOARD_SLOPE_ARR[j];
                revOrderStr = new StringBuffer(PasswordConfigBean.KEYBOARD_SLOPE_ARR[j]).reverse().toString();
                //检测包含字母(区分大小写)
                if (PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_UPPER_LOWER_CASE)) {
                    //考虑 大写键盘匹配的情况
                    String UpperStr = PasswordConfigBean.KEYBOARD_SLOPE_ARR[j].toUpperCase();
                    if(configStr.contains(distinguishStr) || UpperStr.contains(distinguishStr)) {
                        return true;
                    }
                    //考虑逆序输入情况下 连续输入
                    String revUpperStr = new StringBuffer(UpperStr).reverse().toString();
                    if(revOrderStr.contains(distinguishStr) || revUpperStr.contains(distinguishStr)) {
                        return true;
                    }
                } else {
                    if(configStr.contains(str)) return true;
                    //考虑逆序输入情况下 连续输入
                    if(revOrderStr.contains(str)) return true;
                }
            }
        }
        return false;
    }

    public static boolean checkSequentialChars(String password) {
        int limitNumber = Integer.parseInt(PasswordConfigBean.LIMIT_LOGIC_NUMBER);
        int normalCount,reversedCount;
        //检测包含字母(区分大小写)
        if (!PasswordConfigBean.PASS_WORD_STATUS_TRUE.equals(PasswordConfigBean.CHECK_CONTAIN_UPPER_LOWER_CASE)) {
            password = password.toLowerCase();
        }
        char[] passwordArray = password.toCharArray();
        for (int i = 0; i + limitNumber <= password.length(); i++) {
            normalCount = 0;
            reversedCount = 0;
            for (int j = 0; j < limitNumber - 1; j++) {
                if (passwordArray[i + j + 1] - passwordArray[i + j] == 1) {
                    normalCount++;
                    if(normalCount == limitNumber - 1){
                        return true;
                    }
                }
                if (passwordArray[i + j] - passwordArray[i + j + 1] == 1) {
                    reversedCount++;
                    if(reversedCount == limitNumber - 1){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static boolean checkSequentialSameChars(String password) {
        char[] passwordArray = password.toCharArray();
        int limitNumber = Integer.parseInt(PasswordConfigBean.LIMIT_SEQUENTIAL_CHAR_NUMBER);
        int count;
        for (int i = 0; i + limitNumber <= password.length(); i++) {
            count = 0;
            for (int j = 0; j < limitNumber - 1; j++) {
                if(passwordArray[i + j] == passwordArray[i + j + 1]) {
                    count++;
                    if (count == limitNumber - 1){
                        return true;
                    }
                }
            }
        }
        return false;
    }
}

3 : 验证

需要注意的是,配置文件交给Spring管理的,所以验证时,需要将项目启动。

public static void main(String[] args) {
    Boolean check = checkPassword("123");
    System.out.print(check);
}

在这里插入图片描述

4 : 相关链接

Springboot基于BCrypt非对称加密字符串:https://blog.csdn.net/qq_38254635/article/details/129746320
SpringBoot加载自定义yml中的配置参数:https://blog.csdn.net/qq_38254635/article/details/112033193

OK,整理到这吧!

如有不正确之处,还望指正!书写不易,觉得有帮助就点个赞吧!☺☺☺

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你了解这2类神经性皮炎吗?常常预示着这5类疾病!

属于慢性皮肤病&#xff0c;患者皮肤可出现局限性苔藓样变&#xff0c;同时伴有阵发性瘙痒。神经性皮炎易发生在颈部两侧和四肢伸侧&#xff0c;中年人是高发人群。到目前为止神经性皮炎病因还并不是很明确&#xff0c;不过一部分病人发病前常常出现精神神经方面异常&#xff0…

SLAM 十四讲(第一版)各章方法总结与理解

SLAM 十四讲&#xff08;第一版&#xff09;各章方法总结与理解 总结十四讲中各章各步骤提到的各种方法&#xff0c;以及具体方法在哪个 c 库中可以调用。目的在于能更直观地了解 slam 过程各步骤到底在做什么&#xff0c;以及是怎么联系在一起的。 2. 初识 SLAM SLAM&#x…

ggplot作图中的图例处理方法

文章目录 改变坐标轴和图例的名称方法1, labs()方法2&#xff0c;scale_xxx_discrete/continuous() 删除坐标轴和图例的名称方法1&#xff0c; labs()方法2&#xff0c;scale_xxx_discrete/continuous()方法3&#xff0c;theme()方法4&#xff0c;guides()可以去图例名称 改变图…

怎么挣点零花钱,哪里可以赚点零花钱?以下这些方式值得参考一下

想赚零花钱的人群包括但不限于&#xff1a;大学生、宝妈/宝爸、自由职业者、比较有闲暇时间的上班族。 他们想要赚零花钱的原因不尽相同&#xff0c;但主要就是这几点&#xff1a;经济需求、个人发展、好奇心和乐趣等等。想赚取零花钱的人具有实际需求和个人发展的目标&#xf…

【hello C++】模板初阶

目录 1. 泛型编程 2. 函数模板 2.1 函数模板的概念 2.2 函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5 模板参数的匹配原则 3. 类模板 3.1 类模板的定义格式 3.2 类模板的实例化 4. STL简介 4.1 什么是STL 4.2 STL的版本 4.3 STL的六大组件 4.4 STL的重要性 4.5 …

基于.Net开发的ChatGPT客户端,兼容Windows、IOS、安卓、MacOS、Linux

2023年目前要说最热的点,肯定是ChatGPT了。 ChatGPT官方提供的网页版本,还有需要科学上网,很多人都会基于此进行封装。 现在是移动互联网时代,基于手机APP的需求还是很大的。 所以,今天给大家推荐一个ChatGPT客户端开源项目,兼容苹果和安卓手机、PC。 项目简介 这是…

若依管理系统修改页面标题和logo

一&#xff1a;修改网页上的logo 把public目录下favicon.ico&#xff0c;换成自己logo 注&#xff1a;替换图片的名字最好还是以favicon.ico命名&#xff0c;如果改变,就要改public目录下的index.html代码 二&#xff1a;修改页面上的logo 把src/assets/logo/logo.png换成自己l…

【Chano的SFM教程】3dmax 面部表情.VTA基本制作教程

本篇教程作者为&#xff1a;小鸟Chano&#xff0c;转载请表明作者和出处&#xff1a;CSDN 欢迎观看本次教程 本教程将会为你演示使用3D MAX 制作一个基本的SFM表情控制器【表情滑条】并导入SFM进行使用。 Chano自己也是近期才掌握的这项知识&#xff0c;所以过程中可能有很多…

GDB调试实验

一、实验准备 在 Linux 环境软件开发中&#xff0c;GDB 是调试 C 和 C 程序的主要工具。本次实验围绕着GDB常用的调试操作进行。 1、设置断点的意义 当我们想查看变量内容&#xff0c;堆栈情况等等&#xff0c;可以指定断点。程序执行到断点处会暂停执行。break 命令用来设置…

React 条件渲染组件

组件通常需要根据不同的条件显示不同的内容&#xff0c;以及根据应用的状态变化只渲染其中的一部分。 在 React 中&#xff0c;可以使用 JavaScript 语法有条件地呈现 JSX&#xff0c;比如 if 语句、&&和 ?: 操作符。 根据条件返回 JSX Demo.js 文件&#xff1a; …

【高危】vm2 <3.9.17 沙箱逃逸漏洞(POC)(CVE-2023-30547 )

漏洞描述 vm2 是一个基于 Node.js 的沙箱环境&#xff0c;可以使用列入白名单的 Node 内置模块运行不受信任的代码。 由于 CVE-2023-29199 的修复不完整&#xff0c;vm2 3.9.17 之前版本的 transformer.js 文件中的 transformer 函数异常处理逻辑存在缺陷。攻击者可以利用这个…

【01-Java Web先导课】-如何进行JDK的安装(或Java环境的配置)

文章目录 一、JDK&#xff08;jdk-8u371-windows-x64.exe&#xff09;的下载1、下载网址2、选择相应版本进行下载 二、JDK&#xff08;jdk-8u371-windows-x64.exe&#xff09;的安装1、JDK安装2、系统环境变量配置3、classspath环境变量设置 免责说明 一、JDK&#xff08;jdk-8…

❤echarts 南丁格尔玫瑰图的使用以及南丁格尔玫瑰图详细配置

❤echarts 南丁格尔玫瑰图的使用以及南丁格尔玫瑰图详细配置 1、认识 使用可以参考之前文章&#xff0c;会使用直接跳过1 引入官网的南丁格尔玫瑰图效果如下&#xff1a; 使用函数配置分为三个部分&#xff1a;初始化> 设置配置> 地图使用参数 配置代码如下 option…

法学考生必看—外经贸法学专业在职研究生

法学专业就业面比较广&#xff0c;但很多人工作后都觉得还是缺少核心竞争力&#xff0c;想通过读研来改变现状&#xff0c;23考研已经落幕&#xff0c;想要今年就能入班学习的院校有吗&#xff1f;有法学专业的吗&#xff1f; 一、学校介绍 对外经济贸易大学创建于1951年&…

STM32 USB资料整理

CypressUSB中文文档 https://img.anfulai.cn/bbs/90026/AN57294%20USB%20101%20An%20Introduction%20to%20Universal%20Serial%20Bus%202.0%20(Chinese).pdf RL-USB教程 https://www.armbbs.cn/forum.php?modviewthread&tid99710 USB应用实战教程第3期&#xff1a;手把…

Java Jvm中的垃圾回收机制

jvm的垃圾回收机制是什么 jvm的垃圾回收机制是GC&#xff08;Garbage Collection&#xff09;&#xff0c;也叫垃圾收集器。 GC基本原理&#xff1a;将内存中不再被使用的对象进行回收&#xff1b;GC中用于回收的方法称为收集器&#xff0c;由于GC需要消耗一些资源和时间&…

认识BASH这个Shell

文章目录 认识BASH这个Shell硬件、内核与shell为什么要学命令行模式的Shell&#xff1f;Bash Shell的功能命令与文件补全(TAB)命令别名设置(alias)历史命令(history)任务管理、前台、后台控制(jobs&#xff0c;fg&#xff0c;bg)通配符程序化脚本 查询命令是否为Bash shell 的内…

前端--移动端布局--2移动开发之flex布局

目标&#xff1a; 能够说出flex盒子的布局原理 能够使用flex布局的常用属性 能够独立完成携程移动端首页案例 目录&#xff1a; flex布局体验 flex布局原理 flex布局父项常见属性 flex布局子项常见属性 写出网首页案例制作 1.flex布局体验 1.1传统布局与flex布局 传…

nacos 部署 配置

文章目录 一、Nacos简介 1、为什么叫Nacos2、Nacos是什么3、能干嘛4、去哪下二、安装并运行Nacos 2.1 基础环境及配置&#xff1a;三、Nacos作为服务注册中心演示 3.1 基于Nacos的服务提供者 2、POM文件3、YML文件4、主启动5、业务类6、测试7、nacos控制台3.2 基于Nacos的服务消…

[POJ - 1080 ]Palindrome(区间DP)

[POJ - 1080 ]Palindrome&#xff08; 区间DP&#xff09; 1、问题2、分析状态表示状态转移空间优化 3、代码 1、问题 给定一个字符串&#xff0c;通过添加最少的字符&#xff0c;使得这个字符串成为一个回文字符串。 2、分析 状态表示 f [ i ] [ j ] f[i][j] f[i][j]表示将…