위챗 공중번호 지불(二) 통합 주문 인터페이스 실현

전편 사용자의 OpenId가 확보되었습니다.
이 글은 주로 위챗 공중 결제의 통일된 주문 API를 호출하는 것이다
API 주소:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
문서를 보면 주요 절차는 20개 정도의 매개 변수를 XML 형식으로 봉하여 위챗에서 보낸 인터페이스 주소로 보내면 되돌아오는 내용을 얻을 수 있다. 성공하면 지불에 필요한 선불 ID가 있다
요청 매개 변수는 설명하지 않습니다.
여기서 랜덤 문자열: UUID를 사용하여 중간선을 그립니다

 public static String create_nonce_str() {
 return UUID.randomUUID().toString().replace("-","");
 }
상점 주문 번호: 매 주문 번호는 한 번만 사용할 수 있기 때문에 시스템의 주문 번호에 시간 스탬프를 추가합니다.
총 금액:
알림 주소: 위챗 결제 성공 또는 실패가 시스템에 전송된 주소
서명:

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()
   +"&notify_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 턴맵

 @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() 이 방법은 1편에서
위에서 얻은 맵이 성공하면 안에

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입니다.후불은 그것을 필요로 한다.

좋은 웹페이지 즐겨찾기