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 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 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 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 parameters) { if (parameters == null || parameters.isEmpty()) { return urlPath; } boolean isFirst = true; for (Map.Entry 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 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(); } }