parent
0dd31e262d
commit
2995ed21bc
17 changed files with 1145 additions and 208 deletions
@ -0,0 +1,82 @@ |
|||||||
|
package com.ynxbd.common.bean.xk; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField; |
||||||
|
import lombok.Getter; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import lombok.Setter; |
||||||
|
import lombok.ToString; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
@Setter |
||||||
|
@Getter |
||||||
|
@ToString |
||||||
|
@NoArgsConstructor |
||||||
|
public class HisRxItem implements Serializable { |
||||||
|
private static final long serialVersionUID = 2026082712724000001L; |
||||||
|
|
||||||
|
// 项目编码
|
||||||
|
@JSONField(ordinal = 1) |
||||||
|
private String xmCode; |
||||||
|
// 项目名称
|
||||||
|
@JSONField(ordinal = 2) |
||||||
|
private String xmName; |
||||||
|
// 科目编码
|
||||||
|
@JSONField(ordinal = 3) |
||||||
|
private String kmCode; |
||||||
|
// 科目名称
|
||||||
|
@JSONField(ordinal = 4) |
||||||
|
private String kmName; |
||||||
|
// 项目单位
|
||||||
|
@JSONField(ordinal = 5) |
||||||
|
private String xmUnit; |
||||||
|
// 项目单价
|
||||||
|
@JSONField(ordinal = 6) |
||||||
|
private String xmPrice; |
||||||
|
// 项目数量
|
||||||
|
@JSONField(ordinal = 7) |
||||||
|
private String xmCount; |
||||||
|
// 项目金额
|
||||||
|
@JSONField(ordinal = 8) |
||||||
|
private String xmMoney; |
||||||
|
// 项目标识
|
||||||
|
@JSONField(ordinal = 9) |
||||||
|
private Integer xmFlag; |
||||||
|
// 药品剂量
|
||||||
|
@JSONField(ordinal = 10) |
||||||
|
private String ypJl; |
||||||
|
// 药品剂量单位
|
||||||
|
@JSONField(ordinal = 11) |
||||||
|
private String ypJlUnit; |
||||||
|
// 用法频次 qd/bid等
|
||||||
|
@JSONField(ordinal = 12) |
||||||
|
private String yzUsedMethod; |
||||||
|
// 每日次数
|
||||||
|
@JSONField(ordinal = 13) |
||||||
|
private String yzCountForDay; |
||||||
|
// 每周次数
|
||||||
|
@JSONField(ordinal = 14) |
||||||
|
private String yzCountForWeek; |
||||||
|
// 用药途径:口服
|
||||||
|
@JSONField(ordinal = 15) |
||||||
|
private String ypPath; |
||||||
|
// 药房编码
|
||||||
|
@JSONField(ordinal = 16) |
||||||
|
private String yfCode; |
||||||
|
// 药房名称
|
||||||
|
@JSONField(ordinal = 17) |
||||||
|
private String yfName; |
||||||
|
// 医保类别编码
|
||||||
|
@JSONField(ordinal = 18) |
||||||
|
private String yblb; |
||||||
|
// 医保类别名称
|
||||||
|
@JSONField(ordinal = 19) |
||||||
|
private String yblbName; |
||||||
|
// 总数量
|
||||||
|
@JSONField(ordinal = 20) |
||||||
|
private String totCount; |
||||||
|
// 备注
|
||||||
|
@JSONField(ordinal = 21) |
||||||
|
private String note; |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
package com.ynxbd.jy.bean; |
||||||
|
|
||||||
|
import lombok.Getter; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import lombok.Setter; |
||||||
|
import lombok.ToString; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.apache.commons.lang3.ObjectUtils; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
@ToString |
||||||
|
@NoArgsConstructor |
||||||
|
public class JYPayNotify { |
||||||
|
// 交易代码 M 支付:001;
|
||||||
|
private String tradeCode; |
||||||
|
// 应用编号 M 第三方应用接入唯一编号,由后台设置
|
||||||
|
private String applicationId; |
||||||
|
// 应用商户编号 M 应用商户唯一编号,请按照商户规则使用正确的商户号
|
||||||
|
private String merchantId; |
||||||
|
// 返回码 M 0000为成功,其他为失败
|
||||||
|
private String respCode; |
||||||
|
// 商户订单号 M 由商户端(应用方、接入方)生成的订单号,如:00000100005115 (不大于64位长度),不许有重复。
|
||||||
|
private String merOrderNum; |
||||||
|
// 支付平台订单号 M 如:00000100005115
|
||||||
|
private String orderId; |
||||||
|
// 支付平台流水号 M 如:00000100005115
|
||||||
|
private String orderTransId; |
||||||
|
// 支付网关订单号 F 第三方支付平台(微信/支付宝/银行等)记录的商户订单号
|
||||||
|
private String threeTradeNo; |
||||||
|
// 支付网关流水号 F 第三方支付平台(微信/支付宝/银行等)记录的商户流水号
|
||||||
|
private String threeTransNo; |
||||||
|
// 银行流水号 F 第三方支付平台(微信/支付宝/银行等)的原始流水号
|
||||||
|
private String finalTransNo; |
||||||
|
// 订单金额 M 精确到分,例如100
|
||||||
|
private Long orderAmt; |
||||||
|
// 交易时间 M YYYYMMDDHHMMSS(商户订单提交时间) | 退款交易时间
|
||||||
|
private String tranDateTime; |
||||||
|
// 支付时间 M YYYYMMDDHHMMSS(订单支付时间)
|
||||||
|
private String paymentTime; |
||||||
|
// 订单类型 M 如:挂号费、医疗费、药品费,详见字典#_数据字典
|
||||||
|
private String orderType; |
||||||
|
// 订单状态 M 02:已支付04:已冲正06:已退款,详见字典#订单状态
|
||||||
|
private String orderStatus; |
||||||
|
// 微信公众号用户标识 F 微信公众号用户标识,只有微信公众平台支付方式会返回,比如微信扫码支付
|
||||||
|
private String openId; |
||||||
|
// 商户ID F 应用方对账可能需要
|
||||||
|
private String appId; |
||||||
|
// 商户号 F 应用方对账可能需要
|
||||||
|
private String merchantNo; |
||||||
|
// 数字签名 M 本平台生成的签名,供接入方验证签名 生成签名规则参考#_加签验签规则说明
|
||||||
|
private String signValue; |
||||||
|
|
||||||
|
// 退款====================================================
|
||||||
|
// 商户退款流水号,由应用端(应用方、接入方)生成,要求唯一。对应入参
|
||||||
|
private String refundTransId; |
||||||
|
// 退款金额,精确到分,例如100
|
||||||
|
private Long refundAmt; |
||||||
|
// 交易状态,退款交易状态,详见数据字典#交易流水状态
|
||||||
|
private String tranStatus; |
||||||
|
// 交易代码,002 撤销 004 退费 005 冲正,详细请参考数据字典#交易代码
|
||||||
|
private String tranCode; |
||||||
|
// 支付方式,如:UPOP_APP, UPOP_WEB
|
||||||
|
private String payType; |
||||||
|
|
||||||
|
// 是否为退费订单
|
||||||
|
public boolean isRefundOrder() { |
||||||
|
return !ObjectUtils.isEmpty(refundTransId); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,569 @@ |
|||||||
|
package com.ynxbd.jy.bean; |
||||||
|
|
||||||
|
import com.ynxbd.jy.helper.JYPayConfig; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.security.KeyFactory; |
||||||
|
import java.security.PrivateKey; |
||||||
|
import java.security.PublicKey; |
||||||
|
import java.security.Signature; |
||||||
|
import java.security.spec.PKCS8EncodedKeySpec; |
||||||
|
import java.security.spec.X509EncodedKeySpec; |
||||||
|
import java.util.*; |
||||||
|
import java.util.Map.Entry; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class JYPayRSAUtil { |
||||||
|
|
||||||
|
// public static void main(String[] args) {
|
||||||
|
// Map<String, String> packageParams = new HashMap<>();
|
||||||
|
// packageParams.put("mch_id", "sddda");
|
||||||
|
// packageParams.put("appid", "sss");
|
||||||
|
// packageParams.put("xingming", "张三");
|
||||||
|
// packageParams.put("b", "b");
|
||||||
|
// String signValue = createSign(packageParams, "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAPupORdqoiZrdkwUlwjcrVjlvgbVCJsznugvQXIdx2yVNTrSJOZUMF2ALOUqEwEVG/V126JVF+aBJ4y52oiCfqGicSPqsvxeQ1iErKnu1KKMQ9flw9EIvb2LUicLtcG8ah6cfj4elij7XWk1QDpXyPy9KMBZ0G10sHHWs+mTgRTNAgMBAAECgYBWMD2STH3eJJ2uLrsPWOyxbnVnR5yb8tDwegay+4nqISvKyl/C1oB99UDq9z7s9vrNVSD0dqop0n/mDVzPtcmCCg/ue4lV3kj4rCDWVCc1Ooyjcu1JKCruOgrCdL72EwUeriBtXs+alGmU0KMrzpvUnSpKb6rcwMkwcvpsCii8TQJBAP/FVxmY4Z9HZz2GJuudHyokwTUUnCFJ198G5ttLhLAo0m5wCSKo8Aw8k0MZHwB9pHbHPrEjHatu+T9Re1jthXsCQQD74vCxlCyz7xPQKSoAv0JOLKlQmy1nycb7D8O5jUdY7t9PYbDS8kg0wgprvLuJNaj+KU3PKu3FGtCJ2PJSkKhXAkBKw4+bTuIc4g1eoZk85DfY5NeJQZYF8QTmD6lpzuBhcf1ZBOzWsdVBbm+JfI1gYlmx0roTo3UnyI+ZH6NTslKDAkBdD5JnuVvuupSyYpL/JaqEoWGIw1w6LUVTupZQdo72n4JnnKsstJDS1SHufhM3dVjTVkVGFhE0slx7oWid8o4PAkEAr9L1uUWyhXbcVo50dHC9e2OiDSmUPVZvzVj2AKJU1dz3lI+ZLLLdzCgdRNngT5CPz8DRttXCGLjiQ52P4g3atQ==");
|
||||||
|
// System.out.println(signValue);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception { |
||||||
|
Map<String, String> packageParams = new HashMap<>(); |
||||||
|
packageParams.put("appId", "wx2a6376841d35ad5c"); |
||||||
|
packageParams.put("applicationId", "30007"); |
||||||
|
packageParams.put("finalTransNo", "4500000373202608316223118562"); |
||||||
|
packageParams.put("merOrderNum", "JYba651f16d83a48a44167f975f022"); |
||||||
|
packageParams.put("merchantId", "20007"); |
||||||
|
packageParams.put("merchantNo", "1112699888"); |
||||||
|
packageParams.put("openId", "oiext28gL8UzoST4jQxcqcGTjc1g"); |
||||||
|
packageParams.put("orderAmt", "1"); |
||||||
|
packageParams.put("orderId", "IIPS7432026083116014812802354822"); |
||||||
|
packageParams.put("orderTransId", "SN3752026083116014813302421029"); |
||||||
|
packageParams.put("orderType", "001"); |
||||||
|
packageParams.put("payType", "WX_PUBLIC"); |
||||||
|
packageParams.put("paymentTime", "20260831160155"); |
||||||
|
packageParams.put("refundOrder", "false"); |
||||||
|
packageParams.put("respCode", "0000"); |
||||||
|
packageParams.put("signValue", "LGi1a/qL1YsYf7lvNwnDsCQ5fyhlqLb3olM/YHqREH1BTxQa7XRW2mttBHGpendKYn4jK1dOvlYs7q96+KJJ/IvVz3GAIcFsg888qJAgG4/OdCajowuOxSQN/em02tsGq6lSERhccNkVCmbY/0aL2JgAAQXzKwnXZlodmqLCUXw="); |
||||||
|
packageParams.put("threeTradeNo", "4500000373202608316223118562"); |
||||||
|
packageParams.put("threeTransNo", "4500000373202608316223118562"); |
||||||
|
packageParams.put("tranDateTime", "20260831160148"); |
||||||
|
|
||||||
|
// String stringA = "applicationId=2017051721001004270219620138&backURL=http://xian.kyee.com.cn:8621/qy_iips_pay/notify/payNotify&merOrderNum=MER000000000000000004&merchantId=12312312312&orderAmt=1&orderType=001&payType=WX_CODE";
|
||||||
|
// String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAPupORdqoiZrdkwUlwjcrVjlvgbVCJsznugvQXIdx2yVNTrSJOZUMF2ALOUqEwEVG/V126JVF+aBJ4y52oiCfqGicSPqsvxeQ1iErKnu1KKMQ9flw9EIvb2LUicLtcG8ah6cfj4elij7XWk1QDpXyPy9KMBZ0G10sHHWs+mTgRTNAgMBAAECgYBWMD2STH3eJJ2uLrsPWOyxbnVnR5yb8tDwegay+4nqISvKyl/C1oB99UDq9z7s9vrNVSD0dqop0n/mDVzPtcmCCg/ue4lV3kj4rCDWVCc1Ooyjcu1JKCruOgrCdL72EwUeriBtXs+alGmU0KMrzpvUnSpKb6rcwMkwcvpsCii8TQJBAP/FVxmY4Z9HZz2GJuudHyokwTUUnCFJ198G5ttLhLAo0m5wCSKo8Aw8k0MZHwB9pHbHPrEjHatu+T9Re1jthXsCQQD74vCxlCyz7xPQKSoAv0JOLKlQmy1nycb7D8O5jUdY7t9PYbDS8kg0wgprvLuJNaj+KU3PKu3FGtCJ2PJSkKhXAkBKw4+bTuIc4g1eoZk85DfY5NeJQZYF8QTmD6lpzuBhcf1ZBOzWsdVBbm+JfI1gYlmx0roTo3UnyI+ZH6NTslKDAkBdD5JnuVvuupSyYpL/JaqEoWGIw1w6LUVTupZQdo72n4JnnKsstJDS1SHufhM3dVjTVkVGFhE0slx7oWid8o4PAkEAr9L1uUWyhXbcVo50dHC9e2OiDSmUPVZvzVj2AKJU1dz3lI+ZLLLdzCgdRNngT5CPz8DRttXCGLjiQ52P4g3atQ==";
|
||||||
|
// String signValue = createSign(packageParams, JYPayConfig.PRIVATE_KEY);
|
||||||
|
|
||||||
|
String signValue = createSign(packageParams, JYPayConfig.PRIVATE_KEY); |
||||||
|
System.out.println("======="); |
||||||
|
System.out.println(signValue); |
||||||
|
} |
||||||
|
|
||||||
|
public static String createSign(Map<String, String> packageParams, String privateKey) { |
||||||
|
String sourceJson = getSignString(packageParams, false); |
||||||
|
System.out.println("RSA加密前的Json:" + sourceJson); |
||||||
|
String sign = ""; |
||||||
|
try { |
||||||
|
sign = JYPayRSAUtil.sign(sourceJson, privateKey); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("生成签名异常"); |
||||||
|
} |
||||||
|
return sign; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 从map得到一个key1=value1&key2=value2的格式字符串(主要用于签名运算), 1.排除map中value为空的entry |
||||||
|
* 2.排除签名字段 3.key按字典顺序 |
||||||
|
* |
||||||
|
* @param map map |
||||||
|
* @param isSortedMap 是否是有序的map |
||||||
|
* @return sign |
||||||
|
*/ |
||||||
|
public static <V> String getSignString(Map<String, V> map, boolean isSortedMap) { |
||||||
|
if (map == null || map.isEmpty()) { |
||||||
|
throw new IllegalArgumentException("map must be not empty"); |
||||||
|
} |
||||||
|
|
||||||
|
SortedMap<String, V> sortedMap; |
||||||
|
if (isSortedMap && map instanceof SortedMap) { |
||||||
|
sortedMap = (SortedMap<String, V>) map; |
||||||
|
} else { |
||||||
|
sortedMap = getNewTreeMap(true); |
||||||
|
sortedMap.putAll(map); |
||||||
|
} |
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (Entry<String, V> e : sortedMap.entrySet()) { |
||||||
|
String k = e.getKey(); |
||||||
|
String v; |
||||||
|
if (e.getValue() instanceof String[]) { |
||||||
|
v = String.valueOf(((String[]) e.getValue())[0]); |
||||||
|
} else { |
||||||
|
v = String.valueOf(e.getValue()); |
||||||
|
} |
||||||
|
|
||||||
|
if (null != v && !"".equals(v) && !"signValue".equals(k) && !"privateKey".equals(k)) { |
||||||
|
sb.append("&").append(k).append("=").append(v); |
||||||
|
} |
||||||
|
} |
||||||
|
sb = sb.length() > 0 ? sb.deleteCharAt(0) : sb; |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:获取一个key按指定顺序排序的TreeMap<K,V> |
||||||
|
* @param flag:true按key升序排列的TreeMap<K,V>;false按key降序排列的TreeMap<K,V> |
||||||
|
* @return 返回按key指定顺序排列的TreeMap<K,V> |
||||||
|
* returnType:TreeMap<K,V> |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
public static <K extends Comparable<K>, V> TreeMap<K, V> getNewTreeMap(boolean flag) { |
||||||
|
TreeMap<K, V> treeMap; |
||||||
|
if (flag) { |
||||||
|
treeMap = new TreeMap<>(Comparable::compareTo); |
||||||
|
} else { |
||||||
|
treeMap = new TreeMap<>(Comparator.reverseOrder()); |
||||||
|
} |
||||||
|
return treeMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 加密解密使用的算法名称 |
||||||
|
*/ |
||||||
|
public static final String KEY_ALGORITHM = "RSA"; |
||||||
|
|
||||||
|
/** |
||||||
|
* 数字签名使用的算法名称(MD2withRSA、MD5withRSA或SHA1withRSA、SHA256WithRSA) |
||||||
|
*/ |
||||||
|
public static final String SIGNATURE_ALGORITHM = "SHA256WithRSA"; |
||||||
|
|
||||||
|
/** |
||||||
|
* RSA最大加密明文大小 |
||||||
|
*/ |
||||||
|
private static final int MAX_ENCRYPT_BLOCK = 117; |
||||||
|
|
||||||
|
/** |
||||||
|
* RSA最大解密密文大小 |
||||||
|
*/ |
||||||
|
private static final int MAX_DECRYPT_BLOCK = 128; |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:用私钥对信息生成签名(默认字符集) |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:18:04 |
||||||
|
* @param content 要生成签名的字符串 |
||||||
|
* @param privateKey base64加密的私钥字符串 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:String |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
public static String sign(String content, String privateKey) |
||||||
|
throws Exception { |
||||||
|
return sign(content, privateKey, "UTF-8"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:用私钥对信息生成签名(指定字符集) |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:15:08 |
||||||
|
* @param content 要生成签名的字符串 |
||||||
|
* @param privateKey base64加密的私钥字符串 |
||||||
|
* @param input_charset 要生成签名的字符串对应的字符集 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:String |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
public static String sign(String content, String privateKey, |
||||||
|
String input_charset) throws Exception { |
||||||
|
// 用私钥对信息生成数字签名
|
||||||
|
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); |
||||||
|
signature.initSign(getPrivateKey(privateKey)); |
||||||
|
signature.update(content.getBytes(input_charset)); |
||||||
|
// return Base64Util.getBase64StringByByteArray(signature.sign());
|
||||||
|
return encode(signature.sign()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:校验数字签名,验签成功返回true失败返回false(默认字符集) |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:53:02 |
||||||
|
* @param content 要验签的字符串 |
||||||
|
* @param publicKey base64加密的公钥字符串 |
||||||
|
* @param sign 要验签的字符串签名 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:boolean |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
public static boolean verify(String content, String publicKey, String sign) throws Exception { |
||||||
|
return verify(content, publicKey, "UTF-8", sign); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:校验数字签名,验签成功返回true失败返回false(指定字符集) |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:53:02 |
||||||
|
* @param content 要验签的字符串 |
||||||
|
* @param publicKey base64加密的公钥字符串 |
||||||
|
* @param input_charset 要验签的字符串对应的字符集 |
||||||
|
* @param sign 要验签的字符串签名 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:boolean |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
public static boolean verify(String content, String publicKey, String input_charset, String sign) throws Exception { |
||||||
|
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); |
||||||
|
signature.initVerify(getPublicKey(publicKey)); |
||||||
|
signature.update(content.getBytes(input_charset)); |
||||||
|
if (isStrBlank(sign)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
// 验证签名是否正常
|
||||||
|
return signature.verify(decode(sign)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* 描述: 判断字符串是否为 空 JIRA单号: KYEEAPP-947<br/> |
||||||
|
* 创建人: tianlong <br/> |
||||||
|
* |
||||||
|
* @param str |
||||||
|
* @return bool |
||||||
|
* @since Ver 1.1 |
||||||
|
*/ |
||||||
|
public static boolean isStrBlank(String str) { |
||||||
|
return (null == str || "".equals(str.trim()) || "NULL".equalsIgnoreCase(str.trim())); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:根据base64加密的私钥字符串生成RSA私钥对象 |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:41:50 |
||||||
|
* @param privateKey base64加密的私钥字符串 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:PrivateKey |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
private static PrivateKey getPrivateKey(String privateKey) throws Exception { |
||||||
|
// 解密由base64编码的私钥
|
||||||
|
// byte[] keyBytes = Base64Util.getByteArrayByBase64String(privateKey);
|
||||||
|
byte[] keyBytes = decode(privateKey); |
||||||
|
// 构造PKCS8EncodedKeySpec对象
|
||||||
|
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); |
||||||
|
// KEY_ALGORITHM 指定的加密算法
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); |
||||||
|
// 取私钥匙对象
|
||||||
|
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); |
||||||
|
return priKey; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* <pre> |
||||||
|
* 描述:根据base64加密的公钥字符串生成RSA公钥对象 |
||||||
|
* 作者:fengqianning |
||||||
|
* 时间:2016年5月4日下午9:48:52 |
||||||
|
* @param publicKey base64加密的公钥字符串 |
||||||
|
* @return |
||||||
|
* @throws Exception |
||||||
|
* returnType:PublicKey |
||||||
|
* </pre> |
||||||
|
*/ |
||||||
|
private static PublicKey getPublicKey(String publicKey) throws Exception { |
||||||
|
// 解密由base64编码的公钥
|
||||||
|
byte[] keyBytes = decode(publicKey); |
||||||
|
// 构造X509EncodedKeySpec对象
|
||||||
|
X509EncodedKeySpec x509keySpec = new X509EncodedKeySpec(keyBytes); |
||||||
|
// KEY_ALGORITHM 指定的加密算法
|
||||||
|
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); |
||||||
|
// 取公钥匙对象
|
||||||
|
PublicKey pubKey = keyFactory.generatePublic(x509keySpec); |
||||||
|
return pubKey; |
||||||
|
} |
||||||
|
|
||||||
|
static private final int BASELENGTH = 128; |
||||||
|
static private final int LOOKUPLENGTH = 64; |
||||||
|
static private final int TWENTYFOURBITGROUP = 24; |
||||||
|
static private final int EIGHTBIT = 8; |
||||||
|
static private final int SIXTEENBIT = 16; |
||||||
|
static private final int FOURBYTE = 4; |
||||||
|
static private final int SIGN = -128; |
||||||
|
static private final char PAD = '='; |
||||||
|
static private final boolean fDebug = false; |
||||||
|
static final private byte[] base64Alphabet = new byte[BASELENGTH]; |
||||||
|
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; |
||||||
|
|
||||||
|
static { |
||||||
|
Arrays.fill(base64Alphabet, (byte) -1); |
||||||
|
for (int i = 'Z'; i >= 'A'; i--) { |
||||||
|
base64Alphabet[i] = (byte) (i - 'A'); |
||||||
|
} |
||||||
|
for (int i = 'z'; i >= 'a'; i--) { |
||||||
|
base64Alphabet[i] = (byte) (i - 'a' + 26); |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = '9'; i >= '0'; i--) { |
||||||
|
base64Alphabet[i] = (byte) (i - '0' + 52); |
||||||
|
} |
||||||
|
|
||||||
|
base64Alphabet['+'] = 62; |
||||||
|
base64Alphabet['/'] = 63; |
||||||
|
|
||||||
|
for (int i = 0; i <= 25; i++) { |
||||||
|
lookUpBase64Alphabet[i] = (char) ('A' + i); |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 26, j = 0; i <= 51; i++, j++) { |
||||||
|
lookUpBase64Alphabet[i] = (char) ('a' + j); |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 52, j = 0; i <= 61; i++, j++) { |
||||||
|
lookUpBase64Alphabet[i] = (char) ('0' + j); |
||||||
|
} |
||||||
|
lookUpBase64Alphabet[62] = (char) '+'; |
||||||
|
lookUpBase64Alphabet[63] = (char) '/'; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isWhiteSpace(char octect) { |
||||||
|
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isPad(char octect) { |
||||||
|
return (octect == PAD); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isData(char octect) { |
||||||
|
return (octect < BASELENGTH && base64Alphabet[octect] != -1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Encodes hex octects into Base64 |
||||||
|
* |
||||||
|
* @param binaryData Array containing binaryData |
||||||
|
* @return Encoded Base64 array |
||||||
|
*/ |
||||||
|
public static String encode(byte[] binaryData) { |
||||||
|
|
||||||
|
if (binaryData == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
int lengthDataBits = binaryData.length * EIGHTBIT; |
||||||
|
if (lengthDataBits == 0) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; |
||||||
|
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; |
||||||
|
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets; |
||||||
|
char[] encodedData = new char[numberQuartet * 4]; |
||||||
|
|
||||||
|
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; |
||||||
|
|
||||||
|
int encodedIndex = 0; |
||||||
|
int dataIndex = 0; |
||||||
|
if (fDebug) { |
||||||
|
//edit begin 支付模块打印整改 zhoufeng 2014年12月2日09:32:19
|
||||||
|
//KYEEAPP-1060
|
||||||
|
// HLogger.info("number of triplets = " + numberTriplets);
|
||||||
|
//edit end
|
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 0; i < numberTriplets; i++) { |
||||||
|
b1 = binaryData[dataIndex++]; |
||||||
|
b2 = binaryData[dataIndex++]; |
||||||
|
b3 = binaryData[dataIndex++]; |
||||||
|
|
||||||
|
if (fDebug) { |
||||||
|
//edit begin 支付模块打印整改 zhoufeng 2014年12月2日09:32:19
|
||||||
|
//KYEEAPP-1060
|
||||||
|
// HLogger.info("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
|
||||||
|
//edit end
|
||||||
|
} |
||||||
|
|
||||||
|
l = (byte) (b2 & 0x0f); |
||||||
|
k = (byte) (b1 & 0x03); |
||||||
|
|
||||||
|
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
||||||
|
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); |
||||||
|
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); |
||||||
|
|
||||||
|
if (fDebug) { |
||||||
|
//edit begin 支付模块打印整改 zhoufeng 2014年12月2日09:32:19
|
||||||
|
//KYEEAPP-1060
|
||||||
|
// HLogger.info("val2 = " + val2);
|
||||||
|
// HLogger.info("k4 = " + (k << 4));
|
||||||
|
// HLogger.info("vak = " + (val2 | (k << 4)));
|
||||||
|
//edit end
|
||||||
|
} |
||||||
|
|
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; |
||||||
|
} |
||||||
|
|
||||||
|
// form integral number of 6-bit groups
|
||||||
|
if (fewerThan24bits == EIGHTBIT) { |
||||||
|
b1 = binaryData[dataIndex]; |
||||||
|
k = (byte) (b1 & 0x03); |
||||||
|
if (fDebug) { |
||||||
|
//edit begin 支付模块打印整改 zhoufeng 2014年12月2日09:32:19
|
||||||
|
//KYEEAPP-1060
|
||||||
|
// HLogger.info("b1=" + b1);
|
||||||
|
// HLogger.info("b1<<2 = " + (b1 >> 2));
|
||||||
|
//edit end
|
||||||
|
} |
||||||
|
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; |
||||||
|
encodedData[encodedIndex++] = PAD; |
||||||
|
encodedData[encodedIndex++] = PAD; |
||||||
|
} else if (fewerThan24bits == SIXTEENBIT) { |
||||||
|
b1 = binaryData[dataIndex]; |
||||||
|
b2 = binaryData[dataIndex + 1]; |
||||||
|
l = (byte) (b2 & 0x0f); |
||||||
|
k = (byte) (b1 & 0x03); |
||||||
|
|
||||||
|
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); |
||||||
|
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); |
||||||
|
|
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; |
||||||
|
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; |
||||||
|
encodedData[encodedIndex++] = PAD; |
||||||
|
} |
||||||
|
|
||||||
|
return new String(encodedData); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Decodes Base64 data into octects |
||||||
|
* |
||||||
|
* @param encoded string containing Base64 data |
||||||
|
* @return Array containind decoded data. |
||||||
|
*/ |
||||||
|
public static byte[] decode(String encoded) { |
||||||
|
|
||||||
|
if (encoded == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
char[] base64Data = encoded.toCharArray(); |
||||||
|
// remove white spaces
|
||||||
|
int len = removeWhiteSpace(base64Data); |
||||||
|
|
||||||
|
if (len % FOURBYTE != 0) { |
||||||
|
return null;//should be divisible by four
|
||||||
|
} |
||||||
|
|
||||||
|
int numberQuadruple = (len / FOURBYTE); |
||||||
|
|
||||||
|
if (numberQuadruple == 0) { |
||||||
|
return new byte[0]; |
||||||
|
} |
||||||
|
|
||||||
|
byte[] decodedData = null; |
||||||
|
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; |
||||||
|
char d1 = 0, d2 = 0, d3 = 0, d4 = 0; |
||||||
|
|
||||||
|
int i = 0; |
||||||
|
int encodedIndex = 0; |
||||||
|
int dataIndex = 0; |
||||||
|
decodedData = new byte[(numberQuadruple) * 3]; |
||||||
|
|
||||||
|
for (; i < numberQuadruple - 1; i++) { |
||||||
|
|
||||||
|
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])) |
||||||
|
|| !isData((d3 = base64Data[dataIndex++])) |
||||||
|
|| !isData((d4 = base64Data[dataIndex++]))) { |
||||||
|
return null; |
||||||
|
}//if found "no data" just return null
|
||||||
|
|
||||||
|
b1 = base64Alphabet[d1]; |
||||||
|
b2 = base64Alphabet[d2]; |
||||||
|
b3 = base64Alphabet[d3]; |
||||||
|
b4 = base64Alphabet[d4]; |
||||||
|
|
||||||
|
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
||||||
|
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
||||||
|
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); |
||||||
|
} |
||||||
|
|
||||||
|
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) { |
||||||
|
return null;//if found "no data" just return null
|
||||||
|
} |
||||||
|
|
||||||
|
b1 = base64Alphabet[d1]; |
||||||
|
b2 = base64Alphabet[d2]; |
||||||
|
|
||||||
|
d3 = base64Data[dataIndex++]; |
||||||
|
d4 = base64Data[dataIndex++]; |
||||||
|
if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
|
||||||
|
if (isPad(d3) && isPad(d4)) { |
||||||
|
if ((b2 & 0xf) != 0)//last 4 bits should be zero
|
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
byte[] tmp = new byte[i * 3 + 1]; |
||||||
|
System.arraycopy(decodedData, 0, tmp, 0, i * 3); |
||||||
|
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); |
||||||
|
return tmp; |
||||||
|
} else if (!isPad(d3) && isPad(d4)) { |
||||||
|
b3 = base64Alphabet[d3]; |
||||||
|
if ((b3 & 0x3) != 0)//last 2 bits should be zero
|
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
byte[] tmp = new byte[i * 3 + 2]; |
||||||
|
System.arraycopy(decodedData, 0, tmp, 0, i * 3); |
||||||
|
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
||||||
|
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
||||||
|
return tmp; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} else { //No PAD e.g 3cQl
|
||||||
|
b3 = base64Alphabet[d3]; |
||||||
|
b4 = base64Alphabet[d4]; |
||||||
|
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); |
||||||
|
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); |
||||||
|
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
return decodedData; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* remove WhiteSpace from MIME containing encoded Base64 data. |
||||||
|
* |
||||||
|
* @param data the byte array of base64 data (with WS) |
||||||
|
* @return the new length |
||||||
|
*/ |
||||||
|
private static int removeWhiteSpace(char[] data) { |
||||||
|
if (data == null) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
// count characters that's not whitespace
|
||||||
|
int newSize = 0; |
||||||
|
int len = data.length; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
if (!isWhiteSpace(data[i])) { |
||||||
|
data[newSize++] = data[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
return newSize; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,96 @@ |
|||||||
|
package com.ynxbd.jy.bean; |
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject; |
||||||
|
import lombok.*; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.apache.commons.lang3.ObjectUtils; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Getter |
||||||
|
@Setter |
||||||
|
@ToString |
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE) |
||||||
|
public class JYResult { |
||||||
|
private String code; |
||||||
|
private String message; |
||||||
|
private String success; |
||||||
|
private String status; |
||||||
|
|
||||||
|
private JSONObject data; |
||||||
|
|
||||||
|
public JYResult(JSONObject resp) { |
||||||
|
if (resp == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
this.code = resp.getString("resultCode"); |
||||||
|
this.success = resp.getString("success"); |
||||||
|
this.status = resp.getString("status"); |
||||||
|
this.message = resp.getString("message"); |
||||||
|
this.data = resp; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isSuccess() { |
||||||
|
return "true".equals(success); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private JSONObject logError(String tip) { |
||||||
|
log.error("[京颐]预下单返回[{}]为空", tip == null ? "" : tip); |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public JSONObject toWxPrepay() { |
||||||
|
if (this.data == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
String appId = this.data.getString("wxAppId"); |
||||||
|
String timeStamp = this.data.getString("wxTimeStamp"); // 时间戳
|
||||||
|
String nonceStr = this.data.getString("wxUuid"); // 随机字符串
|
||||||
|
String packagePrepayId = this.data.getString("tn"); // 预支付交易会话标识
|
||||||
|
String signType = this.data.getString("wxSignType"); // 签名类型
|
||||||
|
String paySign = this.data.getString("wxSign"); // 签名值
|
||||||
|
|
||||||
|
String outTradeNo = this.data.getString("orderId"); |
||||||
|
String bankTransNo = this.data.getString("orderTransId"); |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(appId)) { |
||||||
|
return logError("appId"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(timeStamp)) { |
||||||
|
return logError("时间戳"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(nonceStr)) { |
||||||
|
return logError("随机字符串"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(packagePrepayId)) { |
||||||
|
return logError("预支付交易会话标识"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(signType)) { |
||||||
|
return logError("签名类型"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(paySign)) { |
||||||
|
return logError("签名值"); |
||||||
|
} |
||||||
|
|
||||||
|
if (ObjectUtils.isEmpty(outTradeNo)) { |
||||||
|
return logError("商户订单号"); |
||||||
|
} |
||||||
|
|
||||||
|
JSONObject prepayInfo = new JSONObject(); // 预下单信息
|
||||||
|
prepayInfo.put("appId", appId); |
||||||
|
prepayInfo.put("timeStamp", timeStamp); |
||||||
|
prepayInfo.put("nonceStr", nonceStr); |
||||||
|
prepayInfo.put("package", "prepay_id=" + packagePrepayId); |
||||||
|
|
||||||
|
prepayInfo.put("signType", signType); |
||||||
|
prepayInfo.put("paySign", paySign); |
||||||
|
prepayInfo.put("outTradeNo", outTradeNo); |
||||||
|
prepayInfo.put("bankTransNo", bankTransNo); |
||||||
|
return prepayInfo; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue