This commit is contained in:
2024-01-06 14:40:10 +08:00
11 changed files with 155 additions and 80 deletions

View File

@@ -1,4 +1,4 @@
package com.jsowell.thirdparty.camera.service;
package com.jsowell.service;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
@@ -8,21 +8,28 @@ import com.aliyun.oss.model.ObjectMetadata;
import com.jsowell.common.config.AliyunOssConfig;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.util.DateUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.file.AliyunOssUploadUtils;
import com.jsowell.common.util.file.ImageUtils;
import com.jsowell.common.util.sign.MD5Util;
import com.jsowell.netty.server.mqtt.BootNettyMqttChannelInboundHandler;
import com.jsowell.pile.domain.PileCameraInfo;
import com.jsowell.pile.dto.GenerateOccupyOrderDTO;
import com.jsowell.pile.dto.camera.CameraHeartBeatDTO;
import com.jsowell.pile.dto.camera.CameraIdentifyResultsDTO;
import com.jsowell.pile.service.IMemberBasicInfoService;
import com.jsowell.pile.service.IMemberPlateNumberRelationService;
import com.jsowell.pile.service.IPileCameraInfoService;
import com.jsowell.pile.service.OrderPileOccupyService;
import com.jsowell.pile.vo.uniapp.MemberVO;
import io.netty.channel.Channel;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -36,6 +43,7 @@ import java.util.Base64;
import javax.imageio.ImageIO;
import java.util.List;
import java.util.Locale;
/**
* 相机管理系统 Service
@@ -56,6 +64,12 @@ public class CameraService {
@Autowired
private OrderPileOccupyService orderPileOccupyService;
@Autowired
private BootNettyMqttChannelInboundHandler handler;
@Autowired
private IMemberBasicInfoService memberBasicInfoService;
public void receiveIdentifyResults(JSONObject jsonObject) {
// 区分入场和出场
@@ -85,6 +99,7 @@ public class CameraService {
/**
* 车辆入场
*
* @param jsonObject
*/
private void vehicleEntry(JSONObject jsonObject, String parkingState) {
@@ -92,7 +107,34 @@ public class CameraService {
// boolean result = saveCarPicture2Redis(jsonObject, parkingState);
// 将信息存数据库
saveInfo2DataBase(jsonObject);
boolean result = saveInfo2DataBase(jsonObject);
if (!result) {
logger.error("车辆入场,将信息存入数据库 error, 源数据:{}", jsonObject);
return;
}
// 根据车牌号找出绑定小程序的用户
CameraIdentifyResultsDTO.ProductH.Plate plate = JSONObject.parseObject(jsonObject.getJSONObject("product_h").getJSONObject("plate").toJSONString(),
CameraIdentifyResultsDTO.ProductH.Plate.class);
if (plate == null) {
return;
}
// Base64 解密
String plateNumber = cn.hutool.core.codec.Base64.decodeStr(plate.getPlate());
List<MemberVO> memberList = memberBasicInfoService.getMemberInfoByPlateNumber(plateNumber);
if (CollectionUtils.isNotEmpty(memberList)) {
// 如果是有小程序的用户则先降地锁然后生成一笔占桩订单
// 发送降锁指令
// 生成占桩订单
} else {
// 如果没有小程序账号再根据此车牌是否有挂起的占桩订单
// 如果没有则先降锁再生成一笔占桩订单
// 如果有已挂起的占桩订单则不予降锁已存在有未支付的占桩订单信息返回
}
// TODO 生成占桩订单
// GenerateOccupyOrderDTO dto = new GenerateOccupyOrderDTO();
@@ -163,7 +205,7 @@ public class CameraService {
/**
* 保存图像
* @param base64Image 图像的Base64编码
* @param fileName 文件名
* @param fileName 文件名
* @return
*/
private String saveImage(String base64Image, String fileName) {
@@ -195,6 +237,63 @@ public class CameraService {
return null;
}
/**
* 发送具体指令到某主题
* @param sn 设备 sn
* @param msgType 消息类型
* @param msgPrefix 消息前缀
* @param topic 主题
* @param msgData 消息内容
* @throws InterruptedException
*/
public void sendMsg2Topic(String sn, String msgType, String msgPrefix, String topic, JSONObject msgData) throws InterruptedException {
JSONObject jsonObject = spliceStr(sn, msgType, msgPrefix);
// 通过sn查找出对应的channelId
String mqttConnectRedisKey = CacheConstants.MQTT_CONNECT_SN + sn;
Object cacheObject = redisCache.getCacheObject(mqttConnectRedisKey);
if (cacheObject == null) {
return;
}
String channelId = (String) cacheObject;
if (msgData != null) {
jsonObject.put("msg_data", msgData);
}
logger.info("给相机发送远程命令sn:{}, 消息类型:{}, 主题:{}, 最终发送数据:{}", sn, msgType, topic, jsonObject.toJSONString());
// 发送消息
handler.sendMsg(channelId, topic, jsonObject.toJSONString());
}
/**
* 根据规则拼装字符串
* @param sn 设备 sn
* @param msgType 消息类型
* @param msgPrefix 消息前缀
* @return 拼装好的json对象
*/
private JSONObject spliceStr(String sn, String msgType, String msgPrefix) {
StringBuilder sb = new StringBuilder();
String msgId = msgPrefix + DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS) + "01";
String timeStamp = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);
sb.append("sn=").append(sn)
.append("&timestamp=").append(timeStamp)
.append("&msg_id=").append(msgId)
.append("&msg_type=").append(msgType);
// 进行 32 MD5 计算
String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase(Locale.ROOT);
JSONObject jsonObject = new JSONObject();
jsonObject.put("sign", sign);
jsonObject.put("sn", sn);
jsonObject.put("timestamp", timeStamp);
jsonObject.put("msg_id", msgId);
jsonObject.put("msg_type", msgType);
return jsonObject;
}
/**
* 将车辆图片信息存入缓存

View File

@@ -4,13 +4,11 @@ import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.jsowell.common.annotation.Anonymous;
import com.jsowell.common.core.controller.BaseController;
import com.jsowell.netty.server.mqtt.BootNettyMqttChannelInboundHandler;
import com.jsowell.netty.service.camera.CameraBusinessService;
import com.jsowell.pile.dto.camera.CameraHeartBeatDTO;
import com.jsowell.pile.dto.camera.SendMsg2TopicDTO;
import com.jsowell.thirdparty.camera.common.CameraCommonResult;
import com.jsowell.thirdparty.camera.service.CameraService;
import io.netty.channel.ChannelFuture;
import com.jsowell.service.CameraService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -66,7 +64,7 @@ public class CameraController extends BaseController {
@PostMapping("/sendMsg2Topic")
public void sendMsg2Topic(@RequestBody SendMsg2TopicDTO dto) {
try {
cameraBusinessService.sendGroundLockCommand(dto.getSn(), dto.getMsgType(), dto.getMsgPrefix(), dto.getTopic(), dto.getMsgData());
cameraService.sendMsg2Topic(dto.getSn(), dto.getMsgType(), dto.getMsgPrefix(), dto.getTopic(), dto.getMsgData());
} catch (Exception e) {
logger.error("发送消息 error, ", e);
}

View File

@@ -670,12 +670,12 @@ public class TransactionRecordsRequestHandler extends AbstractHandler {
// 给车辆绑定优惠券
try {
BigDecimal totalElectricity = new BigDecimal(data.getTotalElectricity());
if (totalElectricity.compareTo(BigDecimal.TEN) > 0) {
// 充电度数大于10度
String bindResult = bindCoupon(orderBasicInfo);
log.info("绑定优惠券 订单信息:{}, result:{}", orderBasicInfo, bindResult);
}
// BigDecimal totalElectricity = new BigDecimal(data.getTotalElectricity());
// if (totalElectricity.compareTo(BigDecimal.TEN) > 0) {
// // 充电度数大于10度
// }
String bindResult = bindCoupon(orderBasicInfo);
log.info("绑定优惠券 订单信息:{}, result:{}", orderBasicInfo, bindResult);
} catch (BusinessException e) {
log.error("绑定优惠券 error, code:{}, msg:{}", e.getCode(), e.getMessage());
} catch (Exception e) {

View File

@@ -6,7 +6,6 @@ import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.bean.BeanUtils;
import com.jsowell.netty.domain.MqttRequest;
import com.jsowell.netty.service.camera.CameraBusinessService;
import com.jsowell.netty.service.camera.impl.CameraBusinessServiceImpl;
import com.jsowell.thirdparty.camera.service.CameraService;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
@@ -17,9 +16,6 @@ import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**

View File

@@ -13,16 +13,6 @@ import java.net.UnknownHostException;
* @Date 2023/12/20 15:15:26
*/
public interface CameraBusinessService {
/**
* 发送具体指令到某主题
* @param sn 设备 sn
* @param msgType 消息类型
* @param msgPrefix 消息前缀
* @param topic 主题
* @param msgData 消息内容
* @throws InterruptedException
*/
public void sendGroundLockCommand(String sn, String msgType, String msgPrefix, String topic, JSONObject msgData) throws InterruptedException;
/**
* 解析channel中的ip地址 并将 sn 和 channelId 进行绑定,存入缓存

View File

@@ -33,33 +33,6 @@ public class CameraBusinessServiceImpl implements CameraBusinessService {
@Autowired
private BootNettyMqttChannelInboundHandler handler;
/**
* 发送具体指令到某主题
* @param sn 设备 sn
* @param msgType 消息类型
* @param msgPrefix 消息前缀
* @param topic 主题
* @param msgData 消息内容
* @throws InterruptedException
*/
public void sendGroundLockCommand(String sn, String msgType, String msgPrefix, String topic, JSONObject msgData) throws InterruptedException {
JSONObject jsonObject = spliceStr(sn, msgType, msgPrefix);
// 通过sn查找出对应的channelId
String mqttConnectRedisKey = CacheConstants.MQTT_CONNECT_SN + sn;
Object cacheObject = redisCache.getCacheObject(mqttConnectRedisKey);
if (cacheObject == null) {
return;
}
String channelId = (String) cacheObject;
if (msgData != null) {
jsonObject.put("msg_data", msgData);
}
log.info("给相机发送远程命令sn:{}, 消息类型:{}, 主题:{}, 最终发送数据:{}", sn, msgType, topic, jsonObject.toJSONString());
// 发送消息
handler.sendMsg(channelId, topic, jsonObject.toJSONString());
}
/**
* 解析channel中的ip地址 并将 sn 和 channelId 进行绑定,存入缓存
* @param channel
@@ -90,32 +63,6 @@ public class CameraBusinessServiceImpl implements CameraBusinessService {
}
}
/**
* 根据规则拼装字符串
* @param sn 设备 sn
* @param msgType 消息类型
* @param msgPrefix 消息前缀
* @return 拼装好的json对象
*/
private JSONObject spliceStr(String sn, String msgType, String msgPrefix) {
StringBuilder sb = new StringBuilder();
String msgId = msgPrefix + DateUtils.dateTimeNow(DateUtils.YYYYMMDDHHMMSS) + "01";
String timeStamp = DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS);
sb.append("sn=").append(sn)
.append("&timestamp=").append(timeStamp)
.append("&msg_id=").append(msgId)
.append("&msg_type=").append(msgType);
// 进行 32 位 MD5 计算
String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase(Locale.ROOT);
JSONObject jsonObject = new JSONObject();
jsonObject.put("sign", sign);
jsonObject.put("sn", sn);
jsonObject.put("timestamp", timeStamp);
jsonObject.put("msg_id", msgId);
jsonObject.put("msg_type", msgType);
return jsonObject;
}
public static void main(String[] args) {
System.out.println(System.currentTimeMillis());

View File

@@ -120,4 +120,11 @@ public interface MemberBasicInfoMapper {
List<MerchantInfoVO> getMerchantListByAuth(@Param("deptIds") List<String> deptIds);
List<MerchantVipVO> queryMerchantVipList(@Param("merchantIdList") List<String> merchantIdList, @Param("dto") QueryMemberInfoDTO dto);
/**
* 通过车牌号查询用户基本信息
* @param plateNumber
* @return
*/
List<MemberVO> getMemberInfoByPlateNumber(@Param("plateNumber") String plateNumber);
}

View File

@@ -152,4 +152,11 @@ public interface IMemberBasicInfoService {
List<MerchantVipVO> queryMerchantVipList(QueryMemberInfoDTO dto);
void createMerchantVip(CreateMerchantVipDTO dto);
/**
* 通过车牌号查询用户基本信息
* @param plateNumber
* @return
*/
List<MemberVO> getMemberInfoByPlateNumber(String plateNumber);
}

View File

@@ -595,4 +595,14 @@ public class MemberBasicInfoServiceImpl implements IMemberBasicInfoService {
updateMemberBalance(updateMemberBalanceDTO);
}
/**
* 通过车牌号查询用户基本信息
* @param plateNumber
* @return
*/
@Override
public List<MemberVO> getMemberInfoByPlateNumber(String plateNumber) {
return memberBasicInfoMapper.getMemberInfoByPlateNumber(plateNumber);
}
}

View File

@@ -89,4 +89,9 @@ public class MemberVO {
* 头像地址
*/
private String avatarUrl;
/**
* 车牌号
*/
private String plateNumber;
}

View File

@@ -281,4 +281,20 @@
</if>
<if test="dto.memberId != null and dto.memberId != ''">and t2.member_id like '%${dto.memberId}%'</if>
</select>
<select id="getMemberInfoByPlateNumber" resultType="com.jsowell.pile.vo.uniapp.MemberVO">
SELECT
t2.member_id AS memberId,
t2.merchant_id AS merchantId,
t1.license_plate_number AS plateNumber,
t2.STATUS,
t2.mobile_number AS mobileNumber
FROM
member_plate_number_relation t1
JOIN member_basic_info t2 ON t1.member_id = t2.member_id
WHERE
t1.license_plate_number = #{plateNumber,jdbcType=VARCHAR}
AND t1.del_flag = '0'
AND t2.STATUS = '1'
</select>
</mapper>