diff --git a/jsowell-admin/src/main/java/com/jsowell/lianlian/LianLianController.java b/jsowell-admin/src/main/java/com/jsowell/lianlian/LianLianController.java index b702e057f..673ac4fa0 100644 --- a/jsowell-admin/src/main/java/com/jsowell/lianlian/LianLianController.java +++ b/jsowell-admin/src/main/java/com/jsowell/lianlian/LianLianController.java @@ -32,6 +32,24 @@ public class LianLianController extends BaseController { private LianLianService lianLianService; + @PostMapping("/pushStationInfo") + public RestApiResponse pushStationInfo(@RequestBody QueryStationInfoDTO dto) { + logger.info("推送联联平台充电站信息 params:{}", JSONObject.toJSONString(dto)); + RestApiResponse response = null; + try { + lianLianService.pushStationInfo(Long.parseLong(dto.getStationID())); + response = new RestApiResponse<>(); + }catch (BusinessException e) { + logger.error("推送联联平台充电站信息 error",e); + response = new RestApiResponse<>(e.getCode(), e.getMessage()); + }catch (Exception e) { + logger.error("推送联联平台充电站信息 error", e); + response = new RestApiResponse<>(e); + } + logger.info("推送联联平台充电站信息 result:{}", response); + return response; + } + /** * 联联平台查询充电站信息 * http://localhost:8080/LianLian/query_stations_info @@ -58,6 +76,7 @@ public class LianLianController extends BaseController { /** * 联联平台查询充电站状态信息 + * http://localhost:8080/LianLian/query_station_status * @param StationIDs * @return */ @@ -84,6 +103,8 @@ public class LianLianController extends BaseController { /** * 查询统计信息 + * http://localhost:8080/LianLian/query_station_stats + * * @param dto * @return */ @@ -107,6 +128,7 @@ public class LianLianController extends BaseController { /** * 请求设备认证 + * http://localhost:8080/LianLian/query_equip_auth * @param dto * @return */ @@ -130,6 +152,7 @@ public class LianLianController extends BaseController { /** * 请求启动充电 + * http://localhost:8080/LianLian/query_start_charge * @param dto * @return */ @@ -153,6 +176,7 @@ public class LianLianController extends BaseController { /** * 查询充电状态 + * http://localhost:8080/LianLian/query_equip_charge_status/{startChargeSeq} * @param startChargeSeq * @return */ @@ -176,6 +200,7 @@ public class LianLianController extends BaseController { /** * 请求停止充电 + * http://localhost:8080/LianLian/query_stop_charge * @param dto * @return */ diff --git a/jsowell-admin/src/test/java/SpringBootTestController.java b/jsowell-admin/src/test/java/SpringBootTestController.java index b2a2df73b..a67e6a328 100644 --- a/jsowell-admin/src/test/java/SpringBootTestController.java +++ b/jsowell-admin/src/test/java/SpringBootTestController.java @@ -9,15 +9,12 @@ import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.ykc.OrderStatusEnum; import com.jsowell.common.exception.BusinessException; -import com.jsowell.common.util.BytesUtil; -import com.jsowell.common.util.DateUtils; -import com.jsowell.common.util.DictUtils; -import com.jsowell.common.util.JWTUtils; -import com.jsowell.common.util.StringUtils; -import com.jsowell.common.util.YKCUtils; +import com.jsowell.common.util.*; +import com.jsowell.common.util.http.HttpUtils; import com.jsowell.common.util.id.SnUtils; import com.jsowell.common.util.id.SnowflakeIdWorker; import com.jsowell.common.util.ip.AddressUtils; +import com.jsowell.common.util.lianlian.LianLianUtils; import com.jsowell.netty.command.ykc.IssueQRCodeCommand; import com.jsowell.netty.command.ykc.ProofreadTimeCommand; import com.jsowell.netty.handler.HeartbeatRequestHandler; @@ -29,14 +26,7 @@ import com.jsowell.pile.domain.PileBillingDetail; import com.jsowell.pile.domain.PileBillingTemplate; import com.jsowell.pile.domain.PileStationInfo; import com.jsowell.pile.domain.WxpayCallbackRecord; -import com.jsowell.pile.dto.BasicPileDTO; -import com.jsowell.pile.dto.BatchCreatePileDTO; -import com.jsowell.pile.dto.ImportBillingTemplateDTO; -import com.jsowell.pile.dto.QueryOrderDTO; -import com.jsowell.pile.dto.QueryPileDTO; -import com.jsowell.pile.dto.QueryStationDTO; -import com.jsowell.pile.dto.RefundableWxPayOrderData; -import com.jsowell.pile.dto.WeixinPayDTO; +import com.jsowell.pile.dto.*; import com.jsowell.pile.mapper.MemberBasicInfoMapper; import com.jsowell.pile.mapper.PileBillingTemplateMapper; import com.jsowell.pile.service.IOrderBasicInfoService; @@ -55,6 +45,8 @@ import com.jsowell.service.MemberService; import com.jsowell.service.OrderService; import com.jsowell.service.PileRemoteService; import com.jsowell.service.PileService; +import com.jsowell.thirdparty.domain.StationInfo; +import com.jsowell.thirdparty.service.LianLianService; import com.jsowell.wxpay.common.WeChatPayParameter; import com.jsowell.wxpay.dto.AppletTemplateMessageSendDTO; import com.jsowell.wxpay.dto.WeChatRefundDTO; @@ -73,13 +65,7 @@ import org.springframework.util.StopWatch; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @ActiveProfiles("dev") @SpringBootTest(classes = JsowellApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -154,6 +140,13 @@ public class SpringBootTestController { @Autowired private IPileAuthCardService pileAuthCardService; + @Autowired + private LianLianService lianLianService; + + static final String MAC_KEY = "53TtFpc4gdVZbF3x"; + + static final String ALGORITHM_MAC = "HmacMD5"; + @Test public void testupdateElecAmount() { orderBasicInfoService.updateElecAmount(); @@ -165,6 +158,70 @@ public class SpringBootTestController { System.out.println(pileAuthCard); } + @Test + public void testLianLian() throws Exception { + // Long stationId = 2L; + // // 通过id查询站点相关信息 + // PileStationInfo pileStationInfo = pileStationInfoService.selectPileStationInfoById(stationId); + // // 组装联联平台所需要的数据格式 + // StationInfo info = StationInfo.builder() + // .StationID(String.valueOf(stationId)) + // .OperatorID(Constants.OPERATORID_LIANLIAN) + // .EquipmentOwnerID(Constants.OPERATORID_LIANLIAN) + // .StationName(pileStationInfo.getStationName()) + // .IsAloneApply(Integer.valueOf(pileStationInfo.getAloneApply())) + // .IsPublicParkingLot(Integer.valueOf(pileStationInfo.getPublicParking())) + // .CountryCode(pileStationInfo.getCountryCode()) + // .AreaCode(pileStationInfo.getAreaCode()) + // .Address(pileStationInfo.getAddress()) + // .ServiceTel(pileStationInfo.getServiceTel()) + // .StationType(Integer.valueOf(pileStationInfo.getStationType())) + // .StationStatus(Integer.valueOf(pileStationInfo.getStationStatus())) + // .ParkNums(Integer.valueOf(pileStationInfo.getParkNums())) + // .StationLng(new BigDecimal(pileStationInfo.getStationLng())) + // .StationLat(new BigDecimal(pileStationInfo.getStationLat())) + // .Construction(Integer.valueOf(pileStationInfo.getConstruction())) + // .OpenAllDay(Integer.valueOf(pileStationInfo.getOpenAllDay())) + // // .MinElectricityPrice() + // // .ElectricityFee() + // // .ServiceFee() + // .ParkFree(Integer.valueOf(pileStationInfo.getParkFree())) + // // .ParkFee() + // .Payment(pileStationInfo.getPayment()) + // .SupportOrder(Integer.valueOf(pileStationInfo.getSupportOrder())) + // // .equipmentInfos() + // // .ParkFeeType() + // .ToiletFlag(Integer.valueOf(pileStationInfo.getToiletFlag())) + // .StoreFlag(Integer.valueOf(pileStationInfo.getStoreFlag())) + // .RestaurantFlag(Integer.valueOf(pileStationInfo.getRestaurantFlag())) + // .LoungeFlag(Integer.valueOf(pileStationInfo.getLoungeFlag())) + // .CanopyFlag(Integer.valueOf(pileStationInfo.getCanopyFlag())) + // .PrinterFlag(Integer.valueOf(pileStationInfo.getPrinterFlag())) + // .BarrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag())) + // .ParkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag())) + // + // .build(); + + // List pileList = lianLianService.getPileList(pileStationInfo); + // if (CollectionUtils.isNotEmpty(pileList)) { + // info.setEquipmentInfos(pileList); // 充电设备信息列表 + // } + + String url = "http://testdataexchange.evchargeonline.com:82/shevcs/v1/" + "notification_stationInfo"; + JSONObject json = new JSONObject(); + json.put("OperatorID", "MA1JLFUU8"); + json.put("OperatorSecret", "Nh62XxllR5OjAzFj"); + // json.put("StationInfo", info); + + LianLianGetTokenDTO dto = new LianLianGetTokenDTO(); + dto.setOperatorId("987654321"); + dto.setOperatorSecret("1234567890abcdef"); + String token = lianLianService.getToken(dto); + System.out.println("token:" + token); + + } + + @Test public void testRefundForBalance() { BigDecimal refundAmount = new BigDecimal("2"); diff --git a/jsowell-common/src/main/java/com/jsowell/common/constant/Constants.java b/jsowell-common/src/main/java/com/jsowell/common/constant/Constants.java index 478fc9724..96d68d6b9 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/constant/Constants.java +++ b/jsowell-common/src/main/java/com/jsowell/common/constant/Constants.java @@ -33,6 +33,8 @@ public class Constants { public static final String partnerId = "1632405339"; // 商户号Id + public static final String OPERATORID_LIANLIAN = "MA1JLFUU8"; + // public static final String APP_ID = "wxbb3e0d474569481d"; // 举视充电网 wxbb3e0d474569481d // // public static final String APP_SECRET = "bbac689f4654b209de4d6944808ec80b"; // 举视充电网 bbac689f4654b209de4d6944808ec80b diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/LianLianUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/LianLianUtils.java deleted file mode 100644 index 712ea2107..000000000 --- a/jsowell-common/src/main/java/com/jsowell/common/util/LianLianUtils.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.jsowell.common.util;/** - * TODO - * - * @author JS-ZZA - * @date 2023/5/6 14:22 - */public class LianLianUtils { -} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Cryptos.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Cryptos.java new file mode 100644 index 000000000..9e4da21f2 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Cryptos.java @@ -0,0 +1,248 @@ +/** + */ +package com.jsowell.common.util.lianlian; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; + +public class Cryptos { + + private static final String AES = "AES"; + private static final String AES_CBC = "AES/CBC/PKCS5Padding"; + private static final String HMACSHA1 = "HmacSHA1"; + + private static final String DEFAULT_URL_ENCODING = "UTF-8"; + private static final int DEFAULT_HMACSHA1_KEYSIZE = 160; //RFC2401 + private static final int DEFAULT_AES_KEYSIZE = 128; + private static final int DEFAULT_IVSIZE = 16; + + private static final byte[] DEFAULT_KEY = new byte[]{-97,88,-94,9,70,-76,126,25,0,3,-20,113,108,28,69,125}; + + private static SecureRandom random = new SecureRandom(); + + //-- HMAC-SHA1 funciton --// + /** + * 使用HMAC-SHA1进行消息签名, 返回字节数组,长度为20字节. + * + * @param input 原始输入字符数组 + * @param key HMAC-SHA1密钥 + */ + public static byte[] hmacSha1(byte[] input, byte[] key) { + try { + SecretKey secretKey = new SecretKeySpec(key, HMACSHA1); + Mac mac = Mac.getInstance(HMACSHA1); + mac.init(secretKey); + return mac.doFinal(input); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * 校验HMAC-SHA1签名是否正确. + * + * @param expected 已存在的签名 + * @param input 原始输入字符串 + * @param key 密钥 + */ + public static boolean isMacValid(byte[] expected, byte[] input, byte[] key) { + byte[] actual = hmacSha1(input, key); + return Arrays.equals(expected, actual); + } + + /** + * 生成HMAC-SHA1密钥,返回字节数组,长度为160位(20字节). + * HMAC-SHA1算法对密钥无特殊要求, RFC2401建议最少长度为160位(20字节). + */ + public static byte[] generateHmacSha1Key() { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance(HMACSHA1); + keyGenerator.init(DEFAULT_HMACSHA1_KEYSIZE); + SecretKey secretKey = keyGenerator.generateKey(); + return secretKey.getEncoded(); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + //-- AES funciton --// + + /** + * 使用AES加密原始字符串. + * + * @param input 原始输入字符数组 + */ + public static String aesEncrypt(String input) { + try { + return Encodes.encodeHex(aesEncrypt(input.getBytes(DEFAULT_URL_ENCODING), DEFAULT_KEY)); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * 使用AES加密原始字符串. + * + * @param input 原始输入字符数组 + * @param key 符合AES要求的密钥 + */ + public static String aesEncrypt(String input, String key) { + try { + return Encodes.encodeHex(aesEncrypt(input.getBytes(DEFAULT_URL_ENCODING), Encodes.decodeHex(key))); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * 使用AES加密原始字符串. + * + * @param input 原始输入字符数组 + * @param key 符合AES要求的密钥 + */ + public static byte[] aesEncrypt(byte[] input, byte[] key) { + return aes(input, key, Cipher.ENCRYPT_MODE); + } + + /** + * 使用AES加密原始字符串. + * + * @param input 原始输入字符数组 + * @param key 符合AES要求的密钥 + * @param iv 初始向量 + */ + public static byte[] aesEncrypt(byte[] input, byte[] key, byte[] iv) { + return aes(input, key, iv, Cipher.ENCRYPT_MODE); + } + + /** + * 使用AES解密字符串, 返回原始字符串. + * + * @param input Hex编码的加密字符串 + */ + public static String aesDecrypt(String input) { + try { + return new String(aesDecrypt(Encodes.decodeHex(input), DEFAULT_KEY), DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * 使用AES解密字符串, 返回原始字符串. + * + * @param input Hex编码的加密字符串 + * @param key 符合AES要求的密钥 + */ + public static String aesDecrypt(String input, String key) { + try { + return new String(aesDecrypt(Encodes.decodeHex(input), Encodes.decodeHex(key)), DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * 使用AES解密字符串, 返回原始字符串. + * + * @param input Hex编码的加密字符串 + * @param key 符合AES要求的密钥 + */ + public static byte[] aesDecrypt(byte[] input, byte[] key) { + return aes(input, key, Cipher.DECRYPT_MODE); + } + + /** + * 使用AES解密字符串, 返回原始字符串. + * + * @param input Hex编码的加密字符串 + * @param key 符合AES要求的密钥 + * @param iv 初始向量 + */ + public static byte[] aesDecrypt(byte[] input, byte[] key, byte[] iv) { + return aes(input, key, iv, Cipher.DECRYPT_MODE); + } + + /** + * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果. + * + * @param input 原始字节数组 + * @param key 符合AES要求的密钥 + * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE + */ + private static byte[] aes(byte[] input, byte[] key, int mode) { + try { + SecretKey secretKey = new SecretKeySpec(key, AES); + Cipher cipher = Cipher.getInstance(AES); + cipher.init(mode, secretKey); + return cipher.doFinal(input); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果. + * + * @param input 原始字节数组 + * @param key 符合AES要求的密钥 + * @param iv 初始向量 + * @param mode Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE + */ + private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) { + try { + SecretKey secretKey = new SecretKeySpec(key, AES); + IvParameterSpec ivSpec = new IvParameterSpec(iv); + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(mode, secretKey, ivSpec); + return cipher.doFinal(input); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * 生成AES密钥,返回字节数组, 默认长度为128位(16字节). + */ + public static String generateAesKeyString() { + return Encodes.encodeHex(generateAesKey(DEFAULT_AES_KEYSIZE)); + } + + /** + * 生成AES密钥,返回字节数组, 默认长度为128位(16字节). + */ + public static byte[] generateAesKey() { + return generateAesKey(DEFAULT_AES_KEYSIZE); + } + + /** + * 生成AES密钥,可选长度为128,192,256位. + */ + public static byte[] generateAesKey(int keysize) { + try { + KeyGenerator keyGenerator = KeyGenerator.getInstance(AES); + keyGenerator.init(keysize); + SecretKey secretKey = keyGenerator.generateKey(); + return secretKey.getEncoded(); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * 生成随机向量,默认大小为cipher.getBlockSize(), 16字节. + */ + public static byte[] generateIV() { + byte[] bytes = new byte[DEFAULT_IVSIZE]; + random.nextBytes(bytes); + return bytes; + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Digests.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Digests.java new file mode 100644 index 000000000..32d885051 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Digests.java @@ -0,0 +1,113 @@ +/** + */ +package com.jsowell.common.util.lianlian; + +import org.apache.commons.lang3.Validate; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.SecureRandom; + +public class Digests { + + private static final String SHA1 = "SHA-1"; + private static final String MD5 = "MD5"; + + private static SecureRandom random = new SecureRandom(); + + /** + * 对输入字符串进行md5散列. + */ + public static byte[] md5(byte[] input) { + return digest(input, MD5, null, 1); + } + public static byte[] md5(byte[] input, int iterations) { + return digest(input, MD5, null, iterations); + } + + /** + * 对输入字符串进行sha1散列. + */ + public static byte[] sha1(byte[] input) { + return digest(input, SHA1, null, 1); + } + + public static byte[] sha1(byte[] input, byte[] salt) { + return digest(input, SHA1, salt, 1); + } + + public static byte[] sha1(byte[] input, byte[] salt, int iterations) { + return digest(input, SHA1, salt, iterations); + } + + /** + * 对字符串进行散列, 支持md5与sha1算法. + */ + private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + + if (salt != null) { + digest.update(salt); + } + + byte[] result = digest.digest(input); + + for (int i = 1; i < iterations; i++) { + digest.reset(); + result = digest.digest(result); + } + return result; + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * 生成随机的Byte[]作为salt. + * + * @param numBytes byte数组的大小 + */ + public static byte[] generateSalt(int numBytes) { + Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes); + + byte[] bytes = new byte[numBytes]; + random.nextBytes(bytes); + return bytes; + } + + /** + * 对文件进行md5散列. + */ + public static byte[] md5(InputStream input) throws IOException { + return digest(input, MD5); + } + + /** + * 对文件进行sha1散列. + */ + public static byte[] sha1(InputStream input) throws IOException { + return digest(input, SHA1); + } + + private static byte[] digest(InputStream input, String algorithm) throws IOException { + try { + MessageDigest messageDigest = MessageDigest.getInstance(algorithm); + int bufferLength = 8 * 1024; + byte[] buffer = new byte[bufferLength]; + int read = input.read(buffer, 0, bufferLength); + + while (read > -1) { + messageDigest.update(buffer, 0, read); + read = input.read(buffer, 0, bufferLength); + } + + return messageDigest.digest(); + } catch (GeneralSecurityException e) { + throw Exceptions.unchecked(e); + } + } + +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Encodes.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Encodes.java new file mode 100644 index 000000000..7f37dfdb3 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Encodes.java @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2005-2012 springside.org.cn + */ +package com.jsowell.common.util.lianlian; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.StringEscapeUtils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +public class Encodes { + + private static final String DEFAULT_URL_ENCODING = "UTF-8"; + private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + + /** + * Hex编码. + */ + public static String encodeHex(byte[] input) { + return new String(Hex.encodeHex(input)); + } + + /** + * Hex解码. + */ + public static byte[] decodeHex(String input) { + try { + return Hex.decodeHex(input.toCharArray()); + } catch (DecoderException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * Base64编码. + */ + public static String encodeBase64(byte[] input) { + return new String(Base64.encodeBase64(input)); + } + + /** + * Base64编码. + */ + public static String encodeBase64(String input) { + try { + return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING))); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + +// /** +// * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548). +// */ +// public static String encodeUrlSafeBase64(byte[] input) { +// return Base64.encodeBase64URLSafe(input); +// } + + /** + * Base64解码. + */ + public static byte[] decodeBase64(String input) { + return Base64.decodeBase64(input.getBytes()); + } + + /** + * Base64解码. + */ + public static String decodeBase64String(String input) { + try { + return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * Base62编码。 + */ + public static String encodeBase62(byte[] input) { + char[] chars = new char[input.length]; + for (int i = 0; i < input.length; i++) { + chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)]; + } + return new String(chars); + } + + /** + * Html 转码. + */ + public static String escapeHtml(String html) { + return StringEscapeUtils.escapeHtml4(html); + } + + /** + * Html 解码. + */ + public static String unescapeHtml(String htmlEscaped) { + return StringEscapeUtils.unescapeHtml4(htmlEscaped); + } + + /** + * Xml 转码. + */ + public static String escapeXml(String xml) { + return StringEscapeUtils.escapeXml10(xml); + } + + /** + * Xml 解码. + */ + public static String unescapeXml(String xmlEscaped) { + return StringEscapeUtils.unescapeXml(xmlEscaped); + } + + /** + * URL 编码, Encode默认为UTF-8. + */ + public static String urlEncode(String part) { + try { + return URLEncoder.encode(part, DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + throw Exceptions.unchecked(e); + } + } + + /** + * URL 解码, Encode默认为UTF-8. + */ + public static String urlDecode(String part) { + + try { + return URLDecoder.decode(part, DEFAULT_URL_ENCODING); + } catch (UnsupportedEncodingException e) { + throw Exceptions.unchecked(e); + } + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Exceptions.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Exceptions.java new file mode 100644 index 000000000..02ce6e0af --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Exceptions.java @@ -0,0 +1,72 @@ +package com.jsowell.common.util.lianlian; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * 关于异常的工具类. + */ +public class Exceptions { + private static Logger logger = LoggerFactory.getLogger(Exceptions.class); + + /** + * 将CheckedException转换为UncheckedException. + */ + public static RuntimeException unchecked(Exception e) { + if (e instanceof RuntimeException) { + return (RuntimeException) e; + } else { + return new RuntimeException(e); + } + } + + /** + * 将ErrorStack转化为String. + */ + public static String getStackTraceAsString(Throwable e) { + if (e == null) { + return ""; + } + StringWriter stringWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } + + /** + * 判断异常是否由某些底层的异常引起. + */ + public static boolean isCausedBy(Exception ex, Class... causeExceptionClasses) { + Throwable cause = ex.getCause(); + while (cause != null) { + for (Class causeClass : causeExceptionClasses) { + if (causeClass.isInstance(cause)) { + return true; + } + } + cause = cause.getCause(); + } + return false; + } + + /** + * 在request中获取异常类 + * + * @param request + * @return + */ + public static Throwable getThrowable(HttpServletRequest request) { + Throwable ex = null; + if (request.getAttribute("exception") != null) { + ex = (Throwable) request.getAttribute("exception"); + } else if (request.getAttribute("javax.servlet.error.exception") != null) { + ex = (Throwable) request.getAttribute("javax.servlet.error.exception"); + } + return ex; + } + + +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/GBSignUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/GBSignUtils.java new file mode 100644 index 000000000..1dace0d68 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/GBSignUtils.java @@ -0,0 +1,58 @@ +package com.jsowell.common.util.lianlian; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.util.Map; + +public class GBSignUtils { + + public static final Logger logger = LoggerFactory.getLogger(GBSignUtils.class); + + public static String sign(Map paramValues, String secret) { + try { + StringBuilder sb = new StringBuilder(); + for (String value : paramValues.values()) { + if (StringUtils.isNotBlank(value)) { + sb.append(value); + } + } + logger.debug("需要签名的内容:{},密钥{}", sb.toString(), secret); + byte[] md5Digest = HmacMD5Encrypt(sb.toString(), secret); + String result = Encodes.encodeHex(md5Digest).toUpperCase(); + logger.debug("HmacSHA1的签名内容:{}", result); + return result; + } catch (Exception e) { + throw new RuntimeException("数据签名出错", e); + } + } + + /** + * 使用 HMAC-MD5 签名方法对对encryptText进行签名 + * + * @param encryptText + * 被签名的字符串 + * @param encryptKey + * 密钥 + * @return + * @throws Exception + */ + public static byte[] HmacMD5Encrypt(String encryptText, String encryptKey) throws Exception { + byte[] data = encryptKey.getBytes("UTF-8"); + // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称 + SecretKey secretKey = new SecretKeySpec(data, "HmacMD5"); + // 生成一个指定 Mac 算法 的 Mac 对象 + Mac mac = Mac.getInstance("HmacMD5"); + // 用给定密钥初始化 Mac 对象 + mac.init(secretKey); + + byte[] text = encryptText.getBytes("UTF-8"); + // 完成 Mac 操作 + return mac.doFinal(text); + } + +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/HttpRequestUtil.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/HttpRequestUtil.java new file mode 100644 index 000000000..847e26aa2 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/HttpRequestUtil.java @@ -0,0 +1,85 @@ +package com.jsowell.common.util.lianlian; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +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.util.EntityUtils; + +/** + * @author 联联充电 + */ +@Slf4j +@SuppressWarnings(value = "unused") +public class HttpRequestUtil { + + + /** + * httpClient--post请求--http + * + * @param url + * @param json + * @return + */ + public static String httpPost(String url, String json, String token) { + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + try { + //创建httpPost + HttpPost httpPost = new HttpPost(url); + + //设置Content-Type + httpPost.setHeader("Content-Type", "application/json"); + httpPost.setHeader("Authorization", token); + + //写入json数据 + httpPost.setEntity(new StringEntity(json)); + + RequestConfig requestConfig = RequestConfig.custom() + .setConnectTimeout(50000) + .setConnectionRequestTimeout(50000) + .setSocketTimeout(50000) + .build(); + httpPost.setConfig(requestConfig); + + //发起请求,获取response对象 + response = httpClient.execute(httpPost); + + //获取结果状态码 + int resultCode = response.getStatusLine().getStatusCode(); + if (resultCode == 200) { + //获取返回数据实体对象 + HttpEntity entity = response.getEntity(); + + //转化为字符串 + String result = EntityUtils.toString(entity, "UTF-8"); + //封装统一的返回数据接收类 + //ResponseMsg responseMsg = (ResponseMsg) JSON.parse(result); + return result; + } else { + log.info("http请求失败"); + } + } catch (Exception e) { + log.info("http请求异常"); + } finally { + try { + if (httpClient != null) { + httpClient.close(); + } + if (response != null) { + response.close(); + } + } catch (Exception e) { + log.info(e.getMessage(), e); + } + } + + return null; + } + + +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/LianLianUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/LianLianUtils.java new file mode 100644 index 000000000..8379cfb50 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/LianLianUtils.java @@ -0,0 +1,48 @@ +package com.jsowell.common.util.lianlian; + +import com.jsowell.common.constant.Constants; +import com.jsowell.common.util.BytesUtil; +import com.jsowell.common.util.DateUtils; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.util.Locale; + +/** + * 联联平台工具类 + * + * @author JS-ZZA + * @date 2023/5/6 14:22 + */ +public class LianLianUtils { + static final String ALGORITHM_MAC = "HmacMD5"; + + /** 密钥 **/ + static final String MAC_KEY = "TmsdVaFVTtjzZbLi"; + + + /** + * HMAC加密 + * @return + * @throws Exception + */ + public static String encryptionHMAC(String source) throws Exception { + SecretKey secretKey = new SecretKeySpec(MAC_KEY.getBytes("UTF-8"), ALGORITHM_MAC); + Mac mac = Mac.getInstance(ALGORITHM_MAC); + mac.init(secretKey); + mac.update(source.getBytes("UTF-8")); + return BytesUtil.binary(mac.doFinal(), 16).toUpperCase(Locale.ROOT); + } + + /** + * 拼接参数 + * @param Data + * @return + */ + public static String connectData(String Data){ + String timeStamp = DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS); + String number = "0001"; + return Constants.OPERATORID_LIANLIAN + Data + timeStamp + number; + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/SignUtils.java b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/SignUtils.java new file mode 100644 index 000000000..e92ae8008 --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/util/lianlian/SignUtils.java @@ -0,0 +1,116 @@ +package com.jsowell.common.util.lianlian; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.util.*; + +public class SignUtils { + + private static String UTF_8 = "UTF-8"; + + /** + * 使用secret对paramValues按以下算法进行签名:
+ * uppercase(hex(sha1(secretkey1value1key2value2...secret)) + * + * @param paramValues + * 参数列表 + * @param secret + * @return + */ + public static String sign(Map paramValues, String secret) { + return sign(paramValues, null, secret); + } + + /** + * 对paramValues进行签名,其中ignoreParamNames这些参数不参与签名 + * + * @param paramValues + * @param ignoreParamNames + * @param secret + * @return + */ + public static String sign(Map paramValues, List ignoreParamNames, String secret) { + try { + StringBuilder sb = new StringBuilder(); + List paramNames = new ArrayList(paramValues.size()); + paramNames.addAll(paramValues.keySet()); + if (ignoreParamNames != null && ignoreParamNames.size() > 0) { + for (String ignoreParamName : ignoreParamNames) { + paramNames.remove(ignoreParamName); + } + } + Collections.sort(paramNames); + + sb.append(secret); + for (String paramName : paramNames) { + sb.append(paramName).append(paramValues.get(paramName)); + } + sb.append(secret); + System.out.println("原始的签名:" + sb.toString()); + byte[] sha1Digest = getSHA1Digest(sb.toString()); + System.out.println("sha-1的二进制码:" + String.valueOf(sha1Digest)); + return byte2hex(sha1Digest); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String utf8Encoding(String value, String sourceCharsetName) { + try { + return new String(value.getBytes(sourceCharsetName), UTF_8); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + } + + private static byte[] getSHA1Digest(String data) throws IOException { + byte[] bytes = null; + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + bytes = md.digest(data.getBytes(UTF_8)); + } catch (GeneralSecurityException gse) { + throw new IOException(gse.getMessage()) ; + } + return bytes; + } + + // private static byte[] getMD5Digest(String data) throws IOException { + // byte[] bytes = null; + // try { + // MessageDigest md = MessageDigest.getInstance("MD5"); + // bytes = md.digest(data.getBytes(UTF_8)); + // } catch (GeneralSecurityException gse) { + // throw new IOException(gse.getMessage()); + // } + // return bytes; + // } + + /** + * 二进制转十六进制字符串 + * + * @param bytes + * @return + */ + private static String byte2hex(byte[] bytes) { + StringBuilder sign = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(bytes[i] & 0xFF); + if (hex.length() == 1) { + sign.append("0"); + } + sign.append(hex.toUpperCase()); + } + System.out.println("最终的签名:" + sign); + return sign.toString(); + } + + public static String getUUID() { + UUID uuid = UUID.randomUUID(); + return uuid.toString().toUpperCase(); + } + + + +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/LianLianGetTokenDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/LianLianGetTokenDTO.java new file mode 100644 index 000000000..0517e605a --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/LianLianGetTokenDTO.java @@ -0,0 +1,19 @@ +package com.jsowell.pile.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 联联充电获取令牌 + * + * @author JS-ZZA + * @date 2023/5/9 13:54 + */ +@Data +public class LianLianGetTokenDTO { + @JsonProperty(value = "OperatorID") + private String operatorId; + + @JsonProperty(value = "OperatorSecret") + private String operatorSecret; +} diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/LianLianService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/LianLianService.java index d616513a2..94a7860c7 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/LianLianService.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/LianLianService.java @@ -1,5 +1,6 @@ package com.jsowell.thirdparty.service; +import com.jsowell.pile.dto.LianLianGetTokenDTO; import com.jsowell.pile.dto.QueryEquipmentDTO; import com.jsowell.pile.dto.QueryStartChargeDTO; import com.jsowell.thirdparty.domain.StationStatsInfo; @@ -16,6 +17,12 @@ public interface LianLianService { */ void pushMerchantInfo(Long merchantId); + /** + * 根据充电站id,推送充电站信息 + * @param stationId + */ + void pushStationInfo(Long stationId) throws Exception; + /** * 联联平台获取充电站信息 * @param dto @@ -67,4 +74,6 @@ public interface LianLianService { * @return */ QueryStopChargeVO query_stop_charge(QueryStartChargeDTO dto); + + String getToken(LianLianGetTokenDTO dto); } diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/impl/LianLianServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/impl/LianLianServiceImpl.java index e4cbda691..a526b1f89 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/impl/LianLianServiceImpl.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/service/impl/LianLianServiceImpl.java @@ -1,20 +1,28 @@ package com.jsowell.thirdparty.service.impl; import cn.hutool.core.util.PageUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import com.github.pagehelper.PageInfo; import com.google.common.collect.Lists; +import com.jsowell.common.constant.Constants; import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; -import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.ykc.OrderStatusEnum; import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum; import com.jsowell.common.exception.BusinessException; -import com.jsowell.common.util.DateUtils; -import com.jsowell.common.util.PageUtils; -import com.jsowell.common.util.StringUtils; +import com.jsowell.common.util.*; +import com.jsowell.common.util.http.HttpUtils; +import com.jsowell.common.util.lianlian.Cryptos; +import com.jsowell.common.util.lianlian.Encodes; +import com.jsowell.common.util.lianlian.GBSignUtils; +import com.jsowell.common.util.lianlian.LianLianUtils; import com.jsowell.netty.command.ykc.StartChargingCommand; import com.jsowell.netty.command.ykc.StopChargingCommand; import com.jsowell.netty.service.yunkuaichong.YKCPushCommandService; import com.jsowell.pile.domain.*; +import com.jsowell.pile.dto.LianLianGetTokenDTO; import com.jsowell.pile.dto.QueryEquipmentDTO; import com.jsowell.pile.dto.QueryStartChargeDTO; import com.jsowell.pile.dto.QueryStationInfoDTO; @@ -27,7 +35,6 @@ import com.jsowell.pile.service.IPileStationInfoService; import com.jsowell.pile.vo.base.ConnectorInfoVO; import com.jsowell.pile.vo.base.MerchantInfoVO; import com.jsowell.pile.vo.lianlian.AccumulativeInfoVO; -import com.jsowell.pile.vo.uniapp.SendMessageVO; import com.jsowell.pile.vo.web.PileConnectorInfoVO; import com.jsowell.pile.vo.web.PileModelInfoVO; import com.jsowell.thirdparty.domain.ConnectorChargeStatusInfo; @@ -47,9 +54,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; @Service @@ -82,13 +87,81 @@ public class LianLianServiceImpl implements LianLianService { MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(merchantId)); // 组装联联平台所需要的数据格式 OperatorInfo operatorInfo = OperatorInfo.builder() - .OperatorID(merchantInfo.getOrganizationCode()) // 组织机构代码 + .OperatorID(Constants.OPERATORID_LIANLIAN) // 组织机构代码 .OperatorName(merchantInfo.getMerchantName()) // 机构全称 .OperatorTel1(merchantInfo.getMerchantTel()) // 对接平台客服电话1 .build(); // 调用联联平台接口 + } + + /** + * 根据站点id推送站点信息 + * @param stationId + */ + @Override + public void pushStationInfo(Long stationId) throws Exception { + // 通过id查询站点相关信息 + PileStationInfo pileStationInfo = pileStationInfoService.selectPileStationInfoById(stationId); + // 组装联联平台所需要的数据格式 + StationInfo info = StationInfo.builder() + .StationID(String.valueOf(stationId)) + .OperatorID(Constants.OPERATORID_LIANLIAN) + .EquipmentOwnerID(Constants.OPERATORID_LIANLIAN) + .StationName(pileStationInfo.getStationName()) + .IsAloneApply(Integer.valueOf(pileStationInfo.getAloneApply())) + .IsPublicParkingLot(Integer.valueOf(pileStationInfo.getPublicParking())) + .CountryCode(pileStationInfo.getCountryCode()) + .AreaCode(pileStationInfo.getAreaCode()) + .Address(pileStationInfo.getAddress()) + .ServiceTel(pileStationInfo.getServiceTel()) + .StationType(Integer.valueOf(pileStationInfo.getStationType())) + .StationStatus(Integer.valueOf(pileStationInfo.getStationStatus())) + .ParkNums(Integer.valueOf(pileStationInfo.getParkNums())) + .StationLng(new BigDecimal(pileStationInfo.getStationLng())) + .StationLat(new BigDecimal(pileStationInfo.getStationLat())) + .Construction(Integer.valueOf(pileStationInfo.getConstruction())) + .OpenAllDay(Integer.valueOf(pileStationInfo.getOpenAllDay())) + // .MinElectricityPrice() + // .ElectricityFee() + // .ServiceFee() + .ParkFree(Integer.valueOf(pileStationInfo.getParkFree())) + // .ParkFee() + .Payment(pileStationInfo.getPayment()) + .SupportOrder(Integer.valueOf(pileStationInfo.getSupportOrder())) + // .equipmentInfos() + // .ParkFeeType() + .ToiletFlag(Integer.valueOf(pileStationInfo.getToiletFlag())) + .StoreFlag(Integer.valueOf(pileStationInfo.getStoreFlag())) + .RestaurantFlag(Integer.valueOf(pileStationInfo.getRestaurantFlag())) + .LoungeFlag(Integer.valueOf(pileStationInfo.getLoungeFlag())) + .CanopyFlag(Integer.valueOf(pileStationInfo.getCanopyFlag())) + .PrinterFlag(Integer.valueOf(pileStationInfo.getPrinterFlag())) + .BarrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag())) + .ParkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag())) + + .build(); + + List pileList = getPileList(pileStationInfo); + if (CollectionUtils.isNotEmpty(pileList)) { + info.setEquipmentInfos(pileList); // 充电设备信息列表 + } + + // 调用联联平台接口 + String url = "http://dataexchange.evchargeonline.com:81/shevcs/v1/" + "notification_stationInfo"; + + JSONObject jsonObject = new JSONObject(); + // Map map = new HashMap<>(); + jsonObject.put("StationInfo", info); + String s = HttpUtils.sendPost(url, jsonObject.toJSONString()); + + System.out.println(s); + + } + + public static void main(String[] args) throws Exception { + } /** @@ -112,8 +185,8 @@ public class LianLianServiceImpl implements LianLianService { for (PileStationInfo pileStationInfo : pageInfo.getList()) { StationInfo stationInfo = new StationInfo(); stationInfo.setStationID(String.valueOf(pileStationInfo.getId())); - MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(pileStationInfo.getMerchantId())); - stationInfo.setOperatorID(merchantInfo.getOrganizationCode()); // 组织机构代码 + // MerchantInfoVO merchantInfo = pileMerchantInfoService.getMerchantInfo(String.valueOf(pileStationInfo.getMerchantId())); + stationInfo.setOperatorID(Constants.OPERATORID_LIANLIAN); // 组织机构代码 stationInfo.setEquipmentOwnerID(String.valueOf(pileStationInfo.getMerchantId())); stationInfo.setStationName(pileStationInfo.getStationName()); stationInfo.setIsAloneApply(Integer.valueOf(pileStationInfo.getAloneApply())); @@ -481,6 +554,60 @@ public class LianLianServiceImpl implements LianLianService { return vo; } + /** + * 获取令牌 + * @param dto + * @return + */ + @Override + public String getToken(LianLianGetTokenDTO dto) { + String operatorId = dto.getOperatorId(); + String operatorSecret = dto.getOperatorSecret(); + String token = ""; + try { + //测试用请求地址 + String requestUrl = "http://testdataexchange.evchargeonline.com:82/shevcs/v1/query_token"; + + //请求data + Map data = new HashMap<>(); + data.put("OperatorID", operatorId); + data.put("OperatorSecret", operatorSecret); + String dataJson = JSONUtil.toJsonStr(data); + + //加密 + byte[] encryptText = Cryptos.aesEncrypt(dataJson.getBytes("UTF-8"), + operatorSecret.getBytes(), operatorSecret.getBytes()); + String strData = Encodes.encodeBase64(encryptText); + + Map request = new LinkedHashMap<>(); + request.put("OperatorID", operatorId); + request.put("Data", strData); + request.put("TimeStamp", System.currentTimeMillis() + ""); + request.put("Seq", "0001"); + + //生成签名 + String sig = GBSignUtils.sign(request, operatorSecret); + request.put("Sig", sig); + + String tokenRequest = JSONUtil.toJsonStr(request); + + String response = HttpUtil.post(requestUrl, tokenRequest); + LianLianResultVO result = JSON.parseObject(response, LianLianResultVO.class); + + if (result.getRet() == 0) { + //解密data + byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64((String) result.getData()), + operatorSecret.getBytes(), operatorSecret.getBytes()); + String dataStr = new String(plainText, "UTF-8"); + Map resultMap = (Map) JSON.parse(dataStr); + token = resultMap.get("AccessToken"); + } + } catch (Exception e) { + return token; + } + return token; + } + // TODO 推送停止充电结果 notification_stop_charge_result // TODO 推送充电订单信息 notification_charge_order_info diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/vo/LianLianResultVO.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/vo/LianLianResultVO.java new file mode 100644 index 000000000..e861791af --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/vo/LianLianResultVO.java @@ -0,0 +1,43 @@ +package com.jsowell.thirdparty.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 联联平台接口返回对象 + * + * @author JS-ZZA + * @date 2023/5/10 8:36 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class LianLianResultVO { + /** + * 系统错误码 + */ + @JsonProperty("Ret") + int ret = 0; + + /** + * 返回提示信息 + */ + @JsonProperty("Msg") + String msg = ""; + + /** + * 返回结果 + */ + @JsonProperty("Data") + Object data; + + /** + * 签名 + */ + @JsonProperty("Sig") + String sig; +}