Commit 10c6f395 by jscat

nyx javaapp: 架构更新

1. 新增支付功能
parent 40eaa636
......@@ -196,6 +196,26 @@
<version>3.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.springboot/best-pay-sdk jscat 2020/11/16-->
<dependency>
<groupId>cn.springboot</groupId>
<artifactId>best-pay-sdk</artifactId>
<version>1.3.3</version>
</dependency>
<!--wxPay jscat 2020/11/17 -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
</dependencies>
<build>
......
package cn.com.fun.nyxkey.api.utils;
import org.jdom.input.SAXBuilder;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.*;
public class PayUtil{
/**
* 获取当前机器的ip
*/
public static String getLocalIp() {
InetAddress ia = null;
String localip = null;
try {
ia = ia.getLocalHost();
localip = ia.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return localip;
}
@SuppressWarnings("rawtypes")
public static String getRequestXml(SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
/**
* 创建签名Sign
*/
@SuppressWarnings("rawtypes")
public static String createSign(String characterEncoding, Map<String, String> parameters, String key) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator<?> it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
if (entry.getValue() != null || !"".equals(entry.getValue())) {
String v = String.valueOf(entry.getValue());
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
}
sb.append("key=" + key);
String sign = MD5Util.encrypt(sb.toString()).toUpperCase();
return sign;
}
/**
* 生成随机数
*/
public static String makeUUID(int len) {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
}
/**
* 生成订单号
*/
public static String generateOrderNo() {
SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
return sdf.format(new Date()) + makeUUID(16);
}
/**
* 解析xml
*/
public static Map doXMLParse(String strxml) throws Exception {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if (null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
org.jdom.Document doc = builder.build(in);
org.jdom.Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
org.jdom.Element e = (org.jdom.Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
* 获取子节点的xml
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator it = children.iterator();
while (it.hasNext()) {
org.jdom.Element e = (org.jdom.Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
/**
* 转换金额到整型
*/
public static String moneyToIntegerStr(Double money) {
BigDecimal decimal = new BigDecimal(money);
int amount = decimal.multiply(new BigDecimal((100)))
.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
return String.valueOf(amount);
}
/**
* 微信下单,map to xml
* @param params 参数
* @return String
*/
@Deprecated
public static String mapToXml(Map<String, String> params) {
StringBuilder xml = new StringBuilder();
xml.append("<xml>");
for (Map.Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// 略过空值
if (StringUtils.isEmpty(value)) continue;
xml.append("<").append(key).append("><![CDATA[");
xml.append(entry.getValue());
xml.append("]]></").append(key).append(">");
}
xml.append("</xml>");
return xml.toString();
}
public static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
\ No newline at end of file
package cn.com.fun.nyxkey.api.web.controller;
/*
API接口
用于小程序的支付接口
*/
import cn.com.fun.nyxkey.api.common.JSONResult;
import cn.com.fun.nyxkey.api.utils.PayUtil;
import cn.com.fun.nyxkey.api.web.common.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import static org.apache.commons.codec.digest.MessageDigestAlgorithms.MD5;
/**
* Created by jscat on 2020-11-16.
*/
@RestController
@RequestMapping("/api")
public class PayApiController {
@Value("${weixin.appid}")
private String appid;
@Value("${weixin.secret}")
private String secret;
//商家号id
@Value("${weixin.mchid}")
public String mchid;
//商家密钥key
@Value("${weixin.mchkey}")
public String mchkey;
//商家密钥key
@Value("${weixin.notifyUrl}")
public String notifyUrl;
private static final Logger LOGGER = LoggerFactory.getLogger(PayApiController.class);
/**
* @Description 统一下单
* @date jscat 2020/11/16
* https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
*
* 微信支付接口签名验证工具
* https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
*
* 微信公众号支付对接流程 @Java
* https://blog.csdn.net/l15810356216/article/details/88356295
*
* @param
* @return Map
*/
@ApiOperation(value="微信支付统一下单", notes="微信支付统一下单")
@ApiImplicitParams({
@ApiImplicitParam(name = "openId", value = "openId", required = true, dataType = "String", defaultValue = "1"),
@ApiImplicitParam(name = "money", value = "标价金额", required = true, dataType = "String", defaultValue = "1"),
@ApiImplicitParam(name = "body", value = "商品描述", required = true, dataType = "String", defaultValue = "1")
})
@RequestMapping(value = "/nyx/wx/pay/orders", method = RequestMethod.GET)
public Map<String, Object> orders(
@RequestParam(value = "openId", required = true, defaultValue = "1") String openId,
@RequestParam(value = "money", required = true, defaultValue = "1") Double money,
@RequestParam(value = "body", required = true, defaultValue = "0") String body,
HttpServletRequest request
) throws Exception {
Map<String , Object> resMap = new HashMap<String,Object>();
LOGGER.info("=============code:{}");
try {
// 拼接统一下单地址参数
Map<String, String> paraMap = new TreeMap<String, String>();
//获取请求ip地址
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
if(ip.indexOf(",")!=-1){
String[] ips = ip.split(",");
ip = ips[0].trim();
}
paraMap.put("appid", appid); // 商家平台ID
paraMap.put("body", body); // 商家名称-销售商品类目、String(128)
paraMap.put("mch_id", mchid); // 商户ID
paraMap.put("nonce_str", WXPayUtil.generateNonceStr()); // UUID
paraMap.put("notify_url", notifyUrl); // 此路径是微信服务器调用支付结果通知路径随意写
paraMap.put("openid", openId);
paraMap.put("out_trade_no", PayUtil.generateOrderNo());// 订单号,每次都不同
paraMap.put("sign_type", MD5);
paraMap.put("spbill_create_ip", ip);
paraMap.put("total_fee", PayUtil.moneyToIntegerStr(money)); // 支付金额,单位分
paraMap.put("trade_type", "JSAPI"); // 支付类型
String sign = PayUtil.createSign("UTF-8", paraMap, mchkey);
paraMap.put("sign", sign);
String xml = WXPayUtil.mapToXml(paraMap);// 将所有参数(map)转xml格式
// 统一下单 https://api.mch.weixin.qq.com/pay/unifiedorder
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
System.out.println("xml为:" + xml);
String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);
System.out.println("xmlStr为:" + xmlStr);
// 以下内容是返回前端页面的json数据
String prepay_id = "";// 预支付id
if (xmlStr.indexOf("SUCCESS") != -1) {
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
prepay_id = (String) map.get("prepay_id");
}
Map<String, String> payMap = new TreeMap<String, String>();
payMap.put("appId", appid);
payMap.put("timeStamp", new Timestamp(System.currentTimeMillis()) + "");
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
LOGGER.info("=======prepay_id:"+prepay_id);
String paySign = PayUtil.createSign("UTF-8", payMap, mchkey);
payMap.put("prepay_id", prepay_id);
payMap.put("paySign", paySign);
//将这个6个参数传给前端
resMap.put("code",1);
resMap.put("payMap",payMap);
} catch (Exception e) {
e.printStackTrace();
resMap.put("code",0);
resMap.put("msg","调用统一订单接口错误");
}
return resMap;
}
/**
* @Title: callback
* @Description: 支付完成的回调函数
* @param:
* @return:
*/
@RequestMapping(value="/nyx/wx/pay/notify", method = RequestMethod.POST)
public String callback(HttpServletRequest request, HttpServletResponse response) {
System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
InputStream is = null;
try {
is = request.getInputStream();// 获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
String xml = InputStream2String(is);
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);// 将微信发的xml转map
System.out.println("微信返回给回调函数的信息为:"+xml);
if(notifyMap.get("return_code").equals("SUCCESS")){
if(notifyMap.get("result_code").equals("SUCCESS")){
String ordersSn = notifyMap.get("out_trade_no");// 商户订单号
String amountpaid = notifyMap.get("total_fee");// 实际支付的订单金额:单位 分
BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);// 将分转换成元-实际支付金额:元
/*
* 以下是自己的业务处理------仅做参考 更新order对应字段/已支付金额/状态码
*/
System.out.println("===notify===回调方法已经被调!!!");
}
}
System.out.println("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
// 告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static String InputStream2String(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
is.close();
byte[] lens = baos.toByteArray();
String result = new String(lens,"UTF-8");//内容乱码处理
return result;
}
}
......@@ -75,4 +75,7 @@ aliyun:
callbackUrl: http://88.88.88.88:8888
dir: user-dir/
dirQrcode: qrcode-dir/
dirLogo: logo-dir/
\ No newline at end of file
dirLogo: logo-dir/
weixin:
notifyUrl: https://wx.hisuhong.com/api/nyx/wx/pay/notify
\ No newline at end of file
......@@ -59,4 +59,7 @@ aliyun:
callbackUrl: http://88.88.88.88:8888
dir: user-dir/
dirQrcode: qrcode-dir/
dirLogo: logo-dir/
\ No newline at end of file
dirLogo: logo-dir/
weixin:
notifyUrl: https://fun.hisuhong.com/api/nyx/wx/pay/notify
\ No newline at end of file
......@@ -67,9 +67,16 @@ app:
cron:
genT_match_rank: 0 0/20 * * * ?
#mchkey: 在API调用时用来按照指定规则对你的请求参数进行签名,服务器收到你的请求时会进行签名验证
#keyPath: 在调用微信支付安全级别较高的接口(如:退款、企业红包、企业付款)时,会使用到API证书
weixin:
appid: 'wx72555e77d9e5cee2'
secret: '072986d584176aa5aa9b1531841779f2'
appid: wx72555e77d9e5cee2
secret: 072986d584176aa5aa9b1531841779f2
mpAppId:
mchid: 1604143639
mchkey: 6D5129322127E2D33DEE90F4E2EA97A5
keyPath:
appAppId:
aliyun:
oss:
......
......@@ -138,6 +138,12 @@
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论