1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 微信退款小程序支付/退款

微信退款小程序支付/退款

时间:2020-08-08 15:48:30

相关推荐

微信退款小程序支付/退款

最近在写微信退款的时候发现了很多的Demo,但是方法都不同,而且很难确定Demo是不是适用自己的项目。

在发起退款的时候第一步自然还是先去下载证书,这个没话说,下载完成后在退款Controller可以直接引入退款工具类:

package com.tumii.meijing.refund.controller.m;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.jframework.core.helper.UploadFileHelper;import com.tumii.meijing.order.facade.OrderInfoFacade;import com.tumii.meijing.order.model.OrderDetail;import com.tumii.meijing.order.model.OrderInfo;import com.tumii.meijing.order.model.OrderItemInfo;import com.tumii.meijing.order.service.OrderDetailService;import com.tumii.meijing.order.service.OrderItemInfoService;import com.tumii.meijing.project.model.PlatfromProject;import com.tumii.meijing.project.model.ProjectDict;import com.tumii.meijing.refund.model.RefundDetail;import com.tumii.meijing.refund.model.RefundNegotiate;import com.tumii.meijing.refund.model.RefundOrder;import com.tumii.meijing.refund.service.RefundDetailService;import com.tumii.meijing.refund.service.RefundNegotiateService;import com.tumii.meijing.refund.service.RefundOrderService;import com.tumii.meijing.sales_return.model.SalesReturn;import com.tumii.meijing.sales_return.service.SalesReturnService;import com.tumii.meijing.util.DateUtils;import com.tumii.meijing.util.PayUtil;import com.tumii.meijing.wxpay.WeChatConfig;import net.sf.jxls.report.ReportManager;import org.apache.logging.log4j.core.util.UuidUtil;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.joda.time.DateTime;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.util.ObjectUtils;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.monsMultipartFile;import org.springframework.web.servlet.ModelAndView;import com.jframework.core.action.BaseController;import com.jframework.core.bean.ResultMessage;import com.jframework.core.exception.BusinessException;import com.jframework.core.model.DataGrid;import com.jframework.core.model.Page;import com.jframework.core.model.Params;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.tagext.PageData;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.HttpPost;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.ssl.SSLContexts;import org.apache.http.util.EntityUtils;import org.apache.log4j.Logger;import .ssl.SSLContext;import javax.servlet.http.HttpServletRequest;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.security.KeyStore;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Random;@Controller@RequestMapping("/manage/refundOrder")public class RefundOrderController extends BaseController {@Autowiredprivate RefundOrderService refundOrderService;@Autowiredprivate RefundNegotiateService refundNegotiateService;@Autowiredprivate OrderItemInfoService orderItemInfoService;@Autowiredprivate RefundDetailService refundDetailService;@Autowiredprivate OrderInfoFacade orderInfoFacade;@Autowiredprivate OrderDetailService orderDetailService;@Autowiredprivate SalesReturnService salesReturnService;private static final Logger LOGGER = Logger.getLogger(RefundOrderController.class);private int socketTimeout = 10000;// 连接超时时间,默认10秒private int connectTimeout = 30000;// 传输超时时间,默认30秒private static RequestConfig requestConfig;// 请求器的配置private static CloseableHttpClient httpClient;// HTTP请求器@ResponseBody@RequestMapping("update.do")public void update(RefundOrder refundOrder) {RefundOrder oldRefundOrder = refundOrderService.getById(refundOrder.getId());if (oldRefundOrder == null)throw new BusinessException("无效的数据!");refundOrder.setOperatingTime(oldRefundOrder.getOperatingTime());refundOrder.setRefundCreateTime(oldRefundOrder.getRefundCreateTime());// 如果操作人未填写,根据订单id去获取订单,然后获得操作人信息,封装到退款if ((refundOrder.getOperatorId() == null || refundOrder.getOperatorId() == "") && (refundOrder.getOperatorName() == "" || refundOrder.getOperatorName() == null)) {String orderId = refundOrder.getOrderId();if (orderId != null && orderId != "") {OrderItemInfo orderItemInfo = orderItemInfoService.getById(orderId);if (orderItemInfo != null) {if (orderItemInfo.getSupplyId() != null && orderItemInfo.getSupplyId() != "") {refundOrder.setOperatorId(orderItemInfo.getSupplyId());}if (orderItemInfo.getSupplyName() != null && orderItemInfo.getSupplyName() != "") {refundOrder.setOperatorName(orderItemInfo.getSupplyName());}}}}// 当退款状态修改后,及时添加协商历史if (refundOrderService.update(refundOrder) > 0) {ResultMessage result = ResultMessage.success("操作成功");if (refundOrder.getRefundStatus() != null && refundOrder.getRefundStatus() != "") {if (!refundOrder.getRefundStatus().equals(oldRefundOrder.getRefundStatus())) {RefundNegotiate refundNegotiate = refundNegotiateService.addNegotiate(refundOrder);refundNegotiate.setId(refundNegotiateService.getNewId());refundNegotiateService.insert(refundNegotiate);//在确认退款状态改变且等于‘同意退款’得情况下才去退款和退返佣if ("8".equals(refundOrder.getRefundStatus())) { //同意退款String orderNo = refundOrder.getOrderNo();//订单号String orderDetailNo = refundOrder.getOrderDetailNo();//明细订单号String refundCode = refundOrder.getRefundCode();if (refundCode != null && refundCode != "") {RefundDetail refundDetail = refundDetailService.getByRefundCode(refundCode);// 分销退款传参(明细订单号,数量,金额)String num = refundDetail.getNum();//数量String orderPrice = refundDetail.getOrderPrice(); //退款金额String code = WeChatConfig.CODE_SUCCESS;//状态码String msg = WeChatConfig.REFUND_SUCCESS;//提示信息Map<String, String> data = new HashMap<String, String>();try {// 退款成功后需不需要将订单状态修改成退款成功// 还要在这调用线上退款将款打给用户int totalFee = 0;OrderItemInfo orderItemInfo = orderItemInfoService.findByOrderNo(orderNo);if (orderItemInfo != null) {totalFee = orderItemInfo.getFinalSum();}int refundFee = Integer.parseInt(orderPrice);//退款到用户微信String nonce_str = getRandomStringByLength(32);// data.put("userId", String.valueOf(userecord.getUserId()));data.put("appid", WeChatConfig.APP_ID);data.put("mch_id", WeChatConfig.MCH_ID);data.put("nonce_str", nonce_str);data.put("sign_type", "MD5");data.put("out_trade_no", orderNo);//商户订单号data.put("out_refund_no", refundCode);//商户退款单号//Math.round(userecord.getMoney() * 100);data.put("total_fee", String.valueOf(Math.round(totalFee)));//支付金额,微信支付提交的金额是不能带小数点的,且是以分为单位,这边需要转成字符串类型,否则后面的签名会失败/* data.put("refund_fee", String.valueOf(Math.round(refundFee * 100)));*/data.put("refund_fee", String.valueOf(Math.round(refundFee)));//退款总金额,订单总金额,单位为分,只能为整数//data.put("notify_url", Constants.NOTIFY_URL_REFUND);//退款成功后的回调地址String preStr = PayUtil.createLinkString(data); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口String mySign = PayUtil.sign(preStr, WeChatConfig.KEY, "utf-8").toUpperCase();data.put("sign", mySign);//拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去String xmlStr = postData(WeChatConfig.REFUND_URL, PayUtil.GetMapToXML(data)); //支付结果通知的xml格式数据System.out.println(xmlStr);Map notifyMap = PayUtil.doXMLParse(xmlStr);data.put("xml", xmlStr);//可以返回结果操作数据if ("SUCCESS".equals(notifyMap.get("return_code"))) {if ("SUCCESS".equals(notifyMap.get("result_code"))) {//退款成功的操作refundOrder.setApprovalStatus("4");refundOrder.setRefundStatus("6");refundOrderService.update(refundOrder);//将退款状态修改成退款成功String prepay_id = (String) notifyMap.get("prepay_id");//返回的预付单信息System.out.println(prepay_id);Long timeStamp = System.currentTimeMillis() / 1000;//拼接签名需要的参数String stringSignTemp = "appId=" + WeChatConfig.APP_ID + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;//签名算法生成签名String paySign = PayUtil.sign(stringSignTemp, WeChatConfig.KEY, "utf-8").toUpperCase();data.put("package", "prepay_id=" + prepay_id);data.put("timeStamp", String.valueOf(timeStamp));data.put("paySign", paySign);// 退款成功后调用分销退款业务,并且将订单状态修改成部分退款(判断订单得子订单有无已经退款得,如果子订单数多于一个,无退款得,修改成部分退款;如果该子订单数只有一个或者子订单都退款了则改成以退款)orderInfoFacade.doReturnOrderOpCommission(orderDetailNo, Integer.parseInt(num), Integer.parseInt(orderPrice));List<OrderDetail> list = orderDetailService.findByOrderNO(orderNo);Boolean status = true;if (list!=null ){if (list.size() == 1){orderItemInfo.setOrderStatus("RETURN");}else {for (OrderDetail orderDetail : list) {String orderDetailNos = orderDetail.getOrderDetailNo();RefundOrder refundOrder1 = refundOrderService.getByOrderDetailNo(orderDetailNos);if (refundOrder1 == null){// orderItemInfo.setOrderStatus("PARTRETURN");SalesReturn salesReturn = salesReturnService.getByOrderDetailNo(orderDetailNos);if (salesReturn == null){status = false;}}}}}if (status){//当每一个refundOrder1都不为null,说明该订单得子订单都在退款,修改订单状态位已退款orderItemInfo.setOrderStatus("RETURN");}if (!status){//当有refundOrder1为null,说明该订单得子订单有未退款得,修改订单状态未部分退款orderItemInfo.setOrderStatus("PARTRETURN");}/* orderItemInfo.setOrderStatus("PARTRETURN");*/orderItemInfoService.update(orderItemInfo);} else {System.out.println("退款失败:原因" + notifyMap.get("err_code_des"));code = WeChatConfig.CODE_ERROR;msg = (String) notifyMap.get("err_code_des");}} else {System.out.println("退款失败:原因" + notifyMap.get("err_code_des"));code = WeChatConfig.CODE_ERROR;msg = (String) notifyMap.get("err_code_des");}} catch (Exception e) {code = WeChatConfig.CODE_ERROR;msg = WeChatConfig.MSG_01;LOGGER.error(e.toString(), e);}/* Map<String, Object> jsonResult = new HashMap<String, Object>();jsonResult.put("code", code);jsonResult.put("msg", msg);jsonResult.put("data", data);*/// renderJson(jsonResult);result.setMessage(msg + "----------------" + data + "----------------" + code);}}}}result.setRedirect(this.getBasePath() + "/manage/refundOrder/page.do");this.write(result);} else {ResultMessage result = ResultMessage.error("操作失败");//result.setRedirect(this.getBasePath()+"/manage/refundOrder/page.do");this.write(result);}}public void approvalRefuse() {//此处为商户处理退款拒绝的相关业务,不需要调用微信的退款接口}public void updateRefundStatus() {//微信退款服务成功后回调,修改相关业务表的退款状态,订单状态等}/*** 加载证书*/private void initCert() throws Exception {// 证书密码,默认为商户IDString key = WeChatConfig.MCH_ID;// 商户证书的路径String paths = WeChatConfig.CERT_PATH;String resource =this.getClass().getClassLoader().getResource("/").getPath();String path = resource + paths;// 指定读取证书格式为PKCS12KeyStore keyStore = KeyStore.getInstance("PKCS12");// 读取本机存放的PKCS12证书文件FileInputStream instream = new FileInputStream(new File(path));try {// 指定PKCS12的密码(商户ID)keyStore.load(instream, key.toCharArray());} finally {instream.close();}SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();// 指定TLS版本SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);// 设置httpclient的SSLSocketFactoryhttpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();}/*** 通过Https往API post xml数据** @param url API地址* @param xmlObj 要提交的XML数据对象* @return*/public String postData(String url, String xmlObj) {// 加载证书try {initCert();} catch (Exception e) {e.printStackTrace();}String result = null;HttpPost httpPost = new HttpPost(url);// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");httpPost.addHeader("Content-Type", "text/xml");httpPost.setEntity(postEntity);// 根据默认超时限制初始化requestConfigrequestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();// 设置请求器的配置httpPost.setConfig(requestConfig);try {HttpResponse response = null;try {response = httpClient.execute(httpPost);} catch (IOException e) {e.printStackTrace();}HttpEntity entity = response.getEntity();try {result = EntityUtils.toString(entity, "UTF-8");} catch (IOException e) {e.printStackTrace();}} finally {httpPost.abort();}return result;}private String getRandomStringByLength(int length) {String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}}

因为我是在后台直接退款,所以就不用前端发送什么请求了,而微信支付的Config类则是:

package com.tumii.meijing.wxpay;public class WeChatConfig {/*** 公众号AppId*/public static final String APP_ID = "";/*** 公众号AppSecret secret*/public static final String APP_SECRET = "";/*** 微信支付商户号*/public static final String MCH_ID = "";/*** 微信支付API秘钥*/public static final String KEY = "";/*** 微信支付api证书路径*//* public static final String CERT_PATH = "D:/Java/amzgf/apiclient_cert.p12";*/public static final String CERT_PATH = "apiclient_cert.p12";/*** 微信统一下单url*/public static final String UNIFIED_ORDER_URL = "https://api.mch./pay/unifiedorder";/*** 微信申请退款url*/public static final String REFUND_URL = "https://api.mch./secapi/pay/refund";/*** 微信支付通知url*/public static final String NOTIFY_URL = "/order";/*** 微信交易类型:公众号支付*/public static final String TRADE_TYPE_JSAPI = "JSAPI";/*** 微信交易类型:原生扫码支付*/public static final String TRADE_TYPE_NATIVE = "NATIVE";/*** 微信甲乙类型:APP支付*/public static final String TRADE_TYPE_APP = "APP";public static final String CODE_SUCCESS = "000";//状态码public static final String CODE_ERROR = "999";public static final String MSG_NULL = "无效的订单";public static final String MSG_01 = "签名错误";public static final String REFUND_SUCCESS = "退款成功!";//提示信息}

在这出现了一个问题,因为我原本在本地执行退款是可以的成功的,但是在服务器就不行,因为证书是在我本地的,而要将证书上传到服务器我也没解决,因为路径访问还是不成功,经过多次百度之后还是将证书放在了代码resource目录下直接,然后在加载证书的时候获取该证书的相对路径,这是防止出错的。然后再次尝试后就可以成功退款了。

附上支付工具类,而其他的service或者bean都是正常的业务类,都是差不多的。

/*** Copyright (C), -, XXX有限公司* FileName: PayUtil* Author: de'l'l* Date:/10/26 16:21* Description:* History:* <author><time><version><desc>* 作者姓名 修改时间 版本号 描述*/package com.tumii.meijing.util;/*** 〈一句话功能简述〉<br>* 〈〉** @author de'l'l* @create /10/26* @since 1.0.0*/import mons.codec.digest.DigestUtils;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import java.io.*;import .HttpURLConnection;import .URL;import java.security.SignatureException;import java.util.*;public class PayUtil {/*** 签名字符串* @param text 需要签名的字符串* @param key 密钥* @param input_charset 编码格式* @return 签名结果*/public static String sign(String text, String key, String input_charset) {text = text + "&key=" + key;return DigestUtils.md5Hex(getContentBytes(text, input_charset));}/*** @param content* @param charset* @return* @throws SignatureException* @throws UnsupportedEncodingException*/public static byte[] getContentBytes(String content, String charset) {if (charset == null || "".equals(charset)) {return content.getBytes();}try {return content.getBytes(charset);} catch (UnsupportedEncodingException e) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);}}/*** 生成6位或10位随机数 param codeLength(多少位)* @return*/public static String createCode(int codeLength) {String code = "";for (int i = 0; i < codeLength; i++) {code += (int) (Math.random() * 9);}return code;}private static boolean isValidChar(char ch) {if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))return true;if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))return true;// 简体中文汉字编码return false;}/*** 除去数组中的空值和签名参数* @param sArray 签名参数组* @return 去掉空值与签名参数后的新签名参数组*/public static Map paraFilter(Map<String, String> sArray) {Map result = new HashMap();if (sArray == null || sArray.size() <= 0) {return result;}for (String key : sArray.keySet()) {String value = sArray.get(key);if (value == null || value.equals("") || key.equalsIgnoreCase("sign")|| key.equalsIgnoreCase("sign_type")) {continue;}result.put(key, value);}return result;}/*** 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串* @param params 需要排序并参与字符拼接的参数组* @return 拼接后字符串*/public static String createLinkString(Map<String, String> params) {List<String> keys = new ArrayList<String>(params.keySet());Collections.sort(keys);String preStr = "";for (int i = 0; i < keys.size(); i++) {String key = keys.get(i);String value = params.get(key);if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符preStr = preStr + key + "=" + value;} else {preStr = preStr + key + "=" + value + "&";}}return preStr;}/**** @param requestUrl 请求地址* @param requestMethod 请求方法* @param outputStr 参数*/public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {// 创建SSLContextStringBuffer buffer = null;try {URL url = new URL(requestUrl);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod(requestMethod);conn.setDoOutput(true);conn.setDoInput(true);conn.connect();//往服务器端写内容if (null != outputStr) {OutputStream os = conn.getOutputStream();os.write(outputStr.getBytes("utf-8"));os.close();}// 读取服务器端返回的内容InputStream is = conn.getInputStream();InputStreamReader isr = new InputStreamReader(is, "utf-8");BufferedReader br = new BufferedReader(isr);buffer = new StringBuffer();String line = null;while ((line = br.readLine()) != null) {buffer.append(line);}} catch (Exception e) {e.printStackTrace();}return buffer.toString();}public static String urlEncodeUTF8(String source) {String result = source;try {result = .URLEncoder.encode(source, "UTF-8");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}return result;}/*** 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。* @param strxml* @return* @throws IOException*/public static InputStream String2Inputstream(String strxml) throws IOException {return new ByteArrayInputStream(strxml.getBytes("UTF-8"));}public static Map doXMLParse(String strxml) throws Exception {Map<String, String> map = new HashMap<String, String>();if (null == strxml || "".equals(strxml)) {return null;}InputStream in = String2Inputstream(strxml);SAXReader read = new SAXReader();Document doc = read.read(in);//得到xml根元素Element root = doc.getRootElement();//遍历 得到根元素的所有子节点@SuppressWarnings("unchecked")List<Element> list = root.elements();for (Element element : list) {//装进mapmap.put(element.getName(), element.getText());}//关闭流in.close();return map;}public static String GetMapToXML(Map<String, String> param) {StringBuffer sb = new StringBuffer();sb.append("<xml>");for (Map.Entry<String, String> entry : param.entrySet()) {sb.append("<" + entry.getKey() + ">");sb.append(entry.getValue());sb.append("</" + entry.getKey() + ">");}sb.append("</xml>");return sb.toString();}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。