使用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

被测接口信息:

接口URLMethodBody签名规则
v0http://127.0.0.1:5000/api/v0/teachsignPOST{
"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进行签名
v1http://127.0.0.1:5000/api/v1/teachsignPOST{
"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的字母全大写
v2http://127.0.0.1:5000/api/v2/teachsignPOST{
"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中
​​​​​

​​​​​​​​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入探究node搭建socket服务器

自从上篇中sokect实现了视频通话,但是是使用ws依赖库实现的服务端,所以最近再看ws源码,不看不知道,一看很惊讶。 接下来一点点记录一下,如何搭建一个简易的服务端socket,来实现上次的视频通讯。 搭建一个…

Java面试笔记

Java面试笔记 Java面试笔记-网络模块 TCP的三次握手 TCP的简介: 面向连接的、可靠的、基于字节流的传输层通信协议 将应用层的数据流分割成报文段并发送给目标节点的TCP层 数据包都有序号,对方收到则发送ACK确认,未收到则重传 使用校验和来…

OpenCV 4基础篇| OpenCV图像基本操作

目录 1. 图像读取1.1 cv2.imread() 不能读取中文路径和中文名称1.2 cv2.imdecode() 可以读取中文路径和中文名称 2. 图像的显示2.1 openCV显示图像 cv2.imshow()2.2 matplotlib显示图像 plt.imshow() 3. 图像的保存 cv2.imwrite()4. 图像的复制4.1 img.copy()4.2 np.copy()4.3 …

模板(类模板)---C++

模板目录 2.类模板2.1 类模板语法2.2 类模板与函数模板区别2.3 类模板中成员函数创建时机2.4 类模板对象做函数参数2.5 类模板与继承2.6 类模板成员函数类外实现2.7 类模板分文件编写2.8 类模板与友元2.9 类模板案例 2.类模板 2.1 类模板语法 类模板作用: 建立一个…

Stable Diffusion——文生图界面参数讲解与提示词使用技巧

Clip终止层数 什么是Clip CLIP(Contrastive Language-Image Pretraining)是由OpenAI于2021年开发的一种语言图像对比预训练模型。其独特之处在于,CLIP模型中的图像和文本嵌入共享相同的潜在特征空间,这使得模型能够直接在图像和文…

C语言:指针(一)

目录 1.内存和地址2. 指针变量和地址2.1 取地址操作符(&)2.2 指针变量和解引用操作符(*)2.2.1 指针变量2.2.2 解引用操作符(*) 2.3 指针变量的大小 3.指针变量的类型和意义3.1 指针的解引用3.2 指针 -指…

二手货wordpress企业网站主题模板

二手车wordpress主题模板 简洁的二手车wordpress主题模板,适合做二手车业务的公司官方网站使用。 https://www.jianzhanpress.com/?p3473 wordpress二手物资回收主题 绿色wordpress二手物资回收主题,用于二手物资回收公司WP建站使用。 https://www.…

pikachu靶场-XSS

XSS: XSS(跨站脚本)概述 Cross-Site Scripting 简称为“CSS”,为避免与前端叠成样式表的缩写"CSS"冲突,故又称XSS。一般XSS可以分为如下几种常见类型: 1.反射性XSS; 2.存储型XSS; 3.DOM型XSS; …

[Angular 基础] - 自定义指令,深入学习 directive

[Angular 基础] - 自定义指令,深入学习 directive 这篇笔记的前置笔记为 [Angular 基础] - 指令(directives),对 Angular 的 directives 不是很了解的可以先过一下这篇笔记 后面也会拓展一下项目,所以感兴趣的也可以补一下文后对应的项目&a…

VSCODE include错误 找不到 stdio.h

解决办法: Ctrl Shift P 打开命令面板, 键入 “Select Intellisense Configuration”(下图是因为我在写文章之前已经用过这个命令,所以这个历史记录出现在了第一行) 再选择“Use gcc.exe ”(后面的Foun…

【Java程序设计】【C00277】基于Springboot的招生管理系统(有论文)

基于Springboot的招生管理系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的招生管理系统 本系统分为系统功能模块、管理员功能模块以及学生功能模块。 系统功能模块:在系统首页可以查看首页、专业…

C语言——实用调试技巧——第2篇——(第23篇)

坚持就是胜利 文章目录 一、实例二、如何写出好(易于调试)的代码1、优秀的代码2、示范(1)模拟 strcpy 函数方法一:方法二:方法三:有弊端方法四:对方法三进行优化assert 的使用 方法五…

Hive【内部表、外部表、临时表、分区表、分桶表】【总结】

目录 Hive的物种表结构特性 一、内部表 建表 使用场景 二、外部表 建表:关键词【EXTERNAL】 场景: 外部表与内部表可互相转换 三、临时表 建表 临时表横向对比​编辑 四、分区表 建表:关键字【PARTITIONED BY】 场景: 五、分桶表 …

万界星空科技MES系统,实现数字化智能工厂

万界星空科技帮助制造型企业解决生产过程中遇到的生产过程不透明,防错成本高,追溯困难,品质不可控,人工效率低下,库存积压,交期延误等问题,从而达到“降本增效”的目标。打通各个信息孤岛&#…

【算法与数据结构】回溯算法、贪心算法、动态规划、图论(笔记三)

文章目录 七、回溯算法八、贪心算法九、动态规划9.1 背包问题9.2 01背包9.3 完全背包9.4 多重背包 十、图论10.1 深度优先搜索10.2 广度优先搜索10.3 并查集 最近博主学习了算法与数据结构的一些视频,在这个文章做一些笔记和心得,本篇文章就写了一些基础…

2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于ThinkPHP框架

应用介绍 本文来自:2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于ThinkPHP框架 - 源码1688 简介: 2023全新UI千月影视APP源码 | 前后端完美匹配、后端基于thinkphp框架 图片:

.NET Core MongoDB数据仓储和工作单元模式实操

前言 上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装,这一章节主要讲的是MongoDB用户管理相关操作实操。如:获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除…

kafka为什么性能这么高?

Kafka系统架构 Kafka是一个分布式流处理平台,具有高性能和可伸缩性的特点。它使用了一些关键的设计原则和技术,以实现其高性能。 上图是Kafka的架构图,Producer生产消息,以Partition的维度,按照一定的路由策略&#x…

Java知识点一

hello,大家好!我们今天开启Java语言的学习之路,与C语言的学习内容有些许异同,今天我们来简单了解一下Java的基础知识。 一、数据类型 分两种:基本数据类型 引用数据类型 (1)整型 八种基本数…

Unity 2021.3发布WebGL设置以及nginx的配置

使用unity2021.3发布webgl 使用Unity制作好项目之后建议进行代码清理,这样会即将不用的命名空间去除,不然一会在发布的时候有些命名空间webgl会报错。 平台转换 将平台设置为webgl 设置色彩空间压缩方式 Compression Format 设置为DisabledDecompre…