He estado estudiando el pago del código QR de Alipay hace un tiempo. Tengo que decir que el documento Alipay es realmente malo (al menos fue de Mengbi cuando lo leí por primera vez). Los ejemplos anteriores al documento se ven completamente diferentes de los ejemplos de la demostración. A menudo, los ejemplos anteriores al documento son muy simples, mientras que el código de demostración es muy complicado, por lo que no sabía qué código usar al principio. Más tarde, miré cuidadosamente el código en el paquete de demostración y descubrí que también se llamaban las interfaces de los ejemplos de documentos. Solo entonces me di cuenta de que eran lo mismo, pero la demostración solo envolvió las interfaces del documento.
Primero, solicite una cuenta Alipay de una empresa. Esta cuenta tiene un PID y debe agregar una aplicación a esta cuenta. Cada aplicación tiene una aplicación y una clave pública y privada. Las claves públicas y privadas se pueden generar a través de herramientas proporcionadas por Alipay. Además, los desarrolladores de Java deben usar claves privadas en formato PKCS6. Si la aplicación necesita usar la función de escaneo, es necesario agregar la opción de pago en persona en la aplicación, que requiere firmar un contrato. Después de firmar la función de pago en persona, no se puede usar directamente porque la aplicación debe estar en línea antes de que pueda usarse. Por lo tanto, puede usar la versión Sandbox de la aplicación durante el desarrollo. Alipay proporciona la versión Sandbox de Gateway, Alipay Public Key, PID y AppID, que deben modificarse durante la configuración.
El código puede usar directamente el código en la demostración, primero importar la API proporcionada por Alipay en el proyecto (tenga en cuenta que no es el código de demostración) y luego importe el código de demostración, como se muestra en la figura:
Este archivo com.alipay.demo.trade.main se puede ejecutar directamente, pero se debe configurar un archivo de recursos:
# Nombre de puerta de enlace de Alipay, PartnerId y Appid# Esta es la puerta de enlace para el entorno Sandbox Open_api_domain = https://openapi.alipaydev.com/gateway.domcloud_api_domain = http://mcloudmonitor.com/gateway.do#. En el AppIdAppid para su entorno Sandbox en persona aquí = 2016082000300485 # RSA Key private, clave pública y clave pública Alipay # Complete su clave privada comercial aquí y transfiera a PKCS8 format private_key = Miiceqibadanbgkqhkig9w0baqefaascammwggjfageaaogbamkxzrfr+rnvygbs9qz2ce1mcsibreaqan+5pf5+02hyj4hzcnttwqhfm91ih 3WyPyHPM7XLBGJ5YWJTGC4G1LZ75R8A+UCYUXP8BY1LV/44GI/TIFLSGATFQ73OCM9IMXOCRDYZ2ZCWQI1GV+B3UDOY/DA5W07GRWIZFZS6VQ 1RAGMbaAECGYEAQHHC4GRBSRCKEINYTK1VHQCJ0YG11LVY85Z3SI0FNY26DVS8R5GFYDZC/MX5F8RNPUUYUHQN+4CQOR3D/C291X1ITOV2NEVEV Lhejroudknp4oqriqt2w9pz8rzwzp2jcwvrvuf4ztpeimpppmorp6Sprfx6dlzg29sfi6gzwu6tkcqqdp3Mim1bhus3yonezgqc69zn0/dgofk EIX0S18QAU1X4I1FEJVTKY4HPDWIHPGYAJM0UFG1LK8MTIUNHPZRCNAKEA1QF6U1AKJM6ZSVDENRXEDTCC75UVJGSYFJHHHX9PJYD9VX8NSZVV 0Z0U4V0ZG0N0YVHJ5LRO6U5FCQFRW1WIXNQJBALMCKZ8SVF/H9N6LIWMSPY6W5Q82KNRLRC7WSCENSPQT0WQL5+SACG98M0XY5J1HMIOLHXG CTVYRIXOWOBIVQCQQCTNANB4UZ3Q/86R/KUKBVD3DIRWLFRYAHO6YXP8OY+JE/BV/359+VR3CXZYYLDHZOR9/TVSPWR/Y9Q4JLEM Q1takealbu7+4Edzfap7e/fmgykd5dml8h2iaeumrrcpl84ghffk/7psq/40ngkxptgy44nlelhxcrpw5czu6gqdinjoa ==#por favor Complete su comerciante public_key aquí = Migfma0gcsqgsibdqebaquaa4gnadcbiqkbgqdcl2axufq572iabpas9nbnzgkiauxmqmp/ut3+ftnh8o+b83du01qhxzvdsb98gd8oato15w4 Ceclibyauinzc ++ a/gvlasrst/g8ts1f+obov0yhy0oae30o9zndpypl6hexwm9mqskotyffm91a6mvw2ucno4evosxc0ulatawidaqab#this esto es la clave pública del entorno sandbox alipay_public_key = Migfma0gcsqgsib3dqebaquaaa4gnadcbiqkbgqdighnon7llillketd6bfrj0gqgs2y3mn1wmqmyh9zeywlz5p1zrahrahbxafsqshsnfq OMAQZSHRVJCQJSAW1JYQRXAPDKBMR90DIPIXMIYKXV4GGAKPYJ/6FTFY99UHPIQ0QADD/USZQSEFWO0ATVP/65ZI3EOF7TCZ32OWPWIDEQAB# Número máximo de consultas e intervalo de consulta (milisegundos) max_query_retry = 5query_duration = 5000# número máximo de desaceleraciones e intervalos de ruina (ms) en persona max_cancel_cretry = 3cancel_duration = 2000# garantía de transacción Primer retraso de retraso y programación (segundos) Heartbeat_delayy
Luego ejecute el archivo main.java. En cuanto al código de pago para el código de escaneo en nuestra aplicación real, podemos copiar directamente la función test_trade_precreate () en el archivo main.java y crear una función en el controlador:
@RequestMapping (value = "/pay/alipay", método = requestmethod.post) public map <string, string> alipay (@requestparam String cantidad, @requestparam int userId) {map <string, string> map = new Hashmap <String, String> (); // (requerido) El número de pedido único en el sistema de pedido del sitio web comercial, con solo 64 caracteres, solo puede contener letras, números y subrayos. // es necesario asegurarse de que el sistema comercial no se pueda repetir. Se recomienda generarlo a través de la secuencia de la base de datos, string outtradeno = "xxxxx" + system.currentTimemillis () + (long) (math.random () * 10000000l); // (requerido) Título del pedido, describe aproximadamente el propósito de pago del usuario. Por ejemplo, "la marca xxx xxx store paga en persona y escanea el código para consumir" string stem = "pay"; // (requerido) El monto total del pedido es de 100 millones de RMB, y no puede exceder los 100 millones de RMB // si [cantidad con descuento], [no con descuento] y [cantidad total del pedido] se transmiten al mismo tiempo, se deben cumplir las siguientes condiciones: [Monto total de pedido] = [Monto con descuento] + [Cantidad no descuidada] Total de cadena = Cantidad; // (opcional) El pedido no puede descartarse y puede configurarse con la plataforma comercial para configurar actividades de descuento. Si el alcohol no participa en el descuento, el monto correspondiente se llenará en este campo // si el valor no se transmite, pero [la cantidad total de pedidos] y [la cantidad con descuento] se transmiten, el valor predeterminado a [cantidad total de pedidos]-[Cantidad con descuento] Cadena undiscountableAnt = "0"; // La ID de cuenta Alipay del Vendedor se utiliza para admitir el pago a diferentes cuentas de pago bajo una cuenta de contrato (pague a la cuenta de Alipay correspondiente a SellerID) // Si este campo está vacío, por defecto al PID del comerciante firmado con Alipay, es decir, el PID correspondiente al String String SellerID = "208810217232983"; // Descripción del pedido, puede describir la transacción o producto de manera detallada, como completar "2 compras de 2 artículos en total 15.00 yuan" string body = "3 compras de 3 artículos en total 20.00 yuanes"; // Número de operador comercial, agregue este parámetro para hacer estadísticas de ventas para el operador comercial de operadores OperatorId = "test_operator_id"; // (requerido) Número de tienda comercial, a través del número de tienda y el backend comercial, puede configurar la información de descuento en la tienda con precisión. Para obtener más detalles, consulte al soporte técnico de Alipay String StoreID = "2088102172329883"; // Parámetros de expansión empresarial, actualmente puede agregar el número de proveedor del sistema asignado por Alipay (a través del método SetSysServiceProviderId). Para obtener más detalles, consulte al soporte técnico de Alipay ExtendParams ExtendParams = new ExtendParams (); ExtendParams.SetSysServiceProviderId ("2088100200300400500"); // Tiempo de espera de pago, definido como 120 minutos de cadena TimeOutExpress = Timeout; // // Lista de detalles del producto, debe completar los detalles del producto de compra, // List <GoodsDetail> GoodsDetaillist = New ArrayList <GoodsDetail> (); // // Crear información de producto, los parámetros son la identificación del producto (utilizando el nivel nacional), el nombre, el precio de la unidad (la unidad en los puntos), y la cuota y la cuota. Si necesita agregar categorías de productos, consulte GoodsDetail // GoodsDetail Goods1 = GoodsDetail.newinstance ("Goods_id001", "xxx Small Bread", 1000, 1); // // Agregar a la lista de detalles del producto después de crear un producto // Detaillist.add (Bods1); //////////////poco continuado creando y agregue la primera información del producto. El producto comprado por el usuario es "cepillo de dientes negro", con un precio unitario de 5.00 yuanes. Compré dos piezas // bienes de deta de bien // Cree un código de escaneo para pagar al constructor de solicitudes, establezca los parámetros de solicitud alipaytradePreatreaterEctBuilder builder = new AlipaytradePreateRequestBuilder () .SetSubject (Sujeto). .SetBody (Body) .SetOperatorId (OperatorId) .SetStoreId (StoreID) .SetExtendParams (ExtendParams) .SetTimeOutExpress (TimeOutExpress) .SetNotifyUrl ("http://xxx.xx.xxxxxxxxxxx:8080/BeboobiaO/pay/notify"); ruta HTTP especificada en el servidor comercial. Establecido según sea necesario. Aquí establecemos una interfaz que nos escribimos. Lo presentaremos más tarde. // .setgoodsdetaillist (GoodsDetaillist); Alipayf2fprecreatreeSult date = TradeService.tradepRecreate (constructor); switch (result.getTradeStatus ()) {Case Success: Log.info ("Alipay pre-ordenado con éxito :)"); System.out.println ("Alipay pre-ordenado con éxito :)"); AlipaytradepRecreaterSponse respuesta = resultado.getResponse (); // dumesponse (respuesta); // system.out.println (respuesta.getBody ()); // // debe modificarse en la ruta en la máquina en ejecución de la máquina en ejecución filePath = string.format ("/usuarios/liuyangly/qr-%s.png", respuesta. log.info ("filepath:" + filepath); // zxingutils.getqrcodeimge (respuesta.getqrcode (), 256, filepath); // system.out.println (respuesta.getqrcode ()); // Generar un pedido e insertar la base de datos Baobiaoorder Order = new Baobiaoorder (UserID, Outtradeno, "", Double.ParsedOuble (cantidad), nueva fecha (), 1); baobiaoorderservice.insertorder (orden); map.put ("estado", "verdadero"); map.put ("qrcode", respuesta.getqrcode ()); // Regrese al código Código QR del cliente MAP.put ("Outtradeno", Outtradeno); mapa de retorno; Falló el caso: log.error ("Alipay pre-pedido!"); System.out.println ("Alipay pre-pedido!"); System.out.println (result.getResponse (). GetBody ()); romper; Caso desconocido: log.error ("Excepción del sistema, estado de pedido anticipado desconocido !!!"); System.out.println ("Excepción del sistema, estado de pedido anticipado desconocido !!!"); romper; predeterminado: log.error ("estado de transacción no compatible, la transacción devuelve la excepción!"); System.out.println ("Estado de la transacción no compatible, la transacción devuelve la excepción!"); romper; } map.put ("estado", "falso"); map.put ("msg", "El sistema tiene una excepción, ¡inténtelo de nuevo más tarde!"); mapa de retorno; }La lógica es que el usuario escaneará el código en su teléfono móvil para pagar Alipay, y luego, después de que Alipay lo reciba, nos enviará un mensaje de pago exitoso para establecer notify_url, como se muestra a continuación:
@RequestMapping (valor = "/pay/notify", método = requestmethod.post) cadena pública notifyResult (httpservletRequest solicitud, respuesta httpservletreSponse) {log.info ("recibió notificación asíncrona de alipay!"); Map <string, string> params = new HashMap <String, String> (); // Recupere todos los parámetros para verificar la enumeración de la firma <String> parameternames = request.getParamEternames (); while (parameternames.hasmoreElements ()) {string parametername = parameternames.nextelement (); params.put (parametername, request.getParameter (parametername)); } boolean Signverified; Pruebe {Signverified = alipaysignature.rsacheckv1 (params, configs.getalipaypublickey (), "utf-8"); } Catch (Alipayapiexception e) {E.PrintStackTrace (); regresar "fallido"; } if (Signverified) {String ourtradeno = params.get ("out_trade_no"); log.info (Outtradeno + "Orden de notificación de devolución de llamada"); // System.out.println ("Verifique la firma con éxito!"); log.info ("Verifique la firma con éxito!"); // Si el APPID en el parámetro es diferente del APPID completado, es una notificación de excepción if (! Confects.getAppid (). Equals (params.get ("app_id")))) {log.warn ("diferente de la appid en el momento del pago, esto es una notificación de excepción y debe ignorarse!"); regresar "fallido"; } // Encuentre el pedido correspondiente al número de pedido en la base de datos y compare su cantidad con la cantidad en la base de datos. Si no coincide, también notificará la excepción del orden de Baobiaorder = Baobiaoorderservice.FindOrderBYOutTradeno (Outtradeno); if (orden == null) {log.warn (outtradeno + "Verifique este orden sin verificar!"); regresar "fallido"; } if (orden.getamount ()! = double.parsedubo (params.get ("total_amount"))) {log.warn ("diferente de la cantidad en el momento del pago, esta es una notificación de excepción y debe ignorarse!"); regresar "fallido"; } if (orden.getStatus () == baobiaoorder.trade_success) return "éxito"; // Si el pedido se ha pagado con éxito, ignore esta notificación String Status = params.get ("Trade_status"); if (status.equals ("wait_buyer_pay")) {// Si el estado está esperando el pago del usuario if (orden.getStatus ()! = baobiaoorder.wait_buyyer_pay) baobiaoorderservice.modifytradestatus (baobiaoorder.wait_buyer_pay, outtradeno);;;; } else if (status.equals("TRADE_CLOSED")) { //If the status is unpaid transaction timeout closed, or the payment is fully refunded if (order.getStatus() != BaobiaoOrder.TRADE_CLOSED) baobiaoOrderService.modifyTradeStatus(BaobiaoOrder.TRADE_CLOSED, outtradeno); } else if (status.equals ("trade_success") || status.equals ("trade_finished")) {// Si el estado se paga con éxito if (orden.getStatus ()! = baobiaorder.trade_success) baobiaoorderservice.modifytradestatus (baobiaoorder.trade_success, OuttradeRice, OuttradeNeService; } else {BaobiaoorderService.ModifyTradestatus (baobiaorder.unknown_state, outtradeno); } log.info (Outtradeno + "El estado del pedido se ha modificado a" + estado); } else {// Si la firma de verificación no pasa el retorno "falló"; } return "éxito"; }Este es probablemente el caso, pero hay menos notificaciones de pago exitoso al cliente, y también hay algunos problemas de seguridad.
Finalmente, resumamos los problemas encontrados en este proceso:
1. El código QR devuelto por Alipay no se puede abrir directamente en el navegador, pero debe usarse para convertir los códigos QR para generar códigos QR, o puede verlos a través del sitio web de CLI.IM.
2. El código QR generado por el entorno Alipay Sandbox solo se puede escanear utilizando la versión Sandbox del teléfono móvil Alipay. Si la versión normal de los escaneos de Alipay, el código QR caducará y se producirán otros errores.
3. Si no puede recibir la notificación asíncrona enviada por Alipay después del pago, puede usar Postman y otras herramientas para verificar si se puede acceder al Notify_URL que completó utilizando la IP pública.
4. Si encuentra el problema de los permisos de ISV insuficientes, es porque no hay firma de contrato o la aplicación no ha agregado las funciones correspondientes, y la aplicación no puede usarse sin en línea. Puede elegir una aplicación Sandbox durante el desarrollo.
5. Al registrar la versión Sandbox del teléfono móvil Alipay, puede comunicarse con el servicio al cliente para solicitar una cuenta
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.