El pago de WeChat se ha vuelto cada vez más popular ahora, y hay muchos productos que pueden acceder rápidamente al pago de WeChat. Sin embargo, además de ser convenientes, también nos hace depender gradualmente de terceros para hacer cosas y perder la capacidad de pensar de forma independiente. Esta vez, planeamos compartir el pago de WeChat que he desarrollado antes.
1. Pago de cuenta oficial H5
Puntos clave: obtenga correctamente OpenID y unifique la interfaz única, procese correctamente las notificaciones de los resultados del pago y configure correctamente el directorio de autorización de pago
El método de pago de H5 es un método ampliamente utilizado. Este método de pago se utiliza principalmente para páginas web con menús personalizados en WeChat. Se basa en el cliente WeChat instalado en el teléfono móvil. Solo versiones más altas de WeChat apoyan el pago de WeChat. Tenga en cuenta las siguientes instrucciones para seguir mi proceso.
1. Escriba una página para el pago, porque es una prueba, es un poco más simple.
<%@ página lenguaje = "java" import = "java.util.*" pageEncoding = "utf-8"%> <%string path = requit.getContextPath (); String basepath = request.getScheme ()+": //"+request.getServerName ()+":"+request.getServerPort ()+ruta+"/"; %> < < Action = "ScancodePayservlet? Flag = CreateCode" Method = "Post"> Número de pedido: <input type = "text" name = "ordenno"/> <input type = "subt" value = "escane el código para pagar"/> </form> </body> </html>
2 Escriba un servlet para obtener código a través de OAuth
paquete com.debug.weixin.servlet; import java.io.ioException; import java.io.printwriter; import javax.servlet.requestdispatcher; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import com.debug.weixin.util.commonutil; import com.debug.weixin.util.serverconfig; La clase pública OAuthServlet extiende httpservlet {public void doget (httpservletRequest solicitud, respuesta httpservletResponse) lanza ServletException, ioexception {this.dopost (solicitud, respuesta); } public void dopost (httpservletRequest solicitud, respuesta httpservletResponse) lanza ServletException, ioexception {string ordenno = request.getParameter ("OrderNo"); // llame a WeChat Oauth2.0 para obtener String OpenID redirecturl = serverConfig.ServerDomain+"/Basicweixin/PayServletForH5? OrderNo ="+OrderNo; Cadena redirecturi = ""; Pruebe {redirecturi = CommonUtil.initopenID (redirecturl); } Catch (Exception e) {// TODO Auto Generado Bloque E.PrintStackTrace (); } //System.out.println(redirecturi); // requestdispatcher dis = requit.getRequestDispatcher (redirecturi); //dis.forward(Request, respuesta); respuesta.sendedirect (redirecturi); }} 3 Después de obtener el código, obtenga OpenID a través de redirecturi y llame a la interfaz única unificada
paquete com.debug.weixin.servlet; import java.io.ioException; import java.io.printwriter; import java.util.sortedmap; import java.util.Treemap; import javax.servlet.requestdispatcher; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; import com.debug.weixin.pojo.weixinoauth2token; import com.debug.weixin.pojo.weixinqrcode; import com.debug.weixin.util.Advancedutil; import com.debug.weixin.util.commonutil; import com.debug.weixin.util.configutil; import com.debug.weixin.util.paycommonutil; La clase pública PayServletforH5 extiende httpservlet {public void doget (httpservletRequest solicitud, respuesta httpservletreSponse) lanza ServletException, ioexception {this.dopost (solicitud, respuesta); } public void dopost (httpservletRequest solicitud, respuesta httpservletResponse) lanza ServletException, ioexception {string ordenno = request.getParameter ("OrderNo"); Código de cadena = request.getParameter ("código"); // Get AccessToken Weixinauth2Token Token = Advancedutil.getOauth2AccessToken (configUtil.appid, configUtil.app_secrect, código); Cadena OpenId = token.getOpenId (); // Llamando a la interfaz de pago unificada WeChat SortedMap <Object, Object> Parameters = new Treemap <Object, Object> (); parámetros.put ("appid", configUtil.appid); parámetros.put ("mch_id", configUtil.mch_id); parámetros.put ("dispositivo_info", "1000"); parámetros.put ("cuerpo", "mi orden de prueba"); parámetros.put ("nonce_str", payCommonUtil.createNoncestr ()); parámetros.put ("out_trade_no", ordenno); //parameters.put("Total_Fee ", String.ValueOf (Total)); parámetros.put ("Total_fee", "1"); parámetros.put ("spbill_create_ip", request.getRemoteaddr ()); parámetros.put ("notify_url", configUtil.notify_url); parámetros.put ("trade_type", "jsapi"); parámetros.put ("OpenID", OpenID); String Sign = PayCommonUtil.CreateSign ("UTF-8", parámetros); parámetros.put ("firmar", firmar); Cadena requestXml = payCommonUtil.getRequestXml (parámetros); Resultado de cadena = CommonUtil.httpsRequestForStr (configUtil.unified_order_url, "post", requestXml); System.out.println ("----------------------------------"); System.out.println (resultado); System.out.println ("----------------------------------"); request.setAttribute ("Orderno", OrderNo); request.setAttribute ("TotalPrice", "0.01"); String payJson = ""; intente {payJson = CommonUtil.geth5payStr (resultado, solicitud); } Catch (Exception e) {// TODO Auto Generado Bloque E.PrintStackTrace (); } //System.out.println(payJson); request.setAttribute ("unifiedOrder", payJson); RequestDispatcher dis = requit.getRequestDispatcher ("h5pay.jsp"); dis.forward (solicitud, respuesta); }} Llamar a WeChat para unificar una sola interfaz requiere atención al algoritmo de firma. Solo cuando el cálculo de la firma es correcto puede ser el pago sin problemas
public static String geth5payStr (resultado de cadena, solicitud httpservletrequest) lanza la excepción {map <string, string> map = xmlutil.doxmlParse (resultado); SortedMap <Object, Object> Params = new Treemap <Object, Object> (); params.put ("appid", configUtil.appid); params.put ("timestamp", long.ToString (nuevo date (). getTime ())); params.put ("non -CESTR", PayCommonutil.CreateNoncestr ()); params.put ("paquete", "prepay_id ="+map.get ("prepay_id")); params.put ("FIRMTYPE", configUtil.sign_type); String paySign = payCommonUtil.CreateSign ("UTF-8", params); params.put ("PaySign", PaySign); // Las reglas de generación de PaySign son consistentes con las reglas de generación de la cadena de signo JSON = jsonObject.FromObject (params) .ToString (); regresar json; } 4 Escriba la interfaz de pago final para ajustar el pago de WeChat H5
<%@ página lenguaje = "java" import = "java.util.*" pageEncoding = "utf-8"%> <%string path = requit.getContextPath (); String basepath = request.getScheme ()+": //"+request.getServerName ()+":"+request.getServerPort ()+ruta+"/"; %> <! DocType html público "-// w3c // dtd html 4.01 transitional // en"> <html> <fead> <base href = "<%= basepath%>"> <title> wechat h5 pago </title> <meta name = "visual" contenido = "width = dispositivo width, inicial-scale = 1.0, MaximumeS, MaximumeSscal. <script type = "text/javaScript"> function jsapicall () {weixinjsbridge.invoke ('getBrandwcpayRequest', <%= (string) request.getAttribute ("unifiedOrder")%>, function (res) {weixinjsbridge.log (res.err_msg); //alert(res.err_code+res.err_desc+res.err_msg); } function callPay () {if (typeOf weixInjsbridge == "Undefined") {if (document.adDeventListener) {document.adDeventListener ('weixinjsbridgeReady', jsapicall, falso); } else if (document.attachevent) {document.attachevent ('weixinjsbridgeReady', jsapicall); document.attachevent ('onweixinjsbridgeReady', jsapicall); }} else {jsapicall (); }} </script> </head> <body> <input type = "button" value = "pay" onClick = "callPay ()"/> </body> </html> 5. Procesamiento de la notificación de resultados de pagos de WeChat
paquete com.debug.weixin.servlet; import java.io.bytearrayOutputStream; import java.io.ioException; import java.io.inputstream; import java.io.printwriter; import java.util.map; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; importar org.jdom.jdomexception; import com.debug.weixin.util.paycommonutil; import com.debug.weixin.util.xmlutil; Public Class PayHandlerServlet extiende httpservlet {public void doget (httpservletRequest solicitud, respuesta httpservletResponse) lanza ServletException, ioexception {this.dopost (solicitud, respuesta); } public void dopost (httpservletRequest solicitud, respuesta httpservletResponse) lanza ServletException, ioexception {inputStream InSteam = request.getInputStream (); ByteArRayOutputStream OutSteam = new ByteArRaReOutputStream (); byte [] buffer = new Byte [1024]; int len = 0; while ((len = instramp.read (buffer))! = -1) {OutSteam.Write (buffer, 0, len); } OutSteam.Close (); Intileam.close (); String result = new String (OutSteam.TobyTearray (), "UTF-8"); // Obtenga la información de retorno de WeChat llamando a nuestro mapa notify_url <objeto, objeto> map = null; intente {map = xmlutil.doxmlParse (resultado); } Catch (JDomException e) {// toDO Auto Generated Catch Block E.PrintStackTrace (); } para (Object KeyValue: MAP.KeySet ()) {System.out.println (keyValue+"="+map.get (keyValue)); } if (map.get ("result_code"). ToString (). EqualSignorECase ("Success")) {// Operaciones comerciales en pedidos System.out.println ("--------------------------- OK"); Response.getWriter (). Write (PayCommonUtil.SetXml ("éxito", "")); // dígale al servidor WeChat que recibí el mensaje, no llame a la acción de devolución de llamada}}} Para el código anterior, muchos de ellos se refieren a http://blog.csdn.net/u011160656/article/details/41759195, por lo que esta parte del código no se publicará. Si lo necesita, lo sabrá leyendo este blog.
2. Código de escaneo de WeChat para pagar (modo 1)
Puntos clave: debe llamar al enlace largo a la interfaz de enlace corto y configurar correctamente el código de escaneo para pagar la URL de devolución de llamada
1 Generar el código QR de pago WeChat basado en el número de pedido
Aquí hay algunas formas de generar códigos QR:
paquete com.debug.weixin.util; import com.google.zxing.common.bitmatrix; import javax.imageio.imageio; import java.io.file; import java.io.outputstream; import java.io.ioException; import java.awt.image.bufferedImage; Public Final Class MatriXteoImageWriter {private static final int Black = 0xff000000; privado estático final int white = 0xfffffff; privado matriMmoImageWriter () {} public static bufferedImage TobufferedImage (BitMatrix Matrix) {int width = matrix.getWidth (); int hight = matrix.getheight (); Bufferedimage imagen = nueva bufferedimage (ancho, altura, bufferedimage.type_int_rgb); for (int x = 0; x <width; x ++) {for (int y = 0; y <height; y ++) {image.setrgb (x, y, matrix.get (x, y)? negro: blanco); }} imagen de retorno; } public static void writeToFile (BitMatrix Matrix, String Format, File File) lanza IOException {BufferedImage Image = TobufferedImage (matriz); if (! imageio.write (imagen, formato, archivo)) {throw new ioException ("no podría escribir una imagen de formato" + formato + "a" + archivo); }} public static void writeToStream (matriz de bitmatrix, formato de cadena, transmisión de salida) lanza ioexception {bufferedImage image = tobufferedImage (matriz); if (! ImageIO.Write (Image, Format, Stream)) {Throw New IoException ("No se pudo escribir una imagen de formato" + formato); }}} Esta es una clase de herramientas, y hay otro método para mostrar el código QR en la interfaz. CreateQRCode utiliza principalmente bloques de código:
public static void createCodeStream (texto de cadena, respuesta httpservletreSponse) lanza la excepción {// respuesta.setContentType ("Image/jpeg"); ServLetOutputStream SOS = Response.getOutputStream (); int ancho = 500; int altura = 500; // QR Código Formato de formato de imagen Formato = "JPG"; MultiformAtWriter MultiformAtWriter = new MultiformAtWriter (); Sugerencias de mapas = new HashMap (); // el insinuado codificado (encodeHintType.character_set, "UTF-8"); BitMatrix bitMatrix = MultiformAtWriter.Encode (Text, BarCodeFormat.qr_code, ancho, altura, sugerencias); // Generar el código QR matrixteoImageWriter.writeToStream (bitmatrix, format, sos); sos.close (); } 2. Para convertir enlaces largos a enlaces cortos para generar códigos QR, escriba un método de devolución de llamada de pago de código de escaneo y llame a la interfaz única unificada
paquete com.debug.weixin.servlet; import java.io.bytearrayOutputStream; import java.io.ioException; import java.io.inputstream; import java.io.printwriter; import java.util.date; import java.util.map; import java.util.sortedmap; import java.util.Treemap; import javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletRequest; import javax.servlet.http.httpservletResponse; importar org.jdom.jdomexception; import com.debug.weixin.util.commonutil; import com.debug.weixin.util.configutil; import com.debug.weixin.util.createqrcode; import com.debug.weixin.util.paycommonutil; import com.debug.weixin.util.xmlutil; import com.mongodb.dbobject; La clase pública ScancodepayServlet extiende httpservlet {public void doget (httpservletRequest solicitud, respuesta httpServletResponse) lanza ServletException, ioexception {this.dopost (solicitud, respuesta); } public void dopost (httpservletRequest solicitud, respuesta httpservletreSponse) lanza ServletException, ioexception {string flag = request.getParameter ("flag"); if ("createCode" .equals (flag)) {createPayCode (solicitud, respuesta); } else {try {wxscancodeHandler (solicitud, respuesta); } Catch (Exception e) {// TODO Auto Generado Bloque E.PrintStackTrace (); }}} public void CreatePayCode (HttpServletRequest solicitud, respuesta httpServletResponse) {string ordenno = request.getParameter ("ordenno"); SortedMap <Object, Object> paras = new Treemap <Object, Object> (); paras.put ("appid", configUtil.appid); paras.put ("mch_id", configUtil.mch_id); Paras.put ("Time_stamp", long.ToString (nueva fecha (). getTime ())); paras.put ("nonce_str", paycommonutil.createNoncestr ()); Paras.put ("Product_id", OrderNo); // El número de producto debe ser único firma de cadena = PayCommonUtil.CreateSign ("UTF-8", Paras); Paras.put ("firmar", firmar); String url = "weixin: // wxpay/bizpayurl? Sign = firm & appid = appid & mch_id = mchid & product_id = productid & time_stamp = timestamp & nonce_str = nocestr"; Cadena nationalUrl = url.replace ("firmar", firmar) .replace ("appid", configUtil.appid) .replace ("mchid", configUtil.mch_id) .replace ("productid", (string) paras.get ("Product_id")). Reemplazar ("Timestamp", (String) (String) paras.get ("nonce_str")); SortedMap <Object, Object> Parameters = new Treemap <Object, Object> (); parámetros.put ("appid", configUtil.appid); parámetros.put ("mch_id", configUtil.mch_id); parámetros.put ("nonce_str", payCommonUtil.createNoncestr ()); parámetros.put ("long_url", CommonUtil.urlencodeutf8 (nationalUrl)); Cadena sign2 = payCommonUtil.createSign ("UTF-8", parámetros); parámetros.put ("firmar", sign2); Cadena requestXml = payCommonUtil.getRequestXml (parámetros); Resultado de cadena = CommonUtil.httpsRequestForStr (configUtil.short_url, "post", requestXml); Map <string, string> map = null; intente {map = xmlutil.doxmlParse (resultado); } Catch (JDomException e) {// toDO Auto Generated Catch Block E.PrintStackTrace (); } Catch (ioException e) {// tODO Auto Generated BLOCK E.PrintStackTRace (); } Cadena returncode = map.get ("return_code"); Cadena resultCode = map.get ("result_code"); if (returnCode.equalSignorEcase ("éxito") && resultCode.equalSignorEcase ("éxito")) {string shortUrl = map.get ("short_url"); // TODO Get ShortURL, escriba el código para generar el código QR System.out.println ("shorturl ="+shorturl); intente {createqrcode.createCodeStream (shorturl, respuesta); } Catch (Exception e) {// TODO Auto Generado Bloque E.PrintStackTrace (); }}} public void wxscancodeHandler (solicitud httpservletRequest, respuesta httpservletResponse) lanza la excepción {inputStream Insteam = request.getInputStream (); ByteArRayOutputStream OutSteam = new ByteArRaReOutputStream (); byte [] buffer = new Byte [1024]; int len = 0; while ((len = instramp.read (buffer))! = -1) {OutSteam.Write (buffer, 0, len); } OutSteam.Close (); Intileam.close (); String result = new String (OutSteam.TobyTearray (), "UTF-8"); // Obtenga la información de retorno de WeChat llamando a nuestro mapa notify_url <objeto, objeto> map = null; intente {map = xmlutil.doxmlParse (resultado); } Catch (JDomException e) {// toDO Auto Generated Catch Block E.PrintStackTrace (); } para (Object KeyValue: MAP.KeySet ()) {System.out.println (keyValue+"="+map.get (keyValue)); } String ordenno = map.get ("product_id"). ToString (); // Después de recibir el parámetro de solicitud, llame a la interfaz única unificada sortedmap <objeto, objeto> parámetros = new Treemap <Object, Object> (); parámetros.put ("appid", configUtil.appid); parámetros.put ("mch_id", configUtil.mch_id); parámetros.put ("dispositivo_info", "1000"); parámetros.put ("cuerpo", "código de prueba para pagar el orden"); parámetros.put ("nonce_str", payCommonUtil.createNoncestr ()); parámetros.put ("out_trade_no", map.get ("product_id")); //parameters.put("Total_Fee ", String.ValueOf (TotalPrice)); parámetros.put ("Total_fee", "1"); parámetros.put ("spbill_create_ip", request.getRemoteaddr ()); parámetros.put ("notify_url", configUtil.notify_url); parámetros.put ("trade_type", "nativo"); parámetros.put ("OpenID", map.get ("OpenID")); String Sign = PayCommonUtil.CreateSign ("UTF-8", parámetros); parámetros.put ("firmar", firmar); Cadena requestXml = payCommonUtil.getRequestXml (parámetros); Cadena result2 = CommonUtil.httpsRequestForStr (configUtil.unified_order_url, "post", requestXml); System.out.println ("----------------------------- 统一下单结果 ---------------------------"); System.out.println (resultado2); Map <string, string> mm = null; intente {mm = geth5paymap (resultado2, solicitud); } Catch (Exception e) {// TODO Auto Generado Bloque E.PrintStackTrace (); } // string prepayId = getPrePayId (resultado2, solicitud); // cadena returnnonestr = getReturnnonestr (resultado2, solicitud); Cadena prepayId = mm.get ("prepay_id"); Cadena returnnonestr = mm.get ("nonce_str") ;; SortedMap <Object, Object> LastSign = new Treemap <Object, Object> (); dastSign.put ("return_code", "éxito"); lastsign.put ("appid", configUtil.appid); dastSign.put ("mch_id", configUtil.mch_id); lastsign.put ("nonce_str", returnnonestr); dastSign.put ("prepay_id", prepayId); dastSign.put ("result_code", "éxito"); dastSign.put ("Key", configUtil.api_key); String LastSignpara = PayCommonUtil.CreateSign ("UTF-8", LastSign); StringBuffer buf = new StringBuffer (); buf.append ("<xml>"); buf.append ("<Surne_Code> Success </return_code>"); buf.append ("<ppid>"+configUtil.appid+"</appid>"); buf.append ("<Mch_id>"+configUtil.mch_id+"</mch_id>"); buf.append ("<Mch_id>"+configUtil.mch_id+"</mch_id>"); buf.append ("<Nince_str>"+returnnonestr+"</ nonce_str>"); buf.append ("<PREPAY_ID>"+PrepayId+"</pray_id>"); buf.append ("<resultado_code> éxito </resultado_code>"); buf.append ("<girm>"+LastSignpara+"</sign>"); buf.append ("</ xml>"); respuesta.getWriter (). print (buf.ToString ()); } public Map <String, String> Geth5PayMap (resultado de cadena, solicitud httpservletRequest) lanza la excepción {map <string, string> map = xmlutil.doxmlparse (resultado); mapa de retorno; }}Finalmente, echemos un vistazo a la configuración de WeChat para el pago oficial de la cuenta y el pago del código de escaneo:
Espero que a través de este artículo, todos puedan entender que incluso si usa Java para hacer cuentas públicas de WeChat y el pago de WeChat sin usar el código de trampa proporcionado por GitHub, puede desarrollar aplicaciones WeChat que lo satisfagan a usted y a sus clientes. Aunque las demostraciones dadas por WeChat son todas PHP, todas estas son nubes. El lenguaje de desarrollo es el segundo, y comprender la capa subyacente que requiere la interfaz es solo un curso obligatorio para los programadores.