历时两周,终于把银联支付退款搞定了。由于没人指导,走了不少弯路,博主在此贴出相关代码,希望能帮到像我一样没人指导的小伙伴。

银联支付

1:支付,退款流程。


2:支付的相关准备

  1. 去官网下载sdk,官网相关地址会在本文结尾出提供
  2. 下载官网的测试配置文件acp_sdk.properties,测试相关证书acp_test_enc.cer,acp_test_sign.pfx,修改acp_sdk.properties后放在classpath下,如果要用生产环境,相关证书文件有四个,配置文件也有对应的生产环境证书。
  3. 如果支付成功后是跳转页面,则需要准备相关页面,如果是java代码拼接字符串,需要准备相关的java类,用来动态生产html页面。

3:支付,退款相关代码

1:代码结构

2:AutoLoadServlet

 import com.kemile.common.pay.chinapay.sdk.SDKConfig;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;/*** 功能:从应用的classpath下加载acp_sdk.properties属性文件并将该属性文件中的键值对赋值到SDKConfig类中 <br>* */
public class AutoLoadServlet extends HttpServlet {@Overridepublic void init(ServletConfig config) throws ServletException {SDKConfig.getConfig().loadPropertiesFromSrc();super.init();}
}

3:CharsetEncodingFilter

import com.kemile.common.pay.chinapay.config.ChinapayConfig;import java.io.IOException;import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public class CharsetEncodingFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {request.setCharacterEncoding(ChinapayConfig.encoding_UTF8);response.setContentType("text/html; charset="+ ChinapayConfig.encoding_UTF8);chain.doFilter(request, response);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}}

4:ChinapayConfig

import java.text.SimpleDateFormat;
import java.util.Date;public class ChinapayConfig {//商家号//public static String MERID = "777290058137116";//填自己网站相关的商家号//前台请求地址public static String FRONTURL = "fontrev";//后台请求地址public static String BACKURL = "backrev";//默认配置的是UTF-8public static String encoding_UTF8 = "UTF-8";//  public static String encoding_GBK = "GBK";//全渠道固定值public static String version = "5.0.0";// 商户发送交易时间 格式:YYYYMMDDhhmmsspublic static String getCurrentTime() {return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());}// AN8..40 商户订单号,不能含"-"或"_"public static String getOrderId() {return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());}/**招商银行借记卡:6226090000000048手机号:18100000000密码:111101短信验证码:123456(手机)/111111(PC)(先点获取验证码之后再输入)证件类型:01证件号:510265790128303姓名:张三*/
}

5:CYChinaPayController

