使用Postman和JMeter进行signature签名
一、前言
有些接口的请求会带上sign(签名)进行请求,各接口对sign的签名内容、方式可能不一样,但一般都是从接口的入参中选择部分内容组成一个字符串,然后再进行签名操作, 将结果赋值给sign; 完整规范的接口文档都会有sign的算法描述。这里通过Postman的Pre-request Script以及JMeter的BeanShell前置处理器进行接口签名的处理。(完整代码在每部分的最后)
被测系统teachSignServer:
Gitee:江苏豪之诺软件科技有限公司/KnowledgeBroadcast - Gitee.com
直接双击运行.exe文件即可(密钥文件与conf.ini需要与exe处于同一文件夹下)
其余工具:
1.bundle.js:https://github.com/joolfe/postman-util-lib/tree/master/postman
使用方式我们在后面使用到了再进行介绍
2.json.jar: https://mvnrepository.com/artifact/org.json/json
选择适合的版本

点击bundle

将下载的jar包置于jmeter的./lib/ext下并重启jmeter
被测接口信息:
| 接口 | URL | Method | Body | 签名规则 |
|---|---|---|---|---|
| v0 | http://127.0.0.1:5000/api/v0/teachsign | POST | { "AppKey": "z417App", "AppVer": "1.0.0", "Data": "{"SPhone":"18662255783","EType":0}", "DeviceName": "web", "DeviceType": "web", "Lang": "CN", "Sign": "teachsign", "TimeStamp": 1625456804 } | appkey,timestamp,data,secret四个字段的值拼接,使用32位md5进行签名 |
| v1 | http://127.0.0.1:5000/api/v1/teachsign | POST | { "appid": "wxd930u", "mch_id": 10100, "device_info": 100, "body": "{"EType":0}", "DeviceType": "", "nonce_str": "ibuaiVc", "sign": "CD198C36632A274C49E5F2F028FA257C", "source": null, "ts": 1625456804 } | 1. 参与签名运算的参数选用入参里边value非空的参数 2. 参与签名运算的参数按照ASCII顺序排序 3. 组合方式:key=value通过&符连接 4. 最后加上盐key=secret(secret在conf.ini中配置,同理后面的私钥与公钥也可在其中进行配置) 5. 使用32位md5进行签名,sign的字母全大写 |
| v2 | http://127.0.0.1:5000/api/v2/teachsign | POST | { "busId": "", "busCnl": "POS", "requJnINo": "abceefgghkjlafksdffdsf", "reqTxnTm": "16:30:16", "serviceCode": "chengxusong", "bussJnIno": "Arabic - Bahrain", "sign": "fsdfsd", "reqTxnDt": "20210907", "nonceStr": "Language", "sysCnl": "OKPOS", "ts": 1631003416 } | 1. 参与签名运算的参数选用入参里边value非空的参数 2. 参与签名运算的参数按照ASCII顺序排序 3. 使用private_key签名 4. 使用SHA256withRSA进行签名 |
二、v0接口
1.Postman
获取请求参数并将body的参数转换为json对象
javascript
var Json = JSON.parse(pm.request.body);
获取所需变量并将新的时间戳更新到json对象中
javascript
var TimeStamp = Date.parse(new Date()) / 1000 - 10; Json.TimeStamp = TimeStamp; var AppKey = Json.AppKey; var Data = Json.Data; var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
字符串拼接
javascript
var str = AppKey + TimeStamp + Data + secretKey;
进行md5运算并将生成的hash序列转换为字符串
javascript
var strmd5= CryptoJS.MD5(str).toString();
修改json对象中sign并将md5对象写回body中
javascript
Json.Sign = strmd5; pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON转换回字符串格式写回到请求体中
完整代码:
javascript
/* vo加密规则:appkey,timestamp,data,secret四个字段的值拼接,使用32位md5加密 *//** 获取请求参数*/ var Json = JSON.parse(pm.request.body); // 将body的参数转换为json对象 /** 获取所需变量*/ var TimeStamp = Date.parse(new Date()) / 1000 - 10; // 获取时间戳 Json.TimeStamp = TimeStamp; // 修改JSON var AppKey = Json.AppKey; var Data = Json.Data; var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";/* * 拼接字符串并加密*/ var str = AppKey + TimeStamp + Data + secretKey; var strmd5= CryptoJS.MD5(str).toString(); // 调用方法进行md5运算并将生成的hash序列转换为字符串 Json.Sign = strmd5; // 修改JSON pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON写回到请求体中
2.JMeter
在JMeter的时间戳可以直接使用JMeter自带函数在body中获取,当然也可以在BeanShell前置处理器中使用代码获取
/1000是因为JMeter默认生成的时间戳为13位时间戳,我们只需要10位即可。

