From 2147ca2f66dd5ff83db5080988f4832bd10ac213 Mon Sep 17 00:00:00 2001 From: KKSU <15274802129@163.com> Date: Fri, 15 Nov 2024 14:42:09 +0800 Subject: [PATCH] feat(unisoftiot): 新增设备和产品相关功能 --- src/main/java/cc/mrbird/febs/unisoftiot/config/RequestBuilder.java | 72 + src/main/java/cc/mrbird/febs/FebsShiroApplication.java | 2 src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Account.java | 11 src/main/resources/application-prod.yml | 14 src/main/java/cc/mrbird/febs/unisoftiot/enums/DeviceRequestUrlEnum.java | 59 + pom.xml | 6 src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/ProductServiceImpl.java | 41 + src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/InitAccountServiceImpl.java | 28 src/main/java/cc/mrbird/febs/unisoftiot/api/service/DeviceService.java | 10 src/main/java/cc/mrbird/febs/unisoftiot/enums/ResponseCodeEnum.java | 92 ++ src/main/java/cc/mrbird/febs/unisoftiot/api/vo/ApiProductVo.java | 35 src/main/java/cc/mrbird/febs/unisoftiot/enums/ProductRequestUrlEnum.java | 27 src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Product.java | 39 + src/main/java/cc/mrbird/febs/unisoftiot/config/ResponseHandler.java | 104 ++ src/main/java/cc/mrbird/febs/unisoftiot/enums/HttpMethod.java | 9 src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/ProductMapper.java | 7 src/main/java/cc/mrbird/febs/unisoftiot/api/service/InitAccountService.java | 12 src/main/java/cc/mrbird/febs/unisoftiot/config/UniSoftAccount.java | 34 src/main/java/cc/mrbird/febs/unisoftiot/api/service/ProductService.java | 15 src/main/java/cc/mrbird/febs/unisoftiot/utils/OkHttpUtils.java | 330 ++++++++ src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/AccountMapper.java | 7 src/main/java/cc/mrbird/febs/unisoftiot/config/RequestHandler.java | 105 ++ /dev/null | 976 ------------------------- src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Device.java | 9 src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/DeviceServiceImpl.java | 53 + src/main/java/cc/mrbird/febs/unisoftiot/utils/JSONParser.java | 39 + src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/DeviceMapper.java | 7 src/main/java/cc/mrbird/febs/unisoftiot/utils/UrlUtils.java | 160 ++++ 28 files changed, 1,319 insertions(+), 984 deletions(-) diff --git a/pom.xml b/pom.xml index af6a5ee..29148a4 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,12 @@ </properties> <dependencies> + + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20230618</version> + </dependency> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> diff --git a/src/main/java/cc/mrbird/febs/FebsShiroApplication.java b/src/main/java/cc/mrbird/febs/FebsShiroApplication.java index 0983d5c..1ae9fe7 100644 --- a/src/main/java/cc/mrbird/febs/FebsShiroApplication.java +++ b/src/main/java/cc/mrbird/febs/FebsShiroApplication.java @@ -20,7 +20,7 @@ @EnableScheduling @SpringBootApplication @EnableTransactionManagement -@MapperScan("cc.mrbird.febs.*.mapper") +@MapperScan({"cc.mrbird.febs.*.mapper", "cc.mrbird.febs.unisoftiot.*.mapper"}) public class FebsShiroApplication { public static void main(String[] args) { diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Account.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Account.java new file mode 100644 index 0000000..8a9b5a1 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Account.java @@ -0,0 +1,11 @@ +package cc.mrbird.febs.unisoftiot.api.entity; + +import lombok.Data; + +@Data +public class Account { + + private String appId; + + private String appSecret; +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Device.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Device.java new file mode 100644 index 0000000..823d648 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Device.java @@ -0,0 +1,9 @@ +package cc.mrbird.febs.unisoftiot.api.entity; + +import lombok.Data; + +@Data +public class Device { + + private String deviceId; +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Product.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Product.java new file mode 100644 index 0000000..0713360 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/entity/Product.java @@ -0,0 +1,39 @@ +package cc.mrbird.febs.unisoftiot.api.entity; + +import lombok.Data; + +/** + * Product类代表一个产品实体,用于在平台中存储和管理产品相关信息 + * 它包含了产品的基本属性,如产品ID、型号、名称、图标、生产商、设备数量和备注 + */ +@Data +public class Product { + /** + * 产品ID,平台唯一,固定不变 + */ + private int id; + /** + * 产品型号 + */ + private String model; + /** + * 产品名称 + */ + private String title; + /** + * 产品图标 + */ + private String icon; + /** + * 生产商,Unisoft或自定义 + */ + private String producer; + /** + * 工作台(控制台)下此产品类型的设备数量 + */ + private Integer device; + /** + * 备注 + */ + private String remark; +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/AccountMapper.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/AccountMapper.java new file mode 100644 index 0000000..fe5a8fd --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/AccountMapper.java @@ -0,0 +1,7 @@ +package cc.mrbird.febs.unisoftiot.api.mapper; + +import cc.mrbird.febs.unisoftiot.api.entity.Account; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface AccountMapper extends BaseMapper<Account> { +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/DeviceMapper.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/DeviceMapper.java new file mode 100644 index 0000000..c489e51 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/DeviceMapper.java @@ -0,0 +1,7 @@ +package cc.mrbird.febs.unisoftiot.api.mapper; + +import cc.mrbird.febs.unisoftiot.api.entity.Device; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface DeviceMapper extends BaseMapper<Device> { +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/ProductMapper.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/ProductMapper.java new file mode 100644 index 0000000..1064e2e --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/mapper/ProductMapper.java @@ -0,0 +1,7 @@ +package cc.mrbird.febs.unisoftiot.api.mapper; + +import cc.mrbird.febs.unisoftiot.api.entity.Product; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface ProductMapper extends BaseMapper<Product> { +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/DeviceService.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/DeviceService.java new file mode 100644 index 0000000..61ed61a --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/DeviceService.java @@ -0,0 +1,10 @@ +package cc.mrbird.febs.unisoftiot.api.service; + +import cc.mrbird.febs.unisoftiot.api.entity.Device; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface DeviceService extends IService<Device> { + + //控制设备,向设备下发指令 + String controlDevice(Device device); +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/InitAccountService.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/InitAccountService.java new file mode 100644 index 0000000..78bb1b9 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/InitAccountService.java @@ -0,0 +1,12 @@ +package cc.mrbird.febs.unisoftiot.api.service; + +import cc.mrbird.febs.unisoftiot.api.entity.Account; +import cc.mrbird.febs.unisoftiot.config.UniSoftAccount; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface InitAccountService extends IService<Account> { + + UniSoftAccount initAccount(Account account); + + UniSoftAccount initAccountByAppInfo(String appId, String appSecret); +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/ProductService.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/ProductService.java new file mode 100644 index 0000000..56643e6 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/ProductService.java @@ -0,0 +1,15 @@ +package cc.mrbird.febs.unisoftiot.api.service; + +import cc.mrbird.febs.unisoftiot.api.entity.Product; +import cc.mrbird.febs.unisoftiot.api.vo.ApiProductVo; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +public interface ProductService extends IService<Product> { + + /** + * 获取产品列表 + */ + List<ApiProductVo> getProductList(); +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/DeviceServiceImpl.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/DeviceServiceImpl.java new file mode 100644 index 0000000..d07bd5d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/DeviceServiceImpl.java @@ -0,0 +1,53 @@ +package cc.mrbird.febs.unisoftiot.api.service.impl; + +import cc.mrbird.febs.unisoftiot.api.entity.Account; +import cc.mrbird.febs.unisoftiot.api.entity.Device; +import cc.mrbird.febs.unisoftiot.api.mapper.DeviceMapper; +import cc.mrbird.febs.unisoftiot.api.service.DeviceService; +import cc.mrbird.febs.unisoftiot.api.service.InitAccountService; +import cc.mrbird.febs.unisoftiot.config.UniSoftAccount; +import cc.mrbird.febs.unisoftiot.enums.DeviceRequestUrlEnum; +import cc.mrbird.febs.unisoftiot.utils.UrlUtils; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService { + + private final InitAccountService initAccountService; + + /** + * 控制设备的方法 + * 该方法用于向设备发送控制指令,例如开关设备等 + * + * @param device 设备对象,包含设备的相关信息 + * @return 返回控制设备的结果,以字符串形式表示 + */ + @Override + public String controlDevice(Device device) { + // 初始化账户服务,为设备控制做准备 + UniSoftAccount uniSoftAccount = initAccountService.initAccountByAppInfo(UrlUtils.APP_ID,UrlUtils.APP_SECRET); + + // 创建参数集合,用于设备控制 + LinkedHashMap<String, Object> parameters = new LinkedHashMap<>(); + // 添加控制设备的参数,这里的例子是开启设备的某个功能 + parameters.put("device", "1438"); + parameters.put("power3", "1"); + + log.info("parameters",parameters.toString()); + + // 发送签名请求,控制设备 + // 这里使用了签名请求来确保设备控制指令的安全性 + return uniSoftAccount.requestHandler.sendSignedRequest( + UrlUtils.BASE_URL, + DeviceRequestUrlEnum.DEVICE_CONTROL.getRequestUrl(), + parameters, + DeviceRequestUrlEnum.DEVICE_CONTROL.getRequestMethod()); + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/InitAccountServiceImpl.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/InitAccountServiceImpl.java new file mode 100644 index 0000000..47bd3ab --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/InitAccountServiceImpl.java @@ -0,0 +1,28 @@ +package cc.mrbird.febs.unisoftiot.api.service.impl; + +import cc.mrbird.febs.unisoftiot.api.service.InitAccountService; +import cc.mrbird.febs.unisoftiot.api.entity.Account; +import cc.mrbird.febs.unisoftiot.api.mapper.AccountMapper; +import cc.mrbird.febs.unisoftiot.config.UniSoftAccount; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class InitAccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements InitAccountService { + @Override + public UniSoftAccount initAccount(Account account) { + return new UniSoftAccount(account.getAppId(),account.getAppSecret()); + } + + @Override + public UniSoftAccount initAccountByAppInfo(String appId, String appSecret) { + Account account = new Account(); + account.setAppId(appId); + account.setAppSecret(appSecret); + return this.initAccount(account); + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/ProductServiceImpl.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/ProductServiceImpl.java new file mode 100644 index 0000000..e084c7c --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/service/impl/ProductServiceImpl.java @@ -0,0 +1,41 @@ +package cc.mrbird.febs.unisoftiot.api.service.impl; + +import cc.mrbird.febs.unisoftiot.api.entity.Product; +import cc.mrbird.febs.unisoftiot.api.mapper.ProductMapper; +import cc.mrbird.febs.unisoftiot.api.service.InitAccountService; +import cc.mrbird.febs.unisoftiot.api.service.ProductService; +import cc.mrbird.febs.unisoftiot.api.vo.ApiProductVo; +import cc.mrbird.febs.unisoftiot.config.UniSoftAccount; +import cc.mrbird.febs.unisoftiot.enums.ProductRequestUrlEnum; +import cc.mrbird.febs.unisoftiot.utils.UrlUtils; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService { + + private final InitAccountService initAccountService; + @Override + public List<ApiProductVo> getProductList() { + UniSoftAccount uniSoftAccount = initAccountService.initAccountByAppInfo(UrlUtils.APP_ID, UrlUtils.APP_SECRET); + + // 创建参数集合 + LinkedHashMap<String, Object> parameters = new LinkedHashMap<>(); + parameters.put("q", 1); + String bodyStr = uniSoftAccount.requestHandler.sendSignedRequest( + UrlUtils.BASE_URL, ProductRequestUrlEnum.PRODUCT_LIST.getRequestUrl(), + parameters, ProductRequestUrlEnum.PRODUCT_LIST.getRequestMethod()); + + JSONObject jsonObject = JSONUtil.parseObj(bodyStr); + return jsonObject.getJSONArray("data").toList(ApiProductVo.class); + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/api/vo/ApiProductVo.java b/src/main/java/cc/mrbird/febs/unisoftiot/api/vo/ApiProductVo.java new file mode 100644 index 0000000..6064ba1 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/api/vo/ApiProductVo.java @@ -0,0 +1,35 @@ +package cc.mrbird.febs.unisoftiot.api.vo; + +import lombok.Data; + +@Data +public class ApiProductVo { + /** + * 产品ID,平台唯一,固定不变 + */ + private int id; + /** + * 产品型号 + */ + private String model; + /** + * 产品名称 + */ + private String title; + /** + * 产品图标 + */ + private String icon; + /** + * 生产商,Unisoft或自定义 + */ + private String producer; + /** + * 工作台(控制台)下此产品类型的设备数量 + */ + private Integer device; + /** + * 备注 + */ + private String remark; +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestBuilder.java b/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestBuilder.java new file mode 100644 index 0000000..b01c90e --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestBuilder.java @@ -0,0 +1,72 @@ +package cc.mrbird.febs.unisoftiot.config; + +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.unisoftiot.enums.HttpMethod; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; + +/** + * 请求构建器类,用于构建HTTP请求 + */ +public final class RequestBuilder { + + // 定义JSON类型的媒体类型常量 + private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8"); + + // 私有构造方法,防止实例化 + private RequestBuilder() { + } + + /** + * 根据提供的参数构建HTTP请求 + * + * @param fullUrl 完整的请求URL + * @param body 请求体内容 + * @param httpMethod HTTP方法枚举类型 + * @return 构建好的Request对象 + * @throws FebsException 如果URL无效或HTTP方法不支持,则抛出此异常 + */ + public static Request buildRequest(String fullUrl, String body, HttpMethod httpMethod) { + // 校验 URL + if (fullUrl == null || fullUrl.isEmpty()) { + throw new FebsException("Invalid URL: URL cannot be null or empty"); + } + + // 创建Request.Builder对象用于配置请求 + Request.Builder builder = new Request.Builder(); + try { + // 根据HTTP方法构建不同的请求 + final Request request; + switch (httpMethod) { + case POST: + // 构建POST请求,并设置请求体为JSON类型 + request = builder + .url(fullUrl) + .post(RequestBody.create(JSON_TYPE, body)) + .addHeader("X-APISpace-Token","") + .addHeader("Content-Type","") + .build(); + break; + case GET: + // 构建GET请求 + request = builder + .url(fullUrl) + .get() + .addHeader("Content-Type", "application/x-www-form-urlencoded") + .build(); + break; + default: + // 如果HTTP方法不支持,抛出异常 + throw new FebsException("Invalid HTTP method: " + httpMethod); + } + // 返回构建好的请求对象 + return request; + } catch (IllegalArgumentException e) { + // 如果URL格式错误,抛出异常 + throw new FebsException("Invalid URL: " + e.getMessage()); + } + } + + +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestHandler.java b/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestHandler.java new file mode 100644 index 0000000..b53356f --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/config/RequestHandler.java @@ -0,0 +1,105 @@ +package cc.mrbird.febs.unisoftiot.config; + +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.unisoftiot.enums.HttpMethod; +import cc.mrbird.febs.unisoftiot.utils.UrlUtils; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import okhttp3.Request; + +import java.util.LinkedHashMap; + +/** + * 请求处理器类,用于构建和发送API请求 + */ +@Slf4j +public class RequestHandler { + + private String appId; + private String appSecret; + + /** + * 构造函数,初始化appId和appSecret + * + * @param appId 应用ID + * @param appSecret 应用密钥 + */ + public RequestHandler(String appId,String appSecret){ + this.appId = appId; + this.appSecret = appSecret; + } + + /** + * 发送API请求 + * + * @param baseUrl 基础URL + * @param urlPath URL路径 + * @param parameters 请求参数 + * @param httpMethod HTTP方法 + * @return 请求结果字符串 + * @throws FebsException 当HTTP方法不支持时抛出异常 + */ + private String sendApiRequest(String baseUrl, + String urlPath, + LinkedHashMap<String, Object> parametersw, + HttpMethod httpMethod) { + + // 创建参数集合,用于设备控制 + LinkedHashMap<String, Object> parameters = new LinkedHashMap<>(); + // 添加控制设备的参数,这里的例子是开启设备的某个功能 + parameters.put("device", "1438"); + parameters.put("power3", "1"); + log.info("parameters",parameters.toString()); + String fullUrl = ""; + Request request; + // 根据HTTP方法构建请求 + switch (httpMethod) { + case POST: + // 对于POST请求,将参数序列化为JSON体 + fullUrl = UrlUtils.getUrl(baseUrl,appId,appSecret,urlPath,null); + String body = JSON.toJSONString(parameters); + log.info("parametersJson:", JSONUtil.parseObj(parameters)); + log.info("body:",body); + request = RequestBuilder.buildRequest(fullUrl, body,httpMethod); + break; + case GET: + // 对于GET请求,将参数直接拼接到URL中 + fullUrl = UrlUtils.getUrl(baseUrl,appId,appSecret,urlPath,parameters); + request = RequestBuilder.buildRequest(fullUrl, null,httpMethod); + break; + default: + // 不支持的HTTP方法抛出异常 + throw new FebsException("[RequestHandler] HttpMethod 不支持: " + httpMethod); + } + + // 记录请求信息 + log.info("{} {}", httpMethod, fullUrl); + + // 发送请求并处理响应 + return ResponseHandler.handleResponse(request); + } + + /** + * 发送签名请求,确保appId和appSecret不为空 + * + * @param baseUrl 基础URL + * @param urlPath URL路径 + * @param parameters 请求参数 + * @param httpMethod HTTP方法 + * @return 请求结果字符串 + * @throws FebsException 当appId或appSecret为空时抛出异常 + */ + public String sendSignedRequest(String baseUrl, + String urlPath, + LinkedHashMap<String, Object> parameters, + HttpMethod httpMethod) { + // 校验appId和appSecret + if (null == appId || appId.isEmpty() || null == appSecret || appSecret.isEmpty()) { + throw new FebsException("[RequestHandler] appId/appSecret 不能为空!"); + } + // 调用sendApiRequest方法发送请求 + return sendApiRequest(baseUrl, urlPath, parameters, httpMethod); + } + +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/config/ResponseHandler.java b/src/main/java/cc/mrbird/febs/unisoftiot/config/ResponseHandler.java new file mode 100644 index 0000000..8f71e63 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/config/ResponseHandler.java @@ -0,0 +1,104 @@ +package cc.mrbird.febs.unisoftiot.config; + +import cc.mrbird.febs.common.exception.FebsException; +import cc.mrbird.febs.unisoftiot.enums.ResponseCodeEnum; +import cc.mrbird.febs.unisoftiot.utils.OkHttpUtils; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONObject; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import org.json.JSONException; + +import java.io.IOException; + +/** + * 响应处理器类,用于处理OKHTTP请求的响应 + */ +public final class ResponseHandler { + + // 错误信息前缀 + private static final String ERROR_PREFIX = "[ResponseHandler] OKHTTP Error: "; + + // 私有构造方法,防止实例化 + private ResponseHandler() { + } + + /** + * 处理HTTP响应 + * @param request 请求对象 + * @return 响应体字符串 + * @throws FebsException 当响应处理失败时抛出 + */ + public static String handleResponse(Request request) { + try ( + // 执行HTTP请求并获取响应 + Response response = OkHttpUtils.builder().okHttpClient.newCall(request).execute() + ) { + // 获取响应体内容 + String responseBodyStr = getResponseBodyAsString(response.body()); + if (ResponseCodeEnum.isFail(response.code())) { + throw new FebsException(ERROR_PREFIX + responseBodyStr); + } + // 如果响应内容为空,则抛出异常 + if(StrUtil.isEmpty(responseBodyStr)){ + throw new FebsException(ERROR_PREFIX + "请求返回参数为空"); + } + // 解析响应内容为JSON对象 + JSONObject jsonObject = new JSONObject(responseBodyStr); + // 获取响应码 + int code = jsonObject.getInt("code"); + // 如果响应码表示失败,则处理错误响应 + if(ResponseCodeEnum.isFail(code)){ + throw handleErrorResponse(code, responseBodyStr); + } + // 获取响应消息 + String msg = jsonObject.getStr("msg"); + // 如果响应消息不正确,则抛出异常 + if(!ResponseCodeEnum.SUCCESS.getMsg().equals(msg)){ + throw new FebsException(ERROR_PREFIX + "请求返回参数msg不正确"); + } + // 返回响应内容 + return responseBodyStr; + } catch (IOException | IllegalStateException | JSONException e) { + // 捕获异常并抛出自定义异常 + throw new FebsException(ERROR_PREFIX + e.getMessage()); + } + } + + /** + * 处理错误响应 + * @param code 响应码 + * @param responseBodyStr 响应体字符串 + * @return 自定义异常 + * @throws JSONException 当JSON解析失败时抛出 + */ + private static FebsException handleErrorResponse(int code, String responseBodyStr) { + try { + // 获取错误描述和消息 + String desc = ResponseCodeEnum.getDesc(code); + String msg = ResponseCodeEnum.getMsg(code); + // 构造并返回自定义异常 + return new FebsException(ERROR_PREFIX + "{" + msg + "},{" + desc + "}"); + } catch (JSONException e) { + // 如果JSON解析失败,构造并返回自定义异常 + throw new FebsException(ERROR_PREFIX + "{" + responseBodyStr + "}"); + } + } + + /** + * 获取响应体内容作为字符串 + * @param body 响应体 + * @return 响应体字符串 + * @throws IOException 当读取响应体失败时抛出 + */ + private static String getResponseBodyAsString(ResponseBody body) throws IOException { + if (body != null) { + // 如果响应体不为空,读取并返回内容 + return body.string(); + } else { + // 如果响应体为空,返回空字符串 + return ""; + } + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/config/UniSoftAccount.java b/src/main/java/cc/mrbird/febs/unisoftiot/config/UniSoftAccount.java new file mode 100644 index 0000000..4a96e3d --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/config/UniSoftAccount.java @@ -0,0 +1,34 @@ +package cc.mrbird.febs.unisoftiot.config; + +import lombok.Data; + +/** + * 类说明:统一软账号配置类 + * 字段说明: + * - appId: 应用ID,用于标识一个应用 + * - appSecret: 应用密钥,用于验证应用的身份 + * - requestHandler: 处理HTTP请求的处理器,用于封装HTTP请求的处理逻辑 + */ +@Data +public class UniSoftAccount { + + private String appId; + + private String appSecret; + + // 处理HTTP请求的处理器 + public RequestHandler requestHandler; + + /** + * 构造方法说明:初始化UniSoftAccount实例 + * 参数说明: + * - appId: 应用ID,用于标识一个应用 + * - appSecret: 应用密钥,用于验证应用的身份 + * - requestHandler: 处理HTTP请求的处理器,用于封装HTTP请求的处理逻辑 + */ + public UniSoftAccount(String appId, String appSecret){ + this.appId = appId; + this.appSecret = appSecret; + this.requestHandler = new RequestHandler(appId, appSecret); + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/enums/DeviceRequestUrlEnum.java b/src/main/java/cc/mrbird/febs/unisoftiot/enums/DeviceRequestUrlEnum.java new file mode 100644 index 0000000..1797772 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/enums/DeviceRequestUrlEnum.java @@ -0,0 +1,59 @@ +package cc.mrbird.febs.unisoftiot.enums; + +import lombok.Getter; + +/** + * 设备请求URL枚举类 + * 用于定义与设备相关的API请求的URL和方法 + */ +@Getter +public enum DeviceRequestUrlEnum { + + /** + * 设备控制请求配置 + * 使用POST方法发送设备控制指令 + */ + DEVICE_CONTROL(HttpMethod.POST,"/device/control"), + + /** + * 设备分组请求配置 + * 使用POST方法对设备进行分组操作 + */ + DEVICE_GROUP(HttpMethod.POST,"/device/group"), + + /** + * 设备标签请求配置 + * 使用POST方法添加或修改设备标签 + */ + DEVICE_TAG(HttpMethod.POST,"/device/tag"), + + /** + * 设备列表请求配置 + * 使用POST方法获取设备列表 + */ + DEVICE_LIST(HttpMethod.POST,"/device/list"), + + /** + * 设备信息请求配置 + * 使用POST方法获取特定设备的信息 + */ + DEVICE_INFO(HttpMethod.POST,"/device/info"); + + // 请求方法,如POST、GET等 + private HttpMethod requestMethod; + + // 请求的URL路径 + private String requestUrl; + + /** + * 构造函数,初始化设备请求的URL和方法 + * + * @param requestMethod HTTP请求方法,例如POST + * @param requestUrl HTTP请求的URL路径 + */ + DeviceRequestUrlEnum(HttpMethod requestMethod, String requestUrl) { + this.requestMethod = requestMethod; + this.requestUrl = requestUrl; + } + +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/enums/HttpMethod.java b/src/main/java/cc/mrbird/febs/unisoftiot/enums/HttpMethod.java new file mode 100644 index 0000000..82d53b4 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/enums/HttpMethod.java @@ -0,0 +1,9 @@ +package cc.mrbird.febs.unisoftiot.enums; + +public enum HttpMethod { + POST, + GET, + PUT, + DELETE, + INVALID +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/enums/ProductRequestUrlEnum.java b/src/main/java/cc/mrbird/febs/unisoftiot/enums/ProductRequestUrlEnum.java new file mode 100644 index 0000000..d83a02e --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/enums/ProductRequestUrlEnum.java @@ -0,0 +1,27 @@ +package cc.mrbird.febs.unisoftiot.enums; + +import lombok.Getter; + +@Getter +public enum ProductRequestUrlEnum { + + + PRODUCT_LIST(HttpMethod.POST,"/product/list"); + + // 请求方法,如POST、GET等 + private HttpMethod requestMethod; + + // 请求的URL路径 + private String requestUrl; + + /** + * 构造函数,初始化设备请求的URL和方法 + * + * @param requestMethod HTTP请求方法,例如POST + * @param requestUrl HTTP请求的URL路径 + */ + ProductRequestUrlEnum(HttpMethod requestMethod, String requestUrl) { + this.requestMethod = requestMethod; + this.requestUrl = requestUrl; + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/enums/ResponseCodeEnum.java b/src/main/java/cc/mrbird/febs/unisoftiot/enums/ResponseCodeEnum.java new file mode 100644 index 0000000..953b036 --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/enums/ResponseCodeEnum.java @@ -0,0 +1,92 @@ +package cc.mrbird.febs.unisoftiot.enums; + +import lombok.Getter; + +/** + * 响应码枚举类,用于定义API响应的各种状态码及其含义 + */ +@Getter +public enum ResponseCodeEnum { + + // 定义各种错误响应码和成功响应码 + FAIL_5009(5009, "too many request", "单个设备访问最高限制1次/秒,请勿超过此限制"), + FAIL_5008(5008, "ip:*.*.*.* is not in white list", "开启了IP检查,但接口访问IP不在白名单内,请在控制台的开发设置中,将IP加入白名单"), + FAIL_5007(5007, "bad debug key", "指定了debug参数,但未开启调试模式,或者是debug参数不正确或已过期"), + FAIL_5006(5006, "bad sign", "签名错误,正确签名为 md5(md5(开发者密码) + (url中的ts参数))"), + FAIL_5005(5005, "please set app secret", "未设置开发者密码,请在控制台的开发设置中进行设置"), + FAIL_5004(5004, "miss param sign", "请在请求接口中指定sign(签名),这是一个计算值"), + FAIL_5003(5003, "bad ts", "时间戳错误,ts为请求发生时的时间,是一个动态的值,必须为中国时间"), + FAIL_5002(5002, "miss param ts", "请在请求接口中指定ts(时间戳),取值为请求时的时间戳,10位数字"), + FAIL_5001(5001, "miss app id", "请求地址为 https://iot-api.unisoft.cn/{APPID}/,缺少{APPID},请在控制台查看您的appid"), + SUCCESS(200, "ok", ""); + + // 响应码 + private int code; + // 简短消息 + private String msg; + // 描述信息 + private String desc; + + /** + * 构造函数,初始化响应码、消息和描述 + * + * @param code 响应码 + * @param msg 简短消息 + * @param desc 描述信息 + */ + ResponseCodeEnum(int code, String msg, String desc) { + this.code = code; + this.msg = msg; + this.desc = desc; + } + + /** + * 根据响应代码获取描述信息 + * 该方法用于将系统内部的响应代码转换为人类可读的描述信息 + * 主要通过遍历枚举类ResponseCodeEnum来匹配传入的代码,并返回对应的描述 + * 如果没有找到匹配的代码,则返回空字符串 + * + * @param code 响应代码,用于查找对应的描述信息 + * @return 描述信息如果找到匹配的代码,否则返回空字符串 + */ + public static String getDesc(int code) { + for (ResponseCodeEnum item : ResponseCodeEnum.values()) { + if (item.getCode() == code) { + return item.getDesc(); + } + } + return ""; + } + + /** + * 根据响应代码获取消息信息 + * 该方法用于将系统内部的响应代码转换为消息信息 + * 主要通过遍历枚举类ResponseCodeEnum来匹配传入的代码,并返回对应的消息 + * 如果没有找到匹配的代码,则返回空字符串 + * + * @param code 响应代码,用于查找对应的消息信息 + * @return 消息信息如果找到匹配的代码,否则返回空字符串 + */ + public static String getMsg(int code) { + for (ResponseCodeEnum item : ResponseCodeEnum.values()) { + if (item.getCode() == code) { + return item.getMsg(); + } + } + return ""; + } + /** + * 验证响应码是200 + */ + public static boolean isSuccess(int code) { + return SUCCESS.getCode() == code; + } + + /** + * 验证响应码不是200 + */ + public static boolean isFail(int code) { + return !isSuccess(code); + } + +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/utils/JSONParser.java b/src/main/java/cc/mrbird/febs/unisoftiot/utils/JSONParser.java new file mode 100644 index 0000000..49d066b --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/utils/JSONParser.java @@ -0,0 +1,39 @@ +package cc.mrbird.febs.unisoftiot.utils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import java.util.ArrayList; + +public final class JSONParser { + + private JSONParser() { + } + + public static String getJSONStringValue(String json, String key) { + try { + JSONObject obj = new JSONObject(json); + return obj.getString(key); + } catch (JSONException e) { + throw new JSONException(String.format("[JSONParser] Failed to get \"%s\" from JSON object", key)); + } + } + + public static int getJSONIntValue(String json, String key) { + try { + JSONObject obj = new JSONObject(json); + return obj.getInt(key); + } catch (JSONException e) { + throw new JSONException(String.format("[JSONParser] Failed to get \"%s\" from JSON object", key)); + } + } + + public static String getJSONArray(ArrayList<?> symbols, String key) { + try { + JSONArray arr = new JSONArray(symbols); + return arr.toString(); + } catch (JSONException e) { + throw new JSONException(String.format("[JSONParser] Failed to convert \"%s\" to JSON array", key)); + } + } +} diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/utils/OkHttpUtils.java b/src/main/java/cc/mrbird/febs/unisoftiot/utils/OkHttpUtils.java new file mode 100644 index 0000000..39066ac --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/utils/OkHttpUtils.java @@ -0,0 +1,330 @@ +package cc.mrbird.febs.unisoftiot.utils; + +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.json.JSONObject; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.net.URLEncoder; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +/** + * OkHttp请求工具封装 + * 参考:https://blog.csdn.net/DwZ735660836/article/details/119976068 + */ +@Slf4j +public class OkHttpUtils { + public static volatile OkHttpClient okHttpClient = null; + private static volatile Semaphore semaphore = null; + private Map<String, String> headerMap; + private Map<String, String> paramMap; + private String url; + private Request.Builder request; + // 开发环境用的 ShadowsocksR-dotnet4.0 免费版本 正式环境得使用外网服务器 + // 安易代理 http://127.0.0.1:10809/ http://127.0.0.1:10808/ + + /** + * 初始化okHttpClient,并且允许https访问 + */ + private OkHttpUtils() { + if (okHttpClient == null) { + synchronized (OkHttpUtils.class) { + if (okHttpClient == null) { + TrustManager[] trustManagers = buildTrustManagers(); + okHttpClient = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .writeTimeout(20, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0]) + //.hostnameVerifier((hostName, session) -> true) + //配置自定义连接池参数 + .connectionPool(new ConnectionPool(5, 60, TimeUnit.SECONDS)) + .retryOnConnectionFailure(true) + .build(); + addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"); + addHeader("Connection", "close"); + addHeader("Accept-Encoding", "identity"); + } + } + } + } + + /** + * 用于异步请求时,控制访问线程数,返回结果 + * + * @return + */ + private static Semaphore getSemaphoreInstance() { + //只能1个线程同时访问 + synchronized (OkHttpUtils.class) { + if (semaphore == null) { + semaphore = new Semaphore(0); + } + } + return semaphore; + } + + /** + * 创建OkHttpUtils + * + * @return + */ + public static OkHttpUtils builder() { + return new OkHttpUtils(); + } + + /** + * 添加url + * + * @param url + * @return + */ + public OkHttpUtils url(String url) { + this.url = url; + return this; + } + + /** + * 添加参数 + * + * @param key 参数名 + * @param value 参数值 + * @return + */ + public OkHttpUtils addParam(String key, String value) { + if (paramMap == null) { + paramMap = new LinkedHashMap<>(16); + } + paramMap.put(key, value); + return this; + } + + /** + * 添加请求头 + * + * @param key 参数名 + * @param value 参数值 + * @return + */ + public OkHttpUtils addHeader(String key, String value) { + if (headerMap == null) { + headerMap = new LinkedHashMap<>(16); + } + headerMap.put(key, value); + return this; + } + + /** + * 初始化get方法 + * + * @return + */ + public OkHttpUtils get() { + request = new Request.Builder().get(); + StringBuilder urlBuilder = new StringBuilder(url); + if (paramMap != null) { + urlBuilder.append("?"); + try { + for (Map.Entry<String, String> entry : paramMap.entrySet()) { + urlBuilder.append(URLEncoder.encode(entry.getKey(), "utf-8")). + append("="). + append(URLEncoder.encode(entry.getValue(), "utf-8")). + append("&"); + } + } catch (Exception e) { + e.printStackTrace(); + } + urlBuilder.deleteCharAt(urlBuilder.length() - 1); + } + request.url(urlBuilder.toString()); + return this; + } + + /** + * 初始化post方法 + * + * @param isJsonPost true等于json的方式提交数据,类似postman里post方法的raw + * false等于普通的表单提交 + * @return + */ + public OkHttpUtils post(boolean isJsonPost) { + RequestBody requestBody; + if (isJsonPost) { + String json = ""; + if (paramMap != null) { + json = JSONObject.valueToString(paramMap); + } + requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json); + } else { + FormBody.Builder formBody = new FormBody.Builder(); + if (paramMap != null) { + paramMap.forEach(formBody::add); + } + requestBody = formBody.build(); + } + request = new Request.Builder().post(requestBody).url(url); + return this; + } + + /** + * 同步请求 + * + * @return + */ + public Request.Builder sync() { + return setHeader(request); + } + + /** + * 同步请求 + * + * @return + */ + public String syncStr() { + setHeader(request); + try { + Response response = okHttpClient.newCall(request.build()).execute(); + assert response.body() != null; + return response.body().string(); + } catch (IOException e) { + e.printStackTrace(); + return "请求失败:" + e.getMessage(); + } + } + + + /** + * 异步请求,有返回值 + */ + public String async() { + StringBuilder buffer = new StringBuilder(""); + setHeader(request); + okHttpClient.newCall(request.build()).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + buffer.append("请求出错:").append(e.getMessage()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + assert response.body() != null; + buffer.append(response.body().string()); + getSemaphoreInstance().release(); + } + }); + try { + getSemaphoreInstance().acquire(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return buffer.toString(); + } + + /** + * 异步请求,带有接口回调 + * + * @param callBack + */ + public void async(ICallBack callBack) { + setHeader(request); + okHttpClient.newCall(request.build()).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + callBack.onFailure(call, e.getMessage()); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + assert response.body() != null; + callBack.onSuccessful(call, response.body().string()); + } + }); + } + + /** + * 为request添加请求头 + * + * @param request + */ + private Request.Builder setHeader(Request.Builder request) { + if (headerMap != null) { + try { + for (Map.Entry<String, String> entry : headerMap.entrySet()) { + request.addHeader(entry.getKey(), entry.getValue()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return request; + } + + + /** + * 生成安全套接字工厂,用于https请求的证书跳过 + * + * @return + */ + private static SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) { + SSLSocketFactory ssfFactory = null; + try { + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, trustAllCerts, new SecureRandom()); + ssfFactory = sc.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + return ssfFactory; + } + + private static TrustManager[] buildTrustManagers() { + return new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + }; + } + + /** + * 自定义一个接口回调 + */ + public interface ICallBack { + + void onSuccessful(Call call, String data); + + void onFailure(Call call, String errorMsg); + + } + + public static void main(String[] args) { + String url = "https://api2.binance.com/api/v3/ticker/24hr?symbol=BNBUSDT&type=MINI"; + String result = OkHttpUtils.builder() + .url(url) + .addHeader("Content-Type", "application/x-www-form-urlencoded") + .get() + .syncStr(); + System.out.println(result); + } +} + + diff --git a/src/main/java/cc/mrbird/febs/unisoftiot/utils/UrlUtils.java b/src/main/java/cc/mrbird/febs/unisoftiot/utils/UrlUtils.java new file mode 100644 index 0000000..8601bcf --- /dev/null +++ b/src/main/java/cc/mrbird/febs/unisoftiot/utils/UrlUtils.java @@ -0,0 +1,160 @@ +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(); + } + +} diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index a610917..c540f3d 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -15,10 +15,10 @@ datasource: # 数据源-1,名称为 base base: - username: blnka - password: blnka!@#123 + username: db_e2 + password: db_e20806123!@# driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://127.0.0.1:3306/db_blnka?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 + url: jdbc:mysql://127.0.0.1:3306/db_e2?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8 redis: # Redis数据库索引(默认为 0) @@ -26,9 +26,9 @@ # Redis服务器地址 host: 127.0.0.1 # Redis服务器连接端口 - port: 6279 + port: 6379 # Redis 密码 - password: blnka!@#123 + password: lianghua1!qaz2@WSX lettuce: pool: # 连接池中的最小空闲连接 @@ -44,8 +44,8 @@ rabbitmq: host: 127.0.0.1 port: 5672 - username: blnka - password: blnka123 + username: e20210816 + password: e20210816 publisher-confirm-type: correlated pay: diff --git a/src/test/java/cc/mrbird/febs/PayTest.java b/src/test/java/cc/mrbird/febs/PayTest.java deleted file mode 100644 index 0ed41da..0000000 --- a/src/test/java/cc/mrbird/febs/PayTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package cc.mrbird.febs; - -import cc.mrbird.febs.common.properties.XcxProperties; -import cc.mrbird.febs.common.utils.RedisUtils; -import cc.mrbird.febs.common.utils.SpringContextHolder; -import cc.mrbird.febs.pay.util.WechatConfigure; -import cc.mrbird.febs.vip.service.IMallVipConfigService; -import cn.hutool.core.util.StrUtil; -import com.alibaba.fastjson.JSONObject; -import com.alipay.api.AlipayApiException; -import com.alipay.api.domain.AlipayTradeAppPayModel; -import com.alipay.api.response.AlipayTradeAppPayResponse; -import com.baomidou.mybatisplus.extension.exceptions.ApiException; -import com.ijpay.alipay.AliPayApi; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.web.client.RestTemplate; - -import javax.annotation.Resource; - -/** - * @author wzy - * @date 2021-09-27 - **/ -@Slf4j -@SpringBootTest -public class PayTest { - - - @Autowired - private RedisUtils redisUtils; - @Resource - RestTemplate restTemplate; - @Test - public void aliPay(){ - - String appId = "wx16d0b75302b360d4"; - String appSecret = "a2887cd622ed981d2e04d724d29d7454"; - String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; - String jsonStr = restTemplate.getForObject(url, String.class); - - /** - * 返回结果 - * {"access_token":"ACCESS_TOKEN","expires_in":7200} - */ - if (!jsonStr.contains("access_token")) { - System.out.println("获取微信access_token失败"); - } - - String accessTokenKey = WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY; - JSONObject jsonObject = JSONObject.parseObject(jsonStr); - String accessToken = jsonObject.getString(accessTokenKey); - if (StrUtil.isEmpty(accessToken)) { - log.error("获取access token失败: {}" , jsonObject.getString("errmsg")); - throw new ApiException("获取access token失败"); - } else { - log.info("wx access_token : {}",accessToken); - redisUtils.set(accessTokenKey,accessToken); - } - } - - @Autowired - private IMallVipConfigService mallVipConfigService; - - @Test - public void test() { - mallVipConfigService.findConfigList(); - } -} diff --git a/src/test/java/cc/mrbird/febs/ProfitTest.java b/src/test/java/cc/mrbird/febs/ProfitTest.java deleted file mode 100644 index b7b477c..0000000 --- a/src/test/java/cc/mrbird/febs/ProfitTest.java +++ /dev/null @@ -1,976 +0,0 @@ -package cc.mrbird.febs; - -import cc.mrbird.febs.common.enumerates.DataDictionaryEnum; -import cc.mrbird.febs.common.enumerates.FlowTypeEnum; -import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum; -import cc.mrbird.febs.common.exception.FebsException; -import cc.mrbird.febs.common.utils.AppContants; -import cc.mrbird.febs.common.utils.HttpCurlUtil; -import cc.mrbird.febs.common.utils.MallUtils; -import cc.mrbird.febs.common.utils.RedisUtils; -import cc.mrbird.febs.mall.dto.MallMemberCouponDto; -import cc.mrbird.febs.mall.entity.*; -import cc.mrbird.febs.mall.mapper.*; -import cc.mrbird.febs.mall.service.*; -import cc.mrbird.febs.mall.vo.MallGoodsListVo; -import cc.mrbird.febs.mall.vo.MallMemberCouponVo; -import cc.mrbird.febs.pay.model.*; -import cc.mrbird.febs.pay.service.IXcxPayService; -import cc.mrbird.febs.pay.service.WxFaPiaoService; -import cc.mrbird.febs.pay.util.JCEUtil; -import cc.mrbird.febs.pay.util.WechatConfigure; -import cc.mrbird.febs.rabbit.consumer.AgentConsumer; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONUtil; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier; -import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; -import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; -import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler; -import com.wechat.pay.contrib.apache.httpclient.util.AesUtil; -import okhttp3.HttpUrl; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.RequestEntity; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPatch; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.Base64Utils; -import org.springframework.web.client.RestTemplate; - -import javax.annotation.Resource; -import java.io.*; -import java.math.BigDecimal; -import java.net.URLConnection; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -/** - * @author wzy - * @date 2022-06-02 - **/ -@SpringBootTest -public class ProfitTest { - - @Autowired - private AgentConsumer agentConsumer; - - @Autowired - private IAgentService agentService; - - @Autowired - private IMemberProfitService memberProfitService; - - @Test - public void dynamicProfit() { - memberProfitService.dynamicProfit(21L); - } - @Test - public void agentProfit() { - memberProfitService.agentProfit(null); - } - - - @Test - public void staticProfit() { - memberProfitService.staticProfit(new Date()); - } - - @Test - public void thankfulProfit() { - memberProfitService.thankfulProfit(new Date()); - } - @Autowired - private MallMemberCouponMapper mallMemberCouponMapper; - @Autowired - private MallGoodsMapper mallGoodsMapper; - @Autowired - private CouponGoodsMapper couponGoodsMapper; - @Autowired - private WxFaPiaoService wxFaPiaoService; - @Autowired - ResourceLoader resourceLoader; - - @Test - public void redisTest() throws IOException {//配置开发选项 - String obj = redisUtils.getString("mall_goods_json");//获取JSONARRAY字符串对象 - System.out.println(obj); - JSONArray jsonArray = JSONUtil.parseArray(obj);//转换成JSONARRAY对象 - List<MallGoodsListVo> mallGoodsListVos = JSONUtil.toList(jsonArray, MallGoodsListVo.class);//转换成对象集合 - System.out.println(mallGoodsListVos.size()); - - } - @Test - public void rankProfit() throws IOException {//配置开发选项 -// System.out.println(new ClassPathResource("wxP12/apiclient_cert.p12").getFile().exists()); -// System.out.println(new File("src/main/resources/wxP12/apiclient_cert.p12").exists()); -// -// InputStream inputStream = new FileInputStream(file); -// System.out.println(resourceLoader.getResource("classpath:/wxP12/apiclient_cert.p12").exists()); - PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); - HeaderDto headerDto = new HeaderDto(); - headerDto.setCallback_url("https://api.blnka.cn/api/xcxPay/fapiaoCallBack"); - headerDto.setShow_fapiao_cell(false); - String parseObj = JSONUtil.parseObj(headerDto).toString(); - String baseUrl = "https://api.mch.weixin.qq.com"; - String canonicalUrl = "/v3/new-tax-control-fapiao/merchant/development-config"; - String postStr = null; - try { - postStr = wxFaPiaoService.createAuthorization( - "PATCH", - baseUrl+canonicalUrl, - parseObj, - privateKey - ); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - - String token = AppContants.FP_TOKEN_HEADER_TYPE+postStr; - System.out.println("WECHATPAY2-SHA256-RSA2048 "+postStr); - String s = wxFaPiaoService.sendPatch(baseUrl + canonicalUrl, parseObj, token); - System.out.println(s); - } - - @Test - public void rankProfit03() throws IOException {//创建电子发票卡券模板 - FPCardTemplateDto fpCardTemplateDto = new FPCardTemplateDto(); - fpCardTemplateDto.setCard_appid("wxad2fdb2fcad10fb2"); - - FPCardTemplateInformationDto fpCardTemplateInformationDto = new FPCardTemplateInformationDto(); - fpCardTemplateInformationDto.setLogo_url("http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0"); - fpCardTemplateInformationDto.setPayee_name("发票测试"); - - FPCardTemplateCustomCellDto fpCardTemplateCustomCellDto = new FPCardTemplateCustomCellDto(); - fpCardTemplateCustomCellDto.setWords("电子发票"); - fpCardTemplateCustomCellDto.setDescription("查看发票"); - fpCardTemplateCustomCellDto.setJump_url("http://www.qq.com"); - fpCardTemplateCustomCellDto.setMiniprogram_path("gh_86a091e50ad4@app"); - fpCardTemplateCustomCellDto.setMiniprogram_user_name("pages/xxxPage"); - fpCardTemplateInformationDto.setCustom_cell(fpCardTemplateCustomCellDto); - - fpCardTemplateDto.setCard_template_information(fpCardTemplateInformationDto); - - String parseObj = JSONUtil.parseObj(fpCardTemplateDto).toString(); - System.out.println(parseObj); - String baseUrl = "https://api.mch.weixin.qq.com"; - String canonicalUrl = "/v3/new-tax-control-fapiao/card-template"; - PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); - String postStr = null; - try { - postStr = wxFaPiaoService.createAuthorization( - "POST", - baseUrl+canonicalUrl, - parseObj, - privateKey - ); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - String token = AppContants.FP_TOKEN_HEADER_TYPE+postStr; - - System.out.println("WECHATPAY2-SHA256-RSA2048 "+postStr); - String s = wxFaPiaoService.sendPost(baseUrl + canonicalUrl, parseObj, "WECHATPAY2-SHA256-RSA2048 "+postStr); - System.out.println(s); - } - - - - @Test - public void rankProfit04() throws IOException {//获取用户填写的抬头 - //初始化请求参数 - Map<String, Object> params = new HashMap<>(); - params.put("scene","WITH_WECHATPAY"); - params.put("fapiao_apply_id","4200002059202401191880748568"); - - String baseUrl = "https://api.mch.weixin.qq.com"; - String canonicalUrl = "/v3/new-tax-control-fapiao/user-title"; - - String urlparm = baseUrl+canonicalUrl;//有参数的get请求,加密是需要把参数加载进去URL - List<BasicNameValuePair> parameters = new ArrayList<>(); - for (Map.Entry<String, Object> entry : params.entrySet()) { - parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString())); - } - StringBuilder dataparm = new StringBuilder(); - params.forEach((k, v) -> dataparm.append("&" + k + "=" + v)); - String string = dataparm.toString(); - if (!"".equals(string)) { - urlparm = baseUrl+canonicalUrl + "?" + dataparm.substring(1); - } - PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); - String postStr = null; - try { - postStr = wxFaPiaoService.createAuthorization( - "GET", - urlparm, - "", - privateKey - ); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - String s = wxFaPiaoService.sendGet(baseUrl+canonicalUrl, params, "WECHATPAY2-SHA256-RSA2048 "+postStr); - System.out.println(s); - } - - @Test - public void rankProfit2() throws IOException {//查询配置开发选项 - PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); - String baseUrl = "https://api.mch.weixin.qq.com"; - String canonicalUrl = "/v3/new-tax-control-fapiao/merchant/development-config"; - String postStr = null; - try { - postStr = wxFaPiaoService.createAuthorization( - "GET", - baseUrl+canonicalUrl, - "", - privateKey - - ); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - System.out.println("WECHATPAY2-SHA256-RSA2048"+postStr); - String s = wxFaPiaoService.sendGet(baseUrl + canonicalUrl, new HashMap<>(), "WECHATPAY2-SHA256-RSA2048 "+postStr); - - System.out.println(s); -// try { -// HttpClient httpClient = new HttpClient(); -// GetMethod method = new GetMethod(baseUrl+canonicalUrl); -// method.setRequestHeader("Accept", "application/json"); -// method.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36"); -// method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); -// method.setRequestHeader("Connection", "keep-alive"); -// method.setRequestHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 "+postStr); -// httpClient.executeMethod(method); -// System.out.println(method); -// String responseBodyAsString = method.getResponseBodyAsString(); -// cn.hutool.json.JSONObject maps = JSONUtil.parseObj(responseBodyAsString); -// System.out.println(maps); -// } catch (IOException e) { -// e.printStackTrace(); -// } - - } - - @Test - public void rankProfit2_01() throws IOException, ParseException, GeneralSecurityException {//获取平台证书 - JCEUtil.removeCryptographyRestrictions(); - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); - PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); - String baseUrl = "https://api.mch.weixin.qq.com"; - String canonicalUrl = "/v3/certificates"; - String postStr = null; - try { - postStr = wxFaPiaoService.createAuthorization( - "GET", - baseUrl+canonicalUrl, - "", - privateKey - - ); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - String responseBodyAsString = wxFaPiaoService.sendGet(baseUrl + canonicalUrl, new HashMap<>(), "WECHATPAY2-SHA256-RSA2048 "+postStr); - //完成签名并执行请求 - X509Certificate x509Certificate = null; - try { - cn.hutool.json.JSONObject maps = JSONUtil.parseObj(responseBodyAsString); - System.out.println(maps); - - FPCertificateVo certificateVo = com.alibaba.fastjson.JSONObject.parseObject(responseBodyAsString, FPCertificateVo.class); - for (FPCertificates certificates : certificateVo.getData()) { - if (format.parse(certificates.getEffective_time()).before(new Date()) - && format.parse(certificates.getExpire_time()).after(new Date())) { - FPEncryptCertificate encrypt_certificate = certificates.getEncrypt_certificate(); - //解密 - AesUtil aesUtil = new AesUtil("daL341aN5orDt13puXadsAf2rpuX12v3".getBytes("utf-8")); - String pulicKey = aesUtil.decryptToString( - encrypt_certificate.getAssociated_data().getBytes("utf-8"), - encrypt_certificate.getNonce().getBytes("utf-8"), - encrypt_certificate.getCiphertext()); - //获取平台证书 - final CertificateFactory cf = CertificateFactory.getInstance("X509"); - - ByteArrayInputStream inputStream = new ByteArrayInputStream(pulicKey.getBytes(StandardCharsets.UTF_8)); - - x509Certificate = (X509Certificate) cf.generateCertificate(inputStream); - System.out.println(x509Certificate); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - String timestamp = "1705548628"; - String nonce = "sJBCGwYIM8WFJCpTE3gDGifC6VOyrPFY"; - String body = "{\"id\":\"f23942b4-b128-56ef-9172-2da8204b5159\",\"create_time\":\"2024-01-18T11:30:28+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"FAPIAO.USER_APPLIED\",\"summary\":\"用户已申请开票\",\"resource\":{\"original_type\":\"fapiao\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"X7XjgHrepsnVpFqNgjl9EfRbJIdMUf15izFrtnvEf7So3SWlg6CFNofcQAJE+iL1XfkFk7DNNW0rILNbY1cGWGlAlKbbPhv5SFEakZVe9GZsSTd4EC5zTk9D6g+FTS6EQNxCkj4ut2WyYaSSqJjHgYaqdKzLNPSTGRVQnynafFE=\",\"associated_data\":\"fapiao\",\"nonce\":\"X7daAHdejNsm\"}}"; - Map<String, Object> requestBody = JSONUtil.parseObj(body); - String signature = "WECHATPAY/SIGNTEST/9WwfXW/noMdzDPcOrFD51Bf5YIThXLTtLCl5hoGlSfIBdY2UpE+5eHLs0XyF7y2cQc4OlzTzDDxSMTp/p/8ZenE2hMBaQjxVrdbTtrOLA1h13/WjCNaTr1URTqQ5+IF5bLCxAW8BmZ0jEqpmI/HYR3wdK8/7W91c1zfKODYgkvJzxFzd8OWi2GtELE5tLamkOLyb0GEcsGww2DUOypO5HjNyITgsy9R00w3OH92UInCD8Z6c5BAsQNySqFK8N52y38AlIWTtKROHmJtu+kHbt+nMOU0kbB5bZcPAptsnVYpp9KMmjMrmyjiKtHZb2TGIWiN/L+bgceyN3g=="; - //构造验签名串 - String signatureStr = timestamp + "\n" + nonce + "\n" + com.alibaba.fastjson.JSONObject.toJSONString(requestBody) + "\n"; - System.out.println(signature.length()); - System.out.println(signature); - System.out.println(signatureStr.length()); - System.out.println(signatureStr); - // 加载SHA256withRSA签名器 - Signature signer = Signature.getInstance("SHA256withRSA"); - // 用微信平台公钥对签名器进行初始化(调上一节中的获取平台证书方法) - signer.initVerify(x509Certificate); - // 把我们构造的验签名串更新到签名器中 - signer.update(signatureStr.getBytes(StandardCharsets.UTF_8)); - // 把请求头中微信服务器返回的签名用Base64解码 并使用签名器进行验证 - boolean result = signer.verify(Base64Utils.decodeFromString(signature)); - System.out.println(result); - } - - - @Autowired - private MallOrderInfoMapper mallOrderInfoMapper; - - @Test - public void directorProfitTest() { - memberProfitService.storeAndDirectorProfit(new Date()); - } - - @Autowired - private MallOrderItemMapper mallOrderItemMapper; - - @Autowired - private IMallAchieveService mallAchieveService; - - @Test - public void achieveTest() { - List<MallOrderItem> items = mallOrderItemMapper.selectList(null); - for (MallOrderItem item : items) { - mallAchieveService.add(item.getId()); - } - } - - @Test - public void paramTest() { - Map<String, Integer> map = new HashMap<>(); - BigDecimal amount = new BigDecimal("100"); - map.put("amount", 1); - changeAmount(map); - System.out.println(map.get("amount")); - } - - public void changeAmount(Map<String, Integer> amount) { - amount.put("amount", 2); - } - - @Resource - RestTemplate restTemplate; - - @Test - public void getWeChatAccessToken() { - - String appId = "wx5cc58f796224af61"; - String appSecret = "71403646f666f9b9dca308d4f357765c"; - String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; - String jsonStr = restTemplate.getForObject(url, String.class); - - /** - * 返回结果 - * {"access_token":"ACCESS_TOKEN","expires_in":7200} - */ - if (!jsonStr.contains("access_token")) { - System.out.println("获取微信access_token失败"); - } - - JSONObject jsonObject = JSON.parseObject(jsonStr); - System.out.println(jsonObject.get("access_token").toString()); - } - @Resource - IApiMallTeamLeaderService iApiMallTeamLeaderService; - - @Test - public void confirm(){ -// ApiLeaderOrderConfirmDto apiLeaderOrderConfirmDto = new ApiLeaderOrderConfirmDto(); -// apiLeaderOrderConfirmDto.setIds("90"); -// iApiMallTeamLeaderService.leaderOrderConfirm(apiLeaderOrderConfirmDto); - String productNames = getProductNames(35L, 106L); - System.out.println(productNames); - } - - /** - * 根据用户ID和订单ID获取所购买商品名称 - * @return 所含商品名称(多个以","隔开) - */ - public String getProductNames(Long memberId, Long orderId) { - MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderByMemberIdAndId(memberId, orderId); - List<MallOrderItem> details = mallOrderInfo.getItems(); - if (CollectionUtils.isEmpty(details)) { - return ""; - } - StringBuffer productNameBuffer = new StringBuffer(); - Integer maxLength = 30; - for (int i = 0; i< details.size(); i++) { - MallOrderItem mallOrderItem = details.get(i); - String goodsName = mallOrderItem.getGoodsName(); - if (goodsName == null) { - continue; - } - if (i == 0 && goodsName.length() > maxLength) { - productNameBuffer.append(goodsName.substring(0, maxLength) + "..."); - break; - } - if ((productNameBuffer.length() + goodsName.length()) > maxLength) { - productNameBuffer.append("等"); - break; - } - productNameBuffer.append(goodsName + ","); - } - String productNames = productNameBuffer.toString(); - if (productNames.endsWith(",")) { - productNames = productNames.substring(0, productNames.length() - 1); - } - if (productNames.endsWith(",等")) { - productNames = productNames.substring(0, productNames.length() - 2) + "等"; - } - return productNames; - } - @Autowired - private IXcxPayService iXcxPayService; - @Autowired - private IAdminMallTeamLeaderService iAdminMallTeamLeaderService; - - @Test - public void qrcodeBase64(){ - -// Integer integer = mallGoodsMapper.upDateStockAndVolumeByGoodsId(35L, 3); -// System.out.println(integer); -// WxGenerateQrCodeDto wxGenerateQrCodeDto = new WxGenerateQrCodeDto(); -// wxGenerateQrCodeDto.setPage("pages/product/details"); -// wxGenerateQrCodeDto.setScene("35"); -// FebsResponse febsResponse = iXcxPayService.generateQrCode(wxGenerateQrCodeDto); -// String data = febsResponse.get("data").toString(); -// System.out.println(data); -// trackServiceInfo("e024c63342930addc57189c8608cdb01",null); -// String e024c63342930addc57189c8608cdb01 = trackServiceDel("e024c63342930addc57189c8608cdb01", "792477"); -// System.out.println(e024c63342930addc57189c8608cdb01); - String ss = fenceDel("95ede7157929f5f6b6c758971be924b1", "795278","795554"); - System.out.println(ss); - } - - //电子围栏删除 - public String fenceDel(String gaodeKey, String sid,String fenceId) { - String url = "https://tsapi.amap.com/v1/track/geofence/delete?key="+gaodeKey+"&sid="+sid+"&gfids="+fenceId; - HttpPost httpPost = new HttpPost(url); - Map<String,String> map = new HashMap<>(); - map.put("key",gaodeKey); - map.put("sid",sid); - map.put("gfids",fenceId); - String param= JSON.toJSONString(map); - String result = null; - try { - result = HttpCurlUtil.sendPostHttp(url, param); - } catch (IOException e) { - e.printStackTrace(); - } - cn.hutool.json.JSONObject maps = JSONUtil.parseObj(result); - System.out.println(maps); - String errcode = maps.get("errcode").toString(); - if(!"10000".equals(errcode)){ - return "fail"; - }else{ - return maps.toString(); - } - } - //服务删除 - public String trackServiceDel(String gaodeKey, String sid) { - String url = "https://tsapi.amap.com/v1/track/service/delete?key="+gaodeKey+"&sid="+sid; - HttpPost httpPost = new HttpPost(url); - Map<String,String> map = new HashMap<>(); - map.put("key",gaodeKey); - map.put("sid",sid); - String param= JSON.toJSONString(map); - String result = null; - try { - result = HttpCurlUtil.sendPostHttp(url, param); - } catch (IOException e) { - e.printStackTrace(); - } - cn.hutool.json.JSONObject maps = JSONUtil.parseObj(result); - System.out.println(maps); - String errcode = maps.get("errcode").toString(); - if(!"10000".equals(errcode)){ - return "fail"; - }else{ - return maps.toString(); - } -// String str2 = maps.get("data").toString(); -// cn.hutool.json.JSONObject maps2 = JSONUtil.parseObj(str2); -// String serviceId = maps2.get("sid").toString(); -// if(null!=serviceId&&!"".equals(serviceId)){ -// return serviceId; -// }else{ -// return "fail"; -// } - } - - - public String trackServiceInfo(String gaodeKey, String serviceName) { - String url = "https://tsapi.amap.com/v1/track/service/list"; - HttpPost httpPost = new HttpPost(url); - Map<String,String> map = new HashMap<>(); - //高德Key - //用户在高德地图官网申请Web服务API类型Key - map.put("key",gaodeKey); - System.out.println("==高德返回"+map); - String result = null; - try { - result = HttpCurlUtil.sendGetHttp(url, map); - } catch (IOException e) { - e.printStackTrace(); - } - System.out.println("==高德返回"+result); - cn.hutool.json.JSONObject maps = JSONUtil.parseObj(result); - String errCode = maps.get("errcode").toString(); - if("10000".equals(errCode)){ - String dataStr = maps.get("data").toString(); - cn.hutool.json.JSONObject dataResults = JSONUtil.parseObj(dataStr); - String resultsStr = dataResults.get("results").toString(); - return resultsStr; - }else{ - return "fail"; - } - } - - -// -// @Autowired -// private MallOrderInfoMapper mallOrderInfoMapper; -// -// @Autowired -// private MallGoodsSkuMapper mallGoodsSkuMapper; - - @Autowired - private MallLeaderAchieveMapper mallLeaderAchieveMapper; -// -// @Autowired -// private MallTeamLeaderMapper mallTeamLeaderMapper; -// -// @Autowired -// private IMemberProfitService memberProfitService; - -// @Autowired -// private IMallAchieveService mallAchieveService; - - @Autowired - private DataDictionaryCustomMapper dataDictionaryCustomMapper; - - @Autowired - private MallMemberMapper mallMemberMapper; - - @Autowired - private IMallMoneyFlowService mallMoneyFlowService; - - @Autowired - private IApiMallMemberWalletService memberWalletService; - - @Test - public void achieve(){ - DataDictionaryCustom dicBonusSwitch = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.BONUS_SWITCH.getType(), DataDictionaryEnum.BONUS_SWITCH.getCode()); - String bonusSwitch = dicBonusSwitch.getValue(); - if("1".equals(bonusSwitch)){ - DataDictionaryCustom dicBonusPercent = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.BONUS_PERCENT.getType(), DataDictionaryEnum.BONUS_PERCENT.getCode()); - BigDecimal bonusPercent = new BigDecimal(dicBonusPercent.getValue()).setScale(2,BigDecimal.ROUND_DOWN);; - //获取每日提成总数 - /** - * a.unique_code uniqueCode 团长特征码 - * , IFNULL(sum(a.amount),0) amount 每日提成总金额 - */ -// DateTime dateTime = DateUtil.offsetDay(new Date(), -1); - DateTime dateTime = DateUtil.offsetDay(new Date(), 0); - List<Map<String, String>> allLeaderAchieve = mallLeaderAchieveMapper.selectListByStateAndCreateTimeAndUniqueCode(MallLeaderAchieve.STATE_ONE,dateTime); - if (CollUtil.isNotEmpty(allLeaderAchieve)) { - for (Map<String, String> map : allLeaderAchieve) { - String uniqueCode = map.get("uniqueCode"); - Object amountOrder = map.get("amount"); - //直接舍弃小数点的第三位 - BigDecimal amount = new BigDecimal(String.valueOf(amountOrder)).setScale(2,BigDecimal.ROUND_DOWN); - BigDecimal achieveMoney = amount.multiply(bonusPercent).setScale(2,BigDecimal.ROUND_DOWN); - MallMember mallMember = mallMemberMapper.selectInfoByInviteId(uniqueCode); - memberWalletService.addBalance(achieveMoney,mallMember.getId()); - String achieveNo = "TC."+ MallUtils.getOrderNum(); - mallMoneyFlowService.addMoneyFlow( - mallMember.getId(), - achieveMoney, - MoneyFlowTypeEnum.LEADERACHIEVE.getValue(), - achieveNo, - FlowTypeEnum.BALANCE.getValue()); - - - //更新到已提成状态 - mallLeaderAchieveMapper.updateByUniqueCodeStateAndTime(DateUtil.date(),uniqueCode,MallLeaderAchieve.STATE_ONE,dateTime); - } - } - } - - } - @Autowired - private MallMoneyFlowMapper mallMoneyFlowMapper; - - @Test - public void testAddress(){ - MallMember loginUser = mallMemberMapper.selectById(47L); - BigDecimal totalProfit = mallMoneyFlowMapper.selectAmountByFlowtypeAndType(loginUser.getId(),FlowTypeEnum.BALANCE.getValue(),MoneyFlowTypeEnum.LEADERACHIEVE.getValue(),null,null,null); - BigDecimal todayProfit = mallMoneyFlowMapper.selectAmountByFlowtypeAndType(loginUser.getId(),FlowTypeEnum.BALANCE.getValue(), - MoneyFlowTypeEnum.LEADERACHIEVE.getValue(), - null,DateUtil.date(), - null); - - BigDecimal monthProfit = mallMoneyFlowMapper.selectAmountByFlowtypeAndType(loginUser.getId(),FlowTypeEnum.BALANCE.getValue(), - MoneyFlowTypeEnum.LEADERACHIEVE.getValue(), - null,null, - DateUtil.date()); - BigDecimal waitProfit = mallLeaderAchieveMapper.selectProfitByStateAndDateTimeAndUniqueCode(1,null,loginUser.getInviteId()).setScale(2,BigDecimal.ROUND_DOWN); - System.out.println(todayProfit +";"); - System.out.println(waitProfit +";"); - System.out.println(totalProfit +";"); - System.out.println(monthProfit +";"); - } - - @Autowired - RedisUtils redisUtils; - @Autowired - MallRefundMapper mallRefundMapper; - - - - @Test - public void qrcode(){ - MallMember member = mallMemberMapper.selectById(402L); - -// ApiRechargeWalletDto apiRechargeWalletDto = new ApiRechargeWalletDto(); -// apiRechargeWalletDto.setAmount(new BigDecimal(1)); -// apiRechargeWalletDto.setMemberId(402L); -// BrandWCPayRequestData brandWCPayRequestData = null; -// try { -// brandWCPayRequestData = iXcxPayService.startRechargeWallet(apiRechargeWalletDto); -// } catch (Exception e) { -// throw new FebsException("支付失败"); -// } -// String wxResultStr = JSONUtil.toJsonStr(brandWCPayRequestData); -// String payResultStr = brandWCPayRequestData.getPrepay_id(); -// Map<String, Object> map = new HashMap<>(); -// map.put("orderInfo", payResultStr); -// map.put("wxResultStr", wxResultStr); - - Long id = 345417L; - MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectById(id); - BrandWCPayRequestData brandWCPayRequestData = null; - try { - brandWCPayRequestData = iXcxPayService.startPayment(mallOrderInfo); - } catch (Exception e) { - throw new FebsException("支付失败"); - } - String s = JSONUtil.toJsonStr(brandWCPayRequestData); - String prepay_id = brandWCPayRequestData.getPrepay_id(); - - -// if(ObjectUtil.isEmpty(mallOrderInfo)){ -// } -// Integer status = mallOrderInfo.getStatus(); -// if(OrderStatusEnum.WAIT_SHIPPING.getValue() != status){ -// } -// Integer deliveryState = mallOrderInfo.getDeliveryState(); -// if(1 != deliveryState){ -// } -// //根据子订单生成退款记录 -// List<MallOrderItem> mallOrderItemList = mallOrderItemMapper.selectListByOrderId(id); -// if(CollUtil.isEmpty(mallOrderItemList)){ -// } -// for(MallOrderItem mallOrderItem : mallOrderItemList){ -// QueryWrapper<MallRefundEntity> objectQueryWrapper = new QueryWrapper<>(); -// objectQueryWrapper.eq("member_id",member.getId()); -// objectQueryWrapper.eq("order_id",mallOrderInfo.getId()); -// objectQueryWrapper.eq("item_id",mallOrderItem.getId()); -// MallRefundEntity mallRefund = mallRefundMapper.selectOne(objectQueryWrapper); -// MallRefundEntity mallRefundEntity = new MallRefundEntity(); -// if(ObjectUtil.isEmpty(mallRefund)){ -// mallRefundEntity.setRefundNo(mallOrderInfo.getOrderNo()+"_RITEM"+mallOrderItem.getId()); -// mallRefundEntity.setMemberId(member.getId()); -// mallRefundEntity.setOrderId(mallOrderInfo.getId()); -// mallRefundEntity.setItemId(mallOrderItem.getId()); -// if("余额支付".equals(mallOrderInfo.getPayMethod())){ -// mallRefundEntity.setType(3); -// }else if("微信支付".equals(mallOrderInfo.getPayMethod())){ -// mallRefundEntity.setType(1); -// }else{ -// mallRefundEntity.setType(3); -// } -// mallRefundEntity.setState(3); -// mallRefundEntity.setAmount(mallOrderItem.getAmount()); -// mallRefundMapper.insert(mallRefundEntity); -// }else{ -// if(mallRefund.getState() == 2){ -// mallRefundEntity.setId(mallRefund.getId()); -// mallRefundEntity.setRefundNo(mallRefund.getRefundNo()); -// mallRefundEntity.setMemberId(mallRefund.getMemberId()); -// mallRefundEntity.setOrderId(mallRefund.getOrderId()); -// mallRefundEntity.setItemId(mallRefund.getItemId()); -// mallRefundEntity.setType(mallRefund.getType()); -// mallRefundEntity.setState(3); -// mallRefundEntity.setAmount(mallRefund.getAmount()); -// mallRefundMapper.updateById(mallRefundEntity); -// } -// } -// ApiLeaderRefundOrderDto apiLeaderRefundOrderDto = new ApiLeaderRefundOrderDto(); -// apiLeaderRefundOrderDto.setOrderId(mallOrderInfo.getId()); -// apiLeaderRefundOrderDto.setItemId(mallOrderItem.getId()); -// apiLeaderRefundOrderDto.setAgreeState(1); -// iApiMallTeamLeaderService.leaderRefundOrder(apiLeaderRefundOrderDto); -// } - } - - /** - * 获取小程序菊花码 - * @Description //TODO - * @Author zhaowx - * @Date 2020/3/25 15:23 - **/ - @Test - public void getWXCode() { - try { - //这里调用的是上面的获取access_token方法 - String access_token = redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY).toString(); - String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token; - String scene = "15"; - Map<String, String> param = new HashMap<>(); - param.put("scene",scene); - //这里的page如果没有的话可以不写,默认是跳主页,如果写了没有的页面的话,会返回错误信息 - param.put("page","pages/product/details"); - String json = JSON.toJSONString(param); - ByteArrayInputStream inputStream = sendPost(url, json); - - //这里判断的是返回的图片还是错误信息,一般错误信息不会大于200 - if (inputStream.available() <= 200){ - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - int i; - byte[] buffer = new byte[200]; - while ((i = inputStream.read(buffer)) != -1){ - byteArrayOutputStream.write(buffer,0,i); - } - String str = new String(byteArrayOutputStream.toByteArray()); - //错误信息的格式在官方文档里有 - JSONObject jsonObject = JSONObject.parseObject(str); - if ("41030".equals(jsonObject.getString("errcode"))){ - System.out.println("所传page页面不存在,或者小程序没有发布"); - - }else if ("45009".equals(jsonObject.getString("errcode"))){ - System.out.println("调用分钟频率受限"); - } - byteArrayOutputStream.close(); - } - //输出到本地的代码 - FileOutputStream fileOutputStream = new FileOutputStream("D:/123.png"); - int i; - byte[] buffer = new byte[10240000]; - while ((i = inputStream.read(buffer)) != -1){ - fileOutputStream.write(buffer,0,i); - } - - fileOutputStream.flush(); - fileOutputStream.close(); - inputStream.close(); - }catch (Exception e){ - } - } - - - public static ByteArrayInputStream sendPost(String URL, String json) { - InputStream inputStream = null; - ByteArrayInputStream byteArrayInputStream = null; - // 创建默认的httpClient实例. - CloseableHttpClient httpclient = HttpClients.createDefault(); - // 创建httppost - HttpPost httppost = new HttpPost(URL); - httppost.addHeader("Content-type", "application/json; charset=utf-8"); - httppost.setHeader("Accept", "application/json"); - try { - StringEntity s = new StringEntity(json, Charset.forName("UTF-8")); - s.setContentEncoding("UTF-8"); - httppost.setEntity(s); - HttpResponse response = httpclient.execute(httppost); - if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ - // 获取相应实体 - HttpEntity entity = response.getEntity(); - inputStream = entity.getContent(); - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - // 创建一个Buffer字符串 - byte[] buffer = new byte[1024]; - // 每次读取的字符串长度,如果为-1,代表全部读取完毕 - int len = 0; - // 使用一个输入流从buffer里把数据读取出来 - while ((len = inputStream.read(buffer)) != -1) { - // 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度 - outStream.write(buffer, 0, len); - } - // 关闭输入流 - inputStream.close(); - // 把outStream里的数据写入内存 - byteArrayInputStream = new ByteArrayInputStream(outStream.toByteArray()); - byte[] data = outStream.toByteArray(); - String result = new String(Base64.getEncoder().encode(data)); - result = "data:image/jpeg;base64," + result; - System.out.println(result); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - // 关闭连接,释放资源 - try { - httpclient.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return byteArrayInputStream; - } - - - /** - * 传递自定义参数获取二维码保存后并生成url给前端访问 - * @Author yeafel - * @param scene - * @param page - * @param is_hyaline - * @param auto_color - * @return - */ - @Test - public void getQrCodeImgUrl() { - String scene = "pages/product/details"; - String page = "15"; - Boolean is_hyaline = true; - Boolean auto_color = true; - RestTemplate restTemplate = new RestTemplate(); - //首先获取ACCESS_TOKEN - String accessToken = redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY).toString(); - - //然后调用微信官方api生成二维码 - String createQrCodeUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken; - //此处我是使用的阿里巴巴的fastJson - JSONObject createQrParam = new JSONObject(); - createQrParam.put("scene", scene); - createQrParam.put("page", page); - createQrParam.put("is_hyaline", is_hyaline); - createQrParam.put("auto_color", auto_color); - - PrintWriter out = null; - InputStream in = null; - try { - URL realUrl = new URL(createQrCodeUrl); - // 打开和URL之间的连接 - URLConnection conn = realUrl.openConnection(); - // 设置通用的请求属性 - conn.setRequestProperty("accept", "*/*"); - conn.setRequestProperty("connection", "Keep-Alive"); - conn.setRequestProperty("user-agent", - "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); - // 发送POST请求必须设置如下两行 - conn.setDoOutput(true); - conn.setDoInput(true); - // 获取URLConnection对象对应的输出流 - out = new PrintWriter(conn.getOutputStream()); - // 发送请求参数,利用connection的输出流,去写数据到connection中,我的参数数据流出我的电脑内存到connection中,让connection把参数帮我传到URL中去请求。 - out.print(createQrParam); - // flush输出流的缓冲 - out.flush(); - //获取URL的connection中的输入流,这个输入流就是我请求的url返回的数据,返回的数据在这个输入流中,流入我内存,我将从此流中读取数据。 - in = conn.getInputStream(); - //定义个空字节数组 - byte[] data = null; - // 读取图片字节数组 - try { - //创建字节数组输出流作为中转仓库,等待被写入数据 - ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); - byte[] buff = new byte[100]; - int rc = 0; - while ((rc = in.read(buff, 0, 100)) > 0) { - //向中转的输出流循环写出输入流中的数据 - swapStream.write(buff, 0, rc); - } - //此时connection的输入流返回给我们的请求结果数据已经被完全地写入了我们定义的中转输出流swapStream中 - data = swapStream.toByteArray(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - String base64Code = new String(Objects.requireNonNull(Base64.getEncoder().encode(data))); - //Base64转byte[]数组 - System.out.println(base64Code); - } catch (Exception e) { - System.out.println("发送 POST 请求出现异常!" + e); - e.printStackTrace(); - } - - // 使用finally块来关闭输出流、输入流 - finally { - try { - if (out != null) { - out.close(); - } - if (in != null) { - in.close(); - } - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - - - public static void main(String[] args) { - BigDecimal amount = new BigDecimal("0.15").setScale(2,BigDecimal.ROUND_DOWN); - System.out.println(amount); - } - - @Test - public void aaaTest() { -// agentConsumer.vipLevelUp(133L); - agentConsumer.getScoreMsg(217L); - } -} -- Gitblit v1.9.1