更新代码

This commit is contained in:
2026-04-21 20:04:59 +08:00
parent 65bfa963f8
commit b394cc6d13
75 changed files with 3143 additions and 192 deletions

View File

@@ -55,7 +55,7 @@
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.12.0</version> <!-- 请检查最新版本 -->
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>

View File

@@ -63,4 +63,24 @@ public class AssetsController {
return ResultMessage.success(new AssetsVo());
}
@GetMapping("/getBizZones")
public ResultMessage getBizZones() {
try {
return ResultMessage.success(assetsQueryService.getBizZones());
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return ResultMessage.success(new ArrayList<>());
}
@GetMapping("/getFeatures")
public ResultMessage getFeatures() {
try {
return ResultMessage.success(assetsQueryService.getFeatures());
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return ResultMessage.success(new ArrayList<>());
}
}

View File

@@ -45,8 +45,9 @@ public class AssetsQueryService {
assetsVo.setAssetsName(oaAssetsVo.getAssetsName());
assetsVo.setDetailImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsDetailImg",oaAssetsVo.getDetailImg()));
assetsVo.setVrImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsVrImg",oaAssetsVo.getVrImg()));
if(assetsVo.getDetailImgs() != null && assetsVo.getDetailImgs().size() > 1) {
assetsVo.setCoverImgUrl(assetsVo.getDetailImgs().get(0));
List<String> assetsCoverImg = oaFileHandlerService.getUrls(true, oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(), "AssetsCoverImg", oaAssetsVo.getCoverImg());
if(assetsCoverImg != null && assetsCoverImg.size() >= 1) {
assetsVo.setCoverImgUrl(assetsCoverImg.get(0));
}
assetsVoList.add(assetsVo);
}
@@ -54,6 +55,14 @@ public class AssetsQueryService {
return pageResult;
}
public List<String> getBizZones() throws Exception {
return oaAssetService.getBizZones();
}
public List<String> getFeatures() throws Exception {
return oaAssetService.getFeatures();
}
public AssetsVo getAssetsById(String id) throws Exception {
OaAssetsVo oaAssetsVo = oaAssetService.queryAssetsDetail(id);
AssetsVo assetsVo = new AssetsVo();
@@ -76,12 +85,20 @@ public class AssetsQueryService {
assetsVo.setLongitude(oaAssetsVo.getLongitude());
assetsVo.setLayout(oaAssetsVo.getLayout());
assetsVo.setUnitNo(oaAssetsVo.getUnitNo());
assetsVo.setOrientation(oaAssetsVo.getOrientation());
assetsVo.setBizZone(oaAssetsVo.getBizZone());
List<String> features = oaAssetsVo.getFeatures() == null ? new ArrayList<>() : oaAssetsVo.getFeatures();
if(oaAssetsVo.getRenovationStatus() != null) {
features.add(oaAssetsVo.getRenovationStatus());
}
assetsVo.setFeatures(features);
assetsVo.setManagerName(oaAssetsVo.getManagerName());
assetsVo.setManagerPhone(oaAssetsVo.getManagerPhone());
assetsVo.setDetailImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsDetailImg",oaAssetsVo.getDetailImg()));
assetsVo.setVrImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsVrImg",oaAssetsVo.getVrImg()));
if(assetsVo.getDetailImgs() != null) {
assetsVo.setCoverImgUrl(assetsVo.getDetailImgs().get(0));
List<String> assetsCoverImg = oaFileHandlerService.getUrls(true, oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(), "AssetsCoverImg", oaAssetsVo.getCoverImg());
if(assetsCoverImg != null && assetsCoverImg.size() >= 1) {
assetsVo.setCoverImgUrl(assetsCoverImg.get(0));
}
return assetsVo;
}

View File

@@ -2,6 +2,8 @@ package org.chenyon.assets.vo;
import org.rcy.framework.api.entity.PageQueryRequest;
import java.util.List;
public class AssetsPageQueryCondition extends PageQueryRequest {
private String assetsNo;//资产编号
@@ -13,6 +15,11 @@ public class AssetsPageQueryCondition extends PageQueryRequest {
private String assetsName;//资产名称
private String cusNo; //客商编码
private String keyWord; //关键字
private String bizZone; //商圈
private String rentFeeRange;
private String layout;
private String renovationStatus; //装修状态
private String features; //特点
public String getAssetsType() {
return assetsType;
@@ -85,4 +92,44 @@ public class AssetsPageQueryCondition extends PageQueryRequest {
public void setKeyWord(String keyWord) {
this.keyWord = keyWord;
}
public String getRentFeeRange() {
return rentFeeRange;
}
public void setRentFeeRange(String rentFeeRange) {
this.rentFeeRange = rentFeeRange;
}
public String getLayout() {
return layout;
}
public void setLayout(String layout) {
this.layout = layout;
}
public String getBizZone() {
return bizZone;
}
public void setBizZone(String bizZone) {
this.bizZone = bizZone;
}
public String getRenovationStatus() {
return renovationStatus;
}
public void setRenovationStatus(String renovationStatus) {
this.renovationStatus = renovationStatus;
}
public String getFeatures() {
return features;
}
public void setFeatures(String features) {
this.features = features;
}
}

View File

@@ -24,10 +24,12 @@ public class AssetsVo implements Serializable {
private String unitNo; //单元号
private String floorNo; //楼层号
private String roomNo; //房间号
private Boolean hasLift;//有无电梯
private String hasLift;//有无电梯
private String layout; //户型
private String orientation; //朝向
private String assetsAddress; //资产地址
private String bizZone; //商圈
private List<String> features; //特色
public String getManagerName() {
return managerName;
@@ -165,11 +167,11 @@ public class AssetsVo implements Serializable {
this.roomNo = roomNo;
}
public Boolean getHasLift() {
public String getHasLift() {
return hasLift;
}
public void setHasLift(Boolean hasLift) {
public void setHasLift(String hasLift) {
this.hasLift = hasLift;
}
@@ -196,4 +198,20 @@ public class AssetsVo implements Serializable {
public void setAssetsAddress(String assetsAddress) {
this.assetsAddress = assetsAddress;
}
public String getBizZone() {
return bizZone;
}
public void setBizZone(String bizZone) {
this.bizZone = bizZone;
}
public List<String> getFeatures() {
return features;
}
public void setFeatures(List<String> features) {
this.features = features;
}
}

View File

@@ -1,5 +1,7 @@
package org.chenyon.bill;
import org.chenyon.pay.OrderService;
import org.chenyon.pay.OrderVo;
import org.chenyon.user.LoginCheck;
import org.chenyon.user.UserContext;
import org.rcy.framework.api.entity.PageResult;
@@ -17,6 +19,8 @@ public class BillController {
@Autowired
private BillService billService;
@Autowired
private OrderService orderService;
@LoginCheck
@PostMapping("/pageQueryContractBill")
@@ -95,4 +99,38 @@ public class BillController {
}
return ResultMessage.success(0);
}
@LoginCheck
@PostMapping("/pay")
public ResultMessage payBill(@RequestBody OrderVo orderVo) {
try {
UserContext userContext = UserContext.get();
if(userContext == null || userContext.getCusNo() == null) {
return ResultMessage.error();
}
orderVo.setPayer(userContext.getCusNo());
orderVo.setPayerOpenId(userContext.getOpenId());
orderVo.setPayStatus("unpaid");
orderVo.setPayerName(userContext.getUsername());
return ResultMessage.success(orderService.createOrder(orderVo));
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return ResultMessage.success(0);
}
@LoginCheck
@GetMapping("/updateRentBillStatus")
public ResultMessage updateRentBillStatus() {
try {
UserContext userContext = UserContext.get();
if(userContext == null || userContext.getCusNo() == null) {
return ResultMessage.success(0);
}
return ResultMessage.success(billService.countUnpayWaeBills(userContext.getCusNo()));
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return ResultMessage.success(0);
}
}

View File

@@ -3,6 +3,7 @@ package org.chenyon.bill;
import org.chenyon.oa.OaBillService;
import org.chenyon.oa.bill.OaBillVo;
import org.chenyon.oa.bill.OaPayRecordVo;
import org.chenyon.pay.OrderService;
import org.rcy.framework.api.entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -15,6 +16,8 @@ public class BillService {
@Autowired
private OaBillService oaBillService;
@Autowired
private OrderService orderService;
public PageResult<OaBillVo> pageQueryContractBill(BillQueryCondition condition) throws Exception {
return oaBillService.pageQueryContractBill(condition);
@@ -39,4 +42,10 @@ public class BillService {
return oaBillService.countUnpayWaeBills(params);
}
public String getBillPayReceiver(String billNo,String bizType) throws Exception {
Map<String,Object> params = new HashMap<>();
params.put("billNo",billNo);
params.put("bizType",bizType);
return oaBillService.getBillPayReceiver(params);
}
}

View File

@@ -0,0 +1,15 @@
package org.chenyon.bill;
import java.util.List;
public class BillStatusUpdateVo {
private List<String> billIds;
public List<String> getBillIds() {
return billIds;
}
public void setBillIds(List<String> billIds) {
this.billIds = billIds;
}
}

View File

@@ -0,0 +1,41 @@
package org.chenyon.bill;
public class UnpaidBillVo {
private String billNo;
private String payee;
private String amount;
private String bizType;
public String getBillNo() {
return billNo;
}
public void setBillNo(String billNo) {
this.billNo = billNo;
}
public String getPayee() {
return payee;
}
public void setPayee(String payee) {
this.payee = payee;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getBizType() {
return bizType;
}
public void setBizType(String bizType) {
this.bizType = bizType;
}
}

View File

@@ -21,6 +21,14 @@ public final class OaApiUrl {
* 查询资产详情
*/
public static final String QUERY_ASSETS_DETAIL = "/assets/detail";
/**
* 获取所有商圈信息
*/
public static final String QUERY_ALL_BIZZONE = "/assets/getBizZones";
/**
* 获取所有商圈信息
*/
public static final String QUERY_ALL_FEATURE = "/assets/getFeatures";
/**
* 分页查询合同
*/
@@ -61,6 +69,10 @@ public final class OaApiUrl {
* 统计未缴租金账单数
*/
public static final String COUNT_UNPAY_RENT_BILLS = "/bill/countUnpay/rent";
/**
* 获取账单收款方
*/
public static final String BILL_PAY_RECEIVER = "/bill/payreceiver";
/**
* 统计未缴水电费账单数
*/

View File

@@ -9,6 +9,8 @@ public class ContractQueryCondition extends PageQueryRequest {
private String formmainId;
private String signStatus;
private String signWay;
private String startDate;
private String endDate;
public String getCusNo() {
return cusNo;
@@ -49,4 +51,20 @@ public class ContractQueryCondition extends PageQueryRequest {
public void setSignWay(String signWay) {
this.signWay = signWay;
}
public String getStartDate() {
return startDate;
}
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public String getEndDate() {
return endDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
}

View File

@@ -61,9 +61,9 @@ public class ContractService {
if(oaContractVo.getAssetsVos() != null) {
List<OaAssetsVo> assetsVos = oaContractVo.getAssetsVos();
OaAssetsVo assetsVo = assetsVos.get(0);
List<String> assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg());
if(assetsDetailImgs != null) {
contractVo.setCoverImgUrl(assetsDetailImgs.get(0));
List<String> assetsCoverImg = oaFileHandlerService.getUrls(true, assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsCoverImg", assetsVo.getCoverImg());
if(assetsCoverImg != null && assetsCoverImg.size() >= 1) {
contractVo.setCoverImgUrl(assetsCoverImg.get(0));
}
}
contractVo.setSignStatus(convertSignStatus(contractVo.getSignStatus()));
@@ -82,6 +82,16 @@ public class ContractService {
for (OaContractVo oaContractVo : oaContractVos) {
ContractVo contractVo = new ContractVo();
BeanUtils.copyProperties(oaContractVo, contractVo);
if(oaContractVo.getAssetsVos() != null) {
List<ContractAssetsVo> contractAssetsVos = new ArrayList<>();
for (OaAssetsVo assetsVo : oaContractVo.getAssetsVos()) {
ContractAssetsVo contractAssetsVo = new ContractAssetsVo();
contractAssetsVo.setAssetsNo(assetsVo.getAssetsNo());
contractAssetsVo.setAssetsName(assetsVo.getAssetsName());
contractAssetsVos.add(contractAssetsVo);
}
contractVo.setAssetsInfos(contractAssetsVos);
}
contractVos.add(contractVo);
}
return contractVos;
@@ -93,7 +103,7 @@ public class ContractService {
condition.setPageNo(pageNo);
condition.setPageSize(pageSize);
OaAssetsVo assetsVo = oaContractService.pageQueryContractAssets(condition);
List<String> assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg());
List<String> assetsCoverImgs = oaFileHandlerService.getUrls(true, assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsCoverImg", assetsVo.getCoverImg());
ContractAssetsVo assetsInfo = new ContractAssetsVo();
BeanUtils.copyProperties(assetsVo, assetsInfo);
RentFeeInfo rentFeeInfo = new RentFeeInfo();
@@ -101,8 +111,8 @@ public class ContractService {
rentFeeInfo.setRentFee(Double.parseDouble(assetsVo.getRentFee()));
}
assetsInfo.setFeeInfo(rentFeeInfo);
if(assetsDetailImgs != null) {
assetsInfo.setCover(assetsDetailImgs.get(0));
if(assetsCoverImgs != null) {
assetsInfo.setCover(assetsCoverImgs.get(0));
}
return assetsInfo;
}
@@ -122,7 +132,7 @@ public class ContractService {
BeanUtils.copyProperties(oaContractVo, contractVo);
List<OaAssetsVo> assetsVos = oaContractVo.getAssetsVos();
OaAssetsVo assetsVo = assetsVos.get(0);
List<String> assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg());
List<String> assetsCoverImgs = oaFileHandlerService.getUrls(true, assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsCoverImg", assetsVo.getCoverImg());
List<String> eContractUrl = oaFileHandlerService.getUrls(false,cusNo,oaContractVo.getContractNo(),oaContractVo.getFormId(),"eContractFile",oaContractVo.geteContractFile());
ContractAssetsVo assetsInfo = new ContractAssetsVo();
BeanUtils.copyProperties(assetsVo, assetsInfo);
@@ -131,8 +141,8 @@ public class ContractService {
rentFeeInfo.setRentFee(Double.parseDouble(assetsVo.getRentFee()));
}
assetsInfo.setFeeInfo(rentFeeInfo);
if(assetsDetailImgs != null) {
assetsInfo.setCover(assetsDetailImgs.get(0));
if(assetsCoverImgs != null) {
assetsInfo.setCover(assetsCoverImgs.get(0));
}
if(eContractUrl != null) {
contractVo.seteContractUrl(eContractUrl.get(0));

View File

@@ -1,7 +1,5 @@
package org.chenyon.fallback;
import org.chenyon.discharge.DisChargeApplyQueryCondition;
import org.chenyon.discharge.DisChargeApplyVo;
import org.chenyon.oa.OaFallBackService;
import org.chenyon.user.LoginCheck;
import org.chenyon.user.UserContext;
@@ -57,7 +55,7 @@ public class FallbackController {
try {
UserContext userContext = UserContext.get();
if(userContext == null || userContext.getCusNo() == null) {
return ResultMessage.success("您还未实名");
return ResultMessage.error("您还未实名");
}
submitVo.setCusNo(userContext.getCusNo());
submitVo.setTenantType(userContext.getUserType().equals("0") ? "个人" : "单位");

View File

@@ -0,0 +1,22 @@
package org.chenyon.file;
public class AttachmentVo {
private String fileName;
private String fileUrl;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
}

View File

@@ -8,9 +8,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -46,14 +44,38 @@ public class OaFileHandlerService {
oaFileLocalRefVo.setSubRefIds(oaFileVo.getSubRefIds());
oaFileLocalRefVo.setViewPublic(viewPublic);
oaFileLocalRefVo.setOwner(owner);
return refLocalUrl(oaFileLocalRefVo);
Map<String, String> map = refLocalUrl(oaFileLocalRefVo);
return new ArrayList<>(map.keySet());
}
public List<AttachmentVo> getAttachmentUrls(Boolean viewPublic,String owner,String bizId, String formId, String oaFieldFlag, OaFileVo oaFileVo){
if(bizId == null || formId == null || oaFieldFlag == null || oaFileVo == null) {
return null;
}
OaFileLocalRefVo oaFileLocalRefVo = new OaFileLocalRefVo();
oaFileLocalRefVo.setBizId(bizId);
oaFileLocalRefVo.setOaFormId(formId);
oaFileLocalRefVo.setOaFieldFlag(oaFieldFlag);
oaFileLocalRefVo.setRefId(oaFileVo.getMainRefId());
oaFileLocalRefVo.setSubRefIds(oaFileVo.getSubRefIds());
oaFileLocalRefVo.setViewPublic(viewPublic);
oaFileLocalRefVo.setOwner(owner);
Map<String, String> map = refLocalUrl(oaFileLocalRefVo);
List<AttachmentVo> attachmentVos = new ArrayList<>();
for (String key : map.keySet()) {
AttachmentVo attachmentVo = new AttachmentVo();
attachmentVo.setFileUrl(key);
attachmentVo.setFileName(map.get(key));
attachmentVos.add(attachmentVo);
}
return attachmentVos;
}
public List<String> getUrls(Boolean viewPublic,String bizId, String formId, String oaFieldFlag, OaFileVo oaFileVo){
return getUrls(viewPublic,null,bizId,formId,oaFieldFlag,oaFileVo);
}
public List<String> refLocalUrl(OaFileLocalRefVo oaFileLocalRefVo) {
public Map<String,String> refLocalUrl(OaFileLocalRefVo oaFileLocalRefVo) {
OaFileFindCondition condition1 = new OaFileFindCondition();
condition1.setBizId(oaFileLocalRefVo.getBizId());
condition1.setOaFormId(oaFileLocalRefVo.getOaFormId());
@@ -64,7 +86,7 @@ public class OaFileHandlerService {
List<OaFileLocalSubRef> subRefInfos = oaFileLocalSubRefDao.findFileInfoByMainRefId(localRefDb.getRefId());
//先删除旧的
Set<String> subRefSet = oaFileLocalRefVo.getSubRefIds().stream().collect(Collectors.toSet());
List<String> nSubUrls = new ArrayList<>();
Map<String,String> nSubUrls = new HashMap<>();
for (OaFileLocalSubRef subRefInfo : subRefInfos) {
if (!subRefSet.contains(subRefInfo.getRefId())) {
//删除子表
@@ -77,7 +99,7 @@ public class OaFileHandlerService {
tempFile.delete();
}
}else {
nSubUrls.add(subRefInfo.getUrl());
nSubUrls.put(subRefInfo.getUrl(),subRefInfo.getFileName());
}
}
Set<String> dbSubRefSet = subRefInfos.stream().map(s -> s.getRefId()).collect(Collectors.toSet());
@@ -89,7 +111,7 @@ public class OaFileHandlerService {
return nSubUrls;
}
//附件信息完全删除
List<String> ncSubUrls = new ArrayList<>();
Map<String,String> ncSubUrls = new HashMap<>();
List<String> subRefIds = oaFileLocalRefVo.getSubRefIds();
for (String subRefId : subRefIds) {
try {
@@ -113,17 +135,20 @@ public class OaFileHandlerService {
return ncSubUrls;
}
private void reBuildSubRef(String bizType,String subRefId, String mainRefId, Boolean isPublic, String owner, List<String> nSubUrls) {
private void reBuildSubRef(String bizType,String subRefId, String mainRefId, Boolean isPublic, String owner, Map<String,String> nSubUrls) {
//新增
OaFileLocalSubRef oaFileLocalSubRef = new OaFileLocalSubRef();
oaFileLocalSubRef.setRefId(subRefId);
oaFileLocalSubRef.setMainRefId(mainRefId);
//调OA接口写入文件
try {
String subUrl = seeyonHttpClient.downloadFile(bizType,OaApiUrl.FILE_DOWNLOAD,subRefId, isPublic, owner);
Map<String, String> resMap = seeyonHttpClient.downloadFile(bizType, OaApiUrl.FILE_DOWNLOAD, subRefId, isPublic, owner);
String subUrl = resMap.get("url");
String oriFileName = resMap.get("fileName");
oaFileLocalSubRef.setUrl(subUrl);
oaFileLocalSubRef.setFileName(oriFileName);
oaFileLocalSubRefDao.save(oaFileLocalSubRef);
nSubUrls.add(subUrl);
nSubUrls.put(subUrl,oriFileName);
} catch (Exception e) {
}

View File

@@ -11,6 +11,7 @@ public class OaFileLocalSubRef extends BaseEntity {
private String refId;
private String url;
private String mainRefId;
private String fileName;
public String getRefId() {
return refId;
@@ -35,4 +36,12 @@ public class OaFileLocalSubRef extends BaseEntity {
public void setMainRefId(String mainRefId) {
this.mainRefId = mainRefId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}

View File

@@ -1,25 +1,20 @@
package org.chenyon.location;
import org.rcy.framework.utils.net.HttpRequestUtils;
import org.rcy.framework.utils.net.HttpResponse;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.model.CityResponse;
import org.springframework.stereotype.Service;
import java.io.File;
import java.net.InetAddress;
@Service
public class IpLocationService {
private static final String API = "https://apis.map.qq.com/ws/location/v1/ip";
public String getLocationByIP(String ip) {
String key = "CQPBZ-R543L-ZCZPH-E5CPI-KMUF6-VRBGE";
String url = API + "?ip=" + ip + "&key=" + key;
try {
HttpResponse response = HttpRequestUtils.sendGet(url, null);
if(response.getCode() == 200) {
return response.getRespStr();
}
}catch (Exception e) {
}
return null;
public String getLocationByIP(String ip) throws Exception {
File database = new File("/usr/local/localfile/GeoLite2-City.mmdb");
DatabaseReader reader = new DatabaseReader.Builder(database).build();
InetAddress ipAddress = InetAddress.getByName(ip);
CityResponse response = reader.city(ipAddress);
return response.getCity().getName();
}
}

View File

@@ -1,6 +1,8 @@
package org.chenyon.location;
import org.rcy.framework.api.entity.ResultMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -12,17 +14,55 @@ import java.io.IOException;
@RestController
@RequestMapping("/location")
public class LocateController {
private static final Logger log = LoggerFactory.getLogger(LocateController.class);
@Autowired
private IpLocationService ipLocationService;
@GetMapping("/getRealCity")
public ResultMessage getRealCity(HttpServletRequest request) throws IOException {
// String ip = "";
// String locationJson = ipLocationService.getLocationByIP(ip);
// JsonNode root = JsonUtils.parseTree(locationJson);
// JsonNode adInfo = root.path("result").path("ad_info");
// String city = adInfo.path("city").asText();
// return ResultMessage.success(city != null ? city : "未知城市");
return ResultMessage.success("宜昌");
try {
String ip = getClientIp(request);
String city = ipLocationService.getLocationByIP(ip);
return ResultMessage.success(city != null ? city : "未知城市");
}catch (Exception e){
log.error(e.getMessage(),e);
}
return ResultMessage.success("宜昌市");
}
public String getClientIp(HttpServletRequest request) {
String ip;
// 1. X-Forwarded-For
ip = request.getHeader("X-Forwarded-For");
if (isValid(ip)) {
// 多级代理:取第一个
return ip.split(",")[0].trim();
}
// 2. X-Real-IP
ip = request.getHeader("X-Real-IP");
if (isValid(ip)) {
return ip;
}
// 3. 其他兼容头
String[] headers = {
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR"
};
for (String header : headers) {
ip = request.getHeader(header);
if (isValid(ip)) {
return ip;
}
}
// 4. 最后兜底
return request.getRemoteAddr();
}
private boolean isValid(String ip) {
return ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip);
}
}

View File

@@ -4,6 +4,7 @@ import org.rcy.framework.api.entity.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.Map;
@Entity
@Table(name = "MESSAGE")
@@ -15,6 +16,9 @@ public class Message extends BaseEntity {
private String messageReceiver;
private String bizId;
private Boolean hasRead = false;
private SubcribeMsgMode subscribeMsgMode;
private Map<String,String> templateValue;
private String messageText;
public MessageType getMessageType() {
return messageType;
@@ -71,4 +75,28 @@ public class Message extends BaseEntity {
public void setHasRead(Boolean hasRead) {
this.hasRead = hasRead;
}
public SubcribeMsgMode getSubscribeMsgMode() {
return subscribeMsgMode;
}
public void setSubscribeMsgMode(SubcribeMsgMode subscribeMsgMode) {
this.subscribeMsgMode = subscribeMsgMode;
}
public Map<String, String> getTemplateValue() {
return templateValue;
}
public void setTemplateValue(Map<String, String> templateValue) {
this.templateValue = templateValue;
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
}

View File

@@ -2,13 +2,19 @@ package org.chenyon.message;
import org.chenyon.user.LoginCheck;
import org.chenyon.user.UserContext;
import org.chenyon.wx.AesException;
import org.rcy.framework.api.entity.PageResult;
import org.rcy.framework.api.entity.ResultMessage;
import org.rcy.framework.utils.aes.AESUtils;
import org.rcy.framework.utils.string.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.ParserConfigurationException;
@RestController
@RequestMapping("/message")
public class MessageController {
@@ -74,7 +80,16 @@ public class MessageController {
@PostMapping("/sendMessage")
public ResultMessage sendMessage(@RequestBody MessageVo vo){
public ResultMessage sendMessage(@RequestBody MessageVo vo, HttpServletRequest request) throws Exception {
String internalToken = request.getHeader("internalToken");
if(StringUtils.isBlank(internalToken)) {
return ResultMessage.error("无权限");
}
String decrypt = AESUtils.decrypt(internalToken, "rent*123");
if(!"oa".equals(decrypt)){
return ResultMessage.error("无权限");
}
messageService.send(vo);
return ResultMessage.success();
}
}

View File

@@ -25,7 +25,9 @@
<if test="messageReceiver != null">
AND messageReceiver = #{messageReceiver}
</if>
<if test="hasRead != null">
AND hasRead = #{hasRead}
</if>
</where>
</sql>
</mapper>

View File

@@ -5,6 +5,8 @@ import org.rcy.framework.api.entity.PageQueryRequest;
public class MessageQueryCondition extends PageQueryRequest {
private String messageReceiver;
private Boolean hasRead;
private String bizId;
public String getMessageReceiver() {
return messageReceiver;
@@ -13,4 +15,20 @@ public class MessageQueryCondition extends PageQueryRequest {
public void setMessageReceiver(String messageReceiver) {
this.messageReceiver = messageReceiver;
}
public Boolean getHasRead() {
return hasRead;
}
public void setHasRead(Boolean hasRead) {
this.hasRead = hasRead;
}
public String getBizId() {
return bizId;
}
public void setBizId(String bizId) {
this.bizId = bizId;
}
}

View File

@@ -1,7 +1,6 @@
package org.chenyon.message;
import org.chenyon.wx.AesException;
import org.chenyon.wx.WXBizMsgCrypt;
import org.rcy.framework.api.entity.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -16,6 +15,8 @@ public class MessageService {
@Autowired
private MessageDao messageDao;
@Autowired
private List<SubscribeMsgSender> subscribeMsgSenders;
public MessageVo detail(Long id) {
@@ -38,6 +39,7 @@ public class MessageService {
public Integer countUnread(String cusNo){
MessageQueryCondition messageQueryCondition = new MessageQueryCondition();
messageQueryCondition.setMessageReceiver(cusNo);
messageQueryCondition.setHasRead(false);
Long count = messageDao.countCondition(messageQueryCondition);
return count.intValue();
}
@@ -53,21 +55,23 @@ public class MessageService {
public void send(MessageVo messageVo) throws AesException, ParserConfigurationException {
// 消息入库
//
String urlSend = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
// 需要加密的明文
String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";
String token = "pamtest";
String timestamp = "1409304348";
String nonce = "xxxxxx";
String appId = "wxb11529c136998cb6";
String replyMsg = " 中文<xml><ToUserName><![CDATA[oia2TjjewbmiOUlr6X-1crbLOvLw]]></ToUserName><FromUserName><![CDATA[gh_7f083739789a]]></FromUserName><CreateTime>1407743423</CreateTime><MsgType><![CDATA[video]]></MsgType><Video><MediaId><![CDATA[eYJ1MbwPRJtOvIEabaxHs7TX2D-HV71s79GUxqdUkjm6Gs2Ed1KF3ulAOA9H1xG0]]></MediaId><Title><![CDATA[testCallBackReplyVideo]]></Title><Description><![CDATA[testCallBackReplyVideo]]></Description></Video></xml>";
WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce);
System.out.println("加密后: " + mingwen);
Message message = new Message();
message.setMessageType(MessageType.valueOf(messageVo.getMessageType()));
message.setMessageContent(messageVo.getMessageContent());
message.setMessageTime(messageVo.getMessageTime());
message.setMessageReceiver(messageVo.getMessageReceiver());
message.setBizId(messageVo.getBizId());
message.setSubscribeMsgMode(SubcribeMsgMode.valueOf(messageVo.getSubscribeMsgMode()));
message.setTitle(messageVo.getTitle());
message.setHasRead(false);
message.setTemplateValue(messageVo.getTemplateValue());
message.setMessageText(messageVo.getMessageText());
messageDao.save(message);
//发送订阅消息
for (SubscribeMsgSender subscribeMsgSender : subscribeMsgSenders) {
if(subscribeMsgSender.support(messageVo) && Boolean.TRUE.equals(messageVo.getSendSubscribeMsg())){
subscribeMsgSender.sendSubscribeMsg(messageVo);
}
}
}
}

View File

@@ -1,14 +1,20 @@
package org.chenyon.message;
import java.util.Map;
public class MessageVo {
private String id;
private String title;
private String messageType;
private String messageContent;
private String messageText;
private String messageTime;
private String messageReceiver;
private String bizId;
private Boolean hasRead;
private Boolean sendSubscribeMsg;
private String subscribeMsgMode;
private Map<String,String> templateValue;
public String getMessageType() {
return messageType;
@@ -73,4 +79,36 @@ public class MessageVo {
public void setHasRead(Boolean hasRead) {
this.hasRead = hasRead;
}
public Boolean getSendSubscribeMsg() {
return sendSubscribeMsg;
}
public void setSendSubscribeMsg(Boolean sendSubscribeMsg) {
this.sendSubscribeMsg = sendSubscribeMsg;
}
public String getSubscribeMsgMode() {
return subscribeMsgMode;
}
public void setSubscribeMsgMode(String subscribeMsgMode) {
this.subscribeMsgMode = subscribeMsgMode;
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public Map<String, String> getTemplateValue() {
return templateValue;
}
public void setTemplateValue(Map<String, String> templateValue) {
this.templateValue = templateValue;
}
}

View File

@@ -0,0 +1,7 @@
package org.chenyon.message;
public enum SubcribeMsgMode {
WEAPPMINIPROGRAM,
SMS,
EMAIL,;
}

View File

@@ -0,0 +1,6 @@
package org.chenyon.message;
public interface SubscribeMsgSender {
void sendSubscribeMsg(MessageVo messageVo);
Boolean support(MessageVo messageVo);
}

View File

@@ -0,0 +1,111 @@
package org.chenyon.message;
import org.chenyon.user.UserService;
import org.chenyon.user.UserVo;
import org.chenyon.wx.WXBizMsgCrypt;
import org.chenyon.wx.WeChatAccessTokenService;
import org.rcy.framework.utils.json.JsonUtils;
import org.rcy.framework.utils.net.HttpRequestUtils;
import org.rcy.framework.utils.net.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class WeAppMiniProgramMsgSender implements SubscribeMsgSender{
private static final Logger log = LoggerFactory.getLogger(WeAppMiniProgramMsgSender.class);
@Autowired
private UserService userService;
@Autowired
private WeChatAccessTokenService weChatAccessTokenService;
@Override
public void sendSubscribeMsg(MessageVo messageVo) {
try {
if(messageVo == null || messageVo.getMessageReceiver() == null){
return;
}
UserVo userVo = userService.getByCusNo(messageVo.getMessageReceiver());
//用户未开启推送则不发送
if(userVo == null || !Boolean.TRUE.equals(userVo.getSubscribeMsg())){
return;
}
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + weChatAccessTokenService.getAccessToken();
Map<String,Object> params = new HashMap<>();
params.put("touser",userVo.getOpenId());
params.put("template_id",getTemplateId(messageVo.getMessageType()));
params.put("page",getForwardPage(messageVo.getMessageType()));
params.put("miniprogram_state","formal");
params.put("lang","zh_CN");
params.put("data",getPushData(messageVo));
HttpResponse response = HttpRequestUtils.sendPost(url, JsonUtils.convertJson(params), null);
Map respMap = JsonUtils.parseObject(response.getRespStr(), Map.class);
if (respMap.get("errcode") != null) {
log.error("推送消息到小程序失败");
}
}catch (Exception e) {
log.error("推送消息到小程序失败: " + e.getMessage(),e);
}
}
@Override
public Boolean support(MessageVo messageVo) {
return SubcribeMsgMode.WEAPPMINIPROGRAM.name().equals(messageVo.getSubscribeMsgMode());
}
private String getTemplateId(String msgType) {
switch (msgType) {
case "BILL": return "9QlNxNONJBICzw3Vcetqbf9yv4lI9q9cR_px8ujlOu8";
}
return null;
}
private Map<String,Object> getPushData(MessageVo messageVo) {
switch (messageVo.getMessageType()) {
case "BILL": return buildBillData(messageVo);
}
return null;
}
public Map<String,Object> buildBillData(MessageVo messageVo) {
Map<String,Object> data = new HashMap<>();
//设置账单金额
Map<String,Object> amount2 = new HashMap<>();
amount2.put("value",messageVo.getTemplateValue().get("billAmount"));
data.put("amount2",amount2);
//设置账单日期
Map<String,Object> time3 = new HashMap<>();
time3.put("value",messageVo.getTemplateValue().get("billDate"));
data.put("time3",time3);
//设置备注
Map<String,Object> thing4 = new HashMap<>();
thing4.put("value",messageVo.getTemplateValue().get("remark"));
data.put("thing4",thing4);
//设置资产店名
Map<String,Object> thing8 = new HashMap<>();
thing8.put("value",messageVo.getTemplateValue().get("assetsName") + "");
data.put("thing8",thing8);
//设置房间号
Map<String,Object> thing1 = new HashMap<>();
thing1.put("value",messageVo.getTemplateValue().get("roomNo") + "");
data.put("thing1",thing1);
return data;
}
private String getForwardPage(String msgType) {
switch (msgType) {
case "BILL": return "unpaid";
}
return null;
}
}

View File

@@ -1,5 +1,7 @@
package org.chenyon.notice;
import org.chenyon.file.AttachmentVo;
import java.util.List;
public class NoticeVo {
@@ -14,7 +16,7 @@ public class NoticeVo {
private String updateBy;
private String updateTime;
private String remark;
private List<String> attachments;
private List<AttachmentVo> attachments;
private List<String> imgs;
public String getNoticeId() {
@@ -97,11 +99,11 @@ public class NoticeVo {
this.remark = remark;
}
public List<String> getAttachments() {
public List<AttachmentVo> getAttachments() {
return attachments;
}
public void setAttachments(List<String> attachments) {
public void setAttachments(List<AttachmentVo> attachments) {
this.attachments = attachments;
}

View File

@@ -9,6 +9,7 @@ import org.rcy.framework.utils.json.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -42,6 +43,11 @@ public class OaAssetService {
return pageResult;
}
public List<String> getBizZones() throws Exception {
OaResp oaResp = seeyonHttpClient.sendGet("获取商圈信息",OaApiUrl.QUERY_ALL_BIZZONE);
return JsonUtils.parseObject(oaResp.getDataStr(), List.class);
}
public OaAssetsVo queryAssetsDetail(String assetsNo) throws Exception {
Map<String,Object> params = new HashMap<>();
params.put("assetsNo",assetsNo);
@@ -49,4 +55,8 @@ public class OaAssetService {
return JsonUtils.parseObject(oaResp.getDataStr(),OaAssetsVo.class);
}
public List<String> getFeatures() throws Exception {
OaResp oaResp = seeyonHttpClient.sendGet("获取特点信息",OaApiUrl.QUERY_ALL_FEATURE);
return JsonUtils.parseObject(oaResp.getDataStr(), List.class);
}
}

View File

@@ -91,4 +91,9 @@ public class OaBillService {
return (Integer) oaResp.getData();
}
public String getBillPayReceiver(Map<String,Object> params) throws Exception {
OaResp oaResp = seeyonHttpClient.sendPost("获取账单收款方", OaApiUrl.BILL_PAY_RECEIVER, JsonUtils.convertJson(params));
return (String) oaResp.getData();
}
}

View File

@@ -1,10 +1,13 @@
package org.chenyon.oa;
import org.chenyon.constants.OaApiUrl;
import org.chenyon.file.OaFileHandlerService;
import org.chenyon.notice.NoticeQueryCondition;
import org.chenyon.notice.NoticeVo;
import org.chenyon.oa.notice.OaNoticeVo;
import org.rcy.framework.api.entity.PageResult;
import org.rcy.framework.utils.json.JsonUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -17,6 +20,8 @@ public class OaNoticeService {
@Autowired
private SeeyonHttpClient seeyonHttpClient;
@Autowired
private OaFileHandlerService oaFileHandlerService;
public PageResult<NoticeVo> pageQuery(NoticeQueryCondition condition) throws Exception {
OaResp oaResp = seeyonHttpClient.sendPost("分页查询招商公告信息", OaApiUrl.PAGE_QUERY_NOTICE, JsonUtils.convertJson(condition));
@@ -42,6 +47,15 @@ public class OaNoticeService {
Map<String,Object> params = new HashMap<>();
params.put("id",id);
OaResp oaResp = seeyonHttpClient.sendPost("查询公告详情",OaApiUrl.QUERY_NOTICE_DETAIL, params);
return JsonUtils.parseObject(oaResp.getDataStr(),NoticeVo.class);
OaNoticeVo oaNoticeVo = JsonUtils.parseObject(oaResp.getDataStr(), OaNoticeVo.class);
NoticeVo vo = new NoticeVo();
BeanUtils.copyProperties(oaNoticeVo,vo);
if(oaNoticeVo.getAttachments() != null) {
vo.setAttachments(oaFileHandlerService.getAttachmentUrls(true,null,oaNoticeVo.getNoticeId(),oaNoticeVo.getNoticeId(),"noticeAttachment",oaNoticeVo.getAttachments()));
}
if(oaNoticeVo.getImgs() != null) {
vo.setImgs(oaFileHandlerService.getUrls(true,oaNoticeVo.getNoticeId(),oaNoticeVo.getNoticeId(),"noticeImg",oaNoticeVo.getImgs()));
}
return vo;
}
}

View File

@@ -62,7 +62,7 @@ public class SeeyonHttpClient {
return resovleResp(respStr);
}
public String downloadFile(String bizType,String url,String refId,Boolean isPulic,String owner) throws Exception {
public Map<String,String> downloadFile(String bizType,String url,String refId,Boolean isPulic,String owner) throws Exception {
Map<String,String> headers = new HashMap<>();
headers.put("token",getToken());
log.info("下载OA文件请求参数为" + refId + "," + isPulic + "," + owner);
@@ -81,10 +81,15 @@ public class SeeyonHttpClient {
}
savePath += File.separator + refId;
String fileGetUrl = oaHost + "/seeyon/rest" + url + "?refId=" + refId;
File file = HttpRequestUtils.downloadFile(fileGetUrl, headers, savePath);
Map<String, Object> downloadResult = HttpRequestUtils.downloadFile(fileGetUrl, headers, savePath);
File file = (File) downloadResult.get("targetFile");
String bizFileName = (String) downloadResult.get("oriFileName");
log.info("文件绝对路径为:" + file.getAbsolutePath());
returnUrl += "/" + file.getName();
return returnUrl;
Map<String,String> resMap = new HashMap<>();
resMap.put("url",returnUrl);
resMap.put("fileName",bizFileName);
return resMap;
}

View File

@@ -4,6 +4,7 @@ package org.chenyon.oa.asset;
import org.chenyon.file.OaFileVo;
import java.io.Serializable;
import java.util.List;
public class OaAssetsVo implements Serializable {
private String assetsNo; // 资产编号
@@ -15,6 +16,7 @@ public class OaAssetsVo implements Serializable {
private String formId; //表单记录ID
private OaFileVo detailImg; //详情图片
private OaFileVo vrImg; //vr图
private OaFileVo coverImg; //封面图
private String assetsDesc; //资产描述
private String assetsAddress; //资产地址
private String latitude; //纬度
@@ -22,7 +24,7 @@ public class OaAssetsVo implements Serializable {
private String unitNo; //单元号
private String floorNo; //楼层号
private String roomNo; //房间号
private Boolean hasLift;//有无电梯
private String hasLift;//有无电梯
private String managerName; //管理员
private String managerPhone; //管理员电话
private String layout; //户型
@@ -32,6 +34,9 @@ public class OaAssetsVo implements Serializable {
private String waterFeeUnit; //水费单位
private String powerFee; //电费
private String powerFeeUnit; //电费单位
private String bizZone;
private List<String> features;
private String renovationStatus; //装修状态
public String getAssetsNo() {
return assetsNo;
@@ -161,11 +166,11 @@ public class OaAssetsVo implements Serializable {
this.roomNo = roomNo;
}
public Boolean getHasLift() {
public String getHasLift() {
return hasLift;
}
public void setHasLift(Boolean hasLift) {
public void setHasLift(String hasLift) {
this.hasLift = hasLift;
}
@@ -240,4 +245,36 @@ public class OaAssetsVo implements Serializable {
public void setManagerName(String managerName) {
this.managerName = managerName;
}
public String getBizZone() {
return bizZone;
}
public void setBizZone(String bizZone) {
this.bizZone = bizZone;
}
public List<String> getFeatures() {
return features;
}
public void setFeatures(List<String> features) {
this.features = features;
}
public String getRenovationStatus() {
return renovationStatus;
}
public void setRenovationStatus(String renovationStatus) {
this.renovationStatus = renovationStatus;
}
public OaFileVo getCoverImg() {
return coverImg;
}
public void setCoverImg(OaFileVo coverImg) {
this.coverImg = coverImg;
}
}

View File

@@ -1,4 +1,115 @@
package org.chenyon.oa.notice;
import org.chenyon.file.OaFileVo;
public class OaNoticeVo {
private String noticeId;
private String noticeTitle;
private String noticeType;
private String noticeContent;
private String status;
private String createBy;
private String createTime;
private String updateBy;
private String updateTime;
private String remark;
private OaFileVo attachments; //详情图片
private OaFileVo imgs; //vr图
public String getNoticeId() {
return noticeId;
}
public void setNoticeId(String noticeId) {
this.noticeId = noticeId;
}
public String getNoticeTitle() {
return noticeTitle;
}
public void setNoticeTitle(String noticeTitle) {
this.noticeTitle = noticeTitle;
}
public String getNoticeType() {
return noticeType;
}
public void setNoticeType(String noticeType) {
this.noticeType = noticeType;
}
public String getNoticeContent() {
return noticeContent;
}
public void setNoticeContent(String noticeContent) {
this.noticeContent = noticeContent;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public OaFileVo getAttachments() {
return attachments;
}
public void setAttachments(OaFileVo attachments) {
this.attachments = attachments;
}
public OaFileVo getImgs() {
return imgs;
}
public void setImgs(OaFileVo imgs) {
this.imgs = imgs;
}
}

View File

@@ -0,0 +1,28 @@
package org.chenyon.pay;
public class CreateOrderResp {
private String errCode;
private String errMsg;
private String responseTimestamp;
private String mid;
private String tid;
private String msgId;
private String srcReserve;
private String merName;
private String merOrderId;
private String seqId;
// "settleRefId":"35316566855N",
// "status":"NEW_ORDER",
// "totalAmount":"100",
// "targetOrderId":"734605162687061091810",
// "targetSys":"UAC",
// "targetStatus":"SUCCESS",
// "miniPayRequest":
// {
//
// },
// "targetMid":"",
// "yxlmAmount":"100"
}

View File

@@ -2,22 +2,46 @@ package org.chenyon.pay;
public class Goods {
/**
* 商户自定义商品编码
*/
private String goodsId;
/**
* 商品名称
*/
private String goodsName;
/**
* 商品数量
*/
private String quantity;
/**
* 商品单价,单位为分
*/
private String price;
private String unit;
/**
* 商品分类
*/
private String goodsCategory;
/**
* 商品说明
*/
private String body;
private String discount;
/** 子商户号 */
/**
* 子商户号
* */
private String subMerchantId;
/** 子订单号 */
/**
* 子订单号
* */
private String merOrderId;
/** 子订单金额(分) */
/**
* 子订单金额(分)
* */
private String subOrderAmount;
public String getGoodsId() {

View File

@@ -0,0 +1,76 @@
package org.chenyon.pay;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class LocalKvRedis {
// 存储 key -> value
private final ConcurrentHashMap<String, String> store = new ConcurrentHashMap<>();
// 存储 key -> 过期时间(毫秒)
private final ConcurrentHashMap<String, Long> expireMap = new ConcurrentHashMap<>();
// 定时清理器
private final ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor();
public LocalKvRedis() {
// 每秒清理一次过期 key
cleaner.scheduleAtFixedRate(() -> {
long now = System.currentTimeMillis();
for (String key : expireMap.keySet()) {
Long expireTime = expireMap.get(key);
if (expireTime != null && expireTime <= now) {
store.remove(key);
expireMap.remove(key);
}
}
}, 1, 1, TimeUnit.SECONDS);
}
// ========== 操作 ==========
// 设置永久 key
public void set(String key, String value) {
store.put(key, value);
expireMap.remove(key);
}
// 设置带 TTL 的 key
public void set(String key, String value, long ttlSeconds) {
store.put(key, value);
expireMap.put(key, System.currentTimeMillis() + ttlSeconds * 1000);
}
// 获取 key
public String get(String key) {
if (isExpired(key)) return null;
return store.get(key);
}
// 删除 key
public void del(String key) {
store.remove(key);
expireMap.remove(key);
}
// 判断 key 是否过期
private boolean isExpired(String key) {
Long expireTime = expireMap.get(key);
if (expireTime == null) return false;
if (System.currentTimeMillis() > expireTime) {
store.remove(key);
expireMap.remove(key);
return true;
}
return false;
}
// ========== 测试 ==========
}

View File

@@ -1,52 +0,0 @@
package org.chenyon.pay;
import org.rcy.framework.api.entity.BaseEntity;
public class Order extends BaseEntity {
private String bizId;
private String payerId;
private String payDate;
private String amount;
private String status;
public String getBizId() {
return bizId;
}
public void setBizId(String bizId) {
this.bizId = bizId;
}
public String getPayerId() {
return payerId;
}
public void setPayerId(String payerId) {
this.payerId = payerId;
}
public String getPayDate() {
return payDate;
}
public void setPayDate(String payDate) {
this.payDate = payDate;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@@ -0,0 +1,240 @@
package org.chenyon.pay;
import org.apache.commons.lang3.StringUtils;
import org.chenyon.bill.UnpaidBillVo;
import org.chenyon.oa.OaBillService;
import org.chenyon.pay.shopcar.SatInfo;
import org.chenyon.pay.shopcar.ShopCarOrderCreateRequest;
import org.chenyon.pay.shopcar.TmPayOrderRespVo;
import org.chenyon.pay.shopcar.VaFld;
import org.chenyon.user.UserService;
import org.rcy.framework.data.id.LongIdGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
public class OrderService {
@Autowired
private WeAppOrderDao weAppOrderDao;
@Autowired
private WeAppSubOrderDao weAppSubOrderDao;
@Value("${chinaums.mid}")
private String mid;
@Value("${chinaums.tid}")
private String tid;
@Value("${chinaums.sourceNo}")
private String sourceNo;
@Value("${wx.appId}")
private String miniProgramAppId;
@Autowired
private TmPayService tmPayService;
@Autowired
private UserService userService;
@Autowired
private OaBillService oaBillService;
@Value("${chinaums.subMid.gy}")
private String gyMid;
@Value("${chinaums.submid.wjfw}")
private String fwglMid;
@Value("${wx.appId}")
private String wxAppId;
@Value("${chinaums.pay.notifyUrl}")
private String notifyUrl;
/**
* 批量创建支付订单
* 【核心】批量前 校验所有 billNo 是否已经存在子订单
* 子订单唯一键billNo
*/
@Transactional(rollbackFor = Exception.class)
public TmPayOrderRespVo createOrder(OrderVo orderVo) throws Exception {
// 1. 基础入参校验
if (orderVo == null || orderVo.getBillVoList() == null || orderVo.getBillVoList().isEmpty()) {
throw new Exception("批量支付账单不能为空");
}
if (StringUtils.isEmpty(orderVo.getPayerOpenId())) {
throw new Exception("支付人OPENID不能为空");
}
List<UnpaidBillVo> billVoList = orderVo.getBillVoList();
// ======================================================================
// 【批量支付 最强幂等校验】
// 遍历所有子账单,根据 billNo 查询是否已存在支付记录
// 只要有一个已存在 → 整批拒绝支付
// ======================================================================
for (UnpaidBillVo billVo : billVoList) {
String billNo = billVo.getBillNo();
// 子订单唯一键billNo
WeAppSubOrder existSubOrder = weAppSubOrderDao.selectByBillNo(billNo);
if (existSubOrder != null) {
throw new Exception("批量支付失败:账单号【" + billNo + "】已存在支付记录,禁止重复支付");
}
}
// 2. 生成主订单ID
Long mainOrderId = LongIdGenerator.generate();
String bizId = mainOrderId.toString();
orderVo.setBizId(bizId);
// 3. 主订单幂等校验
WeAppOrder existMainOrder = weAppOrderDao.findByBizId(bizId);
if (existMainOrder != null) {
TmPayOrderRespVo resp = new TmPayOrderRespVo();
// resp.setOrderNo(existMainOrder.getTmOrderId());
// resp.setAmount(existMainOrder.getAmount());
return resp;
}
// 4. 生成第三方支付订单号
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
int random = 1000000 + new Random().nextInt(9000000);
String tmOrderNo = sourceNo + sdf.format(new Date()) + random;
// 第三方单号唯一兜底
WeAppOrder orderByTmNo = weAppOrderDao.selectByTmOrderId(tmOrderNo);
if (orderByTmNo != null) {
throw new Exception("支付单号重复,请重新提交");
}
// 5. 调用支付创建分账订单
ShopCarOrderCreateRequest request = buildShopCarOrderCreateRequest(orderVo, tmOrderNo);
TmPayOrderRespVo payResp = tmPayService.weChatPayCreateSplitOrder(request);
// 6. 批量插入子订单 + 修复 BigDecimal 金额BUG
BigDecimal totalAmount = BigDecimal.ZERO;
for (UnpaidBillVo billVo : billVoList) {
WeAppSubOrder subOrder = new WeAppSubOrder();
subOrder.setMainOrderId(mainOrderId);
subOrder.setBillNo(billVo.getBillNo()); // 唯一键
subOrder.setAmount(billVo.getAmount());
subOrder.setPayStatus("0");
weAppSubOrderDao.insert(subOrder);
// 正确累加金额修复原BUG
totalAmount = totalAmount.add(new BigDecimal(billVo.getAmount()));
}
// 7. 插入主订单
WeAppOrder weAppOrder = new WeAppOrder();
weAppOrder.setId(mainOrderId);
weAppOrder.setBizId(bizId);
weAppOrder.setPayerId(orderVo.getPayer());
weAppOrder.setPayerName(orderVo.getPayerName());
weAppOrder.setTmOrderId(tmOrderNo);
weAppOrder.setAmount(totalAmount.toString());
weAppOrder.setPayStatus("0");
weAppOrderDao.insert(weAppOrder);
return payResp;
}
/**
* 构建分账请求(完全按你的业务逻辑)
*/
private ShopCarOrderCreateRequest buildShopCarOrderCreateRequest(OrderVo orderVo, String orderNo) throws Exception {
ShopCarOrderCreateRequest request = new ShopCarOrderCreateRequest();
request.setVaMchntNo(mid);
request.setVaTermNo(tid);
request.setSubAppId(wxAppId);
request.setMchntOrderId(orderNo);
request.setMsgType("wx.unifiedOrder");
request.setNotifyUrl(notifyUrl);
request.setTradeType("MINI");
request.setSubOpenId(orderVo.getPayerOpenId());
request.setSysSource("OPT");
VaFld vaFld = new VaFld();
vaFld.setNewShopFlag("GWCXS");
vaFld.setSatType("01");
List<SatInfo> satInfoList = new ArrayList<>();
vaFld.setSatInfo(satInfoList);
BigDecimal gyAmount = BigDecimal.ZERO;
BigDecimal fwglAmount = BigDecimal.ZERO;
for (UnpaidBillVo billVo : orderVo.getBillVoList()) {
Map<String, Object> param = new HashMap<>();
param.put("billNo", billVo.getBillNo());
param.put("bizType", billVo.getBizType());
String receiver = oaBillService.getBillPayReceiver(param);
billVo.setPayee(receiver);
int amountCent = (int) (Double.parseDouble(billVo.getAmount()) * 100);
BigDecimal cent = new BigDecimal(amountCent);
if (StringUtils.isNotBlank(receiver) && receiver.contains("广源")) {
gyAmount = gyAmount.add(cent);
} else {
fwglAmount = fwglAmount.add(cent);
}
}
if (gyAmount.compareTo(BigDecimal.ZERO) > 0) {
SatInfo info = new SatInfo();
info.setMerId(gyMid);
info.setFeeBear("Y");
info.setSatAmt(gyAmount.toString());
satInfoList.add(info);
}
if (fwglAmount.compareTo(BigDecimal.ZERO) > 0) {
SatInfo info = new SatInfo();
info.setMerId(fwglMid);
info.setFeeBear("Y");
info.setSatAmt(fwglAmount.toString());
satInfoList.add(info);
}
request.setTotalAmount(gyAmount.add(fwglAmount).toString());
request.setVaFld(vaFld);
return request;
}
/**
* 支付回调(幂等 + 批量更新子订单)
*/
@Transactional(rollbackFor = Exception.class)
public void tmPayCallback(String tmOrderNo, String payResult) {
WeAppOrder order = weAppOrderDao.selectByTmOrderId(tmOrderNo);
if (order == null || "1".equals(order.getPayStatus())) {
return;
}
if ("SUCCESS".equalsIgnoreCase(payResult)) {
order.setPayStatus("1");
weAppOrderDao.updateByPrimaryKeySelective(order);
// 批量更新该主订单下 所有子订单billNo状态
List<WeAppSubOrder> subList = weAppSubOrderDao.selectByMainOrderId(order.getId());
for (WeAppSubOrder sub : subList) {
sub.setPayStatus("1");
weAppSubOrderDao.updateById(sub);
}
} else {
order.setPayStatus("2");
weAppOrderDao.updateByPrimaryKeySelective(order);
}
}
public void callBack(String bizId) {
WeAppOrder order = weAppOrderDao.findByBizId(bizId);
if (order != null) {
tmPayCallback(order.getTmOrderId(), "SUCCESS");
}
}
private UnifiedOrderRequest buildUnifiedOrderRequest(OrderVo orderVo) {
return null;
}
}

View File

@@ -0,0 +1,80 @@
package org.chenyon.pay;
import org.chenyon.bill.UnpaidBillVo;
import java.util.List;
public class OrderVo {
private String bizId; //业务id
private String amount; //金额
private String payer; //付款方
private String payerName; //付款方名称
private String payStatus; //支付状态
private String payerOpenId; //
private List<UnpaidBillVo> billVoList;
private String clientIp;
public String getBizId() {
return bizId;
}
public void setBizId(String bizId) {
this.bizId = bizId;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getPayer() {
return payer;
}
public void setPayer(String payer) {
this.payer = payer;
}
public List<UnpaidBillVo> getBillVoList() {
return billVoList;
}
public void setBillVoList(List<UnpaidBillVo> billVoList) {
this.billVoList = billVoList;
}
public String getPayStatus() {
return payStatus;
}
public void setPayStatus(String payStatus) {
this.payStatus = payStatus;
}
public String getPayerName() {
return payerName;
}
public void setPayerName(String payerName) {
this.payerName = payerName;
}
public String getPayerOpenId() {
return payerOpenId;
}
public void setPayerOpenId(String payerOpenId) {
this.payerOpenId = payerOpenId;
}
public String getClientIp() {
return clientIp;
}
public void setClientIp(String clientIp) {
this.clientIp = clientIp;
}
}

View File

@@ -10,6 +10,10 @@ public class SubOrder {
/** 金额(分) */
private String totalAmount;
/** 微信子商户appId*/
private String subAppId;
/** 用户子标识*/
private String subOpenId;
public String getMid() {
return mid;
@@ -34,4 +38,20 @@ public class SubOrder {
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
public String getSubAppId() {
return subAppId;
}
public void setSubAppId(String subAppId) {
this.subAppId = subAppId;
}
public String getSubOpenId() {
return subOpenId;
}
public void setSubOpenId(String subOpenId) {
this.subOpenId = subOpenId;
}
}

View File

@@ -0,0 +1,190 @@
package org.chenyon.pay;
import org.rcy.framework.utils.net.HttpRequestUtils;
import org.rcy.framework.utils.net.HttpResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Component
public class TmHttpUtil {
@Value("${chinaums.appId}")
private String APP_ID;
@Value("${chinaums.appSecret}")
private String APP_KEY;
@Value("${chinaums.api.host}")
private String host;
@Autowired
private TmTokenService tmTokenService;
public enum AuthMode {
TOKEN, SIGNATURE
}
// =============================
// POST 请求
// =============================
public String post(String urlStr, String body, AuthMode mode) {
Map<String,String> headers = new HashMap<>();
try {
String timestamp = now();
String nonce = uuid();
if (mode == AuthMode.TOKEN) {
String token = tmTokenService.getToken();
String authString = "OPEN-ACCESS-TOKEN accessToken=\"" + token + "\"" + "," + "AppId=\"" + APP_ID + "\"";
headers.put("Authorization", authString);
} else {
// 🔥 SIGN模式
String signature = buildBodySignature(body, timestamp, nonce);
String authString =
"OPEN-BODY-SIG " +
"AppId=\"" + APP_ID + "\"," +
"Timestamp=\"" + timestamp + "\"," +
"Nonce=\"" + nonce + "\"," +
"Signature=\"" + signature + "\"";
headers.put("Authorization", authString);
}
HttpResponse response = HttpRequestUtils.sendPost(host + urlStr, body, headers);
return response.getRespStr();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// =============================
// GET 请求
// =============================
public String get(String url, String content, AuthMode mode) {
Map<String,String> headers = new HashMap<>();
String respStr = null;
try {
if (mode == AuthMode.TOKEN) {
String token = tmTokenService.getToken();
String authString = "OPEN-ACCESS-TOKEN accessToken=\"" + token + "\"" + "," + "AppId=\"" + APP_ID + "\"";
headers.put("Authorization", authString);
HttpResponse response = HttpRequestUtils.sendGet(host + url, headers);
respStr = response.getRespStr();
} else {
// 🔥 GET签名模式
String timestamp = now();
String nonce = uuid();
String signature = buildGetSignature(content, timestamp, nonce);
String finalUrl = host + url
+ "?authorization=OPEN-FORM-PARAM"
+ "&appId=" + APP_ID
+ "&timestamp=" + timestamp
+ "&nonce=" + nonce
+ "&content=" + URLEncoder.encode(content, "UTF-8")
+ "&signature=" + signature;
HttpResponse response = HttpRequestUtils.sendGet(finalUrl, null);
respStr = response.getRespStr();
}
return respStr;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// =============================
// 🔐 POST签名
// =============================
private String buildBodySignature(String body, String timestamp, String nonce) {
String bodySha = sha256(body);
String signStr = APP_ID + timestamp + nonce + bodySha;
return base64(hmac(signStr, APP_KEY));
}
// =============================
// 🔐 GET签名
// =============================
private String buildGetSignature(String content, String timestamp, String nonce) throws Exception {
String contentSha = sha256(content);
String signStr = APP_ID + timestamp + nonce + contentSha;
String base64 = base64(hmac(signStr, APP_KEY));
return URLEncoder.encode(base64, "UTF-8");
}
// =============================
// 工具方法
// =============================
private String sha256(String str) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(str.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
String s = Integer.toHexString(0xff & b);
if (s.length() == 1) hex.append('0');
hex.append(s);
}
return hex.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private byte[] hmac(String data, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String base64(byte[] data) {
return Base64.getEncoder().encodeToString(data);
}
private String now() {
return LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
private String uuid() {
return UUID.randomUUID().toString().replace("-", "");
}
private String read(HttpURLConnection conn) throws Exception {
BufferedReader br = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
}

View File

@@ -1,28 +1,24 @@
package org.chenyon.pay;
import com.chinaums.open.api.OpenApiContext;
import com.chinaums.open.api.internal.util.http.HttpTransport;
import org.chenyon.pay.shopcar.MiniPayRequest;
import org.chenyon.pay.shopcar.ShopCarOrderCreateRequest;
import org.chenyon.pay.shopcar.TmPayOrderRespVo;
import org.rcy.framework.utils.json.JsonUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class TmPayService {
@Value("${chinaums.api.dev.host}")
private String devHost;
@Value("chinaums.api.prod.host")
private String prodHost;
@Autowired
private TmHttpUtil tmHttpUtil;
public void weChatPayCreateOrder(UnifiedOrderRequest request) {
String url = "/v1/netpay/wx/unified-order";
String appId = "123456";
String appKey = "123456";
OpenApiContext context = TmPayApiContextBuilder.build(appId, appKey, url);
String url = "/v1/inip/upsp/shop/mini/pay";
Long totalAmount = null;
// if(Boolean.TRUE.equals(divisionFlag)){
// request.setDivisionFlag(divisionFlag);
@@ -35,7 +31,34 @@ public class TmPayService {
request.setMid("");// 设置商户号
request.setTid("");
try {
HttpTransport.getInstance().doPost(context, JsonUtils.convertJson(request));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public TmPayOrderRespVo weChatPayCreateSplitOrder(ShopCarOrderCreateRequest request) {
String url = "/v1/inip/upsp/shop/mini/pay";
try {
String respStr = tmHttpUtil.post(url, JsonUtils.convertJson(request), TmHttpUtil.AuthMode.SIGNATURE);
Map map = JsonUtils.parseObject(respStr, Map.class);
String code = (String)map.get("respCode");
if(!"0000".equals(code)){
throw new RuntimeException("创建订单失败");
}
String forwardUrl = (String)map.get("url");
Map<String,String> miniRequestMap = (Map<String, String>) map.get("miniPayRequest");
MiniPayRequest miniPayRequest = new MiniPayRequest();
miniPayRequest.setAppId(miniRequestMap.get("appId"));
miniPayRequest.setNonceStr(miniRequestMap.get("nonceStr"));
miniPayRequest.setPackageStr(miniRequestMap.get("package"));
miniPayRequest.setPaySign(miniRequestMap.get("paySign"));
miniPayRequest.setSignType(miniRequestMap.get("signType"));
miniPayRequest.setTimeStamp(miniRequestMap.get("timeStamp"));
TmPayOrderRespVo tmPayOrderRespVo = new TmPayOrderRespVo();
tmPayOrderRespVo.setUrl(forwardUrl);
tmPayOrderRespVo.setMiniPayRequest(miniPayRequest);
return tmPayOrderRespVo;
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@@ -0,0 +1,69 @@
package org.chenyon.pay;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
public class TmPaySignatureUtils {
// SHA256返回16进制小写
public static String sha256Hex(String data) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(data.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : hash) {
String s = Integer.toHexString(0xff & b);
if (s.length() == 1) hex.append('0');
hex.append(s);
}
return hex.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// HmacSHA256 + Base64
public static String hmacSha256Base64(String data, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey =
new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKey);
byte[] raw = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(raw);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// =============================
// 🔥 POST Body签名
// =============================
public static String buildBodySignature(String appId, String timestamp, String nonce, String body, String appKey) {
String bodySha = sha256Hex(body);
String signStr = appId + timestamp + nonce + bodySha;
return hmacSha256Base64(signStr, appKey);
}
// =============================
// 🔥 GET签名
// =============================
public static String buildGetSignature(String appId, String timestamp, String nonce, String content, String appKey) {
try {
String contentSha = sha256Hex(content);
String signStr = appId + timestamp + nonce + contentSha;
String base64 = hmacSha256Base64(signStr, appKey);
return URLEncoder.encode(base64, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,133 @@
package org.chenyon.pay;
import org.rcy.framework.utils.json.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
@Service
public class TmTokenService {
@Value("${chinaums.appId}")
private String APP_ID;
@Value("${chinaums.appSecret}")
private String APP_KEY;
@Value("${chinaums.api.host}")
private String host;
private final String TOKEN_URL = "/v2/token/access";
@Autowired
private LocalKvRedis localKvRedis;
// 获取Token自动缓存
public synchronized String getToken() throws IOException {
String token = localKvRedis.get("TM-Token");
if (token != null) {
return token;
}
String timestamp = now();
String nonce = UUID.randomUUID().toString().replace("-", "");
String signature = TmPaySignatureUtils.sha256Hex(APP_ID + timestamp + nonce + APP_KEY);
String json = "{"
+ "\"appId\":\"" + APP_ID + "\","
+ "\"timestamp\":\"" + timestamp + "\","
+ "\"nonce\":\"" + nonce + "\","
+ "\"signMethod\":\"SHA256\","
+ "\"signature\":\"" + signature + "\""
+ "}";
String resp = postJson(host + TOKEN_URL, json, null);
Map map = JsonUtils.parseObject(resp, Map.class);
String accessToken = (String)map.get("accessToken");
Integer expiresIn = Integer.parseInt(map.get("expiresIn") + "");
token = accessToken;
localKvRedis.set("TM-Token", token, expiresIn);
return token;
}
private String now() {
return LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
}
private String postJson(String urlStr, String json, Map<String, String> headers) {
HttpURLConnection conn = null;
BufferedReader reader = null;
try {
URL url = new URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
// =============================
// 基础配置
// =============================
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
// =============================
// 🔥 可选Header比如token接口这里传null
// =============================
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
// =============================
// 写入请求体
// =============================
try (OutputStream os = conn.getOutputStream()) {
os.write(json.getBytes("UTF-8"));
os.flush();
}
// =============================
// 读取响应(成功 or 失败都能读)
// =============================
int statusCode = conn.getResponseCode();
InputStream is;
if (statusCode >= 200 && statusCode < 300) {
is = conn.getInputStream();
} else {
is = conn.getErrorStream(); // 🔥关键:错误流
}
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
} catch (Exception e) {
throw new RuntimeException("POST请求异常: " + e.getMessage(), e);
} finally {
try {
if (reader != null) reader.close();
} catch (IOException ignored) {}
if (conn != null) conn.disconnect();
}
}
}

View File

@@ -17,11 +17,8 @@ public class UnifiedOrderRequest {
private String tid;
/** 订单总金额(分) */
private Long totalAmount;
/** 微信子商户appId*/
private String subAppId;
/** 用户子标识*/
private String subOpenId;
private String totalAmount;
/** 微信MINI / JSAPI */
private String tradeType;
@@ -36,7 +33,7 @@ public class UnifiedOrderRequest {
/** 同步分账标识*/
private Boolean divisionFlag;
/** 分账金额*/
private Long platformAmount;
private String platformAmount;
/** 通知地址 */
private String notifyUrl;
@@ -156,30 +153,6 @@ public class UnifiedOrderRequest {
this.retCommParams = retCommParams;
}
public Long getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(Long totalAmount) {
this.totalAmount = totalAmount;
}
public String getSubAppId() {
return subAppId;
}
public void setSubAppId(String subAppId) {
this.subAppId = subAppId;
}
public String getSubOpenId() {
return subOpenId;
}
public void setSubOpenId(String subOpenId) {
this.subOpenId = subOpenId;
}
public Boolean getDivisionFlag() {
return divisionFlag;
}
@@ -188,11 +161,19 @@ public class UnifiedOrderRequest {
this.divisionFlag = divisionFlag;
}
public Long getPlatformAmount() {
public String getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
public String getPlatformAmount() {
return platformAmount;
}
public void setPlatformAmount(Long platformAmount) {
public void setPlatformAmount(String platformAmount) {
this.platformAmount = platformAmount;
}
}

View File

@@ -0,0 +1,86 @@
package org.chenyon.pay;
import org.rcy.framework.api.entity.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.Date;
@Entity
@Table(name = "ORDER")
public class WeAppOrder extends BaseEntity {
private String bizId;
private String payerId;
private Date payDate;
private String amount;
private String payerName; //付款方名称
private String payStatus; //支付状态
private String payerOpenId; //
private String tmOrderId; //银联支付订单号
public String getBizId() {
return bizId;
}
public void setBizId(String bizId) {
this.bizId = bizId;
}
public String getPayerId() {
return payerId;
}
public void setPayerId(String payerId) {
this.payerId = payerId;
}
public Date getPayDate() {
return payDate;
}
public void setPayDate(Date payDate) {
this.payDate = payDate;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getPayerName() {
return payerName;
}
public void setPayerName(String payerName) {
this.payerName = payerName;
}
public String getPayStatus() {
return payStatus;
}
public void setPayStatus(String payStatus) {
this.payStatus = payStatus;
}
public String getPayerOpenId() {
return payerOpenId;
}
public void setPayerOpenId(String payerOpenId) {
this.payerOpenId = payerOpenId;
}
public String getTmOrderId() {
return tmOrderId;
}
public void setTmOrderId(String tmOrderId) {
this.tmOrderId = tmOrderId;
}
}

View File

@@ -0,0 +1,8 @@
package org.chenyon.pay;
import org.rcy.framework.data.dao.BaseDao;
public interface WeAppOrderDao extends BaseDao<WeAppOrder> {
WeAppOrder findByBizId(String bizId);
WeAppOrder selectByTmOrderId(String tmOrderNo);
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.chenyon.pay.WeAppOrderDao">
<select id="findByBizId" resultType="WeAppOrder">
select * from order where bizId = #{bizId};
</select>
<select id="selectByTmOrderId" resultType="WeAppOrder">
select * from order where bizId = #{bizId};
</select>
</mapper>

View File

@@ -0,0 +1,56 @@
package org.chenyon.pay;
import org.rcy.framework.api.entity.BaseEntity;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "SUB_ORDER")
public class WeAppSubOrder extends BaseEntity {
private String billNo;
private String bizSubType;
private String amount;
private Long mainOrderId;
private String payStatus;
public String getBillNo() {
return billNo;
}
public void setBillNo(String billNo) {
this.billNo = billNo;
}
public String getBizSubType() {
return bizSubType;
}
public void setBizSubType(String bizSubType) {
this.bizSubType = bizSubType;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public Long getMainOrderId() {
return mainOrderId;
}
public void setMainOrderId(Long mainOrderId) {
this.mainOrderId = mainOrderId;
}
public String getPayStatus() {
return payStatus;
}
public void setPayStatus(String payStatus) {
this.payStatus = payStatus;
}
}

View File

@@ -0,0 +1,15 @@
package org.chenyon.pay;
import org.rcy.framework.data.dao.BaseDao;
import java.util.List;
public interface WeAppSubOrderDao extends BaseDao<WeAppSubOrder> {
WeAppSubOrder selectByBillNo(String billNo);
List<WeAppSubOrder> selectByMainOrderId(Long mainOrderId);
Integer updateById(WeAppSubOrder subOrder);
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.chenyon.pay.WeAppSubOrderDao">
</mapper>

View File

@@ -0,0 +1,32 @@
package org.chenyon.pay.shopcar;
public class GoodsInfo {
private String goodsName;
private Integer goodsNum;
private Integer goodsPrice;
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public Integer getGoodsNum() {
return goodsNum;
}
public void setGoodsNum(Integer goodsNum) {
this.goodsNum = goodsNum;
}
public Integer getGoodsPrice() {
return goodsPrice;
}
public void setGoodsPrice(Integer goodsPrice) {
this.goodsPrice = goodsPrice;
}
}

View File

@@ -0,0 +1,58 @@
package org.chenyon.pay.shopcar;
public class MiniPayRequest {
private String timeStamp;
private String packageStr;
private String paySign;
private String appId;
private String signType;
private String nonceStr;
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getPackageStr() {
return packageStr;
}
public void setPackageStr(String packageStr) {
this.packageStr = packageStr;
}
public String getPaySign() {
return paySign;
}
public void setPaySign(String paySign) {
this.paySign = paySign;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getSignType() {
return signType;
}
public void setSignType(String signType) {
this.signType = signType;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
}

View File

@@ -0,0 +1,16 @@
package org.chenyon.pay.shopcar;
import java.util.Map;
public class RetCommParams {
private Map<String, Object> map;
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}

View File

@@ -0,0 +1,105 @@
package org.chenyon.pay.shopcar;
/**
* 分账信息
*/
public class SatInfo {
/**
* 子商户号
*/
private String merId;
/**
* 手续费承担方
*/
private String feeBear;
/**
* 子商户上送交易
*/
private String payBear;
/**
* 商户子订单号
*/
private String merOrderId;
/**
* 分账所得额
*/
private String satAmt;
private String orderDesc;
private String remark;
private Integer subsidyAmt;
private GoodsInfo goodsInfo;
public String getMerId() {
return merId;
}
public void setMerId(String merId) {
this.merId = merId;
}
public String getFeeBear() {
return feeBear;
}
public void setFeeBear(String feeBear) {
this.feeBear = feeBear;
}
public String getPayBear() {
return payBear;
}
public void setPayBear(String payBear) {
this.payBear = payBear;
}
public String getMerOrderId() {
return merOrderId;
}
public void setMerOrderId(String merOrderId) {
this.merOrderId = merOrderId;
}
public String getSatAmt() {
return satAmt;
}
public void setSatAmt(String satAmt) {
this.satAmt = satAmt;
}
public String getOrderDesc() {
return orderDesc;
}
public void setOrderDesc(String orderDesc) {
this.orderDesc = orderDesc;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getSubsidyAmt() {
return subsidyAmt;
}
public void setSubsidyAmt(Integer subsidyAmt) {
this.subsidyAmt = subsidyAmt;
}
public GoodsInfo getGoodsInfo() {
return goodsInfo;
}
public void setGoodsInfo(GoodsInfo goodsInfo) {
this.goodsInfo = goodsInfo;
}
}

View File

@@ -0,0 +1,493 @@
package org.chenyon.pay.shopcar;
import org.chenyon.pay.Goods;
public class ShopCarOrderCreateRequest {
/**
* 商户订单号
*/
private String mchntOrderId;
/**
* 商户号
*/
private String vaMchntNo;
/**
* 终端号
*/
private String vaTermNo;
/**
* 请求预留字段
*/
private String srcReserve;
/**
* 业务模板用来替代mid
* 作为大商户统一接入第三
* 方用于POS通等转商户
* 交易场景
* MINIDEFAULT
*/
private String instMid;
/**
* 消息类型
* 微信: wx.unifiedOrder
* 支付宝: trade.create
* 云闪付: uac.miniOrder
*/
private String msgType;
/**
* 商品信息
*/
private Goods goods;
/**
* 商户附加数据
*/
private String attachedData;
/**
* 订单过期时间
*/
private String expireTime;
/**
* 商品标记
*/
private String goodsTag;
/**
* 商品交易单号
* 跟goods字段二选一商品信息通过goods.add接口
* 提前上送
*/
private String goodsTradeNo;
/**
* 订单描述
*/
private String orderDesc;
/**
* 商品ID
*/
private String productId;
/**
* 订单原始金额,单位分,
* 用于记录前端系统打折前
* 的金额
*/
private String originalAmount;
/**
* 支付总金额,若divisionFlag为true
* totalAmount=subOrders字段中的所有totalAmount
* 值之和 加上 platformAmount值=goods中的所有
* subOrderAmount值之和
*/
private String totalAmount;
/**
* 支付结果通知地址
*/
private String notifyUrl;
/**
* 网页跳转地址
*/
private String returnUrl;
/**
* 下单场景
*/
private String placeOrderScene;
/**
* 订单展示页面
*/
private String showUrl;
/**
* subAppId
*/
private String subAppId;
/**
* 用户子标识,商户自己公众号appid下的用户openid可以通过微
* 信oauth接口获取。
*/
private String subOpenId;
/**
* 支付宝买家ID,支付宝必传
* 需要商户自行调用支付宝接口获取,具体获取方式 请
* 根据支付宝接口文档。
*/
private String userId;
/**
* 交易类型,值为MINI如果使用云闪付云微小程序支付时需要上
* 送UP_WX_MINI
*/
private String tradeType;
/**
* 是否需要限制信用卡支付
*/
private String limitCreditCard;
/**
* 花呗分期数
*/
private String installmentNumber;
/**
* 实名认证姓名,Base64编码
* 跨境交易时,该字段必须传
*/
private String name;
/**
* 实名认证手机号,Base64编码
* 跨境交易时,该字段可选
*/
private String mobile;
/**
* 实名认证证件类型,证件类型,微信,银联支持身份证、支付宝支持身份
* 证IDENTITY_CARD、护照PASSPORT、军官证
* OFFICER_CARD、士兵证SOLDIER_CARD、户口
* 本HOKOU
* 跨境交易时,该字段必须传
*/
private String certType;
/**
* 实名认证证件号,Base64编码
* 跨境交易时,该字段必须传
*/
private String certNo;
/**
* 是否需要实名认证,需要实名认证时置为 T
* 跨境交易时,该字段必须传
*/
private String fixBuyer;
private RetCommParams retCommParams;
private Boolean thirdPartyInstalSubsFlag;
private String bankCardNo;
private String invokeScene;
private String discountCode;
private String ylyxId;
private String ylyxName;
private String ylyxMerAbbr;
/**
* 系统来源,商终密SZM
* 开放平台: OPT
* 当需要接收交易结果通知时需上送从UP系统申请的
* 消息来源同网付msgSrc并且联系业务人员在新购
* 物车录入对应的密钥
*/
private String sysSource;
private VaFld vaFld;
public String getMchntOrderId() {
return mchntOrderId;
}
public void setMchntOrderId(String mchntOrderId) {
this.mchntOrderId = mchntOrderId;
}
public String getVaMchntNo() {
return vaMchntNo;
}
public void setVaMchntNo(String vaMchntNo) {
this.vaMchntNo = vaMchntNo;
}
public String getVaTermNo() {
return vaTermNo;
}
public void setVaTermNo(String vaTermNo) {
this.vaTermNo = vaTermNo;
}
public String getSrcReserve() {
return srcReserve;
}
public void setSrcReserve(String srcReserve) {
this.srcReserve = srcReserve;
}
public String getInstMid() {
return instMid;
}
public void setInstMid(String instMid) {
this.instMid = instMid;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public Goods getGoods() {
return goods;
}
public void setGoods(Goods goods) {
this.goods = goods;
}
public String getAttachedData() {
return attachedData;
}
public void setAttachedData(String attachedData) {
this.attachedData = attachedData;
}
public String getExpireTime() {
return expireTime;
}
public void setExpireTime(String expireTime) {
this.expireTime = expireTime;
}
public String getGoodsTag() {
return goodsTag;
}
public void setGoodsTag(String goodsTag) {
this.goodsTag = goodsTag;
}
public String getGoodsTradeNo() {
return goodsTradeNo;
}
public void setGoodsTradeNo(String goodsTradeNo) {
this.goodsTradeNo = goodsTradeNo;
}
public String getOrderDesc() {
return orderDesc;
}
public void setOrderDesc(String orderDesc) {
this.orderDesc = orderDesc;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getOriginalAmount() {
return originalAmount;
}
public void setOriginalAmount(String originalAmount) {
this.originalAmount = originalAmount;
}
public String getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
public String getPlaceOrderScene() {
return placeOrderScene;
}
public void setPlaceOrderScene(String placeOrderScene) {
this.placeOrderScene = placeOrderScene;
}
public String getShowUrl() {
return showUrl;
}
public void setShowUrl(String showUrl) {
this.showUrl = showUrl;
}
public String getSubAppId() {
return subAppId;
}
public void setSubAppId(String subAppId) {
this.subAppId = subAppId;
}
public String getSubOpenId() {
return subOpenId;
}
public void setSubOpenId(String subOpenId) {
this.subOpenId = subOpenId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getTradeType() {
return tradeType;
}
public void setTradeType(String tradeType) {
this.tradeType = tradeType;
}
public String getLimitCreditCard() {
return limitCreditCard;
}
public void setLimitCreditCard(String limitCreditCard) {
this.limitCreditCard = limitCreditCard;
}
public String getInstallmentNumber() {
return installmentNumber;
}
public void setInstallmentNumber(String installmentNumber) {
this.installmentNumber = installmentNumber;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getCertType() {
return certType;
}
public void setCertType(String certType) {
this.certType = certType;
}
public String getCertNo() {
return certNo;
}
public void setCertNo(String certNo) {
this.certNo = certNo;
}
public String getFixBuyer() {
return fixBuyer;
}
public void setFixBuyer(String fixBuyer) {
this.fixBuyer = fixBuyer;
}
public RetCommParams getRetCommParams() {
return retCommParams;
}
public void setRetCommParams(RetCommParams retCommParams) {
this.retCommParams = retCommParams;
}
public Boolean getThirdPartyInstalSubsFlag() {
return thirdPartyInstalSubsFlag;
}
public void setThirdPartyInstalSubsFlag(Boolean thirdPartyInstalSubsFlag) {
this.thirdPartyInstalSubsFlag = thirdPartyInstalSubsFlag;
}
public String getBankCardNo() {
return bankCardNo;
}
public void setBankCardNo(String bankCardNo) {
this.bankCardNo = bankCardNo;
}
public String getInvokeScene() {
return invokeScene;
}
public void setInvokeScene(String invokeScene) {
this.invokeScene = invokeScene;
}
public String getDiscountCode() {
return discountCode;
}
public void setDiscountCode(String discountCode) {
this.discountCode = discountCode;
}
public String getYlyxId() {
return ylyxId;
}
public void setYlyxId(String ylyxId) {
this.ylyxId = ylyxId;
}
public String getYlyxName() {
return ylyxName;
}
public void setYlyxName(String ylyxName) {
this.ylyxName = ylyxName;
}
public String getYlyxMerAbbr() {
return ylyxMerAbbr;
}
public void setYlyxMerAbbr(String ylyxMerAbbr) {
this.ylyxMerAbbr = ylyxMerAbbr;
}
public String getSysSource() {
return sysSource;
}
public void setSysSource(String sysSource) {
this.sysSource = sysSource;
}
public VaFld getVaFld() {
return vaFld;
}
public void setVaFld(VaFld vaFld) {
this.vaFld = vaFld;
}
}

View File

@@ -0,0 +1,79 @@
package org.chenyon.pay.shopcar;
public class ShopCarOrderQueryRequest {
/**
* 商户订单号,必传
*/
private String mchntOrderId;
/**
* 商户号,必传
*/
private String vaMchntNo;
/**
* 终端号,必传
*/
private String vaTermNo;
private String srcReserve;
private String instMid;
private String sysSource;
/**
* 增值域,必传
*/
private VaFld vaFld;
public String getMchntOrderId() {
return mchntOrderId;
}
public void setMchntOrderId(String mchntOrderId) {
this.mchntOrderId = mchntOrderId;
}
public String getVaMchntNo() {
return vaMchntNo;
}
public void setVaMchntNo(String vaMchntNo) {
this.vaMchntNo = vaMchntNo;
}
public String getVaTermNo() {
return vaTermNo;
}
public void setVaTermNo(String vaTermNo) {
this.vaTermNo = vaTermNo;
}
public String getSrcReserve() {
return srcReserve;
}
public void setSrcReserve(String srcReserve) {
this.srcReserve = srcReserve;
}
public String getInstMid() {
return instMid;
}
public void setInstMid(String instMid) {
this.instMid = instMid;
}
public String getSysSource() {
return sysSource;
}
public void setSysSource(String sysSource) {
this.sysSource = sysSource;
}
public VaFld getVaFld() {
return vaFld;
}
public void setVaFld(VaFld vaFld) {
this.vaFld = vaFld;
}
}

View File

@@ -0,0 +1,23 @@
package org.chenyon.pay.shopcar;
public class TmPayOrderRespVo {
private String url;
private MiniPayRequest miniPayRequest;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public MiniPayRequest getMiniPayRequest() {
return miniPayRequest;
}
public void setMiniPayRequest(MiniPayRequest miniPayRequest) {
this.miniPayRequest = miniPayRequest;
}
}

View File

@@ -0,0 +1,22 @@
package org.chenyon.pay.shopcar;
public class TmPayResponse {
private String respCode;
private String respDesc;
public String getRespCode() {
return respCode;
}
public void setRespCode(String respCode) {
this.respCode = respCode;
}
public String getRespDesc() {
return respDesc;
}
public void setRespDesc(String respDesc) {
this.respDesc = respDesc;
}
}

View File

@@ -0,0 +1,81 @@
package org.chenyon.pay.shopcar;
import java.util.List;
public class VaFld {
/**
* 新购物车标识,
* 新购物车交易需上送 如果不上送则为标准支付交易
* 线上-GWCXS
* 线下-BC-GWCBC
* 线下银行卡-GWCYH
*/
private String newShopFlag;
/**
* 交易上送方式01主商户上送
* 02子商户上送(目前仅支持公众号、小程序、H5、
* App、聚分期)
*/
private String isSubMchntPay;
/**
* 平台分账金额
*/
private String platAmt;
/**
* 分账类型,01-同步分账
* 02-异步分账
*/
private String satType;
private GoodsInfo goodsInfo;
private List<SatInfo> satInfo;
public String getNewShopFlag() {
return newShopFlag;
}
public void setNewShopFlag(String newShopFlag) {
this.newShopFlag = newShopFlag;
}
public String getIsSubMchntPay() {
return isSubMchntPay;
}
public void setIsSubMchntPay(String isSubMchntPay) {
this.isSubMchntPay = isSubMchntPay;
}
public String getPlatAmt() {
return platAmt;
}
public void setPlatAmt(String platAmt) {
this.platAmt = platAmt;
}
public String getSatType() {
return satType;
}
public void setSatType(String satType) {
this.satType = satType;
}
public GoodsInfo getGoodsInfo() {
return goodsInfo;
}
public void setGoodsInfo(GoodsInfo goodsInfo) {
this.goodsInfo = goodsInfo;
}
public List<SatInfo> getSatInfo() {
return satInfo;
}
public void setSatInfo(List<SatInfo> satInfo) {
this.satInfo = satInfo;
}
}

View File

@@ -1,7 +1,7 @@
package org.chenyon.potential;
import org.chenyon.user.LoginCheck;
import org.chenyon.user.UserContext;
import org.apache.commons.lang3.StringUtils;
import org.chenyon.user.UserService;
import org.chenyon.user.UserVo;
import org.chenyon.wx.WxUserSession;
@@ -33,14 +33,23 @@ public class PotentialController {
public ResultMessage addViewRecord(HttpServletRequest request, @RequestParam("assetId") String assetId) {
try {
String token = request.getHeader("WT");
String userType = request.getHeader("USERTYPE");
String userType = request.getParameter("userType");
if(StringUtils.isAnyBlank(token,userType)){
return ResultMessage.success();
}
String assetsNo = request.getParameter("assetId");
String assetsName = request.getParameter("assetsName");
WxUserSession session = wxUserSessionService.getSessionInfoByThirdSession(token);
UserVo userVo = userService.findByOpenIdAndUserType(session.getOpenId(), userType);
ViewRecordVo viewRecordVo = new ViewRecordVo();
viewRecordVo.setAssetsNo(assetId);
viewRecordVo.setAssetsNo(assetsNo);
viewRecordVo.setAssetsName(assetsName);
viewRecordVo.setCusNo(userVo.getCusNo());
viewRecordVo.setPhone(userVo.getPhone());
viewRecordVo.setCusName(userVo.getUserName());
if(StringUtils.isBlank(userVo.getPhone())) {
return ResultMessage.success();
}
potentialService.add(viewRecordVo);
}catch (Exception e) {
log.warn("记录租户浏览记录失败: " + e.getMessage(),e);

View File

@@ -6,6 +6,7 @@ public class ViewRecordVo {
private String cusName;
private String phone;
private String assetsNo;
private String assetsName;
public String getCusNo() {
return cusNo;
@@ -38,4 +39,12 @@ public class ViewRecordVo {
public void setAssetsNo(String assetsNo) {
this.assetsNo = assetsNo;
}
public String getAssetsName() {
return assetsName;
}
public void setAssetsName(String assetsName) {
this.assetsName = assetsName;
}
}

View File

@@ -61,7 +61,7 @@ public class ReservateController {
public ResultMessage countHandling() {
try {
UserContext userContext = UserContext.get();
if(userContext == null || userContext.getCusNo() == null) {
if(userContext == null || userContext.getOpenId() == null) {
return ResultMessage.success(0);
}
return ResultMessage.success(reservateService.countHandling(userContext.getOpenId()));

View File

@@ -8,6 +8,7 @@ import org.rcy.framework.utils.net.HttpRequestUtils;
import org.rcy.framework.utils.net.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@@ -81,6 +82,22 @@ public class LoginController {
return ResultMessage.success(userVo);
}
@GetMapping("/subscribeMsg")
@LoginCheck
public ResultMessage subscribeMsg(@RequestParam("subscribe") Boolean subscribe) throws Exception {
UserContext userContext = UserContext.get();
if(userContext == null) {
return ResultMessage.success();
}
WxUserSession wxUserSession = wxUserSessionService.getSessionInfoByThirdSession(userContext.getToken());
UserVo userVo = userService.findByOpenIdAndUserType(wxUserSession.getOpenId(), userContext.getUserType());
User user = new User();
BeanUtils.copyProperties(userVo,user);
user.setSubscribeMsg(subscribe);
userService.upsert(user);
return ResultMessage.success();
}
@PostMapping("/updateVerifyCode")
@LoginCheck
public ResultMessage updateVerifyCode(HttpServletRequest request,@RequestBody AuthInfoVo authInfoVo) throws Exception {

View File

@@ -4,5 +4,6 @@ import org.rcy.framework.data.dao.BaseDao;
import org.springframework.web.bind.annotation.RequestParam;
public interface UserDao extends BaseDao<User> {
User findByOpenIdAndUserType(@RequestParam("openId") String openId,@RequestParam("loginType") String loginType);
User findByOpenIdAndUserType(@RequestParam("openId") String openId,@RequestParam("userType") String userType);
User findByCusNo(@RequestParam("cusNo") String cusNo);
}

View File

@@ -4,6 +4,9 @@
<mapper namespace="org.chenyon.user.UserDao">
<select id="findByOpenIdAndUserType" resultType="User">
select * from USER where openId = #{openId}
select * from USER where openId = #{openId} and userType = #{userType}
</select>
<select id="findByCusNo" resultType="User">
select * from USER where cusNo = #{cusNo}
</select>
</mapper>

View File

@@ -25,6 +25,11 @@ public class UserService {
if(oldDbData != null) {
if(!oldDbData.getPhone().equals(user.getPhone())){
user.setId(oldDbData.getId());
}
if(user.getSubscribeMsg() != null && !user.getSubscribeMsg().equals(oldDbData.getSubscribeMsg())){
user.setId(oldDbData.getId());
}
if(user.getId() != null) {
userDao.updateByPrimaryKeySelective(user);
}
}else {
@@ -36,7 +41,7 @@ public class UserService {
User user = userDao.findByOpenIdAndUserType(openId, userType);
OaCusVo cusInfo = null;
try {
if(user.getCusNo() != null) {
if(user != null && user.getCusNo() != null) {
cusInfo = oaCusService.getCusInfo(user.getCusNo());
}
}catch (Exception e) {
@@ -53,6 +58,16 @@ public class UserService {
return userVo;
}
public UserVo getByCusNo(String cusNo) {
User user = userDao.findByCusNo(cusNo);
if(user == null) {
return null;
}
UserVo userVo = new UserVo();
BeanUtils.copyProperties(user,userVo);
return userVo;
}
public void updateAuthInfo(String openId,String userType,String verifyCode) throws Exception {
//调用oa接口客商信息
User user = userDao.findByOpenIdAndUserType(openId, userType);

View File

@@ -10,6 +10,7 @@ public class UserVo implements Serializable {
private Boolean oaAuth;
private String userType = "0";
private String userName;
private Boolean subscribeMsg;
public String getOpenId() {
return openId;
@@ -58,4 +59,12 @@ public class UserVo implements Serializable {
public void setUserName(String userName) {
this.userName = userName;
}
public Boolean getSubscribeMsg() {
return subscribeMsg;
}
public void setSubscribeMsg(Boolean subscribeMsg) {
this.subscribeMsg = subscribeMsg;
}
}

View File

@@ -0,0 +1,29 @@
package org.chenyon.vr;
import org.rcy.framework.api.entity.ResultMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/vr")
public class VrDataController {
private static final Logger log = LoggerFactory.getLogger(VrDataController.class);
@Autowired
private VrDataService vrDataService;
@GetMapping("/data")
public ResultMessage getVrData(String id) {
try {
return ResultMessage.success(vrDataService.getVrData(id));
}catch (Exception e) {
log.error(e.getMessage(),e);
}
return ResultMessage.success(new VrDataVo());
}
}

View File

@@ -0,0 +1,45 @@
package org.chenyon.vr;
import org.chenyon.assets.AssetsQueryService;
import org.chenyon.assets.vo.AssetsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class VrDataService {
@Value("${cdn.domain}")
private String cdnDomain;
@Autowired
private AssetsQueryService assetsQueryService;
public VrDataVo getVrData(String id) throws Exception {
AssetsVo assets = assetsQueryService.getAssetsById(id);
if(assets == null || assets.getVrImgs() == null) {
return null;
}
List<String> vrImgs = assets.getVrImgs();
VrDataVo dataVo = new VrDataVo();
dataVo.setName(assets.getAssetsName());
dataVo.setStartInde(0);
dataVo.setSpaces(buildVrSpace(vrImgs));
return dataVo;
}
private List<VrSpace> buildVrSpace(List<String> vrImgs) {
List<VrSpace> vrSpaces = new ArrayList<>();
for (int i = 0; i < vrImgs.size(); i++) {
VrSpace vrSpace = new VrSpace();
vrSpace.setId(String.valueOf(i));
vrSpace.setName("资产全景"+i);
vrSpace.setType("image");
vrSpace.setSrc(cdnDomain + vrImgs.get(i));
vrSpaces.add(vrSpace);
}
return vrSpaces;
}
}

View File

@@ -0,0 +1,33 @@
package org.chenyon.vr;
import java.util.List;
public class VrDataVo {
private String name;
private Integer startInde; // 初始显示空间索引
private List<VrSpace> spaces;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getStartInde() {
return startInde;
}
public void setStartInde(Integer startInde) {
this.startInde = startInde;
}
public List<VrSpace> getSpaces() {
return spaces;
}
public void setSpaces(List<VrSpace> spaces) {
this.spaces = spaces;
}
}

View File

@@ -0,0 +1,61 @@
package org.chenyon.vr;
import java.util.List;
public class VrSpace {
private String id;
private String name;
private String type; // 类型image | video | model | cubemap
private String src;
private Integer modelScale; //模型缩放
private List<Vrhotspot> hotspots;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public Integer getModelScale() {
return modelScale;
}
public void setModelScale(Integer modelScale) {
this.modelScale = modelScale;
}
public List<Vrhotspot> getHotspots() {
return hotspots;
}
public void setHotspots(List<Vrhotspot> hotspots) {
this.hotspots = hotspots;
}
}

View File

@@ -0,0 +1,40 @@
package org.chenyon.vr;
public class Vrhotspot {
private String lon; // 经度
private String lat; // 纬度
private String targetId; // 点击后跳转到的空间 id
private String label;
public String getLon() {
return lon;
}
public void setLon(String lon) {
this.lon = lon;
}
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
public String getTargetId() {
return targetId;
}
public void setTargetId(String targetId) {
this.targetId = targetId;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}

View File

@@ -0,0 +1,27 @@
package org.chenyon.pay;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class TmPayTokenServiceTest {
@Autowired
private TmTokenService tmTokenService;
@Test
public void testGetToken() throws IOException {
String token = tmTokenService.getToken();
System.out.println(token);
}
public void testCreateOrder() {
}
}