导包(org.json为第三方jar包)
java
import org.apache.commons.codec.digest.DigestUtils; import org.apache.jmeter.config.*; import org.json.*;
获取请求传入的body,将其转化为Json对象
java
// 获取请求 Arguments arguments = sampler.getArguments(); // 获取请求中的body内容 Argument arg = arguments.getArgument(0); // 获取body的value,并将其转化为JSONObject对象 JSONObject dataobj = new JSONObject(arg.getValue());
获取变量并拼接
java
String TimeStamp = dataobj.optString("TimeStamp");
String AppKey = dataobj.optString("AppKey");
String Data = dataobj.optString("Data");
String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
String str = AppKey + TimeStamp + Data + secretKey;
进行md5运算
java
sign = DigestUtils.md5Hex(str);
修改json对象的sign并转换为字符串写回body中
java
dataobj.put("Sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中
完整代码:
java
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;/** 获取请求传入的body,将其转化为Json对象*/
// 获取请求
Arguments arguments = sampler.getArguments();
// 获取请求中的body内容
Argument arg = arguments.getArgument(0);
// 获取body的value,并将其转化为JSONObject对象
JSONObject dataobj = new JSONObject(arg.getValue());/** 获取变量并拼接字符串*/
// 获取变量
String TimeStamp = dataobj.optString("TimeStamp");
String AppKey = dataobj.optString("AppKey");
String Data = dataobj.optString("Data");
String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
// 字符串拼接
String str = AppKey + TimeStamp + Data + secretKey;/** 签名,更新body*/
sign = DigestUtils.md5Hex(str); // md5运算
dataobj.put("Sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并写回request-body中
三、v1接口
1.Postman
获取请求参数并将body的参数转换为json对象
javascript
var Json = JSON.parse(pm.request.body);
获取时间戳并修改json对象
javascript
var ts = Date.parse(new Date()) / 1000 - 10; Json.ts = ts;
去除sign参数本身,然后去除值是空的参数
javascript
var keys = [];
// 循环遍历JSON
for (let k in Json ){// 排除json中键位sign以及值为空的数据if (k == 'sign' || !Json[k]){continue;}keys.push(k); // 生成筛选后的key序列
}
排序
javascript
keys.sort();
拼接字符串
javascript
let keys_str = '';
for (let x of keys){keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
}
keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
进行md5运算并将生成的hash序列转换为字母全大写字符串
javascript
var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase();
修改json对象中sign并将md5对象写回body中
javascript
Json.sign = strmd5; pm.request.body.raw = JSON.stringify(Json);
完整代码:
javascript
/*v1加密规则:1. 参与签名运算的参数选用入参里边value非空的参数2. 参与签名运算的参数按照ASCII顺序排序3. 组合方式:key=value通过&符连接4. 最后加上key=secret5. 使用32位md5签名,sign的字母全大写
*//** 获取请求参数*/
var Json = JSON.parse(pm.request.body);
var ts = Date.parse(new Date()) / 1000 - 10; // 获取时间戳
Json.ts = ts; // 修改json/** 去除sign参数本身,然后去除值是空的参数*/
var keys = []; // 定义key序列
// 循环遍历JSON
for (let k in Json ){// 排除json中键位sign以及值为空的数据if (k == 'sign' || !Json[k]){continue;}keys.push(k); // 生成筛选后的key序列
}/** 对请求参数排序*/
keys.sort();/** 拼接字符串*/
let keys_str = '';
for (let x of keys){keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
}
keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";/** 签名并更新body*/
var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase(); // 调用方法进行md5运算并将生成的hash序列转换为字母全大写字符串
Json.sign = strmd5; // 修改Json
pm.request.body.raw = JSON.stringify(Json);
2.JMeter
同样在body中使用内置函数定义时间戳ts
导包
java
import org.apache.commons.codec.digest.DigestUtils; import org.apache.jmeter.config.*; import org.json.*;
获取请求传入的body,将其转化为Json对象
java
// 获取请求 Arguments arguments = sampler.getArguments(); // 获取请求中的body内容 Argument arg = arguments.getArgument(0); // 获取body的value,并将其转化为JSONObject对象 JSONObject dataobj = new JSONObject(arg.getValue());
获取Json的key
java
// 创建list存储body中的key值
List keyArry = new ArrayList();
// 生成迭代对象
Iterator iterator = dataObj.keys();
// 循环key,将其放入list
for (String key : iterator) {if (!key.equals("sign") && !key.equals("Sign")) {keyArry.add(key);}
}
对list进行排序
java
Collections.sort(keyArry);
字符串拼接
java
String str = "";
for (String s : keyArry) {
// log.error(s);String value = dataObj.optString(s);// 剔除值为空或值为null的参数if (!value.equals("") && !value.equals(null)) {str = str+s+"="+ value+"&";}
}
str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
进行md5运算并转换为字母全大写
java
String sign = DigestUtils.md5Hex(str).toUpperCase();
修改json对象的sign并转换为字符串写回body中
java
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中
完整代码:
java
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;/** 获取请求传入的body,将其转化为Json对象*/
// 获取请求
Arguments arguments = sampler.getArguments();
// 获取请求中的body内容
Argument arg = arguments.getArgument(0);
// 获取body的value,并将其转化为JSONObject对象
JSONObject dataObj = new JSONObject(arg.getValue()); /** 获取Json的key进行排序*/
// 创建list存储body中的key值
List keyArry = new ArrayList();
// 生成迭代对象
Iterator iterator = dataObj.keys();
// 循环key,将其放入list
for (String key : iterator) {if (!key.equals("sign") && !key.equals("Sign")) {keyArry.add(key);}
}/** 对list进行排序*/
Collections.sort(keyArry);/** 循环list中的key,读取对应的Value组成字符串*/
String str = "";
for (String s : keyArry) {String value = dataObj.optString(s);// 剔除值为空或值为null的参数if (!value.equals("") && !value.equals(null)) {str = str+s+"="+ value+"&";}
}
str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";/** 签名并更新body*/
String sign = DigestUtils.md5Hex(str).toUpperCase(); // 进行md5运算并转换为字母全大写
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并写回request-body中
四、v2接口
1.Postman
将下载后的json导入到postman,进入Lib install请求

发送请求,该请求会将bundle.js写入到全局变量中

获取请求参数并将body的参数转换为json对象
javascript
var Json = JSON.parse(pm.request.body);
获取时间戳并修改json对象
javascript
var ts = Date.parse(new Date()) / 1000 - 10; Json.ts = ts;
去除sign参数本身,然后去除值是空的参数
javascript
var keys = [];
// 循环遍历JSON
for (let k in Json ){// 排除json中键位sign以及值为空的数据if (k == 'sign' || !Json[k]){continue;}keys.push(k); // 生成筛选后的key序列
}
排序
javascript
keys.sort();
拼接字符串
javascript
let keys_str = '';
for (let x of keys){keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
}
keys_str = keys_str.slice(0,-1); // 删除最后一个&
导入刚才写入到全局变量的js
javascript
eval(pm.globals.get("pmlib_code"));
由于私钥过长,所以这里把私钥的内容写到环境变量中,私钥内容可在pkcs8_rsa_private_key.pem查看(私钥与公钥可自行更换,在conf.ini中进行配置即可)

获取私钥
javascript
const privatekey = pm.environment.get("privatekey");
加密
javascript
const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成签名对象并制定为SHA256withRSA类型
sha256withrsa.init(privatekey); // 初始化privatekey
sha256withrsa.updateString(keys_str); // 更新要签名的数据
const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 签名并转换为Base64字符串
修改json对象中sign并将md5对象写回body中
javascript
Json.sign = sign; pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON转换回字符串格式写回到请求体中
完整代码:
javascript
/*v2加密规则:1. 参与签名运算的参数选用入参里边value非空的参数2. 参与签名运算的参数按照ASCII顺序排序3. 使用private_key签名4. 使用SHA256withRSA进行签名
*//** 获取请求参数*/
var Json = JSON.parse(pm.request.body);
var ts = Date.parse(new Date()) / 1000 - 10; // 获取时间戳
Json.ts = ts; // 修改json/** 去除sign参数本身,然后去除值是空的参数*/
var keys = []; // 定义key序列
// 循环遍历JSON
for (let k in Json ){// 排除json中键位sign以及值为空的数据if (k == 'sign' || !Json[k]){continue;}keys.push(k); // 生成筛选后的key序列
}/** 对请求参数排序*/
keys.sort();/** 拼接字符串*/
let keys_str = '';
for (let x of keys){keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
}
keys_str = keys_str.slice(0,-1); // 删除最后一个&/** 加密并更新body*/
eval(pm.globals.get("pmlib_code")); // 导入写入到全局变量的jsconst privatekey = pm.environment.get("privatekey"); // 从环境变量获取私钥const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成签名对象并制定为SHA256withRSA类型sha256withrsa.init(privatekey); // 初始化privatekey
sha256withrsa.updateString(keys_str); // 更新要签名的数据const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 签名并转换为Base64字符串Json.sign = sign;
pm.request.body.raw = JSON.stringify(Json);
2.JMeter
同样在body中使用内置函数定义时间戳ts,同时添加用户定义的变量配置元件来存放私钥
导包
java
import org.apache.jmeter.config.*; import org.apache.commons.codec.digest.DigestUtils; import org.json.*; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec;
获取请求传入的body,将其转化为Json对象
java
// 获取请求 Arguments arguments = sampler.getArguments(); // 获取请求中的body内容 Argument arg = arguments.getArgument(0); // 获取body的value,并将其转化为JSONObject对象 JSONObject dataobj = new JSONObject(arg.getValue());
获取Json的key
java
// 创建list存储body中的key值
List keyArry = new ArrayList();
// 生成迭代对象
Iterator iterator = dataObj.keys();
// 循环key,将其放入list
for (String key : iterator) {if (!key.equals("sign") && !key.equals("Sign")) {keyArry.add(key);}
}
对list进行排序
java
Collections.sort(keyArry);
字符串拼接
java
String str = "";
for (String s : keyArry) {
// log.error(s);String value = dataObj.optString(s);// 剔除值为空或值为null的参数if (!value.equals("") && !value.equals(null)) {str = str+s+"="+ value+"&";}
}
//删除最后一个&
str = str.substring(0,str.length()-1);
读取私钥
java中读取私钥需要删除前面的“-----BEGIN PRIVATE KEY-----”和后面的“-----END PRIVATE KEY-----”,且需要key首尾连接中间无换行或空格。
java
String privateKeyString = vars.get("privateKey"); // 从用户定义的变量中读取私钥
privateKeyString = privateKeyString.replace(" ", ""); // 删除多余的空格
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 将Base64解码转化为字符串
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私钥对象。
创建 Signature 对象并初始化
java
Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 对象
signature.initSign(privateKey); // // 初始化签署签名的私钥
更新要签名的数据
java
signature.update(str.getBytes("UTF-8")); // 更新要签名或验证的字节
签名
java
byte[] signatureBytes = signature.sign(); // 执行签名 String sign = Base64.getEncoder().encodeToString(signatureBytes); // 将签名结果转换为 Base64 字符串
修改json对象的sign并转换为字符串写回body中
java
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中
完整代码:
java
import org.apache.jmeter.config.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.json.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;/** 获取请求传入的body,将其转化为Json对象*/
// 获取请求
Arguments arguments = sampler.getArguments();
// 获取请求中的body内容
Argument arg = arguments.getArgument(0);
// 获取body的value,并将其转化为JSONObject对象
JSONObject dataObj = new JSONObject(arg.getValue()); /** 获取Json的key进行排序*/
// 创建list存储body中的key值
List keyArry = new ArrayList();
// 生成迭代对象
Iterator iterator = dataObj.keys();
// 循环key,将其放入list
for (String key : iterator) {if (!key.equals("sign") && !key.equals("Sign")) {keyArry.add(key);
// log.error(key);}
}
// 对list进行排序
Collections.sort(keyArry);/** 循环list中的key,读取对应的Value组成字符串*/
String str = "";
for (String s : keyArry) {
// log.error(s);String value = dataObj.optString(s);if (!value.equals("")) {str = str+s+"="+ value+"&";}
}
//删除最后一个&
str = str.substring(0,str.length()-1);/** 读取私钥*/
String privateKeyString = vars.get("privateKey"); // 从用户定义的变量中读取私钥
privateKeyString = privateKeyString.replace(" ", ""); // 删除多余的空格
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 将Base64解码转化为字符串
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私钥对象。/** 读创建 Signature 对象并初始化*/
Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 对象
signature.initSign(privateKey); // 初始化签署签名的私钥 //
/** 更新要签名的数据化*/
signature.update(str.getBytes("UTF-8")); // 更新要签名或验证的字节/** 签名并更新body*/
byte[] signatureBytes = signature.sign(); // 签署所有更新字节的签名// 将签名结果转换为 Base64 字符串
String sign = Base64.getEncoder().encodeToString(signatureBytes); // 编码为Base64字符串dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中

相关文章:
使用Postman和JMeter进行signature签名
一、前言 有些接口的请求会带上sign(签名)进行请求,各接口对sign的签名内容、方式可能不一样,但一般都是从接口的入参中选择部分内容组成一个字符串,然后再进行签名操作, 将结果赋值给sign; 完整规范的接口文档都会…...
uni-app nvue vue3 setup中实现加载webview,解决nvue中获取不到webview实例的问题
注意下面的方法只能在app端使用, let wv plus.webview.create("","custom-webview",{plusrequire:"none", uni-app: none, width: 300,height:400,top:uni.getSystemInfoSync().statusBarHeight44 }) wv.loadURL("https://ww…...
IPD(集成产品开发)—核心思想
企业发展到一定阶段就会遇到管理瓶颈,IPD流程是一种高度结构化的产品开发流程,它集成了业界很多优秀的产品开发方法论,像搭积木一样的组合成一种非常有效的流程。如果我们能根据企业的规模和行业特点,对全流程的IPD进行合适的裁剪…...
uniapp android 原生插件开发-测试流程
前言 最近公司要求研究一下 uniapp 的 android 原生插件的开发,为以后的工作做准备。这篇文章记录一下自己的学习过程,也帮助一下有同样需求的同学们 : ) 一、下载安装Hbuilder X , Android studio(相关的安装配置过程网上有很多,…...
MyCAT从入门到实战(配置文件介绍)
用户(user) 配置文件位置mycat/conf/user/root.user.json。这个配置文件主要是用来配置MyCAT的登录用户 的,也就是我们连接8066这个端口的用户信息。 [rootservice bin]# cat /usr/local/mycat/conf/users/root.user.json {"dialect&q…...
【LeetCode-300】最长递增子序列(动归)
目录 题目描述 解法1:动态规划 代码实现 题目链接 题目描述 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例…...
Mysterious-GIF-攻防世界-MISC
题目简介: 下载得到gif文件,十六进制编辑器查看,发现末尾有50 4B 03 04文件头。提取后保存为zip文件。 解压该zip文件,得到temp.zip。十六进制编辑器查看temp.zip,会发现有多个文件头和文件尾。 用binwalk分离temp.zi…...
【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)
目录 1.前言:顺序表回顾: 1.1顺序表的优缺点 2.主角----链表 2.1链表的概念 2.2定义一个单链表的具体实现代码方式 3.单链表对数据的管理----增删查改 3.1单链表的创建 3.2单链表的遍历实现 3.2.1利用遍历实现一个打印我们链表内容的函数的函数…...
【Go语言】Go语言中的切片
Go语言中的切片 1.切片的定义 Go语言中,切片是一个新的数据类型数据类型,与数组最大的区别在于,切片的类型中只有数据元素的类型,而没有长度: var slice []string []string{"a", "b", "c…...
Qt程序设计-钟表自定义控件实例
本文讲解Qt钟表自定义控件实例。 效果如下: 创建钟表类 #ifndef TIMEPIECE_H #define TIMEPIECE_H#include <QWidget> #include <QPropertyAnimation> #include <QDebug> #include <QPainter> #include <QtMath>#include <QTimer>#incl…...
Redis的发布订阅功能教程,实现实时消息和key过期事件通知功能
Redis的发布订阅 Redis的发布/订阅(Pub/Sub)功能是一种消息传递模式,用于实现消息发布者(publisher)和订阅者(subscriber)之间的消息通信。在这种模式下,消息的发送者(发布者)将消息发送到特定的频道(channel),而订阅了该频道的接收者(订阅者)将会接收到这些消息…...
4核8g服务器能支持多少人访问?
腾讯云4核8G服务器支持多少人在线访问?支持25人同时访问。实际上程序效率不同支持人数在线人数不同,公网带宽也是影响4核8G服务器并发数的一大因素,假设公网带宽太小,流量直接卡在入口,4核8G配置的CPU内存也会造成计算…...
【Android】切换系统全局语言设置
前两种为应用内部处理,第三种为发送广播由系统服务进行处理 使用反射 这种会直接将安卓设置内的语言列表清空,然后将选择的语言设置为系统语言 该方法存在问题,在首次开机后设置会导致国外应用进不去(只对于here地图个别版本) /*** 设置语言…...
【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II
【递归】【回溯】Leetcode 112. 路径总和 113. 路径总和 II 112. 路径总和解法:递归 有递归就有回溯 记得return正确的返回上去 113. 路径总和 II解法 递归 如果需要搜索整棵二叉树,那么递归函数就不要返回值 如果要搜索其中一条符合条件的路径ÿ…...
AxureCloud配置文件详细介绍
AxureCloud配置文件详细介绍 原文地址:https://docs.axure.com/axure-cloud/business/custom-settings-json/ 通过修改 customsettings.json 可以修改AxureCloud私有部署的域名、端口、HTTPS、存储目录、是否开启插件等, 默认安装的路径为: C:\Program Files\Axure…...
Centos开机网卡自启动失败
问题背景 每次都要手动启动在这里插入代码片 解决方案: 关闭 NetworkManager 服务 systemctl disable NetworkManager systemctl stop NetworkManager重启就会发现网卡已经可以自动启动了...
华为OD技术面试案例3-2024年
技术一面: 1.手撕代码,算法题: 【最小路径和】 手撕代码通过,面试官拍了照片 2.深挖项目,做过的自认为最好的一个项目,描述做过的项目的工作过程,使用到哪些技术? 技术二面&…...
全面升级!Apache HugeGraph 1.2.0版本发布
图数据库以独特的数据管理和分析能力,在企业数智化转型的过程中正在成为数据治理的核心,根据IDC调研显示,95%的企业认为图数据库是重要的数据管理工具,超过65%的厂商认为在业务上图数据库优于其他选择,尤其是在金融风控…...
WinCC如何与三菱Q系列PLC进行以太网通讯
本文主要描述人机界面WinCC如何与三菱Q系列PLC进行以太网通讯,主要介绍了CPU自带以太网口和扩展以太网模块两种情况以及分别使用TCP、UDP两种协议进行通讯组态步骤及其注意事项。 一、 说明 WinCC从V7.0 SP2版本开始增加了三菱以太网驱动程序,支持和三…...
Spring11、整合Mybatis
11、整合Mybatis 步骤: 导入相关jar包 junit <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version> </dependency> mybatis <dependency><groupId>org.my…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