@Controller
@RequestMapping(value = "/CYChinapay")
public class CYChinaPayController {Logger logger = Logger.getLogger(AliPayController.class);@Autowiredprivate IMobileCyDishorderService mobileCyDishorderService;//注入service@Autowiredprivate IMobileServiceStyleService mobileServiceStyleService;//支付@RequestMapping("/{order_nbr}")public String pay(@PathVariable String order_nbr, HttpServletRequest request, HttpServletResponse response) {String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();CyDishorderEntity order = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", order_nbr);Map<String, String> requestData = new HashMap<String, String>();requestData.put("version", ChinapayConfig.version);              //版本号,全渠道默认值requestData.put("encoding", ChinapayConfig.encoding_UTF8);              //字符集编码,可以使用UTF-8,GBK两种方式requestData.put("signMethod", "01");                          //签名方法,只支持 01:RSA方式证书加密requestData.put("txnType", "01");                          //交易类型 ,01:消费requestData.put("txnSubType", "01");                          //交易子类型, 01:自助消费requestData.put("bizType", "000201");                      //业务类型,B2C网关支付,手机wap支付requestData.put("channelType", "08");                      //渠道类型,这个字段区分B2C网关支付和手机wap支付;07:PC,平板  08:手机/***商户接入参数***/requestData.put("merId", ChinapayConfig.MERID);                  //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号requestData.put("accessType", "0");                          //接入类型,0:直连商户requestData.put("orderId", order_nbr);             //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则requestData.put("txnTime", ChinapayConfig.getCurrentTime());        //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效requestData.put("currencyCode", "156");                      //交易币种(境内商户一般是156 人民币)BigDecimal totPrice = null;//==========价格计算=========totPrice = new BigDecimal(order.getPayMoney());//查询价格requestData.put("txnAmt", String.valueOf((totPrice.multiply(new BigDecimal(100))).longValue())); //交易金额,单位分,不要带小数点try {//===============================//:TODO://=============================requestData.put("frontUrl", basePath + "/CYChinapay/" + ChinapayConfig.FRONTURL); //前台请求地址requestData.put("backUrl", basePath + "/CYChinapay/" + ChinapayConfig.BACKURL);  //后台请求地址logger.info("回调地址"+basePath + "/CYChinapay/" + ChinapayConfig.FRONTURL);logger.info("回调地址"+basePath + "/CYChinapay/" + ChinapayConfig.BACKURL);Map<String, String> submitFromData = AcpService.sign(requestData, ChinapayConfig.encoding_UTF8); //签名String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrlString html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData, ChinapayConfig.encoding_UTF8);   //生成自动跳转的Html表单//将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过response.getWriter().write(html);} catch (Exception e) {e.printStackTrace();}return null;}private static Map<String, String> valideData(HttpServletRequest req, HttpServletResponse resp) throws IOException {String encoding = req.getParameter(SDKConstants.param_encoding);// 获取银联通知服务器发送的后台通知参数Map<String, String> reqParam = getAllRequestParam(req);Map<String, String> valideData = null;if (null != reqParam && !reqParam.isEmpty()) {Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator();valideData = new HashMap<String, String>(reqParam.size());while (it.hasNext()) {Map.Entry<String, String> e = it.next();String key = (String) e.getKey();String value = (String) e.getValue();value = new String(value.getBytes(encoding), encoding);valideData.put(key, value);}}return valideData;}//后台请求地址@RequestMapping(value = "/backrev")public void BackRcv(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//Map<String,String> map=getAllRequestParam(request);logger.info("[进入银联支付回调方法]");String encoding = req.getParameter(SDKConstants.param_encoding);// 获取银联通知服务器发送的后台通知参数Map<String, String> reqParam = getAllRequestParam(req);//   LogUtil.printRequestLog(reqParam);Map<String, String> valideData = valideData(req, resp);PrintWriter out = null;out = resp.getWriter();//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过if (!AcpService.validate(valideData, encoding)) {logger.info("验证签名结果[失败].");out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "验证签名失败", Const.validateFaliUrl));} else {logger.info("验证签名结果[成功].");//【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态String respCode = valideData.get("respCode");if ("00".equals(respCode)) {//银联返回00代表支付成功//:TODO:该方法在用户支付成功后银联自动异步回调。此处可以写订单支付成功后的业务逻辑if (订单支付成功后) {resp.getWriter().print("ok");//这里一定要写响应。否则银联会认为商户后台没有收到回调信息。}}}LogUtil.writeLog("BackRcvResponse接收后台通知结束");}//前台请求地址@RequestMapping("/fontrev")public void fontrev(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setCharacterEncoding("utf-8");response.setContentType("text/html; charset=utf-8");//设置编码PrintWriter out = null;out = response.getWriter();//获取响应输出流logger.info("FrontRcvResponse前台接收报文返回开始");String encoding = request.getParameter(SDKConstants.param_encoding);logger.info("返回报文中encoding=[" + encoding + "]");Map<String, String> respParam = getAllRequestParam(request);//获取银联回调的参数// 打印请求报文LogUtil.printRequestLog(respParam);Map<String, String> valideData = valideData(request, response);//验证签名if (!AcpService.validate(valideData, encoding)) {//验证签名失败logger.info("验证签名结果[失败].");
//            return "redirect:/pay-failed.html";out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "验证签名失败", Const.validateFaliUrl));} else {String respCode = valideData.get("respCode");//验证成功后获取银联响应码if ("00".equals(respCode)) {//响应码为00表示支付成功。logger.info("验证签名结果[成功]");//=====================//TODO:这个方法在用户支付成功后点击返回商户时,银联回调,这里写回调成功后的一些业务逻辑。} else {out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "银联支付失败", Const.validateFaliUrl));}}out.flush();out.close();}/*** 更新订单数据(状态)此方法根据自己的业务需求编写,最后要返回验证签名后的订单编号。** @param valideData* @return*/private String updateOrder(Map<String, String> valideData) {return valideData.get("orderId");//返回验证签名成功后的订单编号}//退款@ResponseBody@RequestMapping("/Refund/{order_nbr}")public String doPost(@PathVariable String order_nbr, HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String basePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort();CyDishorderEntity order = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", order_nbr);Map<String, String> data = new HashMap<String, String>();/***银联全渠道系统,产品参数 ,除了encoding自行选择外其他不需修改***/data.put("version", ChinapayConfig.version);               //版本号data.put("encoding", ChinapayConfig.encoding_UTF8);             //字符集编码 可以使用UTF-8,GBK两种方式data.put("signMethod", "01");                        //签名方法 目前只支持01-RSA方式证书加密data.put("txnType", "04");                           //交易类型 04-退货data.put("txnSubType", "00");                        //交易子类型  默认00data.put("bizType", "000201");                       //业务类型 B2C网关支付,手机wap支付data.put("channelType", "07");                       //渠道类型,07-PC,08-手机/***商户接入参数***/ /*ChinapayConfig.MERID*/data.put("merId", ChinapayConfig.MERID);                //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试data.put("accessType", "0");                         //接入类型,商户接入固定填0,不需修改data.put("orderId", ChinapayConfig.getOrderId());          //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生,不同于原消费data.put("txnTime", ChinapayConfig.getCurrentTime());      //订单发送时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效data.put("currencyCode", "156");                     //交易币种(境内商户一般是156 人民币)//=================================data.put("txnAmt",String.valueOf((new BigDecimal(order.getPayMoney()).multiply(new BigDecimal(100))).intValue()));                          //****退货金额,单位分,不要带小数点。退货金额小于等于原消费金额,当小于的时候可以多次退货至退货累计金额等于原消费金额//data.put("reqReserved", "透传信息");                  //请求方保留域,如需使用请启用即可;透传字段(可以实现商户自定义参数的追踪)本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回,商户可以按需上传,长度为1-1024个字节data.put("backUrl", basePath + "/CYChinapay/refundBack");               //后台通知地址,后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 退货交易 商户通知,其他说明同消费交易的后台通知/***要调通交易以下字段必须修改***///========================data.put("origQryId", order.getRefund_queryid());      //****原消费交易返回的的queryId,可以从消费交易后台通知接口中或者交易状态查询接口中获取/**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/Map<String, String> reqData = AcpService.sign(data, ChinapayConfig.encoding_UTF8);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。String url = SDKConfig.getConfig().getBackRequestUrl();//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrlSystem.out.print("backurl:" + url);Map<String, String> rspData = AcpService.post(reqData, url, ChinapayConfig.encoding_UTF8);//这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过//   System.out.print("rspData值:"+"sasasasasaaaaaaaaaaaaasasasasasasa sasasas///"+rspData+"------------"+!rspData.isEmpty());/**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**///应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》if (!rspData.isEmpty()) {if (AcpService.validate(rspData, ChinapayConfig.encoding_UTF8)) {LogUtil.writeLog("验证签名成功");String respCode = rspData.get("respCode");LogUtil.writeLog("respCode-------------------------------------------------"+respCode);if ("00".equals(respCode)) {//交易已受理,等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。//TODO:处理退款申请发送成功后的业务逻辑//设置退款状态为正在受理return "申请退款成功!等待银联处理";} else if ("03".equals(respCode) ||"04".equals(respCode) ||"05".equals(respCode)) {return "退款失败";} else {//其他应答码为失败请排查原因,根据银联响应报文的,respCode,respMsg来排查原因。return "退款失败";}} else {LogUtil.writeErrorLog("验证签名失败");return "退款失败";}} else {//未返回正确的http状态LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");return "退款失败";}}//退款回调方法@RequestMapping(value = "/refundBack", method = RequestMethod.POST)public void refundBack(HttpServletRequest req, HttpServletResponse resp) throws Exception {String encoding = req.getParameter(SDKConstants.param_encoding);LogUtil.writeLog("进入退款后台回调-------------------------------------------------");Map<String, String> reqParam = getAllRequestParam(req);LogUtil.printRequestLog(reqParam);Map<String, String> valideData = null;if (null != reqParam && !reqParam.isEmpty()) {Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator();valideData = new HashMap<String, String>(reqParam.size());while (it.hasNext()) {Map.Entry<String, String> e = it.next();String key = e.getKey();String value = e.getValue();value = new String(value.getBytes(encoding), encoding);valideData.put(key, value);}}//重要!验证签名前不要修改reqParam中的键值对的内容,否则会验签不过if (!AcpService.validate(valideData, encoding)) {LogUtil.writeLog("验证签名结果[失败].");//验签失败,需解决验签问题} else {LogUtil.writeLog("验证签名结果[成功].");//【注:为了安全验签成功才应该写商户的成功处理逻辑】交易成功,更新商户订单状态String respCode = valideData.get("respCode"); //获取应答码,收到后台通知了respCode的值一般是00,可以不需要根据这个应答码判断。LogUtil.writeLog("respCode:-------" + respCode);LogUtil.writeLog("respCodeflg:-------" + respCode.equals("00"));if (respCode.equals("00")) {//:TODO:退款回调成功后的业务逻辑}}LogUtil.writeLog("BackRcvResponse接收后台通知结束");//返回给银联服务器http 200  状态码resp.getWriter().print("ok");}/*** 获取请求参数中所有的信息** @param request* @return*/public static Map<String, String> getAllRequestParam(final HttpServletRequest request) {Map<String, String> res = new HashMap<String, String>();Enumeration<?> temp = request.getParameterNames();if (null != temp) {while (temp.hasMoreElements()) {String en = (String) temp.nextElement();String value = request.getParameter(en);res.put(en, value);// 在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>if (res.get(en) == null || "".equals(res.get(en))) {// System.out.println("======为空的字段名===="+en);res.remove(en);}}}return res;}
}

