验证中...
Languages: Java
Categories: Web开发技术
Latest update 2019-09-04 10:47
微信支付
Raw Copy
1、微信jsapi支付
微信JSPAI文档地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
(1)生成统一下单信息
private Map<String, Object> createOrder(String openId,String body,Integer orderPrice,Integer appType,
String orderNum,HttpServletRequest request) throws UnsupportedEncodingException {
//定义随机数
Map packageParams = new LinkedHashMap<>();
//使用小程序的统一下单
if(appType==1) {
packageParams.put("appid",Constant.Applet_AppId);//微信小程序的APPID
} else {
//微信内调起H5支付需要使用公众号的APPID
packageParams.put("appid",Constant.APPID);
}
packageParams.put("mch_id", Constant.Trade_NO); //商户号
packageParams.put("nonce_str", WXPayUtil.generateNonceStr()); //随机数
packageParams.put("body", body); //支付主体参数
packageParams.put("out_trade_no",orderNum); //订单号
packageParams.put("total_fee",orderPrice); //订单金额
packageParams.put("spbill_create_ip",PayUtil.getLocalIp(request)); //终端IP
packageParams.put("notify_url", remoteAddr+notifyUrl); //微信回调地址
packageParams.put("trade_type", "JSAPI"); //支付方式
packageParams.put("openid", openId); //传openId参数
//获取sign(第一次签名)
String sign;
try {
//签名规则最好下载微信提供的demo,使用其中的工具类
sign = WXPayUtil.generateSignature(packageParams, Constant.MAH_PASSWORD);
packageParams.put("sign", sign);
log.info("生成的签名数据为:"+sign);
} catch (Exception e) {
e.printStackTrace();
}
return packageParams;
}
(2)请求微信服务器之后需要进行二次签名认证,将数据返回给客户端,由JS拉起支付
public Map<Object,Object> payResult(String openId,String body,Integer orderPrice,Integer appType,String orderNum,HttpServletRequest request) {
Map packageP = new LinkedHashMap();
try {
String requestXML = WXPayUtil.mapToXml(createOrder(openId,body,orderPrice,appType,orderNum,request));
log.info("转成XML的数据为:"+requestXML);
//得到含有prepay_id的XML
String resXml=HttpClientUtil.doPostCarryJson(Constant.Unifiedorder, requestXML);
log.info("含有prepay_id的XML为:"+resXml);
Map map2 = null;
try {
map2 = WXPayUtil.xmlToMap(resXml);
} catch (Exception e) {
e.printStackTrace();
}
//得到返回状态码
String returnCode=(String) map2.get("return_code");
//得到prepay_id 进行二次签名
if(returnCode.equals("SUCCESS")) {
String prepay_id = (String) map2.get("prepay_id");
//使用小程序的二次签名
if(appType==1) {
packageP.put("appId",Constant.Applet_AppId);//微信小程序的APPID
} else {
packageP.put("appId",Constant.APPID);
}
packageP.put("nonceStr", WXPayUtil.generateNonceStr());//时间戳
packageP.put("package", "prepay_id=" + prepay_id);//必须把package写成 "prepay_id="+prepay_id这种形式
packageP.put("signType", "MD5");
//paySign加密
packageP.put("timeStamp", WXPayUtil.getCurrentTimestampMs());
//得到paySign 用于请求微信 /*String payStr = PayUtil.createLinkString(packageP);
String paySign = WXPayUtil.generateSignature(packageP, Constant.MAH_PASSWORD);
packageP.put("paySign", paySign);
packageP.put("msg", "操作成功");
} else {
packageP.put("msg", getMsgByCode(returnCode));
}
} catch (Exception e) {
log.error("解析密码错误");
e.printStackTrace();
}
return packageP;
}
(3)签名生成方法
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static String generateSignature(final Map<String, Object> data, String key, SignType signType) throws Exception {
Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k)!=null) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k)).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
注意:商户密钥重置以后十五分钟生效
2、微信扫码支付
文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
(1)生成下单请求
private Map<String, Object> createScanOrder(String body,Integer orderPrice,String orderNum,HttpServletRequest request) throws UnsupportedEncodingException {
//定义随机数
Map packageParams = new LinkedHashMap<>();
packageParams.put("appid",Constant.APPID);//微信公众号的APPID
packageParams.put("mch_id", Constant.Trade_NO); //商户号
packageParams.put("nonce_str", WXPayUtil.generateNonceStr()); //随机数
packageParams.put("body", body); //支付主体参数
packageParams.put("out_trade_no",orderNum); //订单号
packageParams.put("total_fee",orderPrice); //订单金额
packageParams.put("spbill_create_ip",PayUtil.getLocalIp(request)); //终端IP
packageParams.put("notify_url", remoteAddr+notifyUrl); //微信回调地址
packageParams.put("trade_type", "NATIVE"); //支付方式
//获取sign(第一次签名)
String sign;
try {
sign = WXPayUtil.generateSignature(packageParams, Constant.MAH_PASSWORD);
packageParams.put("sign", sign);
log.info("生成的签名数据为:"+sign);
} catch (Exception e) {
e.printStackTrace();
}
return packageParams;
}
(2)发起支付请求,返回支付链接
public String payScan(String body, Integer orderPrice, String orderNum, HttpServletRequest request) {
String urlCode=null;
try {
String requestXML = WXPayUtil.mapToXml(createScanOrder(body,orderPrice,orderNum,request));
log.info("转成XML的数据为:"+requestXML);
//得到含有prepay_id的XML
String resXml=HttpClientUtil.doPostCarryJson(Constant.Unifiedorder, requestXML);
log.info("含有prepay_id的XML为:"+resXml);
Map map = WXPayUtil.xmlToMap(resXml);
// 返回微信支付的二维码连接
urlCode = (String) map.get("code_url");
log.info("微信二维码为:"+urlCode);
} catch (Exception e) {
log.error("微信扫码支付异常", e);
}
return urlCode;
}
3、微信退款
文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_4
注意:退款需要双向证书文件,Java建议使用第一个证书文件,其它语言使用其它文件
(1)生成退款订单参数
private Map<String,Object> createRefundOrder(int refundFee,int orderPrice,String orderNo,int orderType) throws UnsupportedEncodingException {
Map packageParams = new HashMap<>();
//如果支付方式为小程序,则创建jsapi退款订单
if(orderType==PayStatus.JsapiPay.getCode()) {
packageParams.put("appid",Constant.Applet_AppId);//微信小程序ID
} else {
packageParams.put("appid",Constant.APPID); //微信公众号ID
}
packageParams.put("mch_id", Constant.Trade_NO); //商户号
packageParams.put("nonce_str", WXPayUtil.generateNonceStr()); //随机数
packageParams.put("out_trade_no",orderNo); //订单号
packageParams.put("out_refund_no", DateTimeUtil.gens("L")); //退款订单号
packageParams.put("total_fee", orderPrice); //订单金额
packageParams.put("refund_fee", refundFee);
//获取sign(第一次签名)
String sign;
try {
sign = WXPayUtil.generateSignature(packageParams, Constant.MAH_PASSWORD);
packageParams.put("sign", sign);
log.info("生成的签名数据为:"+sign);
} catch (Exception e) {
log.error("生成退款异常:{}",e.getMessage());
}
return packageParams;
}
(2)发起退款请求
public DataOutResponse refund(Integer refundFee,String type,Long orderId) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
//获取支付订单号
String orderNum=orderPayDao.findOrdedrById(orderId).getPayNo();
try {
OrderInfo order=OrderInfoDao.findById(orderId);
NavigationBar navigationbar=navigationBarDao.findById(order.getNavigationbarId());
//判断是否需要进行时间条件判断
if(ParameterEnum.ON.getText().equals(type)) {
//当前时间大于退费时间则无法退费
if(df.format(new Date()).compareTo(navigationbar.getRemark())>0) {
//如果已经配送,将无法进行退费
return ReturnFomart.retParam(2025,order);
}
}
//该笔订单金额
int orderPrice=(int) (orderPayDao.findOrderPrice(orderNum)*100);
String requestXML = WXPayUtil.mapToXml(createRefundOrder(refundFee,orderPrice,orderNum,order.getOrderType()));
log.info("解析出的XML文件信息为:"+requestXML);
//发起退款请求
String resXml=HttpClientUtil.doRefund(Constant.RefundOrder, requestXML,filePath);
log.info("返回信息为:"+resXml);
Map map =WXPayUtil.xmlToMap(resXml);
String returnCode=(String) map.get("return_code");
if("SUCCESS".equals(returnCode)) {
String resultCode = map.get("result_code").toString();
if("SUCCESS".equals(resultCode)) {
String refundNo=map.get("out_refund_no").toString();
//计算订单金额
List<DishInfoDto> dishInfo=dishDao.getDishInfo(orderId,order.getNavigationbarId());
Double totalPrice=0d; //该笔订单消费的总金额
for(DishInfoDto dish:dishInfo) {
totalPrice+=dish.getDiningSum()*dish.getDishPrice();
}
//将订单中的状态进行更新
order.setOrderStatus(2);
//将消费明细表中的状态进行更新
ConfirmOrderBill confirmOrderBill=confirmOrderDao.findConsumeByOrderId(orderId);
confirmOrderBill.setOrderStatus(2);
//存入退费明细表当中
patientReturnDao.addPatientReturn(confirmOrderBill, totalPrice,refundNo,order.getCustomerName(),order.getAreaCode());
return ReturnFomart.retParam(200, order);
}
}
return ReturnFomart.retParam(2028, order);
} catch (Exception e) {
log.error("map转XML文件出错:{}",e.getMessage());
return ReturnFomart.retParam(1000, orderNum);
}
}
(3)HttpClientUtil
public static String doRefund(String url, String data,String filePath) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
//windows下的文件路径和Linux下的文件路径转换方式不同
FileInputStream is = new FileInputStream(new File(filePath));
try {
keyStore.load(is, Constant.Trade_NO.toCharArray());
} finally {
is.close();
}
// Trust own CA and all self-signed certs
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial( keyStore,
Constant.Trade_NO.toCharArray()) .build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext,
new String[]{"TLSv1"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost httpost = new HttpPost(url); // 设置响应头信息
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
支付宝支付
Raw Copy
1、支付宝手机网站支付
文档地址:https://docs.open.alipay.com/203/107090/
先去支付文档下载支付所需要的jar包,放入自己的maven私服当中
(1)支付主体对象:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class AlipayVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 支付主题
*/
private String subject;
/**
* 订单号
*/
private String out_trade_no;
/**
* 支付金额(以元为单位)
*/
private double total_amount;
/**
* 产品编码
*/
private String product_code;
}
(2)发起支付请求
public String aliPayOrder(String orderNum, double orderPrice, String body) {
log.info("订单号:",orderNum,"订单金额:",orderPrice,"支付主体:",body);
AlipayVo vo = new AlipayVo();
vo.setOut_trade_no(orderNum);
vo.setTotal_amount(orderPrice);
vo.setSubject(body);
vo.setProduct_code(Constant.Project_Code);
String json=JsonUtils.getBeanToJson(vo);
AlipayClient alipayClient =new DefaultAlipayClient(Constant.AliPay_Server,Constant.AliPay_AppId,Constant.AliPay_PrivateKey,
"json","UTF-8",Constant.AliPay_PublicKey,Constant.AliPay_Sign);
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
alipayRequest.setReturnUrl(Constant.AliPay_Return_Url);
alipayRequest.setNotifyUrl(Constant.AliPay_Notify_Url);
alipayRequest.setBizContent(json);
String result = null;
log.info("调用支付宝支付的参数为:"+JSON.toJSONString(alipayRequest));
try {
result = alipayClient.pageExecute(alipayRequest,"GET").getBody();
}
catch (AlipayApiException e) {
log.error("统一下单出错",e);
}
log.info("支付返回的参数为:" + result);
return result;
}
(3)退款请求
文档地址:https://docs.open.alipay.com/api_1/alipay.trade.refund/
(1)退款对象
public class AlipayRefund {
private String out_trade_no; //特殊可选 商户订单号
private String trade_no; //特殊可选 支付宝交易号
private double refund_amount; //必须 退款金额
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getTrade_no() {
return trade_no;
}
public void setTrade_no(String trade_no) {
this.trade_no = trade_no;
}
public double getRefund_amount() {
return refund_amount;
}
public void setRefund_amount(double refund_amount) {
this.refund_amount = refund_amount;
}
}
(2)发起退款请求
public DataOutResponse aliRefund(String orderNum, double refundAmount,String type) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //设置日期格式
log.info("退款订单号{}:",orderNum,"退款金额{}:",refundAmount);
AlipayRefund refund=new AlipayRefund();
refund.setOut_trade_no(orderNum);
refund.setRefund_amount(refundAmount);
String json=JsonUtils.getBeanToJson(refund);
AlipayTradeRefundResponse response=null;
OrderInfo orderInfo=OrderInfoDao.findOrderInfoByNo(orderNum);
NavigationBar navigationbar=navigationBarDao.findById(orderInfo.getNavigationbarId());
try {
//判断是否需要进行时间条件判断
if(ParameterEnum.ON.getText().equals(type)) {
//当前时间大于退费时间则无法退费
if(df.format(new Date()).compareTo(navigationbar.getRemark())>=0) {
//已经到备餐时间,将无法进行退费
return ReturnFomart.retParam(2025,orderInfo);
}
}
AlipayClient alipayClient =new DefaultAlipayClient(Constant.AliPay_Server,Constant.AliPay_AppId,Constant.AliPay_PrivateKey,
"json","UTF-8",Constant.AliPay_PublicKey,Constant.AliPay_Sign);
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent(json);
//发起退款请求
response = alipayClient.execute(request);
//退款成功则改变订单状态
if ("10000".equals(response.getCode())) {
//将订单中的状态进行更新
orderInfo.setOrderStatus(2);
//将消费明细表中的状态进行更新
ConfirmOrderBill confirmOrderBill=confirmOrderDao.findConsumeByOrderId(orderInfo.getOrderId());
confirmOrderBill.setOrderStatus(2);
//如果已经存入,不要重复存储
if(CompareUtil.isEmpty(patientReturnDao.findReturnInfoByOrderId(orderInfo.getOrderId()))) {
//存入退费明细表当中
patientReturnDao.addPatientReturn(confirmOrderBill, refundAmount,orderNum,orderInfo.getCustomerName(),orderInfo.getAreaCode());
}
return ReturnFomart.retParam(200, response.getMsg());
}
} catch (AlipayApiException e) {
log.error("支付宝退款异常{}:", e);
}
return ReturnFomart.retParam(4001, response.getSubMsg());
}
注意:支付宝的支付和退款都是走异步回调的,而且会回调两次,所以需要判断回调次数,防止库中出现重复的记录

Comment list( 0 )

You need to Sign in for post a comment

Help Search