Merge remote-tracking branch 'origin/test' into test
This commit is contained in:
commit
d65a01fcd9
5
pom.xml
5
pom.xml
@ -98,6 +98,11 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.wechatpay-apiv3</groupId>
|
||||
<artifactId>wechatpay-apache-httpclient</artifactId>
|
||||
<version>0.2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -0,0 +1,24 @@
|
||||
package club.joylink.rtss.controller.pay;
|
||||
|
||||
import club.joylink.rtss.services.pay.wechat.WechatPayService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/wechatPay")
|
||||
public class WechatPayController {
|
||||
|
||||
@Autowired
|
||||
private WechatPayService wechatPayService;
|
||||
|
||||
@PostMapping("/receive")
|
||||
public void receive(@RequestBody String data) {
|
||||
log.info(String.format("微信回调信息:%s", data));
|
||||
wechatPayService.receive(data);
|
||||
}
|
||||
}
|
@ -53,7 +53,10 @@ public enum BusinessExceptionAssertEnum implements BusinessExceptionAssert {
|
||||
WECHAT_CODE_EXPIRED(40029, "wechat code expired"),
|
||||
INVALID_CLIENT(40031, "invalid client"),
|
||||
INCORRECT_VERIFICATION_CODE(40051, "incorrect verification code"),
|
||||
THIRD_SERVICE_CALL_EXCEPTION(40071, "the third service call exception")
|
||||
THIRD_SERVICE_CALL_EXCEPTION(40071, "the third service call exception"),
|
||||
|
||||
//支付异常
|
||||
PAY_ERROR(50000, "pay error")
|
||||
;
|
||||
|
||||
int code;
|
||||
|
@ -295,8 +295,7 @@ public class DraftMapService implements IDraftMapService {
|
||||
section.setDestinationCode(null);
|
||||
section.setDestinationCodePoint(null);
|
||||
}
|
||||
if (Objects.equals(section.getType(), BusinessConsts.Section.SectionType.Type01) ||
|
||||
Objects.equals(section.getType(), BusinessConsts.Section.SectionType.Type04) ||
|
||||
if (Objects.equals(section.getType(), BusinessConsts.Section.SectionType.Type04) ||
|
||||
Objects.equals(section.getType(), BusinessConsts.Section.SectionType.Type05)) {
|
||||
section.setParentCode(null);
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package club.joylink.rtss.services.pay.bean;
|
||||
|
||||
import club.joylink.rtss.vo.client.order.OrderDetailVO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class OrderPay {
|
||||
|
||||
/**
|
||||
* 订单编号*
|
||||
*/
|
||||
private String orderNo;
|
||||
|
||||
/**
|
||||
* 订单描述*
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 订单总价*
|
||||
*/
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* 交易结束时间
|
||||
*/
|
||||
private OffsetDateTime timeExpire;
|
||||
|
||||
/**
|
||||
* 订单中包含的商品详情
|
||||
*/
|
||||
private List<OrderDetailVO> orderDetail;
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package club.joylink.rtss.services.pay.wechat;
|
||||
|
||||
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
|
||||
import club.joylink.rtss.services.IOrderService;
|
||||
import club.joylink.rtss.services.pay.bean.OrderPay;
|
||||
import club.joylink.rtss.services.pay.wechat.bean.WxUnifiedOrder;
|
||||
import club.joylink.rtss.util.JsonUtils;
|
||||
import club.joylink.rtss.vo.client.order.OrderDetailVO;
|
||||
import club.joylink.rtss.websocket.StompMessageService;
|
||||
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
||||
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
||||
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.PrivateKey;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static club.joylink.rtss.services.pay.wechat.constant.WechatConstants.*;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WechatPayService {
|
||||
|
||||
@Autowired
|
||||
private IOrderService iorderService;
|
||||
|
||||
@Autowired
|
||||
private StompMessageService stompMessageService;
|
||||
|
||||
private CloseableHttpClient httpClient;
|
||||
|
||||
/**
|
||||
* 统一下单
|
||||
* @param orderPay
|
||||
* @return 支付二维码url
|
||||
* @throws IOException
|
||||
*/
|
||||
public String unifiedOrder(OrderPay orderPay) throws IOException {
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
if (httpClient == null)
|
||||
buildHttpClient();
|
||||
//构建并发送请求
|
||||
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
|
||||
httpPost.setHeader("Accept", "application/json");
|
||||
WxUnifiedOrder wxUnifiedOrder = new WxUnifiedOrder(orderPay, "http://2i38984j47.qicp.vip/api/wechatPay/receive");
|
||||
String json = JsonUtils.writeValueAsString(wxUnifiedOrder);
|
||||
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
|
||||
entity.setContentType("application/json");
|
||||
httpPost.setEntity(entity);
|
||||
response = httpClient.execute(httpPost);
|
||||
//处理请求结果
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
String result = EntityUtils.toString(response.getEntity());
|
||||
if (statusCode == 200) { //处理成功
|
||||
log.info("微信支付下单成功,return body = " + result);
|
||||
return result;
|
||||
} else if (statusCode == 204) { //处理成功,无返回Body
|
||||
System.out.println("微信支付下单成功");
|
||||
return result;
|
||||
} else {
|
||||
log.error("failed,resp code = " + statusCode+ ",return body = " + result);
|
||||
throw BusinessExceptionAssertEnum.PAY_ERROR.exception();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw BusinessExceptionAssertEnum.PAY_ERROR.exception("微信Native支付异常", e);
|
||||
} finally {
|
||||
if (httpClient != null)
|
||||
httpClient.close();
|
||||
if (response != null)
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void buildHttpClient() {
|
||||
try {
|
||||
PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(MCH_PRIVATE_KEY.getBytes("utf-8")));
|
||||
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
|
||||
new WechatPay2Credentials(MCH_ID, new PrivateKeySigner(MCH_SERIAL_NO, privateKey)), APIV3_KEY.getBytes("utf-8"));
|
||||
httpClient = WechatPayHttpClientBuilder.create()
|
||||
.withMerchant(MCH_ID, MCH_SERIAL_NO, privateKey)
|
||||
.withValidator(new WechatPay2Validator(verifier))
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
throw BusinessExceptionAssertEnum.PAY_ERROR.exception("微信支付httpClient构建异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
OrderPay pay = new OrderPay();
|
||||
pay.setOrderNo("2018081400001");
|
||||
pay.setDescription("标准1号线ATS现地工作站实操");
|
||||
pay.setTotalFee(1);
|
||||
pay.setTimeExpire(OffsetDateTime.now().plusMinutes(10));
|
||||
OrderDetailVO orderDetailVO = new OrderDetailVO();
|
||||
orderDetailVO.setGoodsId(1L);
|
||||
orderDetailVO.setGoodsName("测试");
|
||||
orderDetailVO.setGoodsAmount(1);
|
||||
orderDetailVO.setPrice(1L);
|
||||
pay.setOrderDetail(List.of(orderDetailVO));
|
||||
WechatPayService wps = new WechatPayService();
|
||||
String result = wps.unifiedOrder(pay);
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付结果处理
|
||||
*/
|
||||
public String receive(String data) {
|
||||
String result = "支付结果:" + data;
|
||||
log.info(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
package club.joylink.rtss.services.pay.wechat.bean;
|
||||
|
||||
public class WxPayResult {
|
||||
|
||||
/**
|
||||
* 返回状态码
|
||||
*/
|
||||
private String returnCode;
|
||||
|
||||
/**
|
||||
* 返回信息
|
||||
*/
|
||||
private String returnMsg;
|
||||
|
||||
/**
|
||||
* 公众账号ID*
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 商户号*
|
||||
*/
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* 设备号
|
||||
*/
|
||||
private String deviceInfo;
|
||||
|
||||
/**
|
||||
* 随机字符串*
|
||||
*/
|
||||
private String nonceStr;
|
||||
|
||||
/**
|
||||
* 签名*
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 签名类型
|
||||
*/
|
||||
private String signType;
|
||||
|
||||
/**
|
||||
* 业务结果
|
||||
*/
|
||||
private String resultCode;
|
||||
|
||||
/**
|
||||
* 错误代码
|
||||
*/
|
||||
private String errCode;
|
||||
|
||||
/**
|
||||
* 错误代码描述
|
||||
*/
|
||||
private String errCodeDes;
|
||||
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
private String openId;
|
||||
|
||||
/**
|
||||
* 是否关注公众账号
|
||||
*/
|
||||
private String isSubscribe;
|
||||
|
||||
/**
|
||||
* 交易类型*
|
||||
*/
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 付款银行
|
||||
*/
|
||||
private String bankType;
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
private Integer totalFee;
|
||||
|
||||
/**
|
||||
* 应结订单金额
|
||||
*/
|
||||
private Integer settlementTotalFee;
|
||||
|
||||
/**
|
||||
* 货币种类
|
||||
*/
|
||||
private String feeType;
|
||||
|
||||
/**
|
||||
* 现金支付金额
|
||||
*/
|
||||
private Integer cashFee;
|
||||
|
||||
/**
|
||||
* 现金支付货币类型
|
||||
*/
|
||||
private String cashFeeType;
|
||||
|
||||
/**
|
||||
* 总代金券金额
|
||||
*/
|
||||
private Integer couponFee;
|
||||
|
||||
/**
|
||||
* 代金券使用数量
|
||||
*/
|
||||
private Integer couponCount;
|
||||
|
||||
/**
|
||||
* 微信支付订单号
|
||||
*/
|
||||
private String transactionId;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String outTradeNo;
|
||||
|
||||
/**
|
||||
* 商家数据包
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 支付完成时间
|
||||
*/
|
||||
private String timeEnd;
|
||||
|
||||
public String getReturnCode() {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void setReturnCode(String returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
}
|
||||
|
||||
public String getReturnMsg() {
|
||||
return returnMsg;
|
||||
}
|
||||
|
||||
public void setReturnMsg(String returnMsg) {
|
||||
this.returnMsg = returnMsg;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getMchId() {
|
||||
return mchId;
|
||||
}
|
||||
|
||||
public void setMchId(String mchId) {
|
||||
this.mchId = mchId;
|
||||
}
|
||||
|
||||
public String getDeviceInfo() {
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
public void setDeviceInfo(String deviceInfo) {
|
||||
this.deviceInfo = deviceInfo;
|
||||
}
|
||||
|
||||
public String getNonceStr() {
|
||||
return nonceStr;
|
||||
}
|
||||
|
||||
public void setNonceStr(String nonceStr) {
|
||||
this.nonceStr = nonceStr;
|
||||
}
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
public String getSignType() {
|
||||
return signType;
|
||||
}
|
||||
|
||||
public void setSignType(String signType) {
|
||||
this.signType = signType;
|
||||
}
|
||||
|
||||
public String getResultCode() {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
public void setResultCode(String resultCode) {
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
public String getErrCode() {
|
||||
return errCode;
|
||||
}
|
||||
|
||||
public void setErrCode(String errCode) {
|
||||
this.errCode = errCode;
|
||||
}
|
||||
|
||||
public String getErrCodeDes() {
|
||||
return errCodeDes;
|
||||
}
|
||||
|
||||
public void setErrCodeDes(String errCodeDes) {
|
||||
this.errCodeDes = errCodeDes;
|
||||
}
|
||||
|
||||
public String getOpenId() {
|
||||
return openId;
|
||||
}
|
||||
|
||||
public void setOpenId(String openId) {
|
||||
this.openId = openId;
|
||||
}
|
||||
|
||||
public String getIsSubscribe() {
|
||||
return isSubscribe;
|
||||
}
|
||||
|
||||
public void setIsSubscribe(String isSubscribe) {
|
||||
this.isSubscribe = isSubscribe;
|
||||
}
|
||||
|
||||
public String getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
|
||||
public void setTradeType(String tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
public String getBankType() {
|
||||
return bankType;
|
||||
}
|
||||
|
||||
public void setBankType(String bankType) {
|
||||
this.bankType = bankType;
|
||||
}
|
||||
|
||||
public Integer getTotalFee() {
|
||||
return totalFee;
|
||||
}
|
||||
|
||||
public void setTotalFee(Integer totalFee) {
|
||||
this.totalFee = totalFee;
|
||||
}
|
||||
|
||||
public Integer getSettlementTotalFee() {
|
||||
return settlementTotalFee;
|
||||
}
|
||||
|
||||
public void setSettlementTotalFee(Integer settlementTotalFee) {
|
||||
this.settlementTotalFee = settlementTotalFee;
|
||||
}
|
||||
|
||||
public String getFeeType() {
|
||||
return feeType;
|
||||
}
|
||||
|
||||
public void setFeeType(String feeType) {
|
||||
this.feeType = feeType;
|
||||
}
|
||||
|
||||
public Integer getCashFee() {
|
||||
return cashFee;
|
||||
}
|
||||
|
||||
public void setCashFee(Integer cashFee) {
|
||||
this.cashFee = cashFee;
|
||||
}
|
||||
|
||||
public String getCashFeeType() {
|
||||
return cashFeeType;
|
||||
}
|
||||
|
||||
public void setCashFeeType(String cashFeeType) {
|
||||
this.cashFeeType = cashFeeType;
|
||||
}
|
||||
|
||||
public Integer getCouponFee() {
|
||||
return couponFee;
|
||||
}
|
||||
|
||||
public void setCouponFee(Integer couponFee) {
|
||||
this.couponFee = couponFee;
|
||||
}
|
||||
|
||||
public Integer getCouponCount() {
|
||||
return couponCount;
|
||||
}
|
||||
|
||||
public void setCouponCount(Integer couponCount) {
|
||||
this.couponCount = couponCount;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public void setTransactionId(String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
public String getOutTradeNo() {
|
||||
return outTradeNo;
|
||||
}
|
||||
|
||||
public void setOutTradeNo(String outTradeNo) {
|
||||
this.outTradeNo = outTradeNo;
|
||||
}
|
||||
|
||||
public String getAttach() {
|
||||
return attach;
|
||||
}
|
||||
|
||||
public void setAttach(String attach) {
|
||||
this.attach = attach;
|
||||
}
|
||||
|
||||
public String getTimeEnd() {
|
||||
return timeEnd;
|
||||
}
|
||||
|
||||
public void setTimeEnd(String timeEnd) {
|
||||
this.timeEnd = timeEnd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WxPayResult [returnCode=" + returnCode + ", returnMsg=" + returnMsg + ", appId=" + appId + ", mchId="
|
||||
+ mchId + ", deviceInfo=" + deviceInfo + ", nonceStr=" + nonceStr + ", sign=" + sign + ", signType="
|
||||
+ signType + ", resultCode=" + resultCode + ", errCode=" + errCode + ", errCodeDes=" + errCodeDes
|
||||
+ ", openId=" + openId + ", isSubscribe=" + isSubscribe + ", tradeType=" + tradeType + ", bankType="
|
||||
+ bankType + ", totalFee=" + totalFee + ", settlementTotalFee=" + settlementTotalFee + ", feeType="
|
||||
+ feeType + ", cashFee=" + cashFee + ", cashFeeType=" + cashFeeType + ", couponFee=" + couponFee
|
||||
+ ", couponCount=" + couponCount + ", transactionId=" + transactionId + ", outTradeNo=" + outTradeNo
|
||||
+ ", attach=" + attach + ", timeEnd=" + timeEnd + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package club.joylink.rtss.services.pay.wechat.bean;
|
||||
|
||||
public class WxPayResultReply {
|
||||
|
||||
/**
|
||||
* 返回状态码
|
||||
*/
|
||||
private String returnCode;
|
||||
|
||||
/**
|
||||
* 返回信息
|
||||
*/
|
||||
private String returnMsg;
|
||||
|
||||
public String getReturnCode() {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void setReturnCode(String returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
}
|
||||
|
||||
public String getReturnMsg() {
|
||||
return returnMsg;
|
||||
}
|
||||
|
||||
public void setReturnMsg(String returnMsg) {
|
||||
this.returnMsg = returnMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WxPayResultReply [returnCode=" + returnCode + ", returnMsg=" + returnMsg + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
package club.joylink.rtss.services.pay.wechat.bean;
|
||||
|
||||
import club.joylink.rtss.services.pay.bean.OrderPay;
|
||||
import club.joylink.rtss.services.pay.wechat.constant.WechatConstants;
|
||||
import club.joylink.rtss.vo.client.order.OrderDetailVO;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Getter
|
||||
public class WxUnifiedOrder {
|
||||
|
||||
/**
|
||||
* 公众账号ID*
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 商户号*
|
||||
*/
|
||||
private String mchid;
|
||||
|
||||
/**
|
||||
* 商品描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String out_trade_no;
|
||||
|
||||
/**
|
||||
* 交易结束时间
|
||||
*/
|
||||
private String time_expire;
|
||||
|
||||
/**
|
||||
* 附加数据
|
||||
*/
|
||||
private String attach;
|
||||
|
||||
/**
|
||||
* 通知地址
|
||||
*/
|
||||
private String notify_url;
|
||||
|
||||
/**
|
||||
* 订单优惠标记
|
||||
*/
|
||||
private String goods_tag;
|
||||
|
||||
/**
|
||||
* 订单金额信息
|
||||
*/
|
||||
private WxPayOrderAmountInfo amount;
|
||||
|
||||
/**
|
||||
* 优惠功能(没懂为啥这个参数要叫优惠功能)
|
||||
*/
|
||||
private WxPayOrderDetail detail;
|
||||
|
||||
/**
|
||||
* 场景信息,支付场景描述
|
||||
*/
|
||||
private WxPaySceneInfo scene_info;
|
||||
|
||||
public WxUnifiedOrder(OrderPay orderPay, String notify_url) {
|
||||
this.appid = WechatConstants.APP_ID;
|
||||
this.mchid = WechatConstants.MCH_ID;
|
||||
this.description = orderPay.getDescription();
|
||||
this.out_trade_no = orderPay.getOrderNo();
|
||||
if (orderPay.getTimeExpire() != null) {
|
||||
this.time_expire = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(orderPay.getTimeExpire().withNano(0));
|
||||
}
|
||||
// this.attach =
|
||||
this.notify_url = notify_url;
|
||||
// this.goods_tag =
|
||||
this.amount = new WxPayOrderAmountInfo(orderPay.getTotalFee());
|
||||
// this.detail = new WxPayOrderDetail(out_trade_no, orderPay.getOrderDetail());
|
||||
// this.scene_info = new WxPaySceneInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单金额信息
|
||||
*/
|
||||
@Getter
|
||||
class WxPayOrderAmountInfo {
|
||||
/**
|
||||
* 订单总金额,单位/分
|
||||
*/
|
||||
private int total;
|
||||
|
||||
/**
|
||||
* 货币类型
|
||||
*/
|
||||
private String currency = "CNY";
|
||||
|
||||
public WxPayOrderAmountInfo(int total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
class WxPayOrderDetail {
|
||||
/**
|
||||
* 订单原价
|
||||
* 该字段主要用于防止同一张小票分多次支付,以享受多次优惠的情况,正常支付订单不必上传此参数。
|
||||
*/
|
||||
private int cost_price;
|
||||
|
||||
/**
|
||||
* 商家小票ID
|
||||
*/
|
||||
private String invoice_id;
|
||||
|
||||
/**
|
||||
* 单品列表
|
||||
*/
|
||||
private List<GoodsDetail> goods_detail;
|
||||
|
||||
public WxPayOrderDetail(String invoice_id, List<OrderDetailVO> orderDetailVOS) {
|
||||
this.invoice_id = invoice_id;
|
||||
this.goods_detail = orderDetailVOS.stream().map(GoodsDetail::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Getter
|
||||
class GoodsDetail {
|
||||
/**
|
||||
* 商户侧商品编码
|
||||
* 由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
|
||||
*/
|
||||
private String merchant_goods_id;
|
||||
|
||||
/**
|
||||
* 微信侧商品编码
|
||||
* 微信支付定义的统一商品编号(没有可不传)
|
||||
*/
|
||||
private String wechatpay_goods_id;
|
||||
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
private String goods_name;
|
||||
|
||||
/**
|
||||
* 商品数量
|
||||
*/
|
||||
private int quantity;
|
||||
|
||||
/**
|
||||
* 商品单价,单位为分
|
||||
*/
|
||||
private int unit_price;
|
||||
|
||||
public GoodsDetail(OrderDetailVO orderDetail) {
|
||||
this.merchant_goods_id = orderDetail.getGoodsId().toString();
|
||||
this.goods_name = orderDetail.getGoodsName();
|
||||
this.quantity = orderDetail.getGoodsAmount();
|
||||
this.unit_price = orderDetail.getPrice().intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景信息
|
||||
*/
|
||||
@Getter
|
||||
class WxPaySceneInfo {
|
||||
/**
|
||||
* 用户终端ip。调用微信支付API的机器IP,支持IPv4和IPv6两种格式的IP地址。
|
||||
*/
|
||||
private String payer_client_ip;
|
||||
|
||||
/**
|
||||
* 商户端设备号。商户端设备号(门店号或收银设备ID)。
|
||||
*/
|
||||
private String device_id;
|
||||
|
||||
/**
|
||||
* 商户门店信息
|
||||
*/
|
||||
private StoreInfo store_info;
|
||||
|
||||
public WxPaySceneInfo() {
|
||||
this.payer_client_ip = WechatConstants.SPBILL_CREATE_IP;
|
||||
this.device_id = "1";
|
||||
this.store_info = new StoreInfo();
|
||||
}
|
||||
|
||||
@Getter
|
||||
class StoreInfo {
|
||||
/**
|
||||
* 门店编号,商户侧门店编号
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 门店名称,商户侧门店名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 地区编码,地区编码,详细请见省市区编号对照表。
|
||||
*/
|
||||
private String area_code;
|
||||
|
||||
/**
|
||||
* 详细地址,详细的商户门店地址
|
||||
*/
|
||||
private String address;
|
||||
|
||||
public StoreInfo() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package club.joylink.rtss.services.pay.wechat.bean;
|
||||
|
||||
|
||||
public class WxUnifiedOrderResult {
|
||||
|
||||
/**
|
||||
* 返回状态码*
|
||||
*/
|
||||
private String returnCode;
|
||||
|
||||
/**
|
||||
* 返回信息*
|
||||
*/
|
||||
private String returnMsg;
|
||||
|
||||
/**
|
||||
* 公众账号ID*
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 商户号*
|
||||
*/
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* 设备号
|
||||
*/
|
||||
private String deviceInfo;
|
||||
|
||||
/**
|
||||
* 随机字符串*
|
||||
*/
|
||||
private String nonceStr;
|
||||
|
||||
/**
|
||||
* 签名*
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 业务结果*
|
||||
*/
|
||||
private String resultCode;
|
||||
|
||||
/**
|
||||
* 错误代码
|
||||
*/
|
||||
private String errCode;
|
||||
|
||||
/**
|
||||
* 错误代码描述
|
||||
*/
|
||||
private String errCodeDes;
|
||||
|
||||
/**
|
||||
* 交易类型*
|
||||
*/
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 预支付交易会话标识*
|
||||
*/
|
||||
private String prepayId;
|
||||
|
||||
/**
|
||||
* 二维码链接
|
||||
*/
|
||||
private String codeUrl;
|
||||
|
||||
public String getReturnCode() {
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void setReturnCode(String returnCode) {
|
||||
this.returnCode = returnCode;
|
||||
}
|
||||
|
||||
public String getReturnMsg() {
|
||||
return returnMsg;
|
||||
}
|
||||
|
||||
public void setReturnMsg(String returnMsg) {
|
||||
this.returnMsg = returnMsg;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getMchId() {
|
||||
return mchId;
|
||||
}
|
||||
|
||||
public void setMchId(String mchId) {
|
||||
this.mchId = mchId;
|
||||
}
|
||||
|
||||
public String getDeviceInfo() {
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
public void setDeviceInfo(String deviceInfo) {
|
||||
this.deviceInfo = deviceInfo;
|
||||
}
|
||||
|
||||
public String getNonceStr() {
|
||||
return nonceStr;
|
||||
}
|
||||
|
||||
public void setNonceStr(String nonceStr) {
|
||||
this.nonceStr = nonceStr;
|
||||
}
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
public String getResultCode() {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
public void setResultCode(String resultCode) {
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
public String getErrCode() {
|
||||
return errCode;
|
||||
}
|
||||
|
||||
public void setErrCode(String errCode) {
|
||||
this.errCode = errCode;
|
||||
}
|
||||
|
||||
public String getErrCodeDes() {
|
||||
return errCodeDes;
|
||||
}
|
||||
|
||||
public void setErrCodeDes(String errCodeDes) {
|
||||
this.errCodeDes = errCodeDes;
|
||||
}
|
||||
|
||||
public String getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
|
||||
public void setTradeType(String tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
public String getPrepayId() {
|
||||
return prepayId;
|
||||
}
|
||||
|
||||
public void setPrepayId(String prepayId) {
|
||||
this.prepayId = prepayId;
|
||||
}
|
||||
|
||||
public String getCodeUrl() {
|
||||
return codeUrl;
|
||||
}
|
||||
|
||||
public void setCodeUrl(String codeUrl) {
|
||||
this.codeUrl = codeUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WxUnifiedOrderResult [returnCode=" + returnCode + ", returnMsg=" + returnMsg + ", appId=" + appId
|
||||
+ ", mchId=" + mchId + ", deviceInfo=" + deviceInfo + ", nonceStr=" + nonceStr + ", sign=" + sign
|
||||
+ ", resultCode=" + resultCode + ", errCode=" + errCode + ", errCodeDes=" + errCodeDes + ", tradeType="
|
||||
+ tradeType + ", prepayId=" + prepayId + ", codeUrl=" + codeUrl + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package club.joylink.rtss.services.pay.wechat.constant;
|
||||
|
||||
public interface WechatConstants {
|
||||
|
||||
public static interface PayUrl {
|
||||
/** 统一下单接口地址 */
|
||||
String UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
|
||||
}
|
||||
|
||||
String DATE_FORMAT_STR = "yyyyMMddHHmmss";
|
||||
|
||||
/** 公众账号ID */
|
||||
String APP_ID = "wx41cb66db5faf330f";
|
||||
|
||||
/** 商户号 */
|
||||
String MCH_ID = "1511854231";
|
||||
|
||||
/** 机器IP */
|
||||
String SPBILL_CREATE_IP = "58.87.66.250";
|
||||
|
||||
/** 商户平台设置的密钥key(应该已经没用了) */
|
||||
String MCH_KEY = "a6502d608c64fb2f7e6dbcf854cda32a";
|
||||
|
||||
/** 商户证书序列号 */
|
||||
String MCH_SERIAL_NO = "40980EBE9204E4D8956215FE72A1C89A8480FA27";
|
||||
|
||||
/** APIv3密钥,用于解密接口返回的数据(平台证书公钥) */
|
||||
String APIV3_KEY = "c0666cec1cb15d915f802ce5a3df5c2d";
|
||||
|
||||
/** 商户证书私钥 */
|
||||
String MCH_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDAzmBwXZX7p+bl\n" +
|
||||
"IiSl/5CukfAxOmYTVgCbLQ1SBJMd9c52VsPgWED4o/llkvwWXY9EUTDX09qOBroF\n" +
|
||||
"+iCQBu9iWvStfN2VTmy7ECC3ROv1HzAK2U/aWOsCxv/svpqUoWImqAVaUtOd+kQK\n" +
|
||||
"RtMVvz/kE+BUZO1RFA3YS7dmYPtAuZQOhLXTvg7uS5k/PaSg39Bx+ZNcymUQtHHs\n" +
|
||||
"6nH0RmneY2LBtmLZHw3aeb2VCydEPY9tON/vhBbLXe/+Lq3C8Lx8R2IdURCcR2Wl\n" +
|
||||
"92UlLwR5nBK/kKcgOPA7DjBf4zPGBHgFovytW5gKRY+UscrPgSEHxa9fmRy/SLQS\n" +
|
||||
"k7AjGZC5AgMBAAECggEBALGIFiLA+Y5sbt3DD43OAbHMbSdXB5B8WziHRkGkNraa\n" +
|
||||
"lI5AnEHh4YlQqx7NNdN+OKIGRHwm9ZJbPUStqPgVeqzM5YktdXa6bMHeOtGl48Kk\n" +
|
||||
"Af+rU6zQvSykghjC9OEwrIi9o5gktfg77hSsXEck/7aKWsA64o4KcikcpvXdDNzt\n" +
|
||||
"qrLumHzJ32WLN6q5JClc4zPfpc3CuRUH3SJevDC7b0E+BFth8c1cX1QDbSl1v8kA\n" +
|
||||
"anolAIcHqhFvJHzpY+WjHqGVdN4RbPXl+xsOoo3mXsTHybSWgHd2ZJGAAqtQlaSV\n" +
|
||||
"Y9dRLSU4MQBITNGe5j+rngyRowDkrYqbtAfFqtYQhwUCgYEA5iDlSqu69pr50xf4\n" +
|
||||
"oQmyOk7ep9U8JOTH+C+OOtbVzpS51oLnq95wJ8cu/QV8qhOUVSZ6KKhD37o7XWhZ\n" +
|
||||
"vGjBGrlv/C0anAsZ4S10GmL/gbqpCckSe4ITz4VI03oy/fdRK+VtulgMFvjKEr9F\n" +
|
||||
"cYOkct4IkKAclAECYLhX7VUEKrMCgYEA1ntX1kA4objy7+bgfmxmFkAk50otHJwR\n" +
|
||||
"huCEOMe9MlgAAc9NYk+GEF1tQPzTQVdVL6jovtrZ+L5HP1SXJGQWY6N06XJThN9+\n" +
|
||||
"oks027gQWBoXnTQJ8/wXPQpXq3EIgCThzKNkTLq4fsnGIUgRUH2/W+IjlNEThw26\n" +
|
||||
"KqmuBiXjfOMCgYEAxe6lSIRMWq8RES8c+eWNFfmgKFqPUGw2UpEUlCcT3oqtDIOr\n" +
|
||||
"H3hCnvQCxj1h7CbK/jIJ/846EsPrK3wFMrgm3wV//DYPHQevSq39nnRnrv0NRw1a\n" +
|
||||
"iEBpKaRJ7xq7oRSHDGpY5l20iE2UAGvjHq9LUkEGvN35tpLnqKjld4wX+WECgYEA\n" +
|
||||
"urCwGzDZWoOXCpTHMaP/FD0PIjehnraGVwWUcawClhCdKPYdoIYh5pq734ZyB/0R\n" +
|
||||
"jCOVO5NZibduYsSprqZkCqSbvhuicRTssC2QO/QyXc2QYmiKhVIXlC0tdHA1+vyf\n" +
|
||||
"grVyN4uLzeipygxl7c8Wws7LM9ztB3A+bKY3cOiH5AsCgYEA4XOMKmJeucNOrXTY\n" +
|
||||
"3NdHCb8Yx5JgCYqgdq5uIY7MQ8f3+OlXNwdhh/ftjk8DejWzyY7jpqgj2W3qZFu+\n" +
|
||||
"BxGJZfCDzAqUS9OufMY8tOO/PaIABzSkU4gliBAuxovj9sU6oSSa7aYD+34QW2UU\n" +
|
||||
"L83fUdwBuNbwX6vZM45hIASP6C8=\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
|
||||
/**
|
||||
* 支付类型
|
||||
* @author sheng
|
||||
*/
|
||||
public static interface TradeType {
|
||||
/** 扫码支付 */
|
||||
String NATIVE = "NATIVE";
|
||||
/** 公众号支付 */
|
||||
String JSAPI = "JSAPI";
|
||||
/** APP支付 */
|
||||
String APP = "APP";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package club.joylink.rtss.services.pay.wechat.controller;
|
||||
|
||||
import club.joylink.rtss.services.pay.wechat.WechatPayService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/wechatpay")
|
||||
@Slf4j
|
||||
public class PayResultController {
|
||||
|
||||
@Autowired
|
||||
private WechatPayService wechatPayService;
|
||||
|
||||
@RequestMapping(path="/receive", method= {RequestMethod.POST})
|
||||
public String receive(@RequestBody String data) {
|
||||
log.info("支付结果通知:" + data);
|
||||
return this.wechatPayService.receive(data);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package club.joylink.rtss.services.pay.wechat.util;
|
||||
|
||||
import club.joylink.rtss.util.EncryptUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SignUtil {
|
||||
|
||||
public static String sign(Map<String, String> map, String mchKey) {
|
||||
Set<String> keysSet = map.keySet();
|
||||
Object[] keys = keysSet.toArray();
|
||||
// 排序
|
||||
Arrays.sort(keys);
|
||||
StringBuffer temp = new StringBuffer();
|
||||
boolean first = true;
|
||||
for (Object key : keys) {
|
||||
Object value = map.get(key);
|
||||
if(null != value) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
temp.append("&");
|
||||
}
|
||||
temp.append(key).append("=");
|
||||
String valueString = "";
|
||||
if (null != value) {
|
||||
valueString = value.toString();
|
||||
}
|
||||
temp.append(valueString);
|
||||
}
|
||||
}
|
||||
String tempStr = temp.toString()+"&key="+mchKey;
|
||||
System.out.println(tempStr);
|
||||
return EncryptUtil.md5(tempStr).toUpperCase();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package club.joylink.rtss.simulation.cbtc.ATP.ground;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.CI.CiApiService;
|
||||
import club.joylink.rtss.simulation.cbtc.Simulation;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Responder;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
/** TODO
|
||||
* 应答器信号
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ResponderService {
|
||||
|
||||
@Autowired
|
||||
private CiApiService ciApiService;
|
||||
|
||||
/**循环逻辑,列车到达触发电磁信号,交换数据*/
|
||||
public void exchangeData2Train(Simulation simulation){
|
||||
Map<Section,List<Responder>> sectionRespondersMap = simulation.getRepository().getSectionRespondersMap();
|
||||
if(CollectionUtils.isEmpty(sectionRespondersMap)){
|
||||
return;
|
||||
}
|
||||
log.info("列车触发应答器交换数据");
|
||||
List<VirtualRealityTrain> trainList = simulation.getRepository().getOnlineTrainList();
|
||||
trainList.forEach(train -> {
|
||||
//电磁触发以列车头位置(车载应答器)模拟
|
||||
SectionPosition headPosition = train.getHeadPosition();
|
||||
Section section = headPosition.getSection();
|
||||
var responders = sectionRespondersMap.get(section);
|
||||
if(CollectionUtils.isEmpty(responders)) return;
|
||||
// if(responders.f)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**接受LEU移动授权*/
|
||||
public void receiveMA(){
|
||||
|
||||
log.info("应答器接收移动授权信息");
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -32,12 +32,18 @@ public class TempSpeedLimitService {
|
||||
public void setSectionLimitSpeed(Simulation simulation, Section section, int limitSpeed) {
|
||||
if (section.isSwitchTrack()) {
|
||||
this.setSwitchLimitSpeed(simulation, section.getRelSwitch(), limitSpeed);
|
||||
} else if (section.isCross()) {
|
||||
section.setSpeedUpLimit(limitSpeed);
|
||||
} else if (!CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
for (Section logic : section.getLogicList()) {
|
||||
logic.setSpeedUpLimit(limitSpeed);
|
||||
}
|
||||
} else {
|
||||
section.setSpeedUpLimit(limitSpeed);
|
||||
if(section.isSectionOfCross()){
|
||||
section.getParent().setSpeedUpLimit(limitSpeed);
|
||||
}else{
|
||||
section.setSpeedUpLimit(limitSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,8 @@ public class Operation {
|
||||
Section_Confirm_Axis_Valid(),
|
||||
/**区段详情*/
|
||||
Section_Details(),
|
||||
/**强解*/
|
||||
Section_Force_Unlock(),
|
||||
|
||||
//--------------------------- 信号机 ---------------------------
|
||||
/** 封锁 */
|
||||
|
@ -112,4 +112,11 @@ public class SectionOperateHandler {
|
||||
this.atsSectionService.confirmAxleValid(simulation, section);
|
||||
}
|
||||
|
||||
/**强解*/
|
||||
@OperateHandlerMapping(type = Operation.Type.Section_Force_Unlock)
|
||||
public void forceUnlock(Simulation simulation, String sectionCode) {
|
||||
Section section = simulation.getRepository().getByCode(sectionCode, Section.class);
|
||||
this.atsSectionService.forceUnlock(simulation, section);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,4 +50,12 @@ public class AtsSectionService {
|
||||
}
|
||||
section.confirmValid();
|
||||
}
|
||||
|
||||
public void forceUnlock(Simulation simulation, Section section) {
|
||||
if (Objects.nonNull(section.getParent())) {
|
||||
section = section.getParent();
|
||||
}
|
||||
log.debug("仿真[{}] : 区段/岔心[{}]强解",simulation.getGroup(),String.format("%s(%s)", section.getName(), section.getCode()));
|
||||
section.forceUnlocking();
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class SectionService {
|
||||
}
|
||||
if(!section.isBlockade()) {
|
||||
section.setBlockade(true);
|
||||
if (!CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
if (!section.isCross() && !CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
section.getLogicList().forEach(logic -> logic.setBlockade(true));
|
||||
}
|
||||
}
|
||||
@ -48,7 +48,7 @@ public class SectionService {
|
||||
public void unblock(Section section) {
|
||||
if(section.isBlockade()) {
|
||||
section.setBlockade(false);
|
||||
if (!CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
if (!section.isCross() && !CollectionUtils.isEmpty(section.getLogicList())) {
|
||||
section.getLogicList().forEach(logic -> logic.setBlockade(false));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.build;
|
||||
|
||||
import club.joylink.rtss.constants.BusinessConsts;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.StationTurnBackStrategyOption;
|
||||
@ -51,6 +52,7 @@ public class MapDeviceBuilder {
|
||||
section.setRoadType(sectionVO.getRoadType());
|
||||
section.setPhysical(isPhysicalSection(sectionVO.getType()));
|
||||
section.setAxleCounter(isAxleCounterSection(sectionVO.getType()));
|
||||
section.setCross(isCross(sectionVO.getType()));
|
||||
// 计轴区段和道岔区段,校验实际长度
|
||||
if (isPhysicalSection(sectionVO.getType()) &&
|
||||
(Objects.isNull(sectionVO.getLengthFact()) ||
|
||||
@ -61,7 +63,7 @@ public class MapDeviceBuilder {
|
||||
} else if (isPhysicalSection(sectionVO.getType())) {
|
||||
section.setLen(sectionVO.getLengthFact());
|
||||
}
|
||||
if (Objects.equals(sectionVO.getType(), "02")) { // 逻辑区段
|
||||
if (Objects.equals(sectionVO.getType(), BusinessConsts.Section.SectionType.Type02)) { // 逻辑区段
|
||||
Float startOffset = sectionVO.getLogicSectionStartOffset();
|
||||
Float endOffset = sectionVO.getLogicSectionEndOffset();
|
||||
section.setLen(sectionVO.getLengthFact());
|
||||
@ -197,8 +199,8 @@ public class MapDeviceBuilder {
|
||||
// 区段关系
|
||||
sectionList.forEach(sectionVO -> {
|
||||
Section section = (Section) elementMap.get(sectionVO.getCode());
|
||||
if (Objects.equals("02", sectionVO.getType()) ||
|
||||
Objects.equals("03", sectionVO.getType())) { // 逻辑区段/道岔区段
|
||||
if (Objects.equals(BusinessConsts.Section.SectionType.Type02, sectionVO.getType()) ||
|
||||
Objects.equals(BusinessConsts.Section.SectionType.Type03, sectionVO.getType())) { // 逻辑区段/道岔区段
|
||||
Section parent = (Section) elementMap.get(sectionVO.getParentCode());
|
||||
if (Objects.isNull(parent)) {
|
||||
errMsgList.add(String.format("逻辑区段/道岔区段[%s(%s)]没用关联(道岔)计轴区段或关联的(道岔)计轴区段不存在",
|
||||
@ -228,6 +230,39 @@ public class MapDeviceBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Objects.equals(BusinessConsts.Section.SectionType.Type01, sectionVO.getType())){
|
||||
Section parent = (Section) elementMap.get(sectionVO.getParentCode());//所属岔心
|
||||
if (Objects.nonNull(parent)) {
|
||||
if(!parent.isCross()){
|
||||
errMsgList.add(String.format("物理区段[%s(%s)]关联父区段[%s(%s)]不是岔心",
|
||||
section.getName(), section.getCode(),parent.getName(),parent.getCode()));
|
||||
}else{
|
||||
parent.addLogicSection(section);
|
||||
section.setParent(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (section.isCross()) {
|
||||
List<String> relateSectionList = sectionVO.getRelateSectionList();
|
||||
if (CollectionUtils.isEmpty(relateSectionList)) {
|
||||
errMsgList.add(String.format("岔心[%s(%s)]没有关联物理区段",
|
||||
section.getName(), section.getCode()));
|
||||
} else if (relateSectionList.size() != 2) {
|
||||
errMsgList.add(String.format("岔心[%s(%s)]必须关联2个物理区段",
|
||||
section.getName(), section.getCode()));
|
||||
} else {
|
||||
relateSectionList.forEach(s -> {
|
||||
Section physicalSectionOfCross = (Section) elementMap.get(s);
|
||||
if (Objects.isNull(physicalSectionOfCross)) {
|
||||
errMsgList.add(String.format("岔心[%s(%s)]关联的物理区段[(%s)]不存在",
|
||||
section.getName(), section.getCode(), s));
|
||||
} else if (!physicalSectionOfCross.isAxleCounterSection()) {
|
||||
errMsgList.add(String.format("岔心[%s(%s)]关联的区段[%s(%s)]不是一般计轴物理区段",
|
||||
section.getName(), section.getCode(), physicalSectionOfCross.getName(), s));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// 计轴区段下的逻辑区段排序
|
||||
List<Section> physicalSectionList = elementMap.values().stream()
|
||||
@ -348,6 +383,28 @@ public class MapDeviceBuilder {
|
||||
errMsgList.add(String.format("道岔区段[%s(%s)]有问题",
|
||||
section.getName(), section.getCode()));
|
||||
}
|
||||
if (section.isAxleCounterSection()) {
|
||||
Section leftSection = section.getLeftSection();
|
||||
if (Objects.nonNull(leftSection)) {
|
||||
if (!leftSection.isSwitchTrack()) {
|
||||
errMsgList.add(String.format("岔心关联的计轴区段[%s(%s)]的左向区段[%s(%s)]不是道岔区段",
|
||||
section.getName(), section.getCode(), section.getLeftSection().getName(), section.getLeftSection().getCode()));
|
||||
} else if (!leftSection.getRelSwitch().isC(leftSection)) {
|
||||
errMsgList.add(String.format("岔心关联的计轴区段[%s(%s)]的左向区段[%s(%s)]不是道岔的C位区段",
|
||||
section.getName(), section.getCode(), section.getLeftSection().getName(), section.getLeftSection().getCode()));
|
||||
}
|
||||
}
|
||||
Section rightSection = section.getRightSection();
|
||||
if (Objects.nonNull(rightSection)) {
|
||||
if (!rightSection.isSwitchTrack()) {
|
||||
errMsgList.add(String.format("岔心关联的计轴区段[%s(%s)]的右向区段[%s(%s)]不是道岔区段",
|
||||
section.getName(), section.getCode(), section.getRightSection().getName(), section.getRightSection().getCode()));
|
||||
} else if (!rightSection.getRelSwitch().isC(rightSection)) {
|
||||
errMsgList.add(String.format("岔心关联的计轴区段[%s(%s)]的右向区段[%s(%s)]不是道岔的C位区段",
|
||||
section.getName(), section.getCode(), section.getRightSection().getName(), section.getRightSection().getCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// 站台
|
||||
List<MapStationStandNewVO> standList = graphData.getStationStandList();
|
||||
@ -867,6 +924,53 @@ public class MapDeviceBuilder {
|
||||
}
|
||||
// 接触网
|
||||
buildCatenary(graphData, elementMap, errMsgList, mapDataBuildResult.getCatenaryMap());
|
||||
//应答器
|
||||
buildResponderDataRef(graphData, elementMap, errMsgList);
|
||||
}
|
||||
|
||||
/**应答器数据验证及关系构建*/
|
||||
private static void buildResponderDataRef(MapGraphDataNewVO graphData, Map<String, MapElement> elementMap, List<String> errMsgList) {
|
||||
List<MapResponderVO> responderList = graphData.getResponderList();
|
||||
responderList.forEach(responderVO -> {
|
||||
Responder responder = new Responder(responderVO.getCode(), responderVO.getName());
|
||||
if (Objects.nonNull(elementMap.get(responder.getCode()))) {
|
||||
errMsgList.add(String.format("编码为[%s]的应答器不唯一", responderVO.getCode()));
|
||||
}
|
||||
elementMap.put(responder.getCode(), responder);
|
||||
|
||||
if (Objects.isNull(responderVO.getType())) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]类型未设置", responderVO.getName(), responderVO.getCode()));
|
||||
} else {
|
||||
responder.setType(responderVO.getType());
|
||||
}
|
||||
|
||||
Station deviceStation = (Station) elementMap.get(responderVO.getStationCode());
|
||||
if (Objects.isNull(deviceStation)) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]未设置所属设备集中站或所属设备集中站[(%s)]不存在", responderVO.getName(), responderVO.getCode(), responderVO.getStationCode()));
|
||||
} else if (!deviceStation.isCentralized()) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]所属车站[(%s)]不是设备集中站", responderVO.getName(), responderVO.getCode(), responderVO.getStationCode()));
|
||||
} else {
|
||||
responder.setDeviceStation(deviceStation);
|
||||
}
|
||||
|
||||
// 关联一般计轴区段及偏移量
|
||||
Section section = (Section) elementMap.get(responderVO.getSectionCode());
|
||||
if (Objects.isNull(section)) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]未关联区段或关联区段[(%s)]不存在", responderVO.getName(), responderVO.getCode(), responderVO.getSectionCode()));
|
||||
} else if (!section.isPhysical()) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]关联区段[(%s)]不是物理区段", responderVO.getName(), responderVO.getCode(), responderVO.getSectionCode()));
|
||||
} else {
|
||||
responder.setPhysicalSection(section);
|
||||
}
|
||||
if (Objects.isNull(responderVO.getOffset()) ||
|
||||
(Objects.nonNull(section) && Objects.nonNull(section.getLen()) &&
|
||||
(responderVO.getOffset() < 0 || responderVO.getOffset() > section.getLen()))) {
|
||||
errMsgList.add(String.format("应答器[%s(%s)]的区段偏移量未设置或数据异常[%s]",
|
||||
responderVO.getName(), responderVO.getCode(), responderVO.getOffset()));
|
||||
} else {
|
||||
responder.setSectionOffset(responderVO.getOffset());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1048,10 +1152,14 @@ public class MapDeviceBuilder {
|
||||
}
|
||||
|
||||
private static boolean isPhysicalSection(String type) {
|
||||
return Objects.equals(type, "01") || Objects.equals(type, "03");
|
||||
return Objects.equals(type, BusinessConsts.Section.SectionType.Type01) || Objects.equals(type, BusinessConsts.Section.SectionType.Type03);
|
||||
}
|
||||
|
||||
private static boolean isAxleCounterSection(String type) {
|
||||
return Objects.equals(type, "01") || Objects.equals(type, "04");
|
||||
return Objects.equals(type, BusinessConsts.Section.SectionType.Type01) || Objects.equals(type, BusinessConsts.Section.SectionType.Type04);
|
||||
}
|
||||
|
||||
private static boolean isCross(String type) {
|
||||
return Objects.equals(type, BusinessConsts.Section.SectionType.Type05);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import java.time.LocalTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -181,6 +182,9 @@ public class SimulationDataRepository {
|
||||
*/
|
||||
private final Map<String, Set<Catenary>> catenaryMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
private Map<Section,List<Responder>> sectionRespondersMap = new HashMap<>();
|
||||
|
||||
public Set<Catenary> findCatenaries(String sectionCode) {
|
||||
return this.catenaryMap.get(sectionCode);
|
||||
}
|
||||
@ -319,6 +323,22 @@ public class SimulationDataRepository {
|
||||
return getListByType(MapElement.DeviceType.STATION, Station.class);
|
||||
}
|
||||
|
||||
public List<Responder> getResponderList() {
|
||||
return getListByType(MapElement.DeviceType.RESPONDER, Responder.class);
|
||||
}
|
||||
|
||||
public boolean hasResponder() {
|
||||
return !CollectionUtils.isEmpty(getListByType(MapElement.DeviceType.RESPONDER, Responder.class));
|
||||
}
|
||||
|
||||
public Map<Section,List<Responder>> getSectionRespondersMap() {
|
||||
if(hasResponder() && CollectionUtils.isEmpty(sectionRespondersMap)){
|
||||
sectionRespondersMap = getListByType(MapElement.DeviceType.RESPONDER, Responder.class).stream().collect(Collectors.groupingBy(Responder::getPhysicalSection));
|
||||
return sectionRespondersMap;
|
||||
}
|
||||
return sectionRespondersMap;
|
||||
}
|
||||
|
||||
public Station findStationByName(String stationName) {
|
||||
List<Station> stationList = this.getStationList();
|
||||
List<Station> matchList = new ArrayList<>(1);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package club.joylink.rtss.simulation.cbtc.data.map;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -12,25 +13,54 @@ public class Responder extends MapNamedElement {
|
||||
|
||||
public Responder(String code, String name) {
|
||||
super(code, name, DeviceType.RESPONDER);
|
||||
|
||||
}
|
||||
|
||||
// ------------------固有属性/关联关系---------------------
|
||||
/**应答器类型*/
|
||||
private Responder.ResponderType type;
|
||||
|
||||
/**
|
||||
* 所属设备集中站
|
||||
*/
|
||||
/** 所属设备集中站*/
|
||||
private Station deviceStation;
|
||||
|
||||
/** 物理区段*/
|
||||
private Section physicalSection;
|
||||
|
||||
/** 在区段上的偏移量*/
|
||||
private float sectionOffset;
|
||||
|
||||
|
||||
// ------------------状态属性---------------------
|
||||
|
||||
/**坡度*/
|
||||
/**弯度*/
|
||||
/**限速*/
|
||||
/**移动授权位置*/
|
||||
private MovementAuthority ma;
|
||||
/**其它警示信息:升降弓/进出隧道/鸣笛/...*/
|
||||
|
||||
|
||||
|
||||
// ------------------操作---------------------
|
||||
/***LEU状态数据同步给应答器*/
|
||||
|
||||
|
||||
/**推送数据给列车*/
|
||||
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
|
||||
public boolean isFB(){
|
||||
return ResponderType.FB == type;
|
||||
}
|
||||
public boolean isVB(){
|
||||
return ResponderType.VB == type;
|
||||
}
|
||||
public boolean isIB(){
|
||||
return ResponderType.IB == type;
|
||||
}
|
||||
|
||||
public enum ResponderType {
|
||||
/** 固定应答器*/
|
||||
|
@ -408,8 +408,6 @@ public class Route extends MapNamedElement {
|
||||
}
|
||||
|
||||
public synchronized void startSetting(LocalDateTime systemTime) {
|
||||
if (getCode().equals("Route533"))
|
||||
System.out.println();
|
||||
this.setSetting(true);
|
||||
this.settingStartTime = systemTime;
|
||||
this.requisition = false;
|
||||
|
@ -58,6 +58,9 @@ public class Section extends MayOutOfOrderDevice {
|
||||
*/
|
||||
private boolean physical;
|
||||
|
||||
/**是否岔心*/
|
||||
private boolean cross;
|
||||
|
||||
/**
|
||||
* 是否计轴区段(区段两端有计轴器,道岔计轴区段和一般计轴区段)
|
||||
*/
|
||||
@ -446,7 +449,23 @@ public class Section extends MayOutOfOrderDevice {
|
||||
!CollectionUtils.isEmpty(this.logicList) &&
|
||||
this.logicList.get(0).isSwitchTrack();
|
||||
}
|
||||
/**
|
||||
* 一般计轴区段
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAxleCounterSection() {
|
||||
return this.physical && this.axleCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一般计轴区段
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isSectionOfCross() {
|
||||
return this.physical && this.axleCounter && Objects.nonNull(parent) && parent.isCross();
|
||||
}
|
||||
/**
|
||||
* 是否通信车占用
|
||||
*
|
||||
@ -543,6 +562,15 @@ public class Section extends MayOutOfOrderDevice {
|
||||
}
|
||||
}
|
||||
|
||||
public void forceUnlocking() {
|
||||
this.routeLock = false;
|
||||
this.overlapLock = false;
|
||||
this.lockRight = false;
|
||||
if (!isCross() && !CollectionUtils.isEmpty(this.logicList)) {
|
||||
this.logicList.forEach(logic -> logic.forceUnlocking());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 进路延续保护(连同逻辑区段)
|
||||
*/
|
||||
|
@ -0,0 +1,119 @@
|
||||
package club.joylink.rtss.simulation.cbtc.data.support;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public final class FixedQueue<E> implements Queue<E> {
|
||||
|
||||
private final int limit;
|
||||
|
||||
private final Queue<E> queue = new LinkedList<>();
|
||||
|
||||
public FixedQueue(int limit){
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(E e){
|
||||
if(queue.size() >= limit){
|
||||
//如果超出长度,入队时,先出队
|
||||
queue.poll();
|
||||
}
|
||||
return queue.offer(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E poll() {
|
||||
return queue.poll();
|
||||
}
|
||||
|
||||
public Queue<E> getQueue(){
|
||||
return queue;
|
||||
}
|
||||
|
||||
public int getLimit(){
|
||||
return limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
return queue.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E element() {
|
||||
return queue.element();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E peek() {
|
||||
return queue.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return queue.size() == 0 ? true : false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove() {
|
||||
return queue.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
return queue.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return queue.contains(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return queue.containsAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return queue.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return queue.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return queue.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return queue.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
return queue.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return queue.toArray(a);
|
||||
}
|
||||
}
|
@ -2,11 +2,9 @@ package club.joylink.rtss.simulation.cbtc.data.vr;
|
||||
|
||||
import club.joylink.rtss.simulation.cbtc.constant.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.CalculateService;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Section;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Signal;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.Station;
|
||||
import club.joylink.rtss.simulation.cbtc.data.map.*;
|
||||
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.FixedQueue;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.MovementAuthority;
|
||||
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
|
||||
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
|
||||
@ -16,6 +14,7 @@ import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* 虚拟真实列车
|
||||
@ -358,6 +357,11 @@ public class VirtualRealityTrain extends VirtualRealityDevice {
|
||||
*/
|
||||
private VirtualRealityTrain linkTrain;
|
||||
|
||||
|
||||
|
||||
/**最近经过的两个应答器*/
|
||||
private Queue<Responder> lastTwoPassedResponders = new FixedQueue<>(2);
|
||||
|
||||
public void setAtpOn(boolean on) {
|
||||
this.atpOn = on;
|
||||
if (!on) { //如果是关闭ATP,取消信号EB
|
||||
|
@ -159,29 +159,21 @@ public class MapSectionNewVO {
|
||||
@ApiModelProperty(value = "区段路线类型")
|
||||
private Section.SectionRoadType roadType;
|
||||
|
||||
// /**
|
||||
// * 逻辑区段列表
|
||||
// */
|
||||
// @JsonIgnore
|
||||
// @ApiModelProperty(value = "逻辑区段列表")
|
||||
// List<MapSectionNewVO> logicList;
|
||||
|
||||
/**
|
||||
* 道岔计轴区段关联道岔区段列表
|
||||
*/
|
||||
@ApiModelProperty(value = "道岔计轴区段关联道岔区段列表")
|
||||
List<String> relevanceSectionList;
|
||||
/**
|
||||
* 岔心关联道岔区段列表
|
||||
* 岔心关联计轴区段列表
|
||||
*/
|
||||
@ApiModelProperty(value = "岔心关联道岔区段列表")
|
||||
@ApiModelProperty(value = "岔心关联计轴区段列表")
|
||||
List<String> relateSectionList;
|
||||
|
||||
/**
|
||||
* 是否站台轨
|
||||
*/
|
||||
@ApiModelProperty(value = "是否站台轨")
|
||||
// @JsonProperty("isStandTrack")
|
||||
private boolean standTrack;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +31,7 @@ public class OrderDetailVO {
|
||||
|
||||
private Integer monthAmount;
|
||||
|
||||
private Float price;
|
||||
private Long price;
|
||||
|
||||
public OrderDetailVO(SaleOrderDetail detail) {
|
||||
id = detail.getId();
|
||||
@ -41,7 +41,7 @@ public class OrderDetailVO {
|
||||
startTime = detail.getStartTime();
|
||||
goodsAmount = detail.getGoodsAmount();
|
||||
monthAmount = detail.getMonthAmount();
|
||||
price = (float) detail.getPrice() / 100;
|
||||
price = detail.getPrice();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user