弱口令的基本校验包括:口令字符串长度校验、口令字符串包含的字符类型校验、口令字符串包含的不同字符数校验。
口令字符串长度校验:验证口令字符串的长度不能低于规定值(如6)。
口令字符串包含的字符类型校验:把字符类型分为大写字母、小写字母、数组、特殊字符四类,校验口令字符串包含的字符类型不能低于规定值(如2)。
口令字符串包含的不同字符数校验:不区分大、小写时a与A算同一字符,区分大、小写时a与A为不同字符。校验口令字符串中包含的不同字符数不能低于规定值(如4)。
弱口令的高级校验包括:连续字符校验、键盘输入规则校验、弱口令字典校验。
连续字符校验:校验口令字符串中连续字符组成的子串长度不但能高于规定的值(如40%)。
键盘输入规则校验:详细见2.1.3
弱口令字典校验:在弱口令字典中校验该口令字符串是否为弱口令。
结合笔记本电脑和台式电脑键盘的布局规则,将字符输入键映射为4*10的二维数组矩阵(1-0,q-p,a-;,z-?),把密码字符串中每各字符格式化为键盘矩阵中对应的坐标,判断连续字符的坐标是否相邻,并记录连续相邻的串长度进行安全性评估
1:判断密码是否为null或空,如果不是进入下一步,否则返回结果(密码安全性不符合)
2:判断密码字符串长度是否符合要求,默认是大于等于6位,如果是进入下一步,否则返回结果(密码安全性不符合)
3:循环取出密码串中从0位置到长度下限++的子串,进行下面4到8的操作并记录结果到一个double[]中
4:评估密码中包含的字符类型是否符合要求,如果低于下限返回0,否则返回6-10的double
5:评估密码至少包含的不同字符数(不区分大、小写),返回int,如果字符数小于下限返回0,否则返回6-10的double
6:评估密码字符串是否包含a-z,z-a这样的连续字符,返回一个double,如果连续字符占整个串长度的40%以上返回0,否则返回(1-连续字符占整个串长度的百分比) * 10
7:评估密码字符串是否匹配键盘输入习惯,返回0-10的整数,值越大表示越不符合键盘输入习惯
8:根据3、4、5、6的评估结果综合评估出密码的安全评估值(0-10的double)
9:循环3中double[]的值,如果全是0返回0,否则从第一个不是0的位置开始累加,如果后一个位置为0则加长度修正值1,如果累加结果大于10,循环结束返回10
10:判断7产生的安全评估值是否大于安全评估值的下限(默认7),是返回true,否则返回false
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
/**
* <strong>Title : CheckPWD</strong><br>
* <strong>Description : 密码强度验证</strong><br>
* <strong>Create on : Dec 6, 2011 7:34:45 PM</strong><br>
* @author liulang@mochasoft.com.cn<br>
* @version v1.0<br>
* <br>
* 详细验证步骤说明:<br>
* 1:判断密码是否为null或空,如果不是进入下一步,否则返回结果(密码安全性不符合)<br>
* 2:判断密码字符串长度是否符合要求,默认是大于等于6位,如果是进入下一步,否则返回结果(密码安全性不符合)<br>
* 3:循环取出密码串中从0位置到长度下限++的子串,进行下面4到8的操作并记录结果到一个double[]中
* 4:评估密码中包含的字符类型是否符合要求,如果低于下限返回0,否则返回6-10的double<br>
* 5:评估密码至少包含的不同字符数(不区分大、小写),返回int,如果字符数小于下限返回0,否则返回6-10的double<br>
* 6:评估密码字符串是否包含a-z,z-a这样的连续字符,返回一个double,如果连续字符占整个串长度的40%以上返回0,否则返回(1-连续字符占整个串长度的百分比) * 10<br>
* 7:评估密码字符串是否匹配键盘输入习惯,返回0-10的整数,值越大表示越不符合键盘输入习惯<br>
* 8:根据3、4、5、6的评估结果综合评估出密码的安全评估值(0-10的double)<br>
* 9:循环3中double[]的值,如果全是0返回0,否则从第一个不是0的位置开始累加,如果后一个位置为0则加长度修正值1,如果累加结果大于10,循环结束返回10<br>
* 9:判断7产生的安全评估值是否大于安全评估值的下限(默认7),是返回true,否则返回false
* <br>
* <strong>修改历史:</strong><br>
* 修改人-------------修改日期-------------修改描述<br>
* --------------------------------------------<br>
* liulang-----------2011/12/7---------<br>
* 1:增加容错处理;<br>
* 2:修改键盘输入习惯匹配评估算法的逻辑;<br>
* 3:增加一个更加严格的键盘习惯匹配算法maches2(可匹配类似1z2x3c4v5b这样的特殊字符串)<br>
* <br>
*/
public final class CheckPWD {
private static Logger logger = Logger.getLogger(CheckPWD.class);
/**
* 安全密码评估值的下限,取值范围:0-10,默认:7
*/
public static double PASSWORD_STRONG = 7;
/**
* 密码字符串包含的字符类型(a-z,A-Z,0-9,特殊字符)在密码安全性评估中所占比例,默认:0.15
*/
public static double CHAR_TYPE_NUM_THRESHOLD = 0.15;
/**
* 密码字符串包含的不同字符数(不区分大、小写,同一键位的视为同一字符)在密码安全性评估中所占比例,默认:0.35
*/
public static double MIN_CONTAIN_CHAR_NUM_THRESHOLD = 0.35;
/**
* 密码字符串匹配键盘输入习惯在密码安全性评估中所占比例,默认:0.3
*/
public static double KEYSET_MATCHER_THRESHOLD = 0.3;
/**
* 评估密码字符串中a-z,z-a这样的连续字符在密码安全性评估中所占比例,默认:0.2
*/
public static double SEQUENTIAL_CHARS_THRESHOLD = 0.2;
/**
* 键盘输入习惯匹配规则严格模式
*/
public static int KEYSET_MATCHER_STRICT_MODE = 1;
/**
* 键盘输入习惯匹配规则不严格模式
*/
public static int KEYSET_MATCHER_UNDEMANDING_MODE = 0;
/**
* 密码最小长度,默认为6
*/
private static int MIN_LENGTH = 6;
/**
* 密码至少包含的不同字符数(不区分大、小写),(例如:"aaa"包含一个字符,"aba"包含2个字符,"aA"包含1个字符等),默认为4
*/
private static int MIN_CONTAIN_CHAR_NUM = 4;
/**
* 密码至少包含的字符类型数(a-z,A-Z,0-9,特殊字符),默认为2
*/
private static int MIN_CHAR_TYPE_NUM = 2;
/**
* 中等强度密码键盘规则匹配严格度,默认0.6
*/
private static double THRESHOLD_MEDIUM = 0.6;
/**
* 高安全度密码键盘规则匹配严格度,默认0.4
*/
private static double THRESHOLD_STRONG = 0.4;
/**
* 高安全度密码键盘规则匹配严格度,默认0.4
*/
private static double MAX_SEQUENTIAL_CHARS_THRESHOLD = 0.4;
/**
* 字母顺序A-Z
*/
private static String A_Z = "abcdefghijklmnopqrstuvwxyz";
/**
* 字母顺序Z-A
*/
private static String Z_A = "zyxwvutsrqponmlkjihgfedcba";
/**
* shift键产生的字符与非shift键时对应的字符
*/
private static Map CONVERSION_MAP = new HashMap();
/**
* 将键盘按键格式话为4*10的矩阵的坐标
*/
private static Map DICTIONARY_MAP = new HashMap();
private static String[] dictionary1 = "1 2 3 4 5 6 7 8 9 0".split("\\s+");
private static String[] dictionary2 = "q w e r t y u i o p".split("\\s+");
private static String[] dictionary3 = "a s d f g h j k l ;".split("\\s+");
private static String[] dictionary4 = "z x c v b n m , . /".split("\\s+");
private static String[][] DICTIONARY_MATRIX = {dictionary1, dictionary2, dictionary3, dictionary4};
static {
CONVERSION_MAP.put("!", "1");
CONVERSION_MAP.put("@", "2");
CONVERSION_MAP.put("#", "3");
CONVERSION_MAP.put("$", "4");
CONVERSION_MAP.put("%", "5");
CONVERSION_MAP.put("^", "6");
CONVERSION_MAP.put("&", "7");
CONVERSION_MAP.put("*", "8");
CONVERSION_MAP.put("(", "9");
CONVERSION_MAP.put(")", "0");
CONVERSION_MAP.put(":", ";");
CONVERSION_MAP.put("<", ",");
CONVERSION_MAP.put(">", ".");
CONVERSION_MAP.put("?", "/");
for(int i=0, ln=DICTIONARY_MATRIX.length; i<ln; i++) {
String[] dic = DICTIONARY_MATRIX[i];
for(int j=0, lnt=dic.length; j<lnt; j++) {
int[] row_cell = {i,j};
DICTIONARY_MAP.put(dic[j], row_cell);
}
}
}
private CheckPWD(){
}
/**
* 严格的键盘输入习惯匹配规则,匹配连续或者非连续的(可以匹配:1a2s3d4f5g这样的有规律的串),比matches方法的匹配规则更严格
* @param matcherList
* @param row_cellList
* @param index
*/
private static void maches2(List matcherList, List row_cellList, int index) {
for(; index<row_cellList.size(); index++) {
int[] row_cell_t = (int[]) row_cellList.get(index);
if(row_cell_t != null) {
boolean flag = true;
for(int i=0; i<matcherList.size(); i++) {
List list = (List) matcherList.get(i);
for(int j=0; j<list.size(); j++) {
int[] row_cell = (int[]) list.get(j);
if(((Math.abs(row_cell_t[0] - row_cell[0]) <= 1) && (Math.abs(row_cell_t[1] - row_cell[1]) <= 1))) {
list.add(row_cell_t);
flag = false;
break;
}
}
if(!flag) break;
}
if(flag) {
List arrt = new ArrayList();
arrt.add(row_cell_t);
matcherList.add(arrt);
}
}
}
}
/**
* 键盘输入习惯匹配规则,匹配连续输入(不能匹配:1a2s3d4f5g这样的有规律的串),比maches2方法的匹配规则宽松
* @param matcherList
* @param row_cellList
* @param index
*/
private static void matches(List matcherList, List row_cellList, int index) {
for(int i=0; i<matcherList.size(); i++) {
List list = (List) matcherList.get(i);
for(int ln=row_cellList.size(); index<ln; index++) {
int[] row_cell = (int[]) list.get(list.size()-1);
int[] row_cell_t = (int[]) row_cellList.get(index);
//如果相邻的键盘字符(某一个键的左右、上下、斜向相邻)被连续输入,在原匹配链条上增加新的输入
if((row_cell != null) && (row_cell_t != null) &&
((Math.abs(row_cell_t[0] - row_cell[0]) <= 1) && (Math.abs(row_cell_t[1] - row_cell[1]) <= 1))) {
list.add(row_cell_t);
}else { //如果新字符和上一匹配链条的结尾字符距离较远,这结束上一匹配链条,以该字符为首增加新的匹配链条
List arrt = new ArrayList();
arrt.add(row_cell_t);
matcherList.add(arrt);
index++;
break;
}
}
}
}
/**
* 键盘规则匹配器,返回double
* @param password 密码字符串
* @return
*/
public static double keysetMatcher(String password, int matchesMode) {
String t_password = new String(password);
t_password = t_password.toLowerCase();
t_password = canonicalizeWord(password);
logger.debug("****************将密码字符串转换为键盘矩阵的对应坐标 start******************");
char[] pwdCharArr = t_password.toCharArray();
List row_cellList = new ArrayList();
int Num = 0;
int startIndex = -1;
for(int i=0, ln= pwdCharArr.length; i<ln; i++) {
int[] row_cell = (int[]) DICTIONARY_MAP.get(String.valueOf(pwdCharArr[i]));
if(row_cell != null) {
row_cellList.add(row_cell);
Num++;
if(startIndex == -1) startIndex = i;
} else row_cellList.add(null);
}
logger.debug("****************将密码字符串转换为键盘矩阵的对应坐标 end******************");
logger.debug("****************初始化匹配链条 start******************");
int index = startIndex+1;
int[] row_cell0 = (int[]) row_cellList.get(startIndex);
List matcherList = new ArrayList();
List arr0 = new ArrayList();
arr0.add(row_cell0);
matcherList.add(arr0);
logger.debug("****************初始化匹配链条 end******************");
//根据匹配规则进行匹配
if(KEYSET_MATCHER_UNDEMANDING_MODE == matchesMode) matches(matcherList, row_cellList, index); //不严格的匹配模式
else if(KEYSET_MATCHER_STRICT_MODE == matchesMode) maches2(matcherList, row_cellList, index); //严格的匹配模式
double rValue = 0;
for(double threshold = THRESHOLD_STRONG; threshold <= THRESHOLD_MEDIUM; threshold+=0.1) {
boolean flag = true;
int nMinimumMeaningfulMatchLength = (int) (Num * threshold);
//特殊字符(~ ` - _ = + [ { ] } \ | ' ")所占比率上限
if(threshold <= ((t_password.length() - Num)*1.0/t_password.length())) flag = false;
if(flag) {
for(int i=0; i<matcherList.size(); i++) {
List list = (List) matcherList.get(i);
if(list.size() >= nMinimumMeaningfulMatchLength) {
flag = false;
return rValue;
}
}
}
if(flag) {
if(THRESHOLD_MEDIUM == THRESHOLD_STRONG) rValue = 10;
else rValue = 6 + 4*(THRESHOLD_MEDIUM-threshold)*1.0/(THRESHOLD_MEDIUM-THRESHOLD_STRONG);
break;
}
}
return rValue;
}
/**
* 替换密码中的shift键产生的字符转换为非shift键时对应的字符
* @param password 密码字符串
* @return 替换后的密码字符串
*/
private static String canonicalizeWord(String password) {
StringBuffer sb = new StringBuffer();
if(password != null && password.length() > 0) {
for(int i=0; i<password.length(); i++) {
String cs = String.valueOf(password.charAt(i));
if(CONVERSION_MAP.get(cs) != null) sb.append(CONVERSION_MAP.get(cs));
else sb.append(cs);
}
}
return sb.toString();
}
/**
* 搜索字符str中是否包含有regex指定的正则表达式匹配的子串
* @param str 待搜索字符串
* @param regex 正则表达式字符串
* @return 包含匹配子串返回true,否则返回false
*/
private static boolean stringFind(String str, String regex) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
if(m.find()) return true;
return false;
}
/**
* 评估密码中包含的字符类型是否符合要求,如果低于下限返回0,否则返回6 + (字符类型总数 - 下限) * 2
* @param password 密码字符串
* @param num 密码至少包含的字符类型数(a-z,A-Z,0-9,特殊字符),默认为2
* @return
*/
public static double checkCharTypeNum(String password, int num) {
int typeNum = 0;
if(stringFind(password, "[a-z]+")) typeNum++;
if(stringFind(password, "[0-9]+")) typeNum++;
if(stringFind(password, "[A-Z]+")) typeNum++;
if(stringFind(password, "\\p{Punct}+")) typeNum++;
double rValue = 0;
if(typeNum >= num) {
if(num == 4) rValue = 10;
else rValue = 6 + (typeNum - num)*1.0/(4-num) * 4;
}
return rValue;
}
/**
* 评估a-z,z-a这样的连续字符,返回一个double,如果连续字符占整个串长度的40%以上返回0,否则返回(1-连续字符占整个串长度的百分比) * 10
* @param password
* @return
*/
public static double checkSequentialChars(String password) {
String t_password = new String(password);
t_password = t_password.toLowerCase();
double rValue = 0;
int i = 2;
int n = t_password.length();
for(; i<n; i++) {
boolean flag = true;
for(int j=0; j+i<n; j++) {
String str = t_password.substring(j, j+i);
if((A_Z.indexOf(str) != -1) || (Z_A.indexOf(str) != -1)) {
flag = false;
break;
}
}
if(flag) {
if(i*1.0/n > MAX_SEQUENTIAL_CHARS_THRESHOLD) rValue = 0;
else rValue = (1-i*1.0/n) * 10;
break;
}
}
return rValue;
}
/**
* 评估密码至少包含的不同字符数(不区分大、小写),返回int,如果字符数小于下限返回0,否则返回6 + (包含字符数 - 下限),如果大于10,返回10
* @param password 密码字符串
* @param num 密码至少包含的字符类型数(a-z,A-Z,0-9,特殊字符),默认为2
* @return
*/
public static double checkMinContainCharNum(String password, int num) {
String t_password = new String(password);
// t_password = t_password.replaceAll("(.)\\1+", "$1");
t_password = t_password.toLowerCase();
t_password = canonicalizeWord(password);
Map map = new HashMap();
int snum = 0;
for(int i=0,ln= t_password.length(); i<ln; i++) {
String cs = String.valueOf(t_password.charAt(i));
if(map.get(cs) == null) {
map.put(cs, cs);
snum++;
}
}
double rValue = 0;
if(snum >= num) rValue = 6 + (snum - num);
return (rValue > 10 ? 10 : rValue);
}
/**
* 评估密码强度,根据密码长度,包含的字符类型,包含不同字符数,包含的连续字符,键盘输入习惯综合评估密码强度,返回0-10的double
* @param password
* @return
*/
public static double evalPWD(String password, int matchesMode) {
if(password == null || "".equals(password.replaceAll("\\s+", ""))) return 0; //判断密码为null或""
if(MIN_LENGTH > password.length()) return 0; //判断密码长度是否符合
double[] val = new double[1000];
int n = 0;
for(int i=MIN_LENGTH; i<=password.length(); i++) {
String t_password = password.substring(0, i);
//评估密码中包含的字符类型是否符合要求
double typeNumCheckResult = checkCharTypeNum(t_password,MIN_CHAR_TYPE_NUM);
//评估密码至少包含的不同字符数(不区分大、小写)
double minContainCharNumCheckResult = checkMinContainCharNum(t_password, MIN_CONTAIN_CHAR_NUM);
//评估a-z,z-a这样的连续字符
double sequentialCharsCheckResult = checkSequentialChars(t_password);
//评估键盘输入习惯
double keysetMatcherResult = keysetMatcher(t_password, matchesMode);
logger.debug("评估密码中包含的字符类型结果:"+typeNumCheckResult);
logger.debug("评估密码至少包含的不同字符数结果:"+minContainCharNumCheckResult);
logger.debug("评估a-z,z-a这样的连续字符结果:"+sequentialCharsCheckResult);
logger.debug("评估键盘输入习惯结果:"+keysetMatcherResult);
if(typeNumCheckResult == 0 || minContainCharNumCheckResult == 0 || sequentialCharsCheckResult == 0 || keysetMatcherResult == 0) {
val[n] = 0;
}else {
val[n] = typeNumCheckResult*CHAR_TYPE_NUM_THRESHOLD + minContainCharNumCheckResult*MIN_CONTAIN_CHAR_NUM_THRESHOLD +
sequentialCharsCheckResult*SEQUENTIAL_CHARS_THRESHOLD + keysetMatcherResult*KEYSET_MATCHER_THRESHOLD;
}
n++;
}
double rValue = 0;
boolean flag = false;
for(int i=0; i<n; i++) {
if(val[i] != 0) {
rValue += val[i];
flag = true;
}
if(flag && val[i] == 0) rValue += 1;
if(rValue >= 10) {
rValue = 10;
break;
}
}
return rValue;
// //评估密码中包含的字符类型是否符合要求
// double typeNumCheckResult = checkCharTypeNum(password,MIN_CHAR_TYPE_NUM);
// //评估密码至少包含的不同字符数(不区分大、小写)
// double minContainCharNumCheckResult = checkMinContainCharNum(password, MIN_CONTAIN_CHAR_NUM);
// //评估a-z,z-a这样的连续字符
// double sequentialCharsCheckResult = checkSequentialChars(password);
// //评估键盘输入习惯
// double keysetMatcherResult = keysetMatcher(password, matchesMode);
// logger.debug("评估密码中包含的字符类型结果:"+typeNumCheckResult);
// logger.debug("评估密码至少包含的不同字符数结果:"+minContainCharNumCheckResult);
// logger.debug("评估a-z,z-a这样的连续字符结果:"+sequentialCharsCheckResult);
// logger.debug("评估键盘输入习惯结果:"+keysetMatcherResult);
// if(typeNumCheckResult == 0 || minContainCharNumCheckResult == 0 || sequentialCharsCheckResult == 0 || keysetMatcherResult == 0) {
// return 0;
// }else {
// return typeNumCheckResult*CHAR_TYPE_NUM_THRESHOLD + minContainCharNumCheckResult*MIN_CONTAIN_CHAR_NUM_THRESHOLD +
// sequentialCharsCheckResult*SEQUENTIAL_CHARS_THRESHOLD + keysetMatcherResult*KEYSET_MATCHER_THRESHOLD;
// }
}
/**
* 用严格模式校验密码强度,根据密码评估结果判断密码是否可用,默认评估结果大于7的可用
* @param password
* @return
*/
public static boolean checkPwdInStrictMode(String password) {
double rValue = evalPWD(password, KEYSET_MATCHER_STRICT_MODE);
if(rValue >= PASSWORD_STRONG) return true;
return false;
}
/**
* 非严格模式校验密码强度,根据密码评估结果判断密码是否可用,默认评估结果大于7的可用
* @param password
* @return
*/
public static boolean checkPwdIndemandingMode(String password) {
double rValue = evalPWD(password, KEYSET_MATCHER_UNDEMANDING_MODE);
if(rValue >= PASSWORD_STRONG) return true;
return false;
}
public static void main(String[] args) {
String[] sArr = {
"1a2s3d4f5g6h",
"zcvjlufw123433546",
"~]sdfa^9mi|",
"`%0,uTs85vkj",
"liulanggood123",
"PASSword_123",
"yanghao1234",
"yanghao123",
"yanghao1981"
};
for(int i=0; i<sArr.length; i++) {
System.out.println("严格模式下校验"+sArr[i]+"的密码强度:"+evalPWD(sArr[i], KEYSET_MATCHER_STRICT_MODE));
System.out.println("非格模式下校验"+sArr[i]+"的密码强度:"+evalPWD(sArr[i], KEYSET_MATCHER_UNDEMANDING_MODE));
}
}
}
分享到:
相关推荐
图形化a+b,可以锻炼你的记忆力和算数速度
柔性输送线sw18可编辑全套技术资料100%好用.zip
本汽车票网上预订系统管理员和用户。管理员功能有个人中心,用户管理,汽车票管理,订单管理,退票管理,换票管理,反馈管理,留言板管理,系统管理等。用户功能有个人中心,汽车票管理,订单管理,退票管理,换票管理,反馈管理等。 内含文档,可轻松上手。
自动锁螺丝机细化完全step全套技术资料100%好用.zip
【创新无忧】基于matlab龙格库塔算法RUN优化极限学习机KELM故障诊断【含Matlab源码 10715期】.zip
pll电荷泵锁相环 cppll(已流片)仿真环境搭建好了 电路到版图都已流片验证,另外送PLL书籍电子版和对应工艺库。 另加50就可以得到完整版图 三阶二型锁相环 参考频率50-100MHz 分频比可调 锁定频率600M-2GHz 锁定时间4us 环形振荡器 ring vco 鉴频鉴相器PFD模块 分频器DIV模块 ,ps counter 电荷泵CP模块
智慧社区有管理员和客户两个角色。客户功能有车位信息,社区信息,周边服务,问卷调查,爱心助老,通知公告,留言反馈,个人中心,客服中心,在线报修管理,投诉建议管理,车位租买管理,社区信息管理,参与答卷管理,我的收藏管理。管理员功能有个人中心,客户管理,在线报修管理,投诉建议管理,车位信息管理,车位租买管理,社区信息管理,周边服务管理,问卷调查管理,参与答卷管理,爱心助老管理,留言板管理,系统管理。 内含文档,可轻松上手。
本科生课程设计封面.doc
展示PRD文档的关键要素编写具体示例。同时提供了一份模板,方便撰写PRD文档。
基于matlab的用于分析弧齿锥齿轮啮合轨迹的程序,输出齿轮啮合轨迹及传递误差。 程序已调通,可直接运行。 程序保证可直接运行。
【创新无忧】基于matlab向量加权平均算法INFO优化极限学习机KELM故障诊断【含Matlab源码 10732期】.zip
仓库管理系统(一个毕设) 毕业设计项目《仓库管理系统(manager_sys)》的概述和指南: 项目标题 《基于Spring MVC和Vue.js的仓库管理系统设计与实现 —— 毕业设计项目》 项目概述 本项目是一个基于Spring MVC、Spring Security、Spring、MyBatis、PageHelper和Vue.js框架的仓库管理系统。系统旨在提供高效、安全的库存管理解决方案,包括权限管理、商品管理、订单处理和库存预警等功能。 系统特点 权限管理:利用Spring Security实现基于角色的访问控制(RBAC),动态分配权限。 业务流程:涵盖商品、订单、库存的完整操作流程,确保库存管理的准确性。 日志记录:通过Spring AOP实现操作日志的记录,便于追踪和审计。 数据统计:首页展示商品销量统计图和每日销售统计图,直观展示业务状况。 系统预览 登录和首页:用户登录后进入系统首页,查看统计信息。 产品管理:管理商品信息,包括添加、修改、删除等操作。 订单管理:处理订单,包括创建订单、更新库存等。 权限管理:管理用户角色和权限。 日志管理:查看系统操作日志。 运
A星算法 A*算法 自己研究编写的Matlab路径规划算法 Astar算法走迷宫 可自行设置起始点,目标点,自由更地图。 ——————————————————— 可以和人工势场法融合 动态障碍物
《MATLAB神经网络原理与实例精解》是一本深度学习初学者的理想教程,它全面涵盖了神经网络的基础理论以及MATLAB实现方法。这本书旨在帮助读者理解神经网络的工作原理,并通过具体的MATLAB实例,让读者能够动手实践,从而深入掌握神经网络在实际问题中的应用。 神经网络是一种模仿人脑神经元结构的计算模型,它由大量的处理单元——神经元组成,通过权重连接形成复杂的网络结构。在深度学习领域,神经网络被广泛用于图像识别、语音识别、自然语言处理等任务,因其强大的非线性建模能力而备受青睐。 MATLAB作为一个强大的数值计算和数据可视化环境,为构建和训练神经网络提供了便利的工具箱。MATLAB神经网络工具箱(Neural Network Toolbox)包含了各种类型的神经网络模型,如前馈网络、卷积网络、递归网络等,以及训练算法,如反向传播、遗传算法等。通过这些工具,用户可以快速构建网络结构,调整参数,进行训练和验证,并将模型应用于实际数据。 本书首先会介绍神经网络的基本概念,包括感知机、多层前馈网络和反向传播算法。然后,将详细讲解如何在MATLAB中搭建这些网络,包括网络结构的设计、权重初始
Matlab领域上传的视频是由对应的完整代码运行得来的,完整代码皆可运行,亲测可用,适合小白; 1、从视频里可见完整代码的内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2019b;若运行有误,根据提示修改;若不会,私信博主; 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可私信博主; 4.1 博客或资源的完整代码提供 4.2 期刊或参考文献复现 4.3 Matlab程序定制 4.4 科研合作
ABAQUS动,静力学模型;车辆-轨道耦合动力学;钢轨不平顺程序;批量非线性弹簧;单向弹簧(收拉不受压或受压不受拉),温度耦合等。 轨道检算(超高,超限,出报告);土木建筑有限元建模分析。
教学督导检查情况表.docx
基于springboot的逍遥大药房管理系统--论文.zip
win32汇编环境,理解BeginPaint函数与GetDC函数的区别
调试过可以运行。 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9