이전 글은 사용자의 OpenId를 획득했습니다
본 글은 주로 위챗 공공결제 통합 주문 API를 호출합니다
API 주소: https://pay.weixin.qq. wiki/doc/api/jsapi.php?chapter=9_1
문서를 보면 주요 프로세스는 약 20개의 매개변수를 XML 형식으로 캡슐화하여 WeChat에서 제공하는 인터페이스 주소로 전송하는 것입니다. 반환된 콘텐츠에는 결제에 필요한 선불 ID
가 포함되어 있습니다. 요청 매개변수는 설명되지 않습니다.
그 중 임의의 문자열 : 밑줄을 없애기 위해 UUID를 사용합니다
public static String create_nonce_str() { return UUID.randomUUID().toString().replace("-",""); }
가맹점 주문번호 : 각 주문번호만 가능하며 사용됩니다 시스템의 주문 번호에 추가된 타임스탬프가 사용됩니다.
총액: 불가
알림 주소: WeChat 결제 성공 또는 실패 시스템에 대한 콜백 주소
서명:
import java.io.Serializable; public class PayInfo implements Serializable{ private static final long serialVersionUID = L; private String appid; private String mch_id; private String device_info; private String nonce_str; private String sign; private String body; private String attach; private String out_trade_no; private int total_fee; private String spbill_create_ip; private String notify_url; private String trade_type; private String openid; //下面是get,set方法 } /** * 创建统一下单的xml的java对象 * @param bizOrder 系统中的业务单号 * @param ip 用户的ip地址 * @param openId 用户的openId * @return */ public PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) { PayInfo payInfo = new PayInfo(); payInfo.setAppid(Constants.appid); payInfo.setDevice_info("WEB"); payInfo.setMch_id(Constants.mch_id); payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", "")); payInfo.setBody("这里是某某白米饭的body"); payInfo.setAttach(bizOrder.getId()); payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss"))); payInfo.setTotal_fee((int)bizOrder.getFeeAmount()); payInfo.setSpbill_create_ip(ip); payInfo.setNotify_url(Constants.notify_url); payInfo.setTrade_type("JSAPI"); payInfo.setOpenid(openId); return payInfo; }
서명 받기:
/** * 获取签名 * @param payInfo * @return * @throws Exception */ public String getSign(PayInfo payInfo) throws Exception { String signTemp = "appid="+payInfo.getAppid() +"&attach="+payInfo.getAttach() +"&body="+payInfo.getBody() +"&device_info="+payInfo.getDevice_info() +"&mch_id="+payInfo.getMch_id() +"&nonce_str="+payInfo.getNonce_str() +"¬ify_url="+payInfo.getNotify_url() +"&openid="+payInfo.getOpenid() +"&out_trade_no="+payInfo.getOut_trade_no() +"&spbill_create_ip="+payInfo.getSpbill_create_ip() +"&total_fee="+payInfo.getTotal_fee() +"&trade_type="+payInfo.getTrade_type() +"&key="+Constants.key; //这个key注意 MessageDigest md = MessageDigest.getInstance("MD"); md.reset(); md.update(signTemp.getBytes("UTF-")); String sign = CommonUtil.byteToStr(md.digest()).toUpperCase(); return sign; }
참고: 위의 Constants.key 값은 판매자 계정 API 보안의 API 키에 있습니다.
일부 도구 방법: IP 주소 가져오기, 바이트 배열을 16진수 문자열로 변환, 바이트를 16진수 문자열로 변환
/** * 将字节数组转换为十六进制字符串 * * @param byteArray * @return */ public static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = ; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * 将字节转换为十六进制字符串 * * @param btyes * @return */ public static String byteToHexStr(byte bytes) { char[] Digit = { '', '', '', '', '', '', '', '', '', '', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[]; tempArr[] = Digit[(bytes >>> ) & XF]; tempArr[] = Digit[bytes & XF]; String s = new String(tempArr); return s; } /** * 获取ip地址 * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { InetAddress addr = null; try { addr = InetAddress.getLocalHost(); } catch (UnknownHostException e) { return request.getRemoteAddr(); } byte[] ipAddr = addr.getAddress(); String ipAddrStr = ""; for (int i = ; i < ipAddr.length; i++) { if (i > ) { ipAddrStr += "."; } ipAddrStr += ipAddr[i] & xFF; } return ipAddrStr; }
여기 방식으로 서명을 획득하면 PayInfo에 있는 서명 및 기타 데이터가 XML 형식으로 변환되어 통합 주문 주소에 매개변수로 전달됩니다.
PayInfo pi = pu.createPayInfo(bo,"...",""); String sign = pu.getSign(pi); pi.setSign(sign);
객체를 XML로
/** * 扩展xstream使其支持CDATA */ private static XStream xstream = new XStream(new XppDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) { //增加CDATA标记 boolean cdata = true; @SuppressWarnings("rawtypes") public void startNode(String name, Class clazz) { super.startNode(name, clazz); } protected void writeText(QuickWriter writer, String text) { if (cdata) { writer.write("<![CDATA["); writer.write(text); writer.write("]]>"); } else { writer.write(text); } } }; } }); public static String payInfoToXML(PayInfo pi) { xstream.alias("xml", pi.getClass()); return xstream.toXML(pi); }
xml을 Map으로
@SuppressWarnings("unchecked") public static Map<String, String> parseXml(String xml) throws Exception { Map<String, String> map = new HashMap<String, String>(); Document document = DocumentHelper.parseText(xml); Element root = document.getRootElement(); List<Element> elementList = root.elements(); for (Element e : elementList) map.put(e.getName(), e.getText()); return map; }
다음은 통합주문 호출 URL입니다
log.info(MessageUtil.payInfoToXML(pi).replace("__", "_")); Map<String, String> map = CommonUtil.httpsRequestToXML("https://api.mch.weixin.qq.com/pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("<![CDATA[", "").replace("]]>", "")); log.info(map); public static Map<String, String> httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) { Map<String, String> result = new HashMap<>(); try { StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr); result = MessageUtil.parseXml(buffer.toString()); } catch (ConnectException ce) { log.error("连接超时:"+ce.getMessage()); } catch (Exception e) { log.error("https请求异常:"+ece.getMessage()); } return result; }
httpsRequest() 이 메소드는 첫 번째 글에 있습니다
위에서 얻은 Map이 성공하면
String return_code = map.get("return_code"); if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){ String return_msg = map.get("return_msg"); if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) { return "统一下单错误!"; } }else{ return "统一下单错误!"; } String prepay_Id = map.get("prepay_id");
이 prepay_id가 선불 ID입니다. 나중에 결제할 때 필요합니다.
WeChat 공용 계정 결제(2) 통합 주문 인터페이스 구현과 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!