|
|
@@ -1,60 +1,44 @@
|
|
|
package org.dromara.backstage.wx.service.impl;
|
|
|
|
|
|
-import cn.hutool.core.codec.Base64;
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
-import cn.hutool.core.img.Img;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.core.util.RandomUtil;
|
|
|
import cn.hutool.crypto.digest.MD5;
|
|
|
import cn.hutool.http.HttpRequest;
|
|
|
import cn.hutool.json.JSONArray;
|
|
|
import cn.hutool.json.JSONObject;
|
|
|
-import com.arcsoft.face.FaceInfo;
|
|
|
-import com.arcsoft.face.toolkit.ImageInfo;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.time.DateFormatUtils;
|
|
|
-import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.dromara.backstage.business.accouunt.UserFaceBusiness;
|
|
|
import org.dromara.backstage.cardCenter.domain.PtCard;
|
|
|
import org.dromara.backstage.cardCenter.mapper.PtCardMapper;
|
|
|
import org.dromara.backstage.consumption.mapper.XfCreditAccountMapper;
|
|
|
-import org.dromara.backstage.payment.domain.PtUserAccount;
|
|
|
-import org.dromara.backstage.payment.domain.bo.PtUserAccountBo;
|
|
|
import org.dromara.backstage.payment.domain.vo.PtUserAccountVo;
|
|
|
import org.dromara.backstage.payment.mapper.PtUserAccountMapper;
|
|
|
import org.dromara.backstage.wx.domain.vo.WxCreditAccountVo;
|
|
|
-import org.dromara.backstage.wx.service.FaceEngineService;
|
|
|
import org.dromara.backstage.wx.service.IWxService;
|
|
|
+import org.dromara.common.core.config.DefaultConfig;
|
|
|
+import org.dromara.common.core.constant.DefaultConstants;
|
|
|
import org.dromara.common.core.domain.R;
|
|
|
-import org.dromara.common.core.exception.ServiceException;
|
|
|
import org.dromara.common.core.utils.ByteArrayUtilByYC;
|
|
|
-import org.dromara.common.core.utils.MapstructUtils;
|
|
|
import org.dromara.common.core.utils.StringUtilsByYC;
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
-import org.dromara.consume.api.RemoteConsumeService;
|
|
|
import org.dromara.system.api.RemoteDictService;
|
|
|
import org.dromara.system.api.domain.vo.RemoteDictDataVo;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
-import java.io.ByteArrayInputStream;
|
|
|
-import java.io.ByteArrayOutputStream;
|
|
|
-import java.io.FileOutputStream;
|
|
|
-import java.io.IOException;
|
|
|
import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.TreeMap;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
-import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
|
|
|
-
|
|
|
/**
|
|
|
* 微信Service业务层处理
|
|
|
- *
|
|
|
*/
|
|
|
@RequiredArgsConstructor
|
|
|
@Service
|
|
|
@@ -64,15 +48,9 @@ public class WxServiceImpl implements IWxService {
|
|
|
private final XfCreditAccountMapper creditAccountMapper;
|
|
|
private final PtCardMapper cardMapper;
|
|
|
private final RemoteDictService dictService;
|
|
|
- private final FaceEngineService faceEngineService;
|
|
|
-
|
|
|
- @DubboReference
|
|
|
- private final RemoteConsumeService remoteConsumeService;
|
|
|
+ private final DefaultConfig defaultConfig;
|
|
|
+ private final UserFaceBusiness userFaceBusiness;
|
|
|
|
|
|
- @Value("${upload.upload-path}/") // 文件上传路径
|
|
|
- private String uploadPath;
|
|
|
- @Value("${upload.image.user}/") // 用户头像路径
|
|
|
- private String userPath;
|
|
|
@Value("${dzbp.sync-img.url}/") // 电子班牌照片推送接口
|
|
|
private String syncImgToDzbpUrl;
|
|
|
@Value("${yc.sf.customerName}")
|
|
|
@@ -80,20 +58,73 @@ public class WxServiceImpl implements IWxService {
|
|
|
@Value("${yc.sf.customerNo}")
|
|
|
private String customerNo;
|
|
|
|
|
|
+ /**
|
|
|
+ * 物理卡号转二维码数据
|
|
|
+ *
|
|
|
+ * @param fixId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String getCode(Long fixId) {
|
|
|
+ // Long fixId=123456789l;
|
|
|
+
|
|
|
+ String fixStr = Long.toHexString(fixId);
|
|
|
+ if (fixStr.length() < 8)
|
|
|
+ fixStr = StringUtilsByYC.addString(fixStr, "0", 8, "L");
|
|
|
+ byte[] fixBytes = ByteArrayUtilByYC.parseHexStr2Byte(fixStr);
|
|
|
+
|
|
|
+ // 当前时间
|
|
|
+ String time = DateFormatUtils.format(new Date(), "yy-MM-dd-HH-mm-ss");
|
|
|
+ String[] timeStrs = time.split("-");
|
|
|
+
|
|
|
+ byte[] bytes = new byte[15];
|
|
|
+ bytes[0] = 0;
|
|
|
+ ByteArrayUtilByYC.copy(fixBytes, 0, bytes, 1, 4);
|
|
|
+ bytes[5] = Byte.valueOf(timeStrs[5]);
|
|
|
+ bytes[6] = Byte.valueOf(timeStrs[0]);
|
|
|
+ bytes[7] = Byte.valueOf(timeStrs[1]);
|
|
|
+ bytes[8] = Byte.valueOf(timeStrs[2]);
|
|
|
+ bytes[9] = Byte.valueOf(timeStrs[3]);
|
|
|
+ bytes[10] = Byte.valueOf(timeStrs[4]);
|
|
|
+ bytes[11] = 10;
|
|
|
+ bytes[12] = 5;
|
|
|
+ bytes[13] = 100;
|
|
|
+ bytes[14] = 0;
|
|
|
+
|
|
|
+ // 计算crc校验值
|
|
|
+ byte crcByte = 0;
|
|
|
+ for (int i = 0; i < bytes.length; i++) {
|
|
|
+ crcByte = (byte) ((crcByte ^ (bytes[i])) & 0xFF);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加密后9个字节
|
|
|
+ bytes[5] = (byte) ((bytes[0] ^ bytes[5]) & 0xFF);
|
|
|
+ bytes[6] = (byte) ((bytes[1] ^ bytes[6]) & 0xFF);
|
|
|
+ bytes[7] = (byte) ((bytes[2] ^ bytes[7]) & 0xFF);
|
|
|
+ bytes[8] = (byte) ((bytes[3] ^ bytes[8]) & 0xFF);
|
|
|
+ bytes[9] = (byte) ((bytes[4] ^ bytes[9]) & 0xFF);
|
|
|
+ bytes[10] = (byte) ((bytes[0] ^ bytes[10]) & 0xFF);
|
|
|
+ bytes[11] = (byte) ((bytes[1] ^ bytes[11]) & 0xFF);
|
|
|
+ bytes[12] = (byte) ((bytes[2] ^ bytes[12]) & 0xFF);
|
|
|
+ bytes[13] = (byte) ((bytes[3] ^ bytes[13]) & 0xFF);
|
|
|
+ bytes[14] = crcByte;
|
|
|
+
|
|
|
+ return ByteArrayUtilByYC.parseByte2HexStr(bytes, false);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public PtUserAccountVo getUserInfoByUserId(Long userId) {
|
|
|
Map<String, String> dictMap = dictService.selectDictDataByType("account_open_status")
|
|
|
- .stream()
|
|
|
- .collect(
|
|
|
- Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel));
|
|
|
+ .stream()
|
|
|
+ .collect(
|
|
|
+ Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel));
|
|
|
PtUserAccountVo vo = accountMapper.selectVoById(userId);
|
|
|
vo.setAccountStatus(dictMap.getOrDefault(vo.getAccountStatus(), ""));
|
|
|
- //根据userId查询卡片信息
|
|
|
+ // 根据userId查询卡片信息
|
|
|
PtCard card = cardMapper.selectOne(new LambdaUpdateWrapper<PtCard>()
|
|
|
- .eq(PtCard::getUserId, userId)
|
|
|
- .eq(PtCard::getStatus, "1"));
|
|
|
+ .eq(PtCard::getUserId, userId)
|
|
|
+ .eq(PtCard::getStatus, "1"));
|
|
|
if (ObjectUtil.isNotEmpty(card)) {
|
|
|
- vo.setCardNo(card.getCardNo());
|
|
|
+ vo.setCardNo(card.getCardNo());
|
|
|
}
|
|
|
vo.setCustomerName(customerName);
|
|
|
vo.setCustomerNo(customerNo);
|
|
|
@@ -106,62 +137,52 @@ public class WxServiceImpl implements IWxService {
|
|
|
PageQuery pageQuery) {
|
|
|
|
|
|
return TableDataInfo.build(creditAccountMapper.selectCreditAccountPage(pageQuery.build(), type, userId,
|
|
|
- startTime,
|
|
|
- endTime));
|
|
|
+ startTime,
|
|
|
+ endTime));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public boolean updateCardStatus(Long userId, String cardStatus) {
|
|
|
int count = cardMapper.update(new LambdaUpdateWrapper<PtCard>()
|
|
|
- .set(PtCard::getStatus, cardStatus)
|
|
|
- .set(PtCard::getChangeTime, DateUtil.date())
|
|
|
- .eq(PtCard::getUserId, userId));
|
|
|
+ .set(PtCard::getStatus, cardStatus)
|
|
|
+ .set(PtCard::getChangeTime, DateUtil.date())
|
|
|
+ .eq(PtCard::getUserId, userId));
|
|
|
return count > 0;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public R<String> uploadUserPhoto(Long userId, String imgData) {
|
|
|
- //1.查询用户信息,用于判断身份
|
|
|
- PtUserAccountVo vo = accountMapper.selectVoById(userId);
|
|
|
- if (ObjectUtil.isEmpty(vo)) {
|
|
|
- throw new RuntimeException("用户不存在");
|
|
|
- }
|
|
|
- //2.调用虹软,识别人脸是否正确
|
|
|
+ public R<String> uploadUserPhoto(Long userId, String imgData) throws Exception {
|
|
|
int strIndex = imgData.indexOf(";base64,");
|
|
|
if (strIndex > 0) {
|
|
|
- imgData = imgData.substring(strIndex + 8); // 过滤掉data:image/jpg;base64,字符串
|
|
|
+ // 过滤掉data:image/jpg;base64,字符串
|
|
|
+ imgData = imgData.substring(strIndex + 8);
|
|
|
}
|
|
|
-
|
|
|
- byte[] imageBytes = Base64.decode(imgData);
|
|
|
- ImageInfo imageInfo = getRGBData(imageBytes);
|
|
|
- List<FaceInfo> faceInfosList = faceEngineService.detectFaces(imageInfo);
|
|
|
- if (faceInfosList == null || faceInfosList.size() == 0) {
|
|
|
- return R.fail("人脸识别不成功!");
|
|
|
+ String locationFlag = defaultConfig.getLocationFlag();
|
|
|
+ R<Void> result;
|
|
|
+ // 如果是本地部署
|
|
|
+ if (ObjectUtil.equals(locationFlag, DefaultConstants.LOCAL_FLAG)) {
|
|
|
+ result = userFaceBusiness.extractUserFaces(userId, imgData);
|
|
|
+ } else {
|
|
|
+ result = userFaceBusiness.extractUserFacesForCloud(userId, imgData);
|
|
|
}
|
|
|
-
|
|
|
- try {
|
|
|
- //3.图片压缩处理
|
|
|
- imageBytes = imgCompression(imageBytes);
|
|
|
-
|
|
|
- //4.更新账户表人脸照片地址,上传照片到服务器
|
|
|
- uploadUserPhoto(userId, imageBytes);
|
|
|
-
|
|
|
- //5.如果用户是学员身份,则将照片同步给电子班牌
|
|
|
- if("2".equals(vo.getCategory())){
|
|
|
+ if (R.isError(result)) {
|
|
|
+ return R.fail("图片上传异常", result.getMsg());
|
|
|
+ } else {
|
|
|
+ PtUserAccountVo vo = accountMapper.selectVoById(userId);
|
|
|
+ if ("2".equals(vo.getCategory())) {
|
|
|
syncImgToDZBP(vo, imgData);
|
|
|
}
|
|
|
- }catch (ServiceException e){
|
|
|
- return R.fail(e.getMessage());
|
|
|
+ return R.ok("上传图片成功");
|
|
|
}
|
|
|
- return R.ok("上传图片成功");
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 同步照片到电子班牌
|
|
|
+ *
|
|
|
* @param vo
|
|
|
* @param imgData
|
|
|
*/
|
|
|
- private void syncImgToDZBP(PtUserAccountVo vo, String imgData){
|
|
|
+ private void syncImgToDZBP(PtUserAccountVo vo, String imgData) {
|
|
|
String timestamp = Long.toString(System.currentTimeMillis());
|
|
|
TreeMap<String, Object> params = new TreeMap<String, Object>();
|
|
|
params.put("pid", "hnswdx");
|
|
|
@@ -193,158 +214,19 @@ public class WxServiceImpl implements IWxService {
|
|
|
face.put("data", array);
|
|
|
|
|
|
String res = HttpRequest.post(syncImgToDzbpUrl + "?" + s1.toString())
|
|
|
- .body(face.toString())
|
|
|
- .execute().body();
|
|
|
+ .body(face.toString())
|
|
|
+ .execute().body();
|
|
|
log.info("同步照片到电子班牌返回结果:{}", res);
|
|
|
}
|
|
|
- private void uploadUserPhoto(Long userId, byte[] imageBytes) {
|
|
|
- //1.上传照片到指定目录
|
|
|
- ByteArrayInputStream bis = new ByteArrayInputStream(imageBytes);
|
|
|
- byte[] bytes = new byte[1024];
|
|
|
- int index;
|
|
|
-
|
|
|
- String localFileName = uploadPath + userPath + userId + ".jpg";
|
|
|
- FileOutputStream downloadFile = null;
|
|
|
- try {
|
|
|
- downloadFile = new FileOutputStream(localFileName);
|
|
|
- while ((index = bis.read(bytes)) != -1) {
|
|
|
- downloadFile.write(bytes, 0, index);
|
|
|
- downloadFile.flush();
|
|
|
- }
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("图片处理失败,请稍后重试!", e);
|
|
|
- throw new ServiceException("图片处理失败,请稍后重试!");
|
|
|
- } finally {
|
|
|
- try {
|
|
|
- bis.close();
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("inputStream关闭失败!", e);
|
|
|
- }
|
|
|
- if (downloadFile != null) {
|
|
|
- try {
|
|
|
- downloadFile.close();
|
|
|
- } catch (IOException e) {
|
|
|
- log.error("downloadFile关闭失败!", e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- //2.保存图片路径到数据库
|
|
|
- String photoUrl = userId + ".jpg";
|
|
|
- PtUserAccountBo bo = PtUserAccountBo.builder().userId(userId).photo(photoUrl).build();
|
|
|
- accountMapper.updateById(MapstructUtils.convert(bo, PtUserAccount.class));
|
|
|
- // 生成人脸特征库
|
|
|
- remoteConsumeService.createFeatureDataOne(userId, photoUrl);
|
|
|
- }
|
|
|
- /**
|
|
|
- * 图片压缩
|
|
|
- * @param imageBytes
|
|
|
- * @return
|
|
|
- */
|
|
|
- private static byte[] imgCompression(byte[] imageBytes) {
|
|
|
- // 小于1M就不进行压缩里,浪费执行时间
|
|
|
- float quality = 0f;
|
|
|
- if (imageBytes.length > 1024 * 1024 * 10) { // 大于10M
|
|
|
- quality = 0.1f;
|
|
|
- } else if (imageBytes.length > 1024 * 1024 * 5) { // 大于5M
|
|
|
- quality = 0.2f;
|
|
|
- } else if (imageBytes.length > 1024 * 1024 * 1) {// 大于1M
|
|
|
- quality = 0.5f;
|
|
|
- }
|
|
|
-
|
|
|
- if (quality != 0) {
|
|
|
- ByteArrayInputStream bis = null;
|
|
|
- ByteArrayOutputStream bos = null;
|
|
|
- try {
|
|
|
- bis = new ByteArrayInputStream(imageBytes);
|
|
|
- bos = new ByteArrayOutputStream();
|
|
|
- Img.from(bis).setQuality(quality).write(bos);
|
|
|
- imageBytes = bos.toByteArray();
|
|
|
- } catch (Exception e) {
|
|
|
- throw new ServiceException("图片处理失败,请稍后重试!");
|
|
|
- } finally {
|
|
|
- if (bis != null) {
|
|
|
- try {
|
|
|
- bis.close();
|
|
|
- } catch (IOException e) {
|
|
|
- // TODO Auto-generated catch block
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
- if (bos != null) {
|
|
|
- try {
|
|
|
- bos.close();
|
|
|
- } catch (IOException e) {
|
|
|
- // TODO Auto-generated catch block
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return imageBytes;
|
|
|
- }
|
|
|
|
|
|
@Override
|
|
|
public R<String> getIdCode(Long userId) {
|
|
|
- //根据userId 查询卡片信息
|
|
|
+ // 根据userId 查询卡片信息
|
|
|
PtCard card = cardMapper.selectOne(new LambdaQueryWrapper<PtCard>().eq(PtCard::getUserId, userId));
|
|
|
- if(ObjectUtil.isEmpty(card) || ObjectUtil.isEmpty(card.getFactoryId())){
|
|
|
+ if (ObjectUtil.isEmpty(card) || ObjectUtil.isEmpty(card.getFactoryId())) {
|
|
|
return R.fail("该用户未领取卡片");
|
|
|
- }else {
|
|
|
- return R.ok("操作成功",getCode(card.getFactoryId()));
|
|
|
+ } else {
|
|
|
+ return R.ok("操作成功", getCode(card.getFactoryId()));
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- *物理卡号转二维码数据
|
|
|
- * @param fixId
|
|
|
- * @return
|
|
|
- */
|
|
|
- private static String getCode(Long fixId)
|
|
|
- {
|
|
|
- //Long fixId=123456789l;
|
|
|
-
|
|
|
- String fixStr=Long.toHexString(fixId);
|
|
|
- if(fixStr.length()<8)
|
|
|
- fixStr= StringUtilsByYC.addString(fixStr, "0",8, "L");
|
|
|
- byte[] fixBytes= ByteArrayUtilByYC.parseHexStr2Byte(fixStr);
|
|
|
-
|
|
|
- //当前时间
|
|
|
- String time= DateFormatUtils.format(new Date(), "yy-MM-dd-HH-mm-ss");
|
|
|
- String[] timeStrs=time.split("-");
|
|
|
-
|
|
|
- byte[] bytes=new byte[15];
|
|
|
- bytes[0]=0;
|
|
|
- ByteArrayUtilByYC.copy(fixBytes , 0, bytes, 1, 4);
|
|
|
- bytes[5]=Byte.valueOf(timeStrs[5]);
|
|
|
- bytes[6]=Byte.valueOf(timeStrs[0]);
|
|
|
- bytes[7]=Byte.valueOf(timeStrs[1]);
|
|
|
- bytes[8]=Byte.valueOf(timeStrs[2]);
|
|
|
- bytes[9]=Byte.valueOf(timeStrs[3]);
|
|
|
- bytes[10]=Byte.valueOf(timeStrs[4]);
|
|
|
- bytes[11]=10;
|
|
|
- bytes[12]=5;
|
|
|
- bytes[13]=100;
|
|
|
- bytes[14]=0;
|
|
|
-
|
|
|
- //计算crc校验值
|
|
|
- byte crcByte=0;
|
|
|
- for(int i=0;i<bytes.length;i++) {
|
|
|
- crcByte=(byte) ((crcByte^(bytes[i]))&0xFF);
|
|
|
- }
|
|
|
-
|
|
|
- //加密后9个字节
|
|
|
- bytes[5]=(byte) ((bytes[0]^bytes[5])&0xFF);
|
|
|
- bytes[6]=(byte) ((bytes[1]^bytes[6])&0xFF);
|
|
|
- bytes[7]=(byte) ((bytes[2]^bytes[7])&0xFF);
|
|
|
- bytes[8]=(byte) ((bytes[3]^bytes[8])&0xFF);
|
|
|
- bytes[9]=(byte) ((bytes[4]^bytes[9])&0xFF);
|
|
|
- bytes[10]=(byte) ((bytes[0]^bytes[10])&0xFF);
|
|
|
- bytes[11]=(byte) ((bytes[1]^bytes[11])&0xFF);
|
|
|
- bytes[12]=(byte) ((bytes[2]^bytes[12])&0xFF);
|
|
|
- bytes[13]=(byte) ((bytes[3]^bytes[13])&0xFF);
|
|
|
- bytes[14]=crcByte;
|
|
|
-
|
|
|
- return ByteArrayUtilByYC.parseByte2HexStr(bytes, false);
|
|
|
- }
|
|
|
}
|