6.订单状态枚举类

/**订单状态枚举类*/
public enum CyOrderStatusEnum {//1未支付 2已支付 3退款 4取消订单 5过期NO_PAYMENT("0","未支付"),PREPAID("1","已支付"),APPLYCANCEL("2","取消订单"),CANCEL("3","已取消"),AWARDING("4","正在授理..."),REFUND_SUCCESS("5","退款完成"),NET_ERROR("net_error", "网络异常,请稍后重试");private String code;private String desc;private CyOrderStatusEnum(String code, String desc) {this.code = code;this.desc = desc;}public static CyOrderStatusEnum codeOf(String code) {if(code == null) {return NET_ERROR;} else {CyOrderStatusEnum[] arr$ = values();int len$ = arr$.length;for(int i$ = 0; i$ < len$; ++i$) {CyOrderStatusEnum rtnCodeEnum = arr$[i$];if(code.equals(rtnCodeEnum.getCode())) {return rtnCodeEnum;}}return NET_ERROR;}}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}
}

7.支付成功后,java动态生成成功跳转页面,和失败跳转页面。

/*** @author hff* 点餐预定支付返回*/
public class CyReturnPayEndHtml {private static StringBuffer stringBuffer = null;private static StringBuffer headHtml(boolean isSuccess){if (isSuccess){stringBuffer.append("<head>");stringBuffer.append("   <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">");stringBuffer.append("   <meta charset=\"UTF-8\">");stringBuffer.append("   <link rel=\"stylesheet\" href=\"http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css\">");stringBuffer.append("   <link rel=\"stylesheet\" href=\"http://资源路径\">");stringBuffer.append("   <style type=\"text/css\">");stringBuffer.append("       .paySuccess dd,.paySuccess dt{text-align: center;line-height: 1.6;}.paySuccess dd .i_icon{display: inline-block;width: 130px;height: 130px;font-size: 100px;color: green;}.paySuccess dd b,.paySuccess dt b{color: #ff5409;font-weight: normal;}.paySuccess dt .i_icon{display: inline-block;font-size: 20px;color: #555;padding-right: 5px;}");stringBuffer.append("   </style>");stringBuffer.append("   <title>支付成功</title>");stringBuffer.append("</head>");}return stringBuffer;}private static StringBuffer javascript(String orderNum, String orderno, String url, boolean b){stringBuffer.append("<script src=\"https://code.jquery.com/jquery-1.9.1.min.js\"></script>");stringBuffer.append("<script src=\"js,css等资源路径"></script>");stringBuffer.append("<script>");stringBuffer.append("   function waitToIndex(){");stringBuffer.append("       var second = 3;");stringBuffer.append("       setInterval(function(){");stringBuffer.append("           if(second > 0){");stringBuffer.append("               $(\"#spanSecond\").html(second);");stringBuffer.append("               second--;");stringBuffer.append("           }else{");stringBuffer.append("               gotoIndex();");stringBuffer.append("           }");stringBuffer.append("       },1000);");stringBuffer.append("   }");stringBuffer.append("   function gotoIndex(){");stringBuffer.append("       window.location.href='"+url+"'"+";");stringBuffer.append("   }");if (b){stringBuffer.append("   var num = 10;");stringBuffer.append("   function isSuccess(){");stringBuffer.append("       $.post('查询订单的路径"+orderno+"',{},function(res){");stringBuffer.append("           if(res.rtnCode == '0000000'){");stringBuffer.append("               var resutl = res.bizData;");stringBuffer.append("                   if (resutl.orderStatus == '1') {");stringBuffer.append("                   var timer1 = setInterval(function () {");stringBuffer.append("                       if (num > 0) {");stringBuffer.append("                           num--;");stringBuffer.append("                           isSuccess();");stringBuffer.append("                       } else {");stringBuffer.append("                           clearInterval(timer1);");stringBuffer.append("                           $('#outing').hide();");stringBuffer.append("                           $('#outSuccess').show();");stringBuffer.append("                           waitToIndex();");stringBuffer.append("                       }");stringBuffer.append("                   },1000);");stringBuffer.append("                 }");stringBuffer.append("           }");stringBuffer.append("       });");stringBuffer.append("   }");stringBuffer.append("   isSuccess();");}else {stringBuffer.append("   waitToIndex();");}stringBuffer.append("</script>");return stringBuffer;}public static String successHtml(String orderNum, String orderNo, String url){stringBuffer = new StringBuffer();stringBuffer.append("<!DOCTYPE html>");stringBuffer.append("<html>");headHtml(true);stringBuffer.append("<script src=\"https://code.jquery.com/jquery-1.9.1.min.js\"></script>");stringBuffer.append("<script src=\"相关js,css的路径"></script>");stringBuffer.append("<body>");stringBuffer.append("   <div class=\"p10 paySuccess\">");stringBuffer.append("       <dd><i class=\"ion-checkmark-circled i_icon\"></i></dd>");stringBuffer.append("       <dd id=\"paySuccess\">");stringBuffer.append("           支付成功");stringBuffer.append("           <span id=\"scores\"></span>");stringBuffer.append("       </dd>");stringBuffer.append("       <dt id=\"outing\"><i class=\"ion-load-a i_icon\"></i>正在点餐预定....</dt>");stringBuffer.append("       <dt id=\"outSuccess\" style=\"display: none;\">");stringBuffer.append("           <b id=\"spanSecond\">3</b>秒钟之后<a href=\"javascript:gotoIndex()\"><b>跳转</b></a>回首页");stringBuffer.append("       </dt>");stringBuffer.append("   </div>");javascript(orderNum,orderNo, url, true);stringBuffer.append("</body>");stringBuffer.append("</html>");return stringBuffer.toString();}public static String failedHtml(String orderNo, String errMsg, String url){stringBuffer = new StringBuffer();stringBuffer.append("<!DOCTYPE html>");stringBuffer.append("<html>");headHtml(true);stringBuffer.append("<body>");stringBuffer.append("   <div class=\"p10 paySuccess\">");stringBuffer.append("       <dd><i class=\"ion-checkmark-circled i_icon\"></i></dd>");stringBuffer.append("       <dd id=\"paySuccess\">");stringBuffer.append("           支付失败["+errMsg+"]");stringBuffer.append("           <span id=\"scores\"></span>");stringBuffer.append("       </dd>");stringBuffer.append("       <dt id=\"outSuccess\">");stringBuffer.append("           <b id=\"spanSecond\">3</b>秒钟之后<a href=\"javascript:gotoIndex()\"><b>跳转</b></a>回首页");stringBuffer.append("       </dt>");stringBuffer.append("   </div>");javascript(null,orderNo,url, false);stringBuffer.append("</body>");stringBuffer.append("</html>");return stringBuffer.toString();}public static void main(String[] args) {BigDecimal b1 = new BigDecimal("0.12");BigDecimal b2 = new BigDecimal("0.01");System.out.println(b1.subtract(b2).toString());}}

4.注意事项(可能会出错的地方)

1:开发环境分为测试环境和生产环境
2:不管什么环境,银联相关证书一定要一一对应。
3:若是生产环境的证书有四个,缺一不可,测试环境有两个
4:开发过程中测试环境无法测试回调接口,必须为外网测试,因为这里的回调接口是银联通过外网来回调的。
5:支付发起所需的参数缺一不可,格式一定要规范,符合规则,只有这样才能生成正确的请求报文。
6:支付的两个回调接口,一个回调接口一般叫做frontUrl,这个地址是由用户点击返回商户的时候银联才会调用。另外一个回调接口叫做backUrl,这个地址是银联接到支付请求后异步回调的接口,一般网站的业务逻辑在此处处理。
7:如果要做退款,一定要有退款流水号,支付流水号。
8:退款时,需要拿着接口对应的参数,以及对应的支付流水号去发起退款申请。退款分为交易撤销和交易退货,撤销只能处理当日的订单。
9:不管是支付,退款,回调接口,当出现问题时,一定要仔细产看银联的响应报文,只要请求报文格式正确,银联收到请求,它一定会给响应,通过响应respCode和respMsg来判断接口的问题出自哪里。
10:交易金额都是以分为单位,不能有小数点,金额参数一定要做去小数点处理。
11:银联官网测试环境提供了测试参数,项目没有用生产环境的时候,可以用测试参数来测试。

5.银联官网相关网址

在开发过程中可能需要的网址整理。
官网demo,文档及sdk下载链接:
https://open.unionpay.com/ajweb/help/file/techFile?productId=1
官网api链接:
https://open.unionpay.com/ajweb/help/api
常见问题查看平台:
https://open.unionpay.com/ajweb/help/faq/list?id=140&level=0&from=1
银联社区链接:
https://bbs.unionpay.com/upbbs/forum/topic?id=4

以上博文是自己做完支付后的总结,有不正确的地方,还望各位路过的大牛批评指正。针对以上代码若有疑问,请加群:qq群号 451232132 找博主。

银联网关支付,退款java实现相关推荐

  1. uni-app 接入银联H5支付(Java)思路代码

    uni-app 接入银联H5支付(Java)思路代码 uni-app-web-view Java(后台部分代码)可以参考官方的Demo取代码 银联文档地址: H5支付. 第一次接触银联支付的话建议 跑 ...

  2. 银联在线 网关支付(中国银联全渠道系统商户接入 测试指引-银联网关支付产品)

    https://blog.csdn.net/yulei_qq/article/details/49025045 中国银联全渠道系统商户接入 测试指引-银联网关支付产品 https://blog.csd ...

  3. springMvc之银联网关支付(详解)

    一.申请与配置 1.了解产品和申请测试账号 无论接入什么平台,首先就是了解自己的需求,然后从开发文档中查看接入方式. 进入银联技术开放平台 点击 点击我是商户,然后进行注册.(注意:注册或登录时用IE ...

  4. 银联网关支付demo

    对接银联支付接口,通过一个例子向商家支付金额. 1.首先在银联开放平台下载支付Demo,点击链接 或者直接拿我修改好的demo,链接: https://pan.baidu.com/s/1FywgOf5 ...

  5. thinkphp集成银联网关支付简单实例

    thinkphp集成银联手机网关支付简单实例 准备工作 网银手机网关支付产品开发包下载: https://open.unionpay.com/ajweb/help/file/toDetailPage? ...

  6. 银联快捷支付退款 Pay

    public void refundPay(){logger.info("=====银联快捷退款开始=====");// 银联退款逻辑String hdurl = "ht ...

  7. java对接银联在线网关支付(已测试)

    访问连接下载银联SDK https://open.unionpay.com/tjweb/acproduct/list?apiSvcId=448&index=5 1.拿到测试证书(下载银联的SD ...

  8. 银联批量结算 java_银联在线 网关支付 (JAVA版)

    这一版本的编写是在我上一次博客的基础上写的,有不懂得童鞋可以先看下我的原先在线支付的博客,熟悉下:http://blog.csdn.net/yulei_qq/article/details/45197 ...

  9. 银联在线支付 java_银联在线 网关支付 (JAVA版)

    这一版本的编写是在我上一次博客的基础上写的,有不懂得童鞋可以先看下我的原先在线支付的博客,熟悉下:http://blog.csdn.net/yulei_qq/article/details/45197 ...

  10. 银联在线网关支付,快速接入指南

    银联在线支付网关是中国银联联合各商业银行为持卡人提供的集成化.综合性互联网支付工具,主要支持输入卡号付款.用户登录支付.网银支付.迷你付(IC卡支付)等多种支付方式,为持卡人提供境内外网上购物支付服务 ...

最新文章

  1. 盘点2015跨境电商:硝烟下的机遇与变革
  2. spring管理hibernate的SessionFactory-多种配置方法
  3. Energetically Consistent Invertible Elasticity
  4. NetApp存储术语介绍
  5. 使用ps修改图片大小不影响清晰度的方法
  6. java在上海就业_叩丁狼教育上海Java一期就业报道
  7. 《勒索软件防护体系建设指南》发布|美创深度参编,入选代表性厂商
  8. 用友NC系统与一卡通集成解决方案
  9. 埃及分数c 语言程序,C语言将真分数分解为埃及分数
  10. 叹为观止,四款让人赞不绝口的优质软件,越用越上瘾
  11. ConcurrentHashMap插入与遍历时出现混乱
  12. 交互式应用中的视线跟踪技术
  13. Linux中$home和波浪号~
  14. py2neo.database.work.ClientError: [Procedure.ProcedureNotFound]
  15. Unity案例课程 - 涂鸦跳跳 Day 2
  16. hibernate+servlet+mysql 实现easypoi_在Maven项目中使用easypoi完成Excel文件上传下载(示例代码)...
  17. gitlab+jenkins 利用webhook自动构建代码
  18. 场效应管(FET)知识点释义
  19. 两种禁止USB autosuspend的方法
  20. 3dmax linux版本,[转载]如何安装Linux版FLOW-3D及注意事项

热门文章

  1. 计算机一级网页制作教程视频教程,网页制作入门教程(一)
  2. 直播带货系统,实现直播间人数统计
  3. CAE软件技术现状调研
  4. 幼儿计算机教材有哪些,中华字经幼儿教材
  5. Struts2拦截器实现异常处理
  6. linux计划任务管理: cron定时任务,详解
  7. android 3d地球,动态3D我的地球app
  8. 百度离线地图开发教程
  9. 计算机电源检测软件,电脑电源检测工具
  10. sis新地址_“这是什么梗?”,互联网上的新梗老梗如何影响你?