From d2eed9ad3a34ce6b8c6f6865491527753ede2d73 Mon Sep 17 00:00:00 2001 From: Lemon Date: Wed, 10 May 2023 08:49:01 +0800 Subject: [PATCH 01/16] =?UTF-8?q?add=20=20=E8=81=94=E8=81=94=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E7=9B=B8=E5=85=B3=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsowell/lianlian/LianLianController.java | 25 ++ .../test/java/SpringBootTestController.java | 99 +++++-- .../jsowell/common/constant/Constants.java | 2 + .../jsowell/common/util/LianLianUtils.java | 7 - .../jsowell/common/util/lianlian/Cryptos.java | 248 ++++++++++++++++++ .../jsowell/common/util/lianlian/Digests.java | 113 ++++++++ .../jsowell/common/util/lianlian/Encodes.java | 142 ++++++++++ .../common/util/lianlian/Exceptions.java | 72 +++++ .../common/util/lianlian/GBSignUtils.java | 58 ++++ .../common/util/lianlian/HttpRequestUtil.java | 85 ++++++ .../common/util/lianlian/LianLianUtils.java | 48 ++++ .../common/util/lianlian/SignUtils.java | 116 ++++++++ .../jsowell/pile/dto/LianLianGetTokenDTO.java | 19 ++ .../thirdparty/service/LianLianService.java | 9 + .../service/impl/LianLianServiceImpl.java | 149 ++++++++++- .../thirdparty/vo/LianLianResultVO.java | 43 +++ 16 files changed, 1196 insertions(+), 39 deletions(-) delete mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/LianLianUtils.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Cryptos.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Digests.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Encodes.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/Exceptions.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/GBSignUtils.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/HttpRequestUtil.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/LianLianUtils.java create mode 100644 jsowell-common/src/main/java/com/jsowell/common/util/lianlian/SignUtils.java create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/dto/LianLianGetTokenDTO.java create mode 100644 jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/vo/LianLianResultVO.java 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; +} From 9215dd458f611f80d0bf1a9d230741c58cde55e3 Mon Sep 17 00:00:00 2001 From: "autumn.g@foxmail.com" Date: Wed, 10 May 2023 08:40:20 +0800 Subject: [PATCH 02/16] =?UTF-8?q?update=20=E7=AB=99=E7=82=B9=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit e5fa93ed9fcdbf28fd982537d8667e9bf73ea3d4) --- .../pile/service/impl/PileStationInfoServiceImpl.java | 6 ++++++ .../main/java/com/jsowell/pile/vo/web/PileStationVO.java | 5 +++++ .../src/views/pile/station/components/SiteInfo.vue | 9 ++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java index a346cc404..9df7f6e24 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java @@ -71,6 +71,8 @@ public class PileStationInfoServiceImpl implements IPileStationInfoService { @Autowired private RedisCache redisCache; + + /** * 查询充电站信息 * @@ -134,6 +136,7 @@ public class PileStationInfoServiceImpl implements IPileStationInfoService { // vo.setOrganizationCode(pileStationInfo.getor); vo.setPublicFlag(pileStationInfo.getPublicFlag()); vo.setOpenFlag(pileStationInfo.getOpenFlag()); + vo.setDeptId(pileStationInfo.getDeptId()); if (StringUtils.isNotBlank(pileStationInfo.getPictures())) { vo.setPictures(pileStationInfo.getPictures()); vo.setPictureList(Lists.newArrayList(pileStationInfo.getPictures().split(","))); @@ -255,6 +258,9 @@ public class PileStationInfoServiceImpl implements IPileStationInfoService { redisCache.deleteObject(redisKey); pileStationInfo.setUpdateBy(SecurityUtils.getUsername()); pileStationInfo.setUpdateTime(DateUtils.getNowDate()); + // 同步组织中的名称,联系人,电话 + // sysDeptService.updateDept() + return pileStationInfoMapper.updatePileStationInfo(pileStationInfo); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/vo/web/PileStationVO.java b/jsowell-pile/src/main/java/com/jsowell/pile/vo/web/PileStationVO.java index 7eb515ac7..34f28f894 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/vo/web/PileStationVO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/vo/web/PileStationVO.java @@ -29,6 +29,11 @@ public class PileStationVO { */ private String stationName; + /** + * 组织id + */ + private String deptId; + /** * 省市辖区编码 */ diff --git a/jsowell-ui/src/views/pile/station/components/SiteInfo.vue b/jsowell-ui/src/views/pile/station/components/SiteInfo.vue index 88011f936..b1f393387 100644 --- a/jsowell-ui/src/views/pile/station/components/SiteInfo.vue +++ b/jsowell-ui/src/views/pile/station/components/SiteInfo.vue @@ -292,6 +292,7 @@ export default { ], }, fileList: [], // 用于图片回显 + dialogVisible: null, }; }, created() { @@ -324,9 +325,11 @@ export default { const res = await getStationInfo(this.stationId); console.log(res); this.station = res.data; - var pictures = res.data.pictures.split(','); - for (let i = 0; i < pictures.length; i++) { - this.fileList.push({"url": pictures[i]}); + if (res.data.pictures != null) { + var pictures = res.data.pictures.split(','); + for (let i = 0; i < pictures.length; i++) { + this.fileList.push({"url": pictures[i]}); + } } console.log("queryStationInfo表格数据", this.station); }, From 4f0f785839879b16453004394e1fb764d0ac80ea Mon Sep 17 00:00:00 2001 From: "autumn.g@foxmail.com" Date: Wed, 10 May 2023 08:41:36 +0800 Subject: [PATCH 03/16] =?UTF-8?q?update=20=E7=AB=99=E7=82=B9=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E8=B5=84=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 4beef45bb210e39b9b6d632df3769a4ab5bb1552) --- jsowell-ui/src/views/pile/station/components/SiteInfo.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/jsowell-ui/src/views/pile/station/components/SiteInfo.vue b/jsowell-ui/src/views/pile/station/components/SiteInfo.vue index b1f393387..795ebdc4c 100644 --- a/jsowell-ui/src/views/pile/station/components/SiteInfo.vue +++ b/jsowell-ui/src/views/pile/station/components/SiteInfo.vue @@ -219,6 +219,7 @@ export default { construction: "", businessHours: "", pictures: "", + deptId: "", }, stationId: this.$route.params.id, publicFlagOptions: [ From f482f71007de7b041a6070dbab46a82b760797f5 Mon Sep 17 00:00:00 2001 From: "autumn.g@foxmail.com" Date: Wed, 10 May 2023 08:50:19 +0800 Subject: [PATCH 04/16] update (cherry picked from commit 0bb109f52368043769399395ebfb28b1d872afb0) --- .../impl/PileStationInfoServiceImpl.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java index 9df7f6e24..89f0795b8 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/PileStationInfoServiceImpl.java @@ -252,16 +252,29 @@ public class PileStationInfoServiceImpl implements IPileStationInfoService { * @return 结果 */ @Override + @Transactional(readOnly = false, propagation = Propagation.REQUIRED) public int updatePileStationInfo(PileStationInfo pileStationInfo) { // 清缓存 String redisKey = CacheConstants.SELECT_PILE_STATION_INFO_BY_ID + pileStationInfo.getId(); redisCache.deleteObject(redisKey); + pileStationInfo.setUpdateBy(SecurityUtils.getUsername()); pileStationInfo.setUpdateTime(DateUtils.getNowDate()); - // 同步组织中的名称,联系人,电话 - // sysDeptService.updateDept() + int i = pileStationInfoMapper.updatePileStationInfo(pileStationInfo); - return pileStationInfoMapper.updatePileStationInfo(pileStationInfo); + // 同步组织中的名称,联系人,电话 + SysDept sysDept = sysDeptService.selectDeptById(Long.parseLong(pileStationInfo.getDeptId())); + if (sysDept != null) { + sysDept.setDeptName(pileStationInfo.getStationName()); + sysDept.setLeader(pileStationInfo.getStationAdminName()); + sysDept.setPhone(pileStationInfo.getStationTel()); + sysDept.setUpdateTime(DateUtils.getNowDate()); + sysDeptService.updateDept(sysDept); + } + + // 再次清缓存 + redisCache.deleteObject(redisKey); + return i; } /** From e89a9ebba53c0f430656594db56a22b65638389b Mon Sep 17 00:00:00 2001 From: JS-LM <2497833386@QQ.com> Date: Wed, 10 May 2023 09:16:09 +0800 Subject: [PATCH 05/16] up --- .../components/MapContainer/MapContainer.vue | 47 +++----- jsowell-ui/src/views/homeIndex/homeIndex.vue | 109 ++++++++++++++---- .../pile/station/components/SiteInfo.vue | 1 + jsowell-ui/src/views/pile/station/detail.vue | 13 ++- 4 files changed, 109 insertions(+), 61 deletions(-) diff --git a/jsowell-ui/src/components/MapContainer/MapContainer.vue b/jsowell-ui/src/components/MapContainer/MapContainer.vue index 9c158b16e..ea9f29442 100644 --- a/jsowell-ui/src/components/MapContainer/MapContainer.vue +++ b/jsowell-ui/src/components/MapContainer/MapContainer.vue @@ -43,6 +43,7 @@ window._AMapSecurityConfig = { securityJsCode: "829b6b73f84682c2eb982eaa47a745b8", }; export default { + props:['stationLat','stationLng'], data() { return { dialogImageUrl: '', @@ -68,7 +69,6 @@ export default { }; }, methods: { - // 点击搜索按钮 send() { this.searchPlaceInput = this.inputObject.userInput; @@ -76,16 +76,16 @@ export default { // 向表单 site-info传值 bus.$emit("inp", this.searchPlaceInput); }, - queryStationInfo() { - getStation(this.stationId).then((response) => { - this.lat = response.data.stationLat; - this.lng = response.data.stationLng; - console.log(this.lat, this.lng); - this.initMap(this.lat, this.lng); - }); - }, + // queryStationInfo() { + // getStation(this.stationId).then((response) => { + // this.lat = response.data.stationLat; + // this.lng = response.data.stationLng; + // console.log(this.lat, this.lng); + // this.initMap(this.lat, this.lng); + // }); + // }, - initMap(lat, lng) { + initMap() { // console.log(lat, lng); AMapLoader.load({ key: "61436c9c789d301a5b73853d176710cf", // 申请好的Web端开发者Key,首次调用 load 时必填 @@ -97,7 +97,7 @@ export default { //设置地图容器id viewMode: "3D", //是否为3D地图模式 zoom: 15, //初始化地图级别 - center: [+lng, +lat], //初始化地图中心点位置 + center: [+this.stationLng, +this.stationLat], //初始化地图中心点位置 }); // this.map.addControl(new AMap.Geolocation()); // console.log("map", this.map); @@ -105,12 +105,12 @@ export default { this.map.setDefaultCursor("pointer"); // 点标记 let marker = new AMap.Marker({ - position: new AMap.LngLat(+lng, +lat), + position: new AMap.LngLat(+this.stationLng, +this.stationLat), }); // 将创建的点标记添加到已有的地图实例 this.map.add(marker); AMap.plugin("AMap.AutoComplete", function () { - auto = new AMap.AutoComplete(this.autoOptions); + let auto = new AMap.AutoComplete(this.autoOptions); //构造地点查询类 auto.on("select", this.select); }); @@ -170,29 +170,10 @@ export default { } }); }, - onFileChange(e) { - console.log(e,'上传图片') - // 1.获取用户选择的文件列表 - const fileList = e.target.files; - console.log(fileList); - // 2.判断有没有选中图片 - if (fileList.length !== 0) { - // 3.选择了图片 - const reader = new FileReader(); - reader.readAsDataURL(fileList[0]); - // 监听load事件,读取完成触发回调函数 - reader.addEventListener("load", () => { - this.avatar = reader.result; - }); - } else { - // 没有选择图片 - this.avatar = ""; - } - }, }, mounted() { //DOM初始化完成进行地图初始化 - // this.queryStationInfo(); + // this.queryStationInfo() }, created() { // this.send(); diff --git a/jsowell-ui/src/views/homeIndex/homeIndex.vue b/jsowell-ui/src/views/homeIndex/homeIndex.vue index 5251f23a5..2d383d470 100644 --- a/jsowell-ui/src/views/homeIndex/homeIndex.vue +++ b/jsowell-ui/src/views/homeIndex/homeIndex.vue @@ -1,11 +1,61 @@