package cc.mrbird.febs.unisoftiot.utils;
|
|
import cc.mrbird.febs.unisoftiot.enums.DeviceRequestUrlEnum;
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.crypto.SecureUtil;
|
|
import java.io.UnsupportedEncodingException;
|
import java.net.URLEncoder;
|
import java.nio.charset.StandardCharsets;
|
import java.util.LinkedHashMap;
|
import java.util.Map;
|
|
/**
|
* URL工具类,用于构造请求物联网控制台接口的URL
|
*/
|
public class UrlUtils {
|
|
/**
|
* http(s)://iot-api.unisoft.cn/{AppID}/{接口列表中的path}/?{其他参数}&sign={sign}&ts={ts}
|
*
|
* sign 签名 所有请求物联网控制台接口,均需在url中携带此参数sign={sign}
|
* 取值方法:md5(md5(开发者密码) + 上面的ts参数),32位字符串
|
* ts 时间戳 所有请求物联网控制台接口,均需在url中携带此参数ts={timestap}
|
* 取值方法:请求时间(timezone,东八区),10位数字
|
*/
|
public static void main(String[] args) {
|
System.out.println(getUrl(BASE_URL,APP_ID,APP_SECRET, DeviceRequestUrlEnum.DEVICE_CONTROL.getRequestUrl(), null));
|
LinkedHashMap<String, Object> parameters = new LinkedHashMap<>();
|
parameters.put("group", "123456789");
|
parameters.put("product", "test");
|
System.out.println(getUrl(BASE_URL,APP_ID,APP_SECRET,"device/info",parameters));
|
}
|
// todo 优化到后台配置中
|
public static final String BASE_URL = " http://iot-api.unisoft.cn/rtyVWcgmlr";
|
public static final String APP_ID = "rtyVWcgmlr";
|
public static final String APP_SECRET = "rtyVWcgmlr";
|
/**
|
* 构造请求物联网控制台接口的URL
|
*
|
* @param baseUrl 基础URL地址
|
* @param appId 应用ID,用于标识应用
|
* @param appSecret 应用密钥,用于生成签名
|
* @param requestPath 请求路径,标识具体的接口
|
* @param parameters 请求参数,包含除sign和ts之外的其他参数
|
* @return 返回构造完成的URL字符串
|
*
|
* 该方法首先会构建基础URL,然后添加appId和请求路径,接着添加其他参数,
|
* 最后通过appSecret和时间戳生成签名(sign),以及添加时间戳(ts)到URL中。
|
*/
|
public static String getUrl(String baseUrl,
|
String appId,
|
String appSecret,
|
String requestPath,
|
LinkedHashMap<String, Object> parameters){
|
StringBuilder fullUrl = new StringBuilder(baseUrl);
|
// fullUrl.append("/"+appId);
|
fullUrl.append(requestPath);
|
fullUrl.append("?");
|
//判断parameters参数是否为空,不为空则拼接在fullUrl
|
parametersSetToUrl(fullUrl,parameters);
|
getSignAndTs(appSecret,fullUrl,parameters);
|
return fullUrl.toString();
|
}
|
|
/**
|
* 将查询参数附加到URL路径上
|
* 此方法接受一个URL路径和一个查询参数的映射,然后将这些参数附加到URL路径上
|
* 如果没有查询参数,URL路径保持不变
|
*
|
* @param urlPath URL路径的StringBuilder对象,用于构建最终的URL
|
* @param parameters 查询参数的LinkedHashMap,键为参数名,值为参数值
|
* @return 返回包含查询参数的URL路径的StringBuilder对象
|
*/
|
public static StringBuilder parametersSetToUrl(StringBuilder urlPath, LinkedHashMap<String, Object> parameters) {
|
// 检查参数是否为空,如果为空则直接返回URL路径
|
if (parameters == null || parameters.isEmpty()) {
|
return urlPath;
|
}
|
joinQueryParameters(urlPath, parameters);
|
// 返回包含查询参数的URL路径
|
return urlPath;
|
}
|
|
/**
|
* 将查询参数拼接到URL路径后
|
*
|
* @param urlPath URL路径
|
* @param parameters 查询参数
|
* @return 拼接后的URL路径
|
*/
|
public static StringBuilder joinQueryParameters(StringBuilder urlPath, LinkedHashMap<String, Object> parameters) {
|
if (parameters == null || parameters.isEmpty()) {
|
return urlPath;
|
}
|
|
boolean isFirst = true;
|
for (Map.Entry<String, Object> mapElement : parameters.entrySet()) {
|
Object value = mapElement.getValue();
|
// 根据是否是第一个参数来决定是否添加&
|
if (isFirst) {
|
isFirst = false;
|
} else {
|
urlPath.append('&');
|
}
|
|
// 拼接参数到URL路径
|
urlPath.append(mapElement.getKey())
|
.append('=')
|
.append(urlEncode(value.toString()));
|
}
|
return urlPath;
|
}
|
|
/**
|
* 对URL参数进行编码
|
*
|
* @param s 参数字符串
|
* @return 编码后的参数字符串
|
*/
|
public static String urlEncode(String s) {
|
try {
|
return URLEncoder.encode(s, StandardCharsets.UTF_8.name());
|
} catch (UnsupportedEncodingException e) {
|
throw new RuntimeException(StandardCharsets.UTF_8.name() + " is unsupported", e);
|
}
|
}
|
|
|
|
/**
|
* 生成签名和时间戳参数
|
* 该方法用于给定的URL路径添加签名(sign)和时间戳(ts)参数,以确保请求的安全性和有效性
|
* 签名是通过将appSecret进行MD5加密,然后与当前时间戳拼接后再进行MD5加密生成
|
* 这种方法确保了每个请求都有一个唯一的、基于时间的签名,从而防止了重放攻击
|
*
|
* @param appSecret 应用密钥,用于生成签名
|
* @param urlPath StringBuilder对象,用于拼接URL路径和查询参数
|
* @param parameters 请求参数,用于判断是否需要添加额外的连接符
|
* @return 返回包含签名和时间戳参数的URL路径字符串
|
*/
|
public static String getSignAndTs(String appSecret,StringBuilder urlPath, LinkedHashMap<String, Object> parameters) {
|
//使用MD5加密appSecret
|
String md5AppSecret = SecureUtil.md5(appSecret);
|
//获取当前时间戳
|
String timestamp = String.valueOf(DateUtil.currentSeconds());
|
//生成sign参数,通过md5加密(appSecret的md5值 + 时间戳)
|
String md5Sign = SecureUtil.md5(md5AppSecret + timestamp);
|
//返回包含sign和ts参数的字符串
|
if (CollUtil.isNotEmpty(parameters)) {
|
urlPath.append("&");
|
}
|
urlPath.append("sign=");
|
urlPath.append(md5Sign);
|
urlPath.append("&ts=");
|
urlPath.append(timestamp);
|
return urlPath.toString();
|
}
|
|
}
|