精华内容
下载资源
问答
  • Java实现银联支付源码

    2018-08-14 10:12:55
    Java实现支付宝, 微信 , 银联支付项目实例源码
  • 银联支付流程图+业务流程说明+关键参数,银联全渠道支付方式
  • 银联在线支付接口 开发文档+开发包(java)

    千次下载 热门讨论 2010-02-07 16:02:39
    银联在线支付 开发文档+开发jar包 for java NetPayClient2.5 内含1pdf+1jar包+1说明txt
  • 银联支付Java开发

    2018-06-27 13:47:00
    注:原来来源于: 《 银联支付Java开发 》银联的demo写的不错,基本上可以直接使用。 首先是对acp_sdk.properties的内容修改,注意这个文件的文件名不能进行修改。 对于文件内的证书路径以及证书对应的密码进行...


    注:原来来源于: 《  银联支付Java开发  》


    银联的demo写的不错,基本上可以直接使用。 
    首先是对acp_sdk.properties的内容修改,注意这个文件的文件名不能进行修改。 
    对于文件内的证书路径以及证书对应的密码进行修改。

    修改完这个文件后,需要对DemoBase这个类中的frontUrl,backUrl进行修改,这个是银联支付后向服务器通知的前台以及后台地址。 
    frontUrl主要处理的前台界面展示,backUrl主要处理后台业务逻辑。

    注意:这两个地址需要是外网地址,否则将无法收到回调信息。

    然后对于Form_6_2_FrontConsume类中的信息进行相应的修改,直接访问服务,会返回给你一段html字符串,把这段html直接传到前台加到页面上。这段代码会自动提交数据,会弹出银联支付的界面。

    注意:测试环境下,微信浏览器无法弹出支付界面,需要换生成环境的证书才能正常的弹出支付界面。

    支付成功后,银联会向你设置的backUrl发送成功信息,具体接受方法如下:

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    支付成功后,界面会有一个返回商户的按钮,那个按钮返回的界面就是在frontUrl设置。获取回调信息的方法与上面相同,就是在后面需要把界面导向你想要显示的界面,顺便带上返回的参数。

    这样就顺利的完成了银联支付的流程。

    展开全文
  • Java实现支付宝、微信、银联支付项目实例源码 (解压密码javazx.com)
  • 最新银联网关支付产品技术开发java net php 包括demo和接入文档
  • java银联支付

    千次阅读 2019-02-21 12:17:03
    貌似最近银联出了什么活动,公司急需接入银联支付, 作为写代码的我们 , 只能服从命令,特地记录下接入银联的过程 ,后续还会说接入支付宝和微信的亲自体验历程.........................................................

    貌似最近银联出了什么活动,公司急需接入银联支付, 作为写代码的我们 , 只能服从命令,特地记录下接入银联的过程  ,后续还会说接入支付宝和微信的亲自体验历程....................................................................

    1.申请商户

        首先得去银联那里开通商户,这个基本上是别人完成的 ,然后银联会给我们发一封邮件,里面包含商户号和生产环境的一些配置,这里有一个注意的就是得使用IE浏览器安装控件 , 谷歌是不行滴,,,,,,,附件里面也有操作文档 ,可以查看,就不多说了,补几张过程图吧

    配置好后 下载一个.pfx的签名文件,后面用到

    2. 下载官方DEMO

     去银联官网上下载官方的DEMO,解压后找到JAVA的SDK,文件如图

    这里面含有一些配置文件,在assets文件夹下

    3.测试环境配置

     下面进入代码阶段,先配置下测试环境,后面改成正式环境即可

    文件的结构:

      

     先贴出配置文件代码,找到一个叫acp_sdk.properties的配置文件

     

    ##############SDK配置文件(证书方式签名)################
    # 说明:
    # 1. 使用时请删除后缀的“.证书”,并将此文件复制到src文件夹下替换原来的acp_sdk.properties。
    # 2. 具体配置项请根据注释修改。
    #
    ################################################
    #商户号
    acpsdk.merId=777290058110048
    
    ##########################入网测试环境交易发送地址(线上测试需要使用生产环境交易请求地址)#############################
    ##交易请求地址
    
    #测试环境
    acpsdk.frontTransUrl=https://gateway.test.95516.com/gateway/api/frontTransReq.do
    acpsdk.backTransUrl=https://gateway.test.95516.com/gateway/api/backTransReq.do
    acpsdk.singleQueryUrl=https://gateway.test.95516.com/gateway/api/queryTrans.do
    acpsdk.batchTransUrl=https://gateway.test.95516.com/gateway/api/batchTrans.do
    acpsdk.fileTransUrl=https://filedownload.test.95516.com/
    acpsdk.appTransUrl=https://gateway.test.95516.com/gateway/api/appTransReq.do
    acpsdk.cardTransUrl=https://gateway.test.95516.com/gateway/api/cardTransReq.do
    
    
    
    
    #以下缴费产品使用,其余产品用不到
    #测试
    acpsdk.jfFrontTransUrl=https://gateway.test.95516.com/jiaofei/api/frontTransReq.do
    acpsdk.jfBackTransUrl=https://gateway.test.95516.com/jiaofei/api/backTransReq.do
    acpsdk.jfSingleQueryUrl=https://gateway.test.95516.com/jiaofei/api/queryTrans.do
    acpsdk.jfCardTransUrl=https://gateway.test.95516.com/jiaofei/api/cardTransReq.do
    acpsdk.jfAppTransUrl=https://gateway.test.95516.com/jiaofei/api/appTransReq.do
    
    ########################################################################
    
    # 报文版本号,固定5.1.0,请勿改动
    acpsdk.version=5.1.0
    
    # 签名方式,证书方式固定01,请勿改动
    acpsdk.signMethod=01
    
    # 是否验证验签证书的CN,测试环境请设置false,生产环境请设置true。非false的值默认都当true处理。
    acpsdk.ifValidateCNName=false
    
    # 是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false。非true的值默认都当false处理。
    acpsdk.ifValidateRemoteCert=false
    
    #前台通知地址,填写后台接收银联前台通知的地址
    acpsdk.frontUrl=https://XXXXXXXXx/union/successRedict
    
    #后台通知地址,填写后台接收银联后台通知的地址,必须外网能访问
    #111.204.128.115:8929 ---> 192.168.0.54:8087
    acpsdk.backUrl=https://XXXXXXXXx/union/backRcvResponse
    #111.204.128.115:8917 ---> 192.168.0.54:8085
    #acpsdk.backUrl=http://111.204.128.115:8917/garage/wx/pay/union/backRcvResponse
    #111.204.128.115:8925 ---> 192.168.1.19:8087
    #acpsdk.backUrl=http://111.204.128.115:8925/garageWechat/wx/pay/union/backRcvResponse
    
    #########################入网测试环境签名证书配置 ################################
    # 多证书的情况证书路径为代码指定,可不对此块做配置。
    # 签名证书路径,必须使用绝对路径,如果不想使用绝对路径,可以自行实现相对路径获取证书的方法;测试证书所有商户共用开发包中的测试签名证书,生产环境请从cfca下载得到。
    # windows样例:
    acpsdk.signCert.path=cert/acp_test_sign.pfx
    # linux样例(注意:在linux下读取证书需要保证证书有被应用读的权限)(后续其他路径配置也同此条说明)
    #acpsdk.signCert.path=/SERVICE01/usr/ac_frnas/conf/ACPtest/acp700000000000001.pfx
    
    # 签名证书密码,测试环境固定000000,生产环境请修改为从cfca下载的正式证书的密码,正式环境证书密码位数需小于等于6位,否则上传到商户服务网站会失败
    acpsdk.signCert.pwd=123456
    # 签名证书类型,固定不需要修改
    acpsdk.signCert.type=PKCS12
    
    ##########################加密证书配置################################
    # 敏感信息加密证书路径(商户号开通了商户对敏感信息加密的权限,需要对 卡号accNo,pin和phoneNo,cvn2,expired加密(如果这些上送的话),对敏感信息加密使用)
    acpsdk.encryptCert.path=cert/acp_test_enc.cer
    
    ##########################验签证书配置################################
    # 验签中级证书路径(银联提供)
    acpsdk.middleCert.path=cert/acp_test_middle.cer
    # 验签根证书路径(银联提供)
    acpsdk.rootCert.path=cert/acp_test_root.cer
    
    

    其中测试环境的证书,在下载的DEMO中含有

    配置文件到此基本上就已经完成了,下面贴出支付的代码

     @Override
        public void pay(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            request.setCharacterEncoding(DemoBase.encoding);
            response.setContentType("text/html; charset="+ DemoBase.encoding);
            String orderId = String.valueOf(System.currentTimeMillis()); //实际上是orderSn
            String txnAmt = null;  //订单金额
            String txnTime = null; //订单发送时间
            //交易金额,单位分,不要带小数点
            BigDecimal amount = new BigDecimal("0.01");
            amount = amount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
            txnAmt = amount.toString();
            //订单发送时间用于查询用
            Date sendPaymentDate = new Date();
            txnTime = formatTime(sendPaymentDate);
    
            Map<String, String> requestData = new HashMap<>();
    
            /***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
            requestData.put("version", DemoBase.version);   			  //版本号,全渠道默认值
            requestData.put("encoding", DemoBase.encoding); 			  //字符集编码,可以使用UTF-8,GBK两种方式
            requestData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
            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", merId);    	          			  //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号
            requestData.put("accessType", "0");             			  //接入类型,0:直连商户
            requestData.put("orderId", String.valueOf(System.currentTimeMillis()));                          //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
            requestData.put("txnTime", formatTime(new Date()));        //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效
            requestData.put("currencyCode", "156");         			  //交易币种(境内商户一般是156 人民币)
            requestData.put("txnAmt", "1");  //交易金额,单位分,不要带小数点
            requestData.put("accType",  "01");   //账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质)
    
    
            //前台通知地址 (需设置为外网能访问 http https均可),支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址
            //如果想要实现过几秒中自动跳转回商户页面权限,需联系银联业务申请开通自动返回商户权限
            //异步通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
          //  requestData.put("frontUrl", DemoBase.frontUrl);
    
            //后台通知地址(需设置为【外网】能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,失败的交易银联不会发送后台通知
            //后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
            //注意:1.需设置为外网能访问,否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码
            //    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200,那么银联会间隔一段时间再次发送。总共发送5次,每次的间隔时间为0,1,2,4分钟。
            //    5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败
            requestData.put("backUrl", DemoBase.backUrl);
    
            // 订单超时时间。
            // 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。
            // 此时间建议取支付时的北京时间加15分钟。
            // 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
           // requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));
    
            //
            //
            //       报文中特殊用法请查看 PCwap网关跳转支付特殊用法.txt
            //
            //
    
            /**请求参数设置完毕,以下对请求参数进行签名并生成html表单,将表单写入浏览器跳转打开银联页面**/
           /* Map<String, String> submitFromData = AcpService.sign(requestData,DemoBase.encoding);  //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
    
            String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
            String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData,DemoBase.encoding);   //生成自动跳转的Html表单*/
    
            Map<String, String> reqData = AcpService.sign(requestData,DemoBase.encoding);			 //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
            String requestAppUrl = SDKConfig.getConfig().getAppRequestUrl();								 //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
            Map<String, String> rspData = AcpService.post(reqData,requestAppUrl,DemoBase.encoding);  //发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
           // LogUtil.writeLog("打印请求HTML,此为请求报文,为联调排查问题的依据:"+html);
            //将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过
            /**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
            //应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
            if(!rspData.isEmpty()){
                if(AcpService.validate(rspData, DemoBase.encoding)){
                    LogUtil.writeLog("验证签名成功");
                    String respCode = rspData.get("respCode") ;
                    if(("00").equals(respCode)){
                        //成功,获取tn号
                        String tn = rspData.get("tn");
                        System.out.println(tn);
                        //TODO
                    }else{
                        //其他应答码为失败请排查原因或做失败处理
                        //TODO
                    }
                }else{
                    LogUtil.writeErrorLog("验证签名失败");
                    //TODO 检查验证签名失败的原因
                }
            }else{
                //未返回正确的http状态
                LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
            }
            String reqMessage = DemoBase.genHtmlResult(reqData);
            String rspMessage = DemoBase.genHtmlResult(rspData);
            response.getWriter().write("请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");
    
    
        }

    如果是手机控件支付的话 将获取到的银联的订单号tn之前返回给手机端即可,无需其他处理

     

    测试商户号在官网申请支付测试,会找到测试商户号

    也含有测试的银行卡和手机号

     

    至此,测试环境即可完成,调用接口,返回如下信息

    大功告成!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

     

    4.正式环境配置

    1.将请求连接换成正式请求连接

    2.将配置文件中的某些false改成true

    3.证书的修改,在下载的DEMo中会找到三个证书,还缺啥呢? 对就是缺少前面下载的那个.pfx结尾的文件,将下载的证书copy进来,然后将配置文件中的证书修改成正式的即可

    4. 注意   注意  注意   

      本人用的是springboot项目 ,发布时使用jar包发布的,那么用官方的包中的读取配置文件方式是有问题的,所以需要修改读取配置文件方式

    修改后

    这下问题是解决了,代码 代码   代码  一个个贴出来

     

    package com.example.demo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * Created by wangfei on 2017/4/22.
     */
    
    @Validated
    @RestController
    @RequestMapping("/union")
    public class UnipayController {
    
        @Autowired
        private UnionPaymentService service;
    
        /**
         * 支付
         * @param request
         * @param response
         * @throws IOException
         */
        @RequestMapping(value = "/pay", method = {RequestMethod.POST, RequestMethod.GET})
        public void pay(HttpServletRequest request, HttpServletResponse response) throws IOException{
            service.pay(request, response);
    
        }
    
        /**
         * 后台回调
         * @param request
         * @param response
         * @throws IOException
         */
        @RequestMapping(value = "/backRcvResponse", method = {RequestMethod.GET, RequestMethod.POST})
        public void backRcvResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
            service.backRcvResponse(request, response);
    
        }
    
        /**
         * 前台回调
         * @param request
         * @param response
         * @throws IOException
         */
        @RequestMapping(value = "/frontRcvResponse", method = RequestMethod.POST)
        public void frontRcvResponse(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    
            service.frontRcvResponse(request, response);
    
        }
    
        /**
         * 成功后跳转
         * @param request
         * @param response
         * @throws IOException
         */
        @RequestMapping(value = "/successRedict", method = RequestMethod.POST)
        public void successRedict(HttpServletRequest request, HttpServletResponse response) throws IOException {
            service.successRedict(request, response);
    
        }
    
        /**
         * 查询、检查交易状态
         * @param request
         * @param response
         */
        @RequestMapping(value = "/query", method = RequestMethod.POST)
        public void query(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            service.query(request, response);
    
        }
    
        /**
         * 交易状态查询
         * @param orderId
         */
        @RequestMapping(value = "/check", method = RequestMethod.POST)
        public JsonResult check(Long orderId) {
    
            try {
                service.check(orderId);
                return JsonResult.resultSuccess("已支付", "");
            } catch (Exception e) {
                e.printStackTrace();
                return JsonResult.resultError("未发现支付信息");
            }
    
        }
    
    
    }
    

     

    package com.example.demo;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public interface UnionPaymentService {
    
    
        /**
         * 支付
         * @param request
         * @param response
         */
        void pay(HttpServletRequest request, HttpServletResponse response) throws IOException;
    
        /**
         * 后台回调
         * @param request
         * @param response
         */
        void backRcvResponse(HttpServletRequest request, HttpServletResponse response) throws IOException;
    
        /**
         * 前台回调
         * @param request
         * @param response
         * @throws IOException
         */
        void frontRcvResponse(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
    
        /**
         * 交易状态查询
         * @param request
         * @param response
         */
        void query(HttpServletRequest request, HttpServletResponse response) throws IOException;
    
        /**
         * 支付成功后的跳转
         * @param request
         * @param response
         */
        void successRedict(HttpServletRequest request, HttpServletResponse response) throws IOException;
    
        /**
         * 检查支付结果
         * @param shopOrderId
         * @throws IOException
         */
        void check(Long shopOrderId);
    }
    package com.example.demo;
    
    import com.example.demo.union.DemoBase;
    import com.example.demo.union.config.SDKConfig;
    import com.example.demo.union.constants.SDKConstants;
    import com.example.demo.union.service.AcpService;
    import com.example.demo.union.util.CertUtil;
    import com.example.demo.union.util.LogUtil;
    import org.apache.commons.lang.StringUtils;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    /**
     * Created by gangsun on 2017/4/12.
     */
    @Service
    public class UnionPaymentServiceImpl implements UnionPaymentService {
        //先取商户号
        private String merId = "700000000000001";
        private String redictUrl = "http://www.baidu.com";
    
        @PostConstruct
        public void  init(){
            System.out.println("银联支付初始化");
            SDKConfig.getConfig().loadPropertiesFromSrc(); //从classpath加载acp_sdk.properties文件
            CertUtil.init();
        }
    
        /**
         * 支付
         * @param request
         * @param response
         */
        @Override
        public void pay(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            request.setCharacterEncoding(DemoBase.encoding);
            response.setContentType("text/html; charset="+ DemoBase.encoding);
            String orderId = String.valueOf(System.currentTimeMillis()); //实际上是orderSn
            String txnAmt = null;  //订单金额
            String txnTime = null; //订单发送时间
            //交易金额,单位分,不要带小数点
            BigDecimal amount = new BigDecimal("0.01");
            amount = amount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP);
            txnAmt = amount.toString();
            //订单发送时间用于查询用
            Date sendPaymentDate = new Date();
            txnTime = formatTime(sendPaymentDate);
    
            Map<String, String> requestData = new HashMap<>();
    
            /***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
            requestData.put("version", DemoBase.version);   			  //版本号,全渠道默认值
            requestData.put("encoding", DemoBase.encoding); 			  //字符集编码,可以使用UTF-8,GBK两种方式
            requestData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
            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", merId);    	          			  //商户号码,请改成自己申请的正式商户号或者open上注册得来的777测试商户号
            requestData.put("accessType", "0");             			  //接入类型,0:直连商户
            requestData.put("orderId", String.valueOf(System.currentTimeMillis()));                          //商户订单号,8-40位数字字母,不能含“-”或“_”,可以自行定制规则
            requestData.put("txnTime", formatTime(new Date()));        //订单发送时间,取系统时间,格式为YYYYMMDDhhmmss,必须取当前时间,否则会报txnTime无效
            requestData.put("currencyCode", "156");         			  //交易币种(境内商户一般是156 人民币)
            requestData.put("txnAmt", "1");  //交易金额,单位分,不要带小数点
            requestData.put("accType",  "01");   //账号类型 01:银行卡02:存折03:IC卡帐号类型(卡介质)
    
    
            //前台通知地址 (需设置为外网能访问 http https均可),支付成功后的页面 点击“返回商户”按钮的时候将异步通知报文post到该地址
            //如果想要实现过几秒中自动跳转回商户页面权限,需联系银联业务申请开通自动返回商户权限
            //异步通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
          //  requestData.put("frontUrl", DemoBase.frontUrl);
    
            //后台通知地址(需设置为【外网】能访问 http https均可),支付成功后银联会自动将异步通知报文post到商户上送的该地址,失败的交易银联不会发送后台通知
            //后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 消费交易 商户通知
            //注意:1.需设置为外网能访问,否则收不到通知    2.http https均可  3.收单后台通知后需要10秒内返回http200或302状态码
            //    4.如果银联通知服务器发送通知后10秒内未收到返回状态码或者应答码非http200,那么银联会间隔一段时间再次发送。总共发送5次,每次的间隔时间为0,1,2,4分钟。
            //    5.后台通知地址如果上送了带有?的参数,例如:http://abc/web?a=b&c=d 在后台通知处理程序验证签名之前需要编写逻辑将这些字段去掉再验签,否则将会验签失败
            requestData.put("backUrl", DemoBase.backUrl);
    
            // 订单超时时间。
            // 超过此时间后,除网银交易外,其他交易银联系统会拒绝受理,提示超时。 跳转银行网银交易如果超时后交易成功,会自动退款,大约5个工作日金额返还到持卡人账户。
            // 此时间建议取支付时的北京时间加15分钟。
            // 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
           // requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));
    
            //
            //
            //       报文中特殊用法请查看 PCwap网关跳转支付特殊用法.txt
            //
            //
    
            /**请求参数设置完毕,以下对请求参数进行签名并生成html表单,将表单写入浏览器跳转打开银联页面**/
           /* Map<String, String> submitFromData = AcpService.sign(requestData,DemoBase.encoding);  //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
    
            String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //获取请求银联的前台地址:对应属性文件acp_sdk.properties文件中的acpsdk.frontTransUrl
            String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData,DemoBase.encoding);   //生成自动跳转的Html表单*/
    
            Map<String, String> reqData = AcpService.sign(requestData,DemoBase.encoding);			 //报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
            String requestAppUrl = SDKConfig.getConfig().getAppRequestUrl();								 //交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
            Map<String, String> rspData = AcpService.post(reqData,requestAppUrl,DemoBase.encoding);  //发送请求报文并接受同步应答(默认连接超时时间30秒,读取返回结果超时时间30秒);这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
           // LogUtil.writeLog("打印请求HTML,此为请求报文,为联调排查问题的依据:"+html);
            //将生成的html写到浏览器中完成自动跳转打开银联支付页面;这里调用signData之后,将html写到浏览器跳转到银联页面之前均不能对html中的表单项的名称和值进行修改,如果修改会导致验签不通过
            /**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
            //应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
            if(!rspData.isEmpty()){
                if(AcpService.validate(rspData, DemoBase.encoding)){
                    LogUtil.writeLog("验证签名成功");
                    String respCode = rspData.get("respCode") ;
                    if(("00").equals(respCode)){
                        //成功,获取tn号
                        String tn = rspData.get("tn");
                        System.out.println(tn);
                        //TODO
                    }else{
                        //其他应答码为失败请排查原因或做失败处理
                        //TODO
                    }
                }else{
                    LogUtil.writeErrorLog("验证签名失败");
                    //TODO 检查验证签名失败的原因
                }
            }else{
                //未返回正确的http状态
                LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
            }
            String reqMessage = DemoBase.genHtmlResult(reqData);
            String rspMessage = DemoBase.genHtmlResult(rspData);
            response.getWriter().write("请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");
    
    
        }
    
        /**
         * 后台回调
         * @param request
         * @param response
         */
        @Override
        public void backRcvResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
            LogUtil.writeLog("BackRcvResponse接收后台通知开始");
    
            String encoding = request.getParameter(SDKConstants.param_encoding);
            // 获取银联通知服务器发送的后台通知参数
            Map<String, String> reqParam = getAllRequestParam(request);
    
            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 = (String) e.getKey();
                    String value = (String) 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 orderId =valideData.get("orderId"); //获取后台通知的数据,其他字段也可用类似方式获取
                String orderSn =orderId; //orderId其实存的是Sn
    
                String respCode = valideData.get("respCode");
                String txnAmt = valideData.get("txnAmt");
                BigDecimal txnAmount = (new BigDecimal(txnAmt)).multiply(new BigDecimal(0.01));
    
                String queryId = valideData.get("queryId");
                String traceTime = valideData.get("traceTime");
                String payCardNo = valideData.get("payCardNo");
                String payCardType = valideData.get("payCardType"); //支付卡类型
                String paymentMethodMethod; //PayPaymentMethod里面的method字段
                if(StringUtils.isEmpty(payCardType)){
                    paymentMethodMethod = "UNION";  //对之前代码做兼容,如果没有支付卡类型的情况走默认
                }else{
                    paymentMethodMethod = "UNION-" + payCardType;
                }
    
                //判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
                if("00".equals(respCode)){  // 00 交易成功
    
                    //todo 若交易成功
                }else if("A6".equals(respCode)){  // A6 部分成功
    
                }
    
            }
            LogUtil.writeLog("BackRcvResponse接收后台通知结束");
            //返回给银联服务器http 200  状态码
            response.getWriter().print("ok");
        }
    
        @Override
        public void frontRcvResponse(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            LogUtil.writeLog("FrontRcvResponse前台接收报文返回开始");
    
            String encoding = request.getParameter(SDKConstants.param_encoding);
            LogUtil.writeLog("返回报文中encoding=[" + encoding + "]");
            String pageResult = "";
            if (DemoBase.encoding.equalsIgnoreCase(encoding)) {
                pageResult = "/utf8_result.jsp";
            } else {
                pageResult = "/gbk_result.jsp";
            }
            Map<String, String> respParam = getAllRequestParam(request);
    
            // 打印请求报文
            LogUtil.printRequestLog(respParam);
    
            Map<String, String> valideData = null;
            StringBuffer page = new StringBuffer();
            if (null != respParam && !respParam.isEmpty()) {
                Iterator<Map.Entry<String, String>> it = respParam.entrySet()
                        .iterator();
                valideData = new HashMap<String, String>(respParam.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);
                    page.append("<tr><td width=\"30%\" align=\"right\">" + key
                            + "(" + key + ")</td><td>" + value + "</td></tr>");
                    valideData.put(key, value);
                }
            }
            if (!AcpService.validate(valideData, encoding)) {
                page.append("<tr><td width=\"30%\" align=\"right\">验证签名结果</td><td>失败</td></tr>");
                LogUtil.writeLog("验证签名结果[失败].");
            } else {
                page.append("<tr><td width=\"30%\" align=\"right\">验证签名结果</td><td>成功</td></tr>");
                LogUtil.writeLog("验证签名结果[成功].");
                System.out.println(valideData.get("orderId")); //其他字段也可用类似方式获取
    
                String respCode = valideData.get("respCode");
                //判断respCode=00、A6后,对涉及资金类的交易,请再发起查询接口查询,确定交易成功后更新数据库。
            }
            request.setAttribute("result", page.toString());
            request.getRequestDispatcher(pageResult).forward(request, response);
    
            LogUtil.writeLog("FrontRcvResponse前台接收报文返回结束");
    
        }
    
        @Override
        public void query(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            String orderId = String.valueOf(System.currentTimeMillis()); //实际上是orderSn
            String txnTime = null; //订单发送时间
    
            //订单发送时间
            Map<String, String> data = new HashMap<String, String>();
    
            /***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
            data.put("version", DemoBase.version);                 //版本号
            data.put("encoding", DemoBase.encoding);               //字符集编码 可以使用UTF-8,GBK两种方式
            data.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
            data.put("txnType", "00");                             //交易类型 00-默认
            data.put("txnSubType", "00");                          //交易子类型  默认00
            data.put("bizType", "000201");                         //业务类型 B2C网关支付,手机wap支付
    
            /***商户接入参数***/
            data.put("merId", merId);                  //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
            data.put("accessType", "0");                           //接入类型,商户接入固定填0,不需修改
    
            /***要调通交易以下字段必须修改***/
            data.put("orderId", orderId);                 //****商户订单号,每次发交易测试需修改为被查询的交易的订单号
            data.put("txnTime", txnTime);                 //****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间
    
            /**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
    
            Map<String, String> reqData = AcpService.sign(data,DemoBase.encoding);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
    
            String url = SDKConfig.getConfig().getSingleQueryUrl();// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl
            //这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
            Map<String, String> rspData = AcpService.post(reqData,url,DemoBase.encoding);
    
            /**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
            //应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
            if(!rspData.isEmpty()){
                if(AcpService.validate(rspData, DemoBase.encoding)){
                    LogUtil.writeLog("验证签名成功");
                    if("00".equals(rspData.get("respCode"))){//如果查询交易成功
                        //处理被查询交易的应答码逻辑
                        String origRespCode = rspData.get("origRespCode");
                        if("00".equals(origRespCode)){
                            //交易成功,更新商户订单状态
                            //TODO
                        }else if("03".equals(origRespCode) ||
                                "04".equals(origRespCode) ||
                                "05".equals(origRespCode)){
                            //需再次发起交易状态查询交易
                            //TODO
                        }else{
                            //其他应答码为失败请排查原因
                            //TODO
                        }
                    }else{//查询交易本身失败,或者未查到原交易,检查查询交易报文要素
                        //TODO
                    }
                }else{
                    LogUtil.writeErrorLog("验证签名失败");
                    //TODO 检查验证签名失败的原因
                }
            }else{
                //未返回正确的http状态
                LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
            }
            String reqMessage = DemoBase.genHtmlResult(reqData);
            String rspMessage = DemoBase.genHtmlResult(rspData);
            response.getWriter().write("</br>请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");
    
        }
    
        @Override
        public void check(Long shopOrderId){
    
            String orderId = String.valueOf(System.currentTimeMillis()); //实际上是orderSn
            String txnTime = null; //订单发送时间
    
            Map<String, String> data = new HashMap<String, String>();
    
            /***银联全渠道系统,产品参数,除了encoding自行选择外其他不需修改***/
            data.put("version", DemoBase.version);                 //版本号
            data.put("encoding", DemoBase.encoding);               //字符集编码 可以使用UTF-8,GBK两种方式
            data.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
            data.put("txnType", "00");                             //交易类型 00-默认
            data.put("txnSubType", "00");                          //交易子类型  默认00
            data.put("bizType", "000201");                         //业务类型 B2C网关支付,手机wap支付
    
            /***商户接入参数***/
            data.put("merId", merId);                  //商户号码,请改成自己申请的商户号或者open上注册得来的777商户号测试
            data.put("accessType", "0");                           //接入类型,商户接入固定填0,不需修改
    
            /***要调通交易以下字段必须修改***/
            data.put("orderId", orderId);                 //****商户订单号,每次发交易测试需修改为被查询的交易的订单号
            data.put("txnTime", txnTime);                 //****订单发送时间,每次发交易测试需修改为被查询的交易的订单发送时间
    
            /**请求参数设置完毕,以下对请求参数进行签名并发送http post请求,接收同步应答报文------------->**/
    
            Map<String, String> reqData = AcpService.sign(data,DemoBase.encoding);//报文中certId,signature的值是在signData方法中获取并自动赋值的,只要证书配置正确即可。
            LogUtil.writeLog("查询请求数据: " + reqData.toString());
    
            String url = SDKConfig.getConfig().getSingleQueryUrl();// 交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.singleQueryUrl
            //这里调用signData之后,调用submitUrl之前不能对submitFromData中的键值对做任何修改,如果修改会导致验签不通过
            Map<String, String> rspData = AcpService.post(reqData,url,DemoBase.encoding);
            LogUtil.writeLog("查询响应数据: " + rspData.toString());
    
            /**对应答码的处理,请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**/
            //应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
            if(!rspData.isEmpty()){
                if(AcpService.validate(rspData, DemoBase.encoding)){
                    LogUtil.writeLog("验证签名成功");
                    if("00".equals(rspData.get("respCode"))){//如果查询交易成功
                        //处理被查询交易的应答码逻辑
                        String origRespCode = rspData.get("origRespCode");
                        if("00".equals(origRespCode)){
                            //交易成功,更新商户订单状态
                            String txnAmt = rspData.get("txnAmt");
                            BigDecimal txnAmount = null;
                            if(!StringUtils.isEmpty(txnAmt)){
                                txnAmount = (new BigDecimal(txnAmt)).multiply(new BigDecimal(0.01));  //分转换为元;
                            }
                            String queryId = rspData.get("queryId");
                            String traceTime = rspData.get("traceTime");
                            String payCardNo = rspData.get("payCardNo");
                            String payCardType = rspData.get("payCardType"); //支付卡类型
                            String paymentMethodMethod; //PayPaymentMethod里面的method字段
                            if(StringUtils.isEmpty(payCardType)){
                                paymentMethodMethod = "UNION";  //对之前代码做兼容,如果没有支付卡类型的情况走默认
                            }else{
                                paymentMethodMethod = "UNION-" + payCardType;
                            }
    
                            //更改支付状态
    
                            //改变工单状态
                        }else if("03".equals(origRespCode) ||
                                "04".equals(origRespCode) ||
                                "05".equals(origRespCode)){
                            //需再次发起交易状态查询交易
                            throw new RuntimeException("查询结果:订单号" + orderId + "交易失败,应答码为“" + origRespCode + "”");
                        }else{
                            //其他应答码为失败请排查原因
                            throw new RuntimeException("查询结果:订单号" + orderId + "交易失败,应答码为“" + origRespCode + "”");
                        }
                    }else{//查询交易本身失败,或者未查到原交易,检查查询交易报文要素
                        throw new RuntimeException("查询失败");
                    }
                }else{
                    LogUtil.writeErrorLog("验证签名失败");
                    throw new RuntimeException("验证签名失败");
                    //TODO 检查验证签名失败的原因
                }
            }else{
                //未返回正确的http状态
                LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
                throw new RuntimeException("未获取到返回报文或返回http状态码非200");
            }
    
        }
    
        @Override
        public void successRedict(HttpServletRequest request, HttpServletResponse response) throws IOException {
            response.sendRedirect(redictUrl);
        }
    
    
        //---------------------------------------------------- private -----------------------------------------------------
    
        /**
         * 获取请求参数中所有的信息
         *
         * @param request
         * @return
         */
        private 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);
                    //在报文上送时,如果字段的值为空,则不上送<下面的处理为在获取所有参数数据时,判断若值为空,则删除这个字段>
                    //System.out.println("ServletUtil类247行  temp数据的键=="+en+"     值==="+value);
                    if (null == res.get(en) || "".equals(res.get(en))) {
                        res.remove(en);
                    }
                }
            }
            return res;
        }
    
    
    
        //收费比率 精确到分保留两位小数四舍五入
        private BigDecimal getFeeAmount(BigDecimal amount, BigDecimal feeRatio, BigDecimal feeMax) {
            BigDecimal fee = new BigDecimal(0);
            if(null == amount || null == feeRatio) return fee;
            //金额乘以费率 = 手续费
            fee = amount.multiply(feeRatio);
            //最大值为feeMax
            if(null != feeMax && feeMax.compareTo(new BigDecimal("0")) >= 0) fee = fee.max(feeMax);
            //设置精确到分并四舍五入
            fee = fee.setScale(4, BigDecimal.ROUND_HALF_UP);
            return fee;
        }
    
        /**
         * 时间格式化
         * @param date
         * @return
         */
        private static String formatTime(Date date){
            return new SimpleDateFormat("yyyyMMddHHmmss").format(date);
        }
        private static Date formatTime(String dateStr){
            if(null == dateStr) return null;
            if(dateStr.length() == 14){
                try {
                    return new SimpleDateFormat("yyyyMMddHHmmss").parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                    return null;
                }
            }else{
                try {
                    return new SimpleDateFormat("MMddHHmmss").parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                    return null;
                }
    
            }
    
        }
    
    
    }
    
    package com.example.demo;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Created by think on 2017/6/5.
     */
    public class JsonResult {
        private Boolean success = Boolean.valueOf(false);
        private String msg = "";
        private Object obj = null;
        private Integer type = Integer.valueOf(0);
        private Map<String, String> fieldErrors = new HashMap();
    
        public JsonResult() {
        }
    
        public JsonResult(Boolean success, String msg) {
            this.success = success;
            this.msg = msg;
        }
    
        public JsonResult(Boolean success, String msg, Integer type) {
            this.success = success;
            this.msg = msg;
            this.type = type;
        }
    
        public JsonResult(Boolean success, String msg, Object obj, Integer type) {
            this.success = success;
            this.msg = msg;
            this.obj = obj;
            this.type = type;
        }
    
        public Boolean getSuccess() {
            return Boolean.valueOf(this.success.booleanValue() && this.fieldErrors.size() == 0);
        }
    
        public void setSuccess(Boolean success) {
            this.success = success;
        }
    
        public String getMsg() {
            return this.msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public Object getObj() {
            return this.obj;
        }
    
        public void setObj(Object obj) {
            this.obj = obj;
        }
    
        public Integer getType() {
            return this.type;
        }
    
        public void setType(Integer type) {
            this.type = type;
        }
    
        public void addFieldError(String field, String message) {
            this.fieldErrors.put(field, message);
        }
    
        public void addFieldErrors(Map<String, String> fieldErrors) {
            this.fieldErrors.putAll(fieldErrors);
        }
    
        public Map<String, String> getFieldErrors() {
            return this.fieldErrors;
        }
    
        public static JsonResult resultError(String message) {
            return resultError(message, 0);
        }
    
        public static JsonResult resultError(String message, int type) {
            return new JsonResult(Boolean.valueOf(false), message, Integer.valueOf(0));
        }
    
        public static JsonResult resultSuccess(Object obj) {
            return resultSuccess("", obj);
        }
    
        public static JsonResult resultSuccess(String message, Object obj) {
            return resultSuccess(message, obj, 0);
        }
    
        public static JsonResult resultSuccess(String message, Object obj, int type) {
            return new JsonResult(Boolean.valueOf(true), message, obj, Integer.valueOf(type));
        }
    }
    
    package com.example.demo.union;
    
    
    import com.example.demo.union.config.SDKConfig;
    import com.example.demo.union.constants.SDKConstants;
    
    import java.io.*;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.Map.Entry;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipInputStream;
    
    
    /**
     * 名称: demo中用到的方法<br>
     * 日期: 2015-09<br>
     * 版本: 1.0.0 
     * 版权: 中国银联<br>
     * 说明:以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己需要,按照技术文档编写。该代码仅供参考。<br>
     */
    public class DemoBase {
    
    	//默认配置的是UTF-8
    	public static String encoding = "UTF-8";
    	
    	//全渠道固定值
    	public static String version = SDKConfig.getConfig().getVersion();
    	
    	//后台服务对应的写法参照 FrontRcvResponse.java
    	public static String frontUrl = SDKConfig.getConfig().getFrontUrl();
    
    	//后台服务对应的写法参照 BackRcvResponse.java
    	public static String backUrl = SDKConfig.getConfig().getBackUrl();//受理方和发卡方自选填写的域[O]--后台通知地址
    
    	// 商户发送交易时间 格式:YYYYMMDDhhmmss
    	public static String getCurrentTime() {
    		return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    	}
    	
    	// AN8..40 商户订单号,不能含"-"或"_"
    	public static String getOrderId() {
    		return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    	}
    	
       /**
    	 * 组装请求,返回报文字符串用于显示
    	 * @param data
    	 * @return
    	 */
        public static String genHtmlResult(Map<String, String> data){
    
        	TreeMap<String, String> tree = new TreeMap<String, String>();
    		Iterator<Entry<String, String>> it = data.entrySet().iterator();
    		while (it.hasNext()) {
    			Entry<String, String> en = it.next();
    			tree.put(en.getKey(), en.getValue());
    		}
    		it = tree.entrySet().iterator();
    		StringBuffer sf = new StringBuffer();
    		while (it.hasNext()) {
    			Entry<String, String> en = it.next();
    			String key = en.getKey(); 
    			String value =  en.getValue();
    			if("respCode".equals(key)){
    				sf.append("<b>"+key + SDKConstants.EQUAL + value+"</br></b>");
    			}else
    				sf.append(key + SDKConstants.EQUAL + value+"</br>");
    		}
    		return sf.toString();
        }
        /**
    	 * 功能:解析全渠道商户对账文件中的ZM文件并以List<Map>方式返回
    	 * 适用交易:对账文件下载后对文件的查看
    	 * @param filePath ZM文件全路径
    	 * @return 包含每一笔交易中 序列号 和 值 的map序列
    	 */
    	public static List<Map> parseZMFile(String filePath){
    		int lengthArray[] = {3,11,11,6,10,19,12,4,2,21,2,32,2,6,10,13,13,4,15,2,2,6,2,4,32,1,21,15,1,15,32,13,13,8,32,13,13,12,2,1,32,98};
    		return parseFile(filePath,lengthArray);
    	}
    	
    	/**
    	 * 功能:解析全渠道商户对账文件中的ZME文件并以List<Map>方式返回
    	 * 适用交易:对账文件下载后对文件的查看
    	 * @param filePath ZME文件全路径
    	 * @return 包含每一笔交易中 序列号 和 值 的map序列
    	 */
    	public static List<Map> parseZMEFile(String filePath){
    		int lengthArray[] = {3,11,11,6,10,19,12,4,2,2,6,10,4,12,13,13,15,15,1,12,2,135};
    		return parseFile(filePath,lengthArray);
    	}
    	
    	/**
    	 * 功能:解析全渠道商户 ZM,ZME对账文件
    	 * @param filePath
    	 * @param lengthArray 参照《全渠道平台接入接口规范 第3部分 文件接口》 全渠道商户对账文件 6.1 ZM文件和6.2 ZME 文件 格式的类型长度组成int型数组
    	 * @return
    	 */
    	private static List<Map> parseFile(String filePath,int lengthArray[]){
    	 	List<Map> ZmDataList = new ArrayList<Map>();
    	 	try {
                String encoding="UTF-8";
                File file=new File(filePath);
                if(file.isFile() && file.exists()){ //判断文件是否存在
                    InputStreamReader read = new InputStreamReader(
                    new FileInputStream(file),encoding);//考虑到编码格式
                    BufferedReader bufferedReader = new BufferedReader(read);
                    String lineTxt = null;
                    while((lineTxt = bufferedReader.readLine()) != null){
                    	//解析的结果MAP,key为对账文件列序号,value为解析的值
            		 	Map<Integer,String> ZmDataMap = new LinkedHashMap<Integer,String>();
                        //左侧游标
                        int leftIndex = 0;
                        //右侧游标
                        int rightIndex = 0;
                        for(int i=0;i<lengthArray.length;i++){
                        	rightIndex = leftIndex + lengthArray[i];
                        	String filed = lineTxt.substring(leftIndex,rightIndex);
                        	leftIndex = rightIndex+1;
                        	ZmDataMap.put(i, filed);
                        }
                        ZmDataList.add(ZmDataMap);
                    }
                    read.close();
            }else{
                System.out.println("找不到指定的文件");
            }
            } catch (Exception e) {
                System.out.println("读取文件内容出错");
                e.printStackTrace();
            }
    	 	
    		return ZmDataList;	
    	}
    	 
        public static String getFileContentTable(List<Map> dataList,String file){
        	StringBuffer  tableSb = new StringBuffer("对账文件的规范参考 https://open.unionpay.com/ajweb/help/file/ 产品接口规范->平台接口规范:文件接口</br> 文件【"+file + "】解析后内容如下:");
        	tableSb.append("<table border=\"1\">");
        	if(dataList.size() > 0){
        		Map<Integer,String> dataMapTmp = dataList.get(0);
        		tableSb.append("<tr>");
    	 		for(Iterator<Integer> it = dataMapTmp.keySet().iterator();it.hasNext();){
    	 			Integer key = it.next();
    	 			String value = dataMapTmp.get(key);
    		 		System.out.println("序号:"+ (key+1) + " 值: '"+ value +"'");
    		 		tableSb.append("<td>序号"+(key+1)+"</td>");
    		 	}
    	 		tableSb.append("</tr>");
        	}
        	
        	for(int i=0;i<dataList.size();i++){
    	 		System.out.println("行数: "+ (i+1));
    	 		Map<Integer,String> dataMapTmp = dataList.get(i);
    	 		tableSb.append("<tr>");
    	 		for(Iterator<Integer> it = dataMapTmp.keySet().iterator();it.hasNext();){
    	 			Integer key = it.next();
    	 			String value = dataMapTmp.get(key);
    		 		System.out.println("序号:"+ (key+1) + " 值: '"+ value +"'");
    		 		tableSb.append("<td>"+value+"</td>");
    		 	}
    	 		tableSb.append("</tr>");
    	 	}
        	tableSb.append("</table>");
        	return tableSb.toString();
        }
    
    	
    	public static List<String> unzip(String zipFilePath,String outPutDirectory){
    		List<String> fileList = new ArrayList<String>();
    		try {
                ZipInputStream zin = new ZipInputStream(new FileInputStream(zipFilePath));//输入源zip路径  
                BufferedInputStream bin = new BufferedInputStream(zin);
                BufferedOutputStream bout = null;
                File file=null;  
                ZipEntry entry;
                try {
                    while((entry = zin.getNextEntry())!=null && !entry.isDirectory()){
                    	file = new File(outPutDirectory,entry.getName());  
                        if(!file.exists()){  
                            (new File(file.getParent())).mkdirs();  
                        }
                        bout = new BufferedOutputStream(new FileOutputStream(file));  
                        int b;
                        while((b=bin.read())!=-1){  
                        	bout.write(b);  
                        }
                        bout.flush();
                        fileList.add(file.getAbsolutePath());
                        System.out.println(file+"解压成功");
                    }
                } catch (IOException e) {  
                    e.printStackTrace();  
                }finally{
                    try {
    					bin.close();
    					zin.close();
    					if(bout!=null){
    						bout.close();
    					}
    				} catch (IOException e) {
    					e.printStackTrace();
    				}  
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();  
            }
    		return fileList;
    	}
    
    }
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28     报文加密解密等操作的工具类
     * =============================================================================
     */
    package com.example.demo.union.util;
    
    import org.apache.commons.codec.binary.Base64;
    import org.bouncycastle.crypto.digests.SM3Digest;
    
    import javax.crypto.Cipher;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.Signature;
    
    /**
     * 
     * @ClassName SecureUtil
     * @Description acpsdk安全算法工具类
     * @date 2016-7-22 下午4:08:32
     *
     */
    public class SecureUtil {
    	/**
    	 * 算法常量: SHA1
    	 */
    	private static final String ALGORITHM_SHA1 = "SHA-1";
    	/**
    	 * 算法常量: SHA256
    	 */
    	private static final String ALGORITHM_SHA256 = "SHA-256";
    	/**
    	 * 算法常量:SHA1withRSA
    	 */
    	private static final String BC_PROV_ALGORITHM_SHA1RSA = "SHA1withRSA";
    	/**
    	 * 算法常量:SHA256withRSA
    	 */
    	private static final String BC_PROV_ALGORITHM_SHA256RSA = "SHA256withRSA";
    
    	/**
    	 * sm3计算后进行16进制转换
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @param encoding
    	 *            编码
    	 * @return 计算结果
    	 */
    	public static String sm3X16Str(String data, String encoding) {
    		byte[] bytes = sm3(data, encoding);
    		StringBuilder sm3StrBuff = new StringBuilder();
    		for (int i = 0; i < bytes.length; i++) {
    			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
    				sm3StrBuff.append("0").append(
    						Integer.toHexString(0xFF & bytes[i]));
    			} else {
    				sm3StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
    			}
    		}
    		return sm3StrBuff.toString();
    	}
    
    	/**
    	 * sha1计算后进行16进制转换
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @param encoding
    	 *            编码
    	 * @return 计算结果
    	 */
    	public static byte[] sha1X16(String data, String encoding) {
    		byte[] bytes = sha1(data, encoding);
    		StringBuilder sha1StrBuff = new StringBuilder();
    		for (int i = 0; i < bytes.length; i++) {
    			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
    				sha1StrBuff.append("0").append(
    						Integer.toHexString(0xFF & bytes[i]));
    			} else {
    				sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
    			}
    		}
    		try {
    			return sha1StrBuff.toString().getBytes(encoding);
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return null;
    		}
    	}
    	
    	
    	/**
    	 * sha256计算后进行16进制转换
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @param encoding
    	 *            编码
    	 * @return 计算结果
    	 */
    	public static String sha256X16Str(String data, String encoding) {
    		byte[] bytes = sha256(data, encoding);
    		StringBuilder sha256StrBuff = new StringBuilder();
    		for (int i = 0; i < bytes.length; i++) {
    			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
    				sha256StrBuff.append("0").append(
    						Integer.toHexString(0xFF & bytes[i]));
    			} else {
    				sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
    			}
    		}
    		return sha256StrBuff.toString();
    	}
    	
    	/**
    	 * sha256计算后进行16进制转换
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @param encoding
    	 *            编码
    	 * @return 计算结果
    	 */
    	public static byte[] sha256X16(String data, String encoding) {
    		byte[] bytes = sha256(data, encoding);
    		StringBuilder sha256StrBuff = new StringBuilder();
    		for (int i = 0; i < bytes.length; i++) {
    			if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
    				sha256StrBuff.append("0").append(
    						Integer.toHexString(0xFF & bytes[i]));
    			} else {
    				sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
    			}
    		}
    		try {
    			return sha256StrBuff.toString().getBytes(encoding);
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return null;
    		}
    	}
    
    	/**
    	 * sha1计算.
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @return 计算结果
    	 */
    	private static byte[] sha1(byte[] data) {
    		MessageDigest md = null;
    		try {
    			md = MessageDigest.getInstance(ALGORITHM_SHA1);
    			md.reset();
    			md.update(data);
    			return md.digest();
    		} catch (Exception e) {
    			LogUtil.writeErrorLog("SHA1计算失败", e);
    			return null;
    		}
    	}
    	
    	/**
    	 * sha256计算.
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @return 计算结果
    	 */
    	private static byte[] sha256(byte[] data) {
    		MessageDigest md = null;
    		try {
    			md = MessageDigest.getInstance(ALGORITHM_SHA256);
    			md.reset();
    			md.update(data);
    			return md.digest();
    		} catch (Exception e) {
    			LogUtil.writeErrorLog("SHA256计算失败", e);
    			return null;
    		}
    	}
    	
    	/**
    	 * SM3计算.
    	 * 
    	 * @param data
    	 *            待计算的数据
    	 * @return 计算结果
    	 */
    	private static byte[] sm3(byte[] data) {
    		SM3Digest sm3 = new SM3Digest();
    		sm3.update(data, 0, data.length);
    		byte[] result = new byte[sm3.getDigestSize()];
    		sm3.doFinal(result, 0);
    		return result;
    	}
    	
    	/**
    	 * sha1计算
    	 * 
    	 * @param datas
    	 *            待计算的数据
    	 * @param encoding
    	 *            字符集编码
    	 * @return
    	 */
    	private static byte[] sha1(String datas, String encoding) {
    		try {
    			return sha1(datas.getBytes(encoding));
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog("SHA1计算失败", e);
    			return null;
    		}
    	}
    	
    	/**
    	 * sha256计算
    	 * 
    	 * @param datas
    	 *            待计算的数据
    	 * @param encoding
    	 *            字符集编码
    	 * @return
    	 */
    	private static byte[] sha256(String datas, String encoding) {
    		try {
    			return sha256(datas.getBytes(encoding));
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog("SHA256计算失败", e);
    			return null;
    		}
    	}
    
    	/**
    	 * sm3计算
    	 * 
    	 * @param datas
    	 *            待计算的数据
    	 * @param encoding
    	 *            字符集编码
    	 * @return
    	 */
    	private static byte[] sm3(String datas, String encoding) {
    		try {
    			return sm3(datas.getBytes(encoding));
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog("SM3计算失败", e);
    			return null;
    		}
    	}
    
    	/**
    	 * 
    	 * @param privateKey
    	 * @param data
    	 * @return
    	 * @throws Exception
    	 */
    	public static byte[] signBySoft(PrivateKey privateKey, byte[] data)
    			throws Exception {
    		byte[] result = null;
    		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
    		st.initSign(privateKey);
    		st.update(data);
    		result = st.sign();
    		return result;
    	}
    	
    	/**
    	 * @param privateKey
    	 * @param data
    	 * @return
    	 * @throws Exception
    	 */
    	public static byte[] signBySoft256(PrivateKey privateKey, byte[] data)
    			throws Exception {
    		byte[] result = null;
    		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
    		st.initSign(privateKey);
    		st.update(data);
    		result = st.sign();
    		return result;
    	}
    
    	public static boolean validateSignBySoft(PublicKey publicKey,
    			byte[] signData, byte[] srcData) throws Exception {
    		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
    		st.initVerify(publicKey);
    		st.update(srcData);
    		return st.verify(signData);
    	}
    	
    	public static boolean validateSignBySoft256(PublicKey publicKey,
    			byte[] signData, byte[] srcData) throws Exception {
    		Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
    		st.initVerify(publicKey);
    		st.update(srcData);
    		return st.verify(signData);
    	}
    
    	/**
    	 * 对数据通过公钥进行加密,并进行base64计算
    	 * 
    	 * @param dataString
    	 *            待处理数据
    	 * @param encoding
    	 *            字符编码
    	 * @param key
    	 *            公钥
    	 * @return
    	 */
    	public static String encryptData(String dataString, String encoding,
    			PublicKey key) {
    		/** 使用公钥对密码加密 **/
    		byte[] data = null;
    		try {
    			data = encryptData(key, dataString.getBytes(encoding));
    			return new String(SecureUtil.base64Encode(data), encoding);
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return "";
    		}
    	}
    
    	/**
    	 * 对数据通过公钥进行加密,并进行base64计算
    	 * 
    	 * @param pin
    	 *            待处理数据
    	 * @param encoding
    	 *            字符编码
    	 * @param key
    	 *            公钥
    	 * @return
    	 */
    	public static String encryptPin(String accNo, String pin, String encoding,
    			PublicKey key) {
    		/** 使用公钥对密码加密 **/
    		byte[] data = null;
    		try {
    			data = pin2PinBlockWithCardNO(pin, accNo);
    			data = encryptData(key, data);
    			return new String(SecureUtil.base64Encode(data), encoding);
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return "";
    		}
    	}
    	
    	/**
    	 * 通过私钥解密
    	 * 
    	 * @param dataString
    	 *            base64过的数据
    	 * @param encoding
    	 *            编码
    	 * @param key
    	 *            私钥
    	 * @return 解密后的数据
    	 */
    	public static String decryptData(String dataString, String encoding,
    			PrivateKey key) {
    		byte[] data = null;
    		try {
    			data = SecureUtil.base64Decode(dataString.getBytes(encoding));
    			data = decryptData(key, data);
    			return new String(data, encoding);
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return "";
    		}
    	}
    
    	/**
    	 * BASE64解码
    	 * 
    	 * @param inputByte
    	 *            待解码数据
    	 * @return 解码后的数据
    	 * @throws IOException
    	 */
    	public static byte[] base64Decode(byte[] inputByte) throws IOException {
    		return Base64.decodeBase64(inputByte);
    	}
    
    	/**
    	 * BASE64编码
    	 * 
    	 * @param inputByte
    	 *            待编码数据
    	 * @return 解码后的数据
    	 * @throws IOException
    	 */
    	public static byte[] base64Encode(byte[] inputByte) throws IOException {
    		return Base64.encodeBase64(inputByte);
    	}
    
    	/**
    	 * 加密除pin之外的其他信息
    	 * 
    	 * @param publicKey
    	 * @param plainData
    	 * @return
    	 * @throws Exception
    	 */
    	private static byte[] encryptData(PublicKey publicKey, byte[] plainData)
    			throws Exception {
    		try {
    			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
    			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    			return cipher.doFinal(plainData);
    		} catch (Exception e) {
    			throw new Exception(e.getMessage());
    		}
    	}
    
    	/**
    	 * @param privateKey
    	 * @param data
    	 * @return
    	 * @throws Exception
    	 */
    	private static byte[] decryptData(PrivateKey privateKey, byte[] data)
    			throws Exception {
    		try {
    			Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding","BC");
    			cipher.init(Cipher.DECRYPT_MODE, privateKey);
    			return cipher.doFinal(data);
    		} catch (Exception e) {
    			LogUtil.writeErrorLog("解密失败", e);
    		}
    		return null;
    	}
    
    	/**
    	 * 
    	 * @param aPin
    	 * @return
    	 */
    	private static byte[] pin2PinBlock(String aPin) {
    		int tTemp = 1;
    		int tPinLen = aPin.length();
    
    		byte[] tByte = new byte[8];
    		try {
    			/*******************************************************************
    			 * if (tPinLen > 9) { tByte[0] = (byte) Integer.parseInt(new
    			 * Integer(tPinLen) .toString(), 16); } else { tByte[0] = (byte)
    			 * Integer.parseInt(new Integer(tPinLen) .toString(), 10); }
    			 ******************************************************************/
    //			tByte[0] = (byte) Integer.parseInt(new Integer(tPinLen).toString(),
    //					10);
    			tByte[0] = (byte) Integer.parseInt(Integer.toString(tPinLen), 10);
    			if (tPinLen % 2 == 0) {
    				for (int i = 0; i < tPinLen;) {
    					String a = aPin.substring(i, i + 2);
    					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
    					if (i == (tPinLen - 2)) {
    						if (tTemp < 7) {
    							for (int x = (tTemp + 1); x < 8; x++) {
    								tByte[x] = (byte) 0xff;
    							}
    						}
    					}
    					tTemp++;
    					i = i + 2;
    				}
    			} else {
    				for (int i = 0; i < tPinLen - 1;) {
    					String a;
    					a = aPin.substring(i, i + 2);
    					tByte[tTemp] = (byte) Integer.parseInt(a, 16);
    					if (i == (tPinLen - 3)) {
    						String b = aPin.substring(tPinLen - 1) + "F";
    						tByte[tTemp + 1] = (byte) Integer.parseInt(b, 16);
    						if ((tTemp + 1) < 7) {
    							for (int x = (tTemp + 2); x < 8; x++) {
    								tByte[x] = (byte) 0xff;
    							}
    						}
    					}
    					tTemp++;
    					i = i + 2;
    				}
    			}
    		} catch (Exception e) {
    		}
    
    		return tByte;
    	}
    
    	/**
    	 * 
    	 * @param aPan
    	 * @return
    	 */
    	private static byte[] formatPan(String aPan) {
    		int tPanLen = aPan.length();
    		byte[] tByte = new byte[8];
    		;
    		int temp = tPanLen - 13;
    		try {
    			tByte[0] = (byte) 0x00;
    			tByte[1] = (byte) 0x00;
    			for (int i = 2; i < 8; i++) {
    				String a = aPan.substring(temp, temp + 2);
    				tByte[i] = (byte) Integer.parseInt(a, 16);
    				temp = temp + 2;
    			}
    		} catch (Exception e) {
    		}
    		return tByte;
    	}
    
    	/**
    	 * 
    	 * @param aPin
    	 * @param aCardNO
    	 * @return
    	 */
    	private static byte[] pin2PinBlockWithCardNO(String aPin, String aCardNO) {
    		byte[] tPinByte = pin2PinBlock(aPin);
    		if (aCardNO.length() == 11) {
    			aCardNO = "00" + aCardNO;
    		} else if (aCardNO.length() == 12) {
    			aCardNO = "0" + aCardNO;
    		}
    		byte[] tPanByte = formatPan(aCardNO);
    		byte[] tByte = new byte[8];
    		for (int i = 0; i < 8; i++) {
    			tByte[i] = (byte) (tPinByte[i] ^ tPanByte[i]);
    		}
    		return tByte;
    	}
    	
    	 /**
        * luhn算法
        * 
        * @param number
        * @return
        */
       public static int genLuhn(String number) {
           number = number + "0";
           int s1 = 0, s2 = 0;
           String reverse = new StringBuffer(number).reverse().toString();
           for (int i = 0; i < reverse.length(); i++) {
               int digit = Character.digit(reverse.charAt(i), 10);
               if (i % 2 == 0) {// this is for odd digits, they are 1-indexed in //
                                // the algorithm
                   s1 += digit;
               } else {// add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
                   s2 += 2 * digit;
                   if (digit >= 5) {
                       s2 -= 9;
                   }
               }
           }
           int check = 10 - ((s1 + s2) % 10);
           if (check == 10)
               check = 0;
           return check;
       }
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28      MPI工具类
     * =============================================================================
     */
    package com.example.demo.union.util;
    
    import com.example.demo.union.config.SDKConfig;
    import com.example.demo.union.constants.SDKConstants;
    import org.apache.commons.lang.StringUtils;
    
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.security.cert.X509Certificate;
    import java.util.*;
    import java.util.Map.Entry;
    import java.util.zip.Deflater;
    import java.util.zip.Inflater;
    
    import static com.example.demo.union.constants.SDKConstants.*;
    
    /**
     * 
     * @ClassName SDKUtil
     * @Description acpsdk工具类
     * @date 2016-7-22 下午4:06:18
     *
     */
    public class SDKUtil {
    
    	/**
    	 * 根据signMethod的值,提供三种计算签名的方法
    	 * 
    	 * @param data
    	 *            待签名数据Map键值对形式
    	 * @param encoding
    	 *            编码
    	 * @return 签名是否成功
    	 */
    	public static boolean sign(Map<String, String> data, String encoding) {
    		
    		if (isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    		String signMethod = data.get(param_signMethod);
    		String version = data.get(SDKConstants.param_version);
    		if (!VERSION_1_0_0.equals(version) && !VERSION_5_0_1.equals(version) && isEmpty(signMethod)) {
    			LogUtil.writeErrorLog("signMethod must Not null");
    			return false;
    		}
    		
    		if (isEmpty(version)) {
    			LogUtil.writeErrorLog("version must Not null");
    			return false;
    		}
    		if (SIGNMETHOD_RSA.equals(signMethod)|| VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    			if (VERSION_5_0_0.equals(version)|| VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    				// 设置签名证书序列号
    				data.put(SDKConstants.param_certId, CertUtil.getSignCertId());
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(data);
    				LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    				byte[] byteSign = null;
    				String stringSign = null;
    				try {
    					// 通过SHA1进行摘要并转16进制
    					byte[] signDigest = SecureUtil
    							.sha1X16(stringData, encoding);
    					byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft(
    							CertUtil.getSignCertPrivateKey(), signDigest));
    					stringSign = new String(byteSign);
    					// 设置签名域值
    					data.put(SDKConstants.param_signature, stringSign);
    					return true;
    				} catch (Exception e) {
    					LogUtil.writeErrorLog("Sign Error", e);
    					return false;
    				}
    			} else if (VERSION_5_1_0.equals(version)) {
    				// 设置签名证书序列号
    				data.put(SDKConstants.param_certId, CertUtil.getSignCertId());
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(data);
    				LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    				byte[] byteSign = null;
    				String stringSign = null;
    				try {
    					// 通过SHA256进行摘要并转16进制
    					byte[] signDigest = SecureUtil
    							.sha256X16(stringData, encoding);
    					byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft256(
    							CertUtil.getSignCertPrivateKey(), signDigest));
    					stringSign = new String(byteSign);
    					// 设置签名域值
    					data.put(SDKConstants.param_signature, stringSign);
    					return true;
    				} catch (Exception e) {
    					LogUtil.writeErrorLog("Sign Error", e);
    					return false;
    				}
    			}
    		} else if (SIGNMETHOD_SHA256.equals(signMethod)) {
    			return signBySecureKey(data, SDKConfig.getConfig()
    					.getSecureKey(), encoding);
    		} else if (SIGNMETHOD_SM3.equals(signMethod)) {
    			return signBySecureKey(data, SDKConfig.getConfig()
    					.getSecureKey(), encoding);
    		}
    		return false;
    	}
    
    	/**
    	 * 通过传入的证书绝对路径和证书密码读取签名证书进行签名并返回签名值<br>
    	 * 
    	 * @param data
    	 *            待签名数据Map键值对形式
    	 * @param encoding
    	 *            编码
    	 * @param secureKey
    	 *            证书绝对路径
    	 * @para certPwd
    	 *            证书密码
    	 * @return 签名值
    	 */
    	public static boolean signBySecureKey(Map<String, String> data, String secureKey,
    			String encoding) {
    		
    		if (isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    		if (isEmpty(secureKey)) {
    			LogUtil.writeErrorLog("secureKey is empty");
    			return false;
    		}
    		String signMethod = data.get(param_signMethod);
    		if (isEmpty(signMethod)) {
    			LogUtil.writeErrorLog("signMethod must Not null");
    			return false;
    		}
    		
    		if (SIGNMETHOD_SHA256.equals(signMethod)) {
    			// 将Map信息转换成key1=value1&key2=value2的形式
    			String stringData = coverMap2String(data);
    			LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    			String strBeforeSha256 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sha256X16Str(secureKey, encoding);
    			String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
    					encoding);
    			// 设置签名域值
    			data.put(SDKConstants.param_signature, strAfterSha256);
    			return true;
    		} else if (SIGNMETHOD_SM3.equals(signMethod)) {
    			String stringData = coverMap2String(data);
    			LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    			String strBeforeSM3 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sm3X16Str(secureKey, encoding);
    			String strAfterSM3 = SecureUtil.sm3X16Str(strBeforeSM3, encoding);
    			// 设置签名域值
    			data.put(SDKConstants.param_signature, strAfterSM3);
    			return true;
    		}
    		return false;
    	}
    
    	/**
    	 * 通过传入的签名密钥进行签名并返回签名值<br>
    	 * 
    	 * @param data
    	 *            待签名数据Map键值对形式
    	 * @param encoding
    	 *            编码
    	 * @param certPath
    	 *            证书绝对路径
    	 * @param certPwd
    	 *            证书密码
    	 * @return 签名值
    	 */
    	public static boolean signByCertInfo(Map<String, String> data,
    			String certPath, String certPwd, String encoding) {
    		
    		if (isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    		if (isEmpty(certPath) || isEmpty(certPwd)) {
    			LogUtil.writeErrorLog("CertPath or CertPwd is empty");
    			return false;
    		}
    		String signMethod = data.get(param_signMethod);
    		String version = data.get(SDKConstants.param_version);
    		if (!VERSION_1_0_0.equals(version) && !VERSION_5_0_1.equals(version) && isEmpty(signMethod)) {
    			LogUtil.writeErrorLog("signMethod must Not null");
    			return false;
    		}
    		if (isEmpty(version)) {
    			LogUtil.writeErrorLog("version must Not null");
    			return false;
    		}
    		
    		if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    			if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    				// 设置签名证书序列号
    				data.put(SDKConstants.param_certId, CertUtil.getCertIdByKeyStoreMap(certPath, certPwd));
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(data);
    				LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    				byte[] byteSign = null;
    				String stringSign = null;
    				try {
    					// 通过SHA1进行摘要并转16进制
    					byte[] signDigest = SecureUtil
    							.sha1X16(stringData, encoding);
    					byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft(
    							CertUtil.getSignCertPrivateKeyByStoreMap(certPath, certPwd), signDigest));
    					stringSign = new String(byteSign);
    					// 设置签名域值
    					data.put(SDKConstants.param_signature, stringSign);
    					return true;
    				} catch (Exception e) {
    					LogUtil.writeErrorLog("Sign Error", e);
    					return false;
    				}
    			} else if (VERSION_5_1_0.equals(version)) {
    				// 设置签名证书序列号
    				data.put(SDKConstants.param_certId, CertUtil.getCertIdByKeyStoreMap(certPath, certPwd));
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(data);
    				LogUtil.writeLog("待签名请求报文串:[" + stringData + "]");
    				byte[] byteSign = null;
    				String stringSign = null;
    				try {
    					// 通过SHA256进行摘要并转16进制
    					byte[] signDigest = SecureUtil
    							.sha256X16(stringData, encoding);
    					byteSign = SecureUtil.base64Encode(SecureUtil.signBySoft256(
    							CertUtil.getSignCertPrivateKeyByStoreMap(certPath, certPwd), signDigest));
    					stringSign = new String(byteSign);
    					// 设置签名域值
    					data.put(SDKConstants.param_signature, stringSign);
    					return true;
    				} catch (Exception e) {
    					LogUtil.writeErrorLog("Sign Error", e);
    					return false;
    				}
    			}
    			
    		} 
    		return false;
    	}
    	
    	/**
    	 * 验证签名
    	 * 
    	 * @param resData
    	 *            返回报文数据
    	 * @param encoding
    	 *            编码格式
    	 * @return
    	 */
    	public static boolean validateBySecureKey(Map<String, String> resData, String secureKey, String encoding) {
    		LogUtil.writeLog("验签处理开始");
    		if (isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    		String signMethod = resData.get(SDKConstants.param_signMethod);
    		if (SIGNMETHOD_SHA256.equals(signMethod)) {
    			// 1.进行SHA256验证
    			String stringSign = resData.get(SDKConstants.param_signature);
    			LogUtil.writeLog("签名原文:["+stringSign+"]");
    			// 将Map信息转换成key1=value1&key2=value2的形式
    			String stringData = coverMap2String(resData);
    			LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    			String strBeforeSha256 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sha256X16Str(secureKey, encoding);
    			String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
    					encoding);
    			return stringSign.equals(strAfterSha256);
    		} else if (SIGNMETHOD_SM3.equals(signMethod)) {
    			// 1.进行SM3验证
    			String stringSign = resData.get(SDKConstants.param_signature);
    			LogUtil.writeLog("签名原文:["+stringSign+"]");
    			// 将Map信息转换成key1=value1&key2=value2的形式
    			String stringData = coverMap2String(resData);
    			LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    			String strBeforeSM3 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sm3X16Str(secureKey, encoding);
    			String strAfterSM3 = SecureUtil
    					.sm3X16Str(strBeforeSM3, encoding);
    			return stringSign.equals(strAfterSM3);
    		}
    		return false;
    	}
    	
    	/**
    	 * 验证签名
    	 * 
    	 * @param resData
    	 *            返回报文数据
    	 * @param encoding
    	 *            编码格式
    	 * @return
    	 */
    	public static boolean validate(Map<String, String> resData, String encoding) {
    		LogUtil.writeLog("验签处理开始");
    		if (isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    		String signMethod = resData.get(SDKConstants.param_signMethod);
    		String version = resData.get(SDKConstants.param_version);
    		if (SIGNMETHOD_RSA.equals(signMethod) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    			// 获取返回报文的版本号
    			if (VERSION_5_0_0.equals(version) || VERSION_1_0_0.equals(version) || VERSION_5_0_1.equals(version)) {
    				String stringSign = resData.get(SDKConstants.param_signature);
    				LogUtil.writeLog("签名原文:["+stringSign+"]");
    				// 从返回报文中获取certId ,然后去证书静态Map中查询对应验签证书对象
    				String certId = resData.get(SDKConstants.param_certId);
    				LogUtil.writeLog("对返回报文串验签使用的验签公钥序列号:["+certId+"]");
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(resData);
    				LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    				try {
    					// 验证签名需要用银联发给商户的公钥证书.
    					return SecureUtil.validateSignBySoft(CertUtil
    							.getValidatePublicKey(certId), SecureUtil
    							.base64Decode(stringSign.getBytes(encoding)),
    							SecureUtil.sha1X16(stringData, encoding));
    				} catch (UnsupportedEncodingException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				} catch (Exception e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				}
    			} else if (VERSION_5_1_0.equals(version)) {
    				// 1.从返回报文中获取公钥信息转换成公钥对象
    				String strCert = resData.get(SDKConstants.param_signPubKeyCert);
    //				LogUtil.writeLog("验签公钥证书:["+strCert+"]");
    				X509Certificate x509Cert = CertUtil.genCertificateByStr(strCert);
    				if(x509Cert == null) {
    					LogUtil.writeErrorLog("convert signPubKeyCert failed");
    					return false;
    				}
    				// 2.验证证书链
    				if (!CertUtil.verifyCertificate(x509Cert)) {
    					LogUtil.writeErrorLog("验证公钥证书失败,证书信息:["+strCert+"]");
    					return false;
    				}
    				
    				// 3.验签
    				String stringSign = resData.get(SDKConstants.param_signature);
    				LogUtil.writeLog("签名原文:["+stringSign+"]");
    				// 将Map信息转换成key1=value1&key2=value2的形式
    				String stringData = coverMap2String(resData);
    				LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    				try {
    					// 验证签名需要用银联发给商户的公钥证书.
    					boolean result = SecureUtil.validateSignBySoft256(x509Cert
    							.getPublicKey(), SecureUtil.base64Decode(stringSign
    							.getBytes(encoding)), SecureUtil.sha256X16(
    							stringData, encoding));
    					LogUtil.writeLog("验证签名" + (result? "成功":"失败"));
    					return result;
    				} catch (UnsupportedEncodingException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				} catch (Exception e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				}
    			}
    
    		} else if (SIGNMETHOD_SHA256.equals(signMethod)) {
    			// 1.进行SHA256验证
    			String stringSign = resData.get(SDKConstants.param_signature);
    			LogUtil.writeLog("签名原文:["+stringSign+"]");
    			// 将Map信息转换成key1=value1&key2=value2的形式
    			String stringData = coverMap2String(resData);
    			LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    			String strBeforeSha256 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sha256X16Str(SDKConfig.getConfig()
    							.getSecureKey(), encoding);
    			String strAfterSha256 = SecureUtil.sha256X16Str(strBeforeSha256,
    					encoding);
    			boolean result =  stringSign.equals(strAfterSha256);
    			LogUtil.writeLog("验证签名" + (result? "成功":"失败"));
    			return result;
    		} else if (SIGNMETHOD_SM3.equals(signMethod)) {
    			// 1.进行SM3验证
    			String stringSign = resData.get(SDKConstants.param_signature);
    			LogUtil.writeLog("签名原文:["+stringSign+"]");
    			// 将Map信息转换成key1=value1&key2=value2的形式
    			String stringData = coverMap2String(resData);
    			LogUtil.writeLog("待验签返回报文串:["+stringData+"]");
    			String strBeforeSM3 = stringData
    					+ SDKConstants.AMPERSAND
    					+ SecureUtil.sm3X16Str(SDKConfig.getConfig()
    							.getSecureKey(), encoding);
    			String strAfterSM3 = SecureUtil
    					.sm3X16Str(strBeforeSM3, encoding);
    			boolean result =  stringSign.equals(strAfterSM3);
    			LogUtil.writeLog("验证签名" + (result? "成功":"失败"));
    			return result;
    		}
    		return false;
    	}
    
    	/**
    	 * 将Map中的数据转换成key1=value1&key2=value2的形式 不包含签名域signature
    	 * 
    	 * @param data
    	 *            待拼接的Map数据
    	 * @return 拼接好后的字符串
    	 */
    	public static String coverMap2String(Map<String, String> data) {
    		TreeMap<String, String> tree = new TreeMap<String, String>();
    		Iterator<Entry<String, String>> it = data.entrySet().iterator();
    		while (it.hasNext()) {
    			Entry<String, String> en = it.next();
    			if (SDKConstants.param_signature.equals(en.getKey().trim())) {
    				continue;
    			}
    			tree.put(en.getKey(), en.getValue());
    		}
    		it = tree.entrySet().iterator();
    		StringBuffer sf = new StringBuffer();
    		while (it.hasNext()) {
    			Entry<String, String> en = it.next();
    			sf.append(en.getKey() + SDKConstants.EQUAL + en.getValue()
    					+ SDKConstants.AMPERSAND);
    		}
    		return sf.substring(0, sf.length() - 1);
    	}
    
    
    	/**
    	 * 兼容老方法 将形如key=value&key=value的字符串转换为相应的Map对象
    	 * 
    	 * @param result
    	 * @return
    	 */
    	public static Map<String, String> coverResultString2Map(String result) {
    		return convertResultStringToMap(result);
    	}
    
    	/**
    	 * 将形如key=value&key=value的字符串转换为相应的Map对象
    	 * 
    	 * @param result
    	 * @return
    	 */
    	public static Map<String, String> convertResultStringToMap(String result) {
    		Map<String, String> map =null;
    		try {
    
    			if (StringUtils.isNotBlank(result)) {
    				if (result.startsWith("{") && result.endsWith("}")) {
    					result = result.substring(1, result.length() - 1);
    				}
    				map = parseQString(result);
    			}
    
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return map;
    	}
    
    	
    	/**
    	 * 解析应答字符串,生成应答要素
    	 * 
    	 * @param str
    	 *            需要解析的字符串
    	 * @return 解析的结果map
    	 * @throws UnsupportedEncodingException
    	 */
    	public static Map<String, String> parseQString(String str)
    			throws UnsupportedEncodingException {
    
    		Map<String, String> map = new HashMap<String, String>();
    		int len = str.length();
    		StringBuilder temp = new StringBuilder();
    		char curChar;
    		String key = null;
    		boolean isKey = true;
    		boolean isOpen = false;//值里有嵌套
    		char openName = 0;
    		if(len>0){
    			for (int i = 0; i < len; i++) {// 遍历整个带解析的字符串
    				curChar = str.charAt(i);// 取当前字符
    				if (isKey) {// 如果当前生成的是key
    					
    					if (curChar == '=') {// 如果读取到=分隔符 
    						key = temp.toString();
    						temp.setLength(0);
    						isKey = false;
    					} else {
    						temp.append(curChar);
    					}
    				} else  {// 如果当前生成的是value
    					if(isOpen){
    						if(curChar == openName){
    							isOpen = false;
    						}
    						
    					}else{//如果没开启嵌套
    						if(curChar == '{'){//如果碰到,就开启嵌套
    							isOpen = true;
    							openName ='}';
    						}
    						if(curChar == '['){
    							isOpen = true;
    							openName =']';
    						}
    					}
    					if (curChar == '&' && !isOpen) {// 如果读取到&分割符,同时这个分割符不是值域,这时将map里添加
    						putKeyValueToMap(temp, isKey, key, map);
    						temp.setLength(0);
    						isKey = true;
    					}else{
    						temp.append(curChar);
    					}
    				}
    				
    			}
    			putKeyValueToMap(temp, isKey, key, map);
    		}
    		return map;
    	}
    
    	private static void putKeyValueToMap(StringBuilder temp, boolean isKey,
    			String key, Map<String, String> map)
    			throws UnsupportedEncodingException {
    		if (isKey) {
    			key = temp.toString();
    			if (key.length() == 0) {
    				throw new RuntimeException("QString format illegal");
    			}
    			map.put(key, "");
    		} else {
    			if (key.length() == 0) {
    				throw new RuntimeException("QString format illegal");
    			}
    			map.put(key, temp.toString());
    		}
    	}
    
    	/**
    	 * 
    	 * 获取应答报文中的加密公钥证书,并存储到本地,并备份原始证书<br>
    	 * 更新成功则返回1,无更新返回0,失败异常返回-1。
    	 * 
    	 * @param resData
    	 * @param encoding
    	 * @return
    	 */
    	public static int getEncryptCert(Map<String, String> resData,
    			String encoding) {
    		String strCert = resData.get(SDKConstants.param_encryptPubKeyCert);
    		String certType = resData.get(SDKConstants.param_certType);
    		if (isEmpty(strCert) || isEmpty(certType))
    			return -1;
    		X509Certificate x509Cert = CertUtil.genCertificateByStr(strCert);
    		if (CERTTYPE_01.equals(certType)) {
    			// 更新敏感信息加密公钥
    			if (!CertUtil.getEncryptCertId().equals(
    					x509Cert.getSerialNumber().toString())) {
    				// ID不同时进行本地证书更新操作
    				String localCertPath = SDKConfig.getConfig().getEncryptCertPath();
    				String newLocalCertPath = genBackupName(localCertPath);
    				// 1.将本地证书进行备份存储
    				if (!copyFile(localCertPath, newLocalCertPath))
    					return -1;
    				// 2.备份成功,进行新证书的存储
    				if (!writeFile(localCertPath, strCert, encoding))
    					return -1;
    				LogUtil.writeLog("save new encryptPubKeyCert success");
    				CertUtil.resetEncryptCertPublicKey();
    				return 1;
    			}else {
    				return 0;
    			}
    
    		} else if (CERTTYPE_02.equals(certType)) {
    //			// 更新磁道加密公钥
    //			if (!CertUtil.getEncryptTrackCertId().equals(
    //					x509Cert.getSerialNumber().toString())) {
    //				// ID不同时进行本地证书更新操作
    //				String localCertPath = SDKConfig.getConfig().getEncryptTrackCertPath();
    //				String newLocalCertPath = genBackupName(localCertPath);
    //				// 1.将本地证书进行备份存储
    //				if (!copyFile(localCertPath, newLocalCertPath))
    //					return -1;
    //				// 2.备份成功,进行新证书的存储
    //				if (!writeFile(localCertPath, strCert, encoding))
    //					return -1;
    //				LogUtil.writeLog("save new encryptPubKeyCert success");
    //				CertUtil.resetEncryptTrackCertPublicKey();
    //				return 1;
    //			}else {
    				return 0;
    //			}
    		}else {
    			LogUtil.writeLog("unknown cerType:"+certType);
    			return -1;
    		}
    	}
    	
    	/**
    	 * 文件拷贝方法
    	 * 
    	 * @param srcFile
    	 *            源文件
    	 * @param destFile
    	 *            目标文件
    	 * @return
    	 * @throws IOException
    	 */
    	public static boolean copyFile(String srcFile, String destFile) {
    		boolean flag = false;
    		FileInputStream fin = null;
    		FileOutputStream fout = null;
    		FileChannel fcin = null;
    		FileChannel fcout = null;
    		try {
    			// 获取源文件和目标文件的输入输出流
    			fin = new FileInputStream(srcFile);
    			fout = new FileOutputStream(destFile);
    			// 获取输入输出通道
    			fcin = fin.getChannel();
    			fcout = fout.getChannel();
    			// 创建缓冲区
    			ByteBuffer buffer = ByteBuffer.allocate(1024);
    			while (true) {
    				// clear方法重设缓冲区,使它可以接受读入的数据
    				buffer.clear();
    				// 从输入通道中将数据读到缓冲区
    				int r = fcin.read(buffer);
    				// read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1
    				if (r == -1) {
    					flag = true;
    					break;
    				}
    				// flip方法让缓冲区可以将新读入的数据写入另一个通道
    				buffer.flip();
    				// 从输出通道中将数据写入缓冲区
    				fcout.write(buffer);
    			}
    			fout.flush();
    		} catch (IOException e) {
    			LogUtil.writeErrorLog("CopyFile fail", e);
    		} finally {
    			try {
    				if (null != fin)
    					fin.close();
    				if (null != fout)
    					fout.close();
    				if (null != fcin)
    					fcin.close();
    				if (null != fcout)
    					fcout.close();
    			} catch (IOException ex) {
    				LogUtil.writeErrorLog("Releases any system resources fail", ex);
    			}
    		}
    		return flag;
    	}
    	
    	/**
    	 * 写文件方法
    	 * 
    	 * @param filePath
    	 *            文件路径
    	 * @param fileContent
    	 *            文件内容
    	 * @param encoding
    	 *            编码
    	 * @return
    	 */
    	public static boolean writeFile(String filePath, String fileContent,
    			String encoding) {
    		FileOutputStream fout = null;
    		FileChannel fcout = null;
    		File file = new File(filePath);
    		if (file.exists()) {
    			file.delete();
    		}
    		
    		try {
    			fout = new FileOutputStream(filePath);
    			// 获取输出通道
    			fcout = fout.getChannel();
    			// 创建缓冲区
    			// ByteBuffer buffer = ByteBuffer.allocate(1024);
    			ByteBuffer buffer = ByteBuffer.wrap(fileContent.getBytes(encoding));
    			fcout.write(buffer);
    			fout.flush();
    		} catch (FileNotFoundException e) {
    			LogUtil.writeErrorLog("WriteFile fail", e);
    			return false;
    		} catch (IOException ex) {
    			LogUtil.writeErrorLog("WriteFile fail", ex);
    			return false;
    		} finally {
    			try {
    				if (null != fout)
    					fout.close();
    				if (null != fcout)
    					fcout.close();
    			} catch (IOException ex) {
    				LogUtil.writeErrorLog("Releases any system resources fail", ex);
    				return false;
    			}
    		}
    		return true;
    	}
    	
    	/**
    	 * 将传入的文件名(xxx)改名 <br>
    	 * 结果为: xxx_backup.cer
    	 * 
    	 * @param fileName
    	 * @return
    	 */
    	public static String genBackupName(String fileName) {
    		if (isEmpty(fileName))
    			return "";
    		int i = fileName.lastIndexOf(POINT);
    		String leftFileName = fileName.substring(0, i);
    		String rightFileName = fileName.substring(i + 1);
    		String newFileName = leftFileName + "_backup" + POINT + rightFileName;
    		return newFileName;
    	}
    	
    
    	public static byte[] readFileByNIO(String filePath) {
    		FileInputStream in = null;
    		FileChannel fc = null;
    		ByteBuffer bf = null;
    		try {
    			in = new FileInputStream(filePath);
    			fc = in.getChannel();
    			bf = ByteBuffer.allocate((int) fc.size());
    			fc.read(bf);
    			return bf.array();
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage());
    			return null;
    		} finally {
    			try {
    				if (null != fc) {
    					fc.close();
    				}
    				if (null != in) {
    					in.close();
    				}
    			} catch (Exception e) {
    				LogUtil.writeErrorLog(e.getMessage());
    				return null;
    			}
    		}
    	}
    	
    	/**
    	 * 过滤请求报文中的空字符串或者空字符串
    	 * @param contentData
    	 * @return
    	 */
    	public static Map<String, String> filterBlank(Map<String, String> contentData){
    		LogUtil.writeLog("打印请求报文域 :");
    		Map<String, String> submitFromData = new HashMap<String, String>();
    		Set<String> keyset = contentData.keySet();
    		
    		for(String key:keyset){
    			String value = contentData.get(key);
    			if (StringUtils.isNotBlank(value)) {
    				// 对value值进行去除前后空处理
    				submitFromData.put(key, value.trim());
    				LogUtil.writeLog(key + "-->" + String.valueOf(value));
    			}
    		}
    		return submitFromData;
    	}
    	
    	/**
    	 * 解压缩.
    	 * 
    	 * @param inputByte
    	 *            byte[]数组类型的数据
    	 * @return 解压缩后的数据
    	 * @throws IOException
    	 */
    	public static byte[] inflater(final byte[] inputByte) throws IOException {
    		int compressedDataLength = 0;
    		Inflater compresser = new Inflater(false);
    		compresser.setInput(inputByte, 0, inputByte.length);
    		ByteArrayOutputStream o = new ByteArrayOutputStream(inputByte.length);
    		byte[] result = new byte[1024];
    		try {
    			while (!compresser.finished()) {
    				compressedDataLength = compresser.inflate(result);
    				if (compressedDataLength == 0) {
    					break;
    				}
    				o.write(result, 0, compressedDataLength);
    			}
    		} catch (Exception ex) {
    			System.err.println("Data format error!\n");
    			ex.printStackTrace();
    		} finally {
    			o.close();
    		}
    		compresser.end();
    		return o.toByteArray();
    	}
    
    	/**
    	 * 压缩.
    	 * 
    	 * @param inputByte
    	 *            需要解压缩的byte[]数组
    	 * @return 压缩后的数据
    	 * @throws IOException
    	 */
    	public static byte[] deflater(final byte[] inputByte) throws IOException {
    		int compressedDataLength = 0;
    		Deflater compresser = new Deflater();
    		compresser.setInput(inputByte);
    		compresser.finish();
    		ByteArrayOutputStream o = new ByteArrayOutputStream(inputByte.length);
    		byte[] result = new byte[1024];
    		try {
    			while (!compresser.finished()) {
    				compressedDataLength = compresser.deflate(result);
    				o.write(result, 0, compressedDataLength);
    			}
    		} finally {
    			o.close();
    		}
    		compresser.end();
    		return o.toByteArray();
    	}
    	
    	/**
    	 * 判断字符串是否为NULL或空
    	 * 
    	 * @param s
    	 *            待判断的字符串数据
    	 * @return 判断结果 true-是 false-否
    	 */
    	public static boolean isEmpty(String s) {
    		return null == s || "".equals(s.trim());
    	}
    	
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28       日志打印工具类
     * =============================================================================
     */
    package com.example.demo.union.util;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    /**
     * 
     * @ClassName LogUtil
     * @Description acpsdk日志工具类
     * @date 2016-7-22 下午4:04:35
     *
     */
    public class LogUtil {
    
    	private final static Logger GATELOG = LoggerFactory.getLogger("ACP_SDK_LOG");
    	private final static Logger GATELOG_ERROR = LoggerFactory.getLogger("SDK_ERR_LOG");
    	private final static Logger GATELOG_MESSAGE = LoggerFactory.getLogger("SDK_MSG_LOG");
    
    	final static String LOG_STRING_REQ_MSG_BEGIN = "============================== SDK REQ MSG BEGIN ==============================";
    	final static String LOG_STRING_REQ_MSG_END = "==============================  SDK REQ MSG END  ==============================";
    	final static String LOG_STRING_RSP_MSG_BEGIN = "============================== SDK RSP MSG BEGIN ==============================";
    	final static String LOG_STRING_RSP_MSG_END = "==============================  SDK RSP MSG END  ==============================";
    
    	/**
    	 * 记录普通日志
    	 * 
    	 * @param cont
    	 */
    	public static void writeLog(String cont) {
    		GATELOG.info(cont);
    	}
    
    	/**
    	 * 记录ERORR日志
    	 * 
    	 * @param cont
    	 */
    	public static void writeErrorLog(String cont) {
    		GATELOG_ERROR.error(cont);
    	}
    
    	/**
    	 * 记录ERROR日志
    	 * 
    	 * @param cont
    	 * @param ex
    	 */
    	public static void writeErrorLog(String cont, Throwable ex) {
    		GATELOG_ERROR.error(cont, ex);
    	}
    
    	/**
    	 * 记录通信报文
    	 * 
    	 * @param msg
    	 */
    	public static void writeMessage(String msg) {
    		GATELOG_MESSAGE.info(msg);
    	}
    
    	/**
    	 * 打印请求报文
    	 * 
    	 * @param reqParam
    	 */
    	public static void printRequestLog(Map<String, String> reqParam) {
    		writeMessage(LOG_STRING_REQ_MSG_BEGIN);
    		Iterator<Entry<String, String>> it = reqParam.entrySet().iterator();
    		while (it.hasNext()) {
    			Entry<String, String> en = it.next();
    			writeMessage("[" + en.getKey() + "] = [" + en.getValue() + "]");
    		}
    		writeMessage(LOG_STRING_REQ_MSG_END);
    	}
    
    	/**
    	 * 打印响应报文.
    	 * 
    	 * @param res
    	 */
    	public static void printResponseLog(String res) {
    		writeMessage(LOG_STRING_RSP_MSG_BEGIN);
    		writeMessage(res);
    		writeMessage(LOG_STRING_RSP_MSG_END);
    	}
    
    	/**
    	 * debug方法
    	 * 
    	 * @param cont
    	 */
    	public static void debug(String cont) {
    		if (GATELOG.isDebugEnabled()) {
    			GATELOG.debug(cont);
    		}
    	}
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28       HTTP通信工具类
     * =============================================================================
     */
    package com.example.demo.union.util;
    
    
    import com.example.demo.union.config.SDKConfig;
    import com.example.demo.union.service.BaseHttpSSLSocketFactory;
    
    import javax.net.ssl.HttpsURLConnection;
    import java.io.*;
    import java.net.*;
    import java.util.Map;
    import java.util.Map.Entry;
    
    /**
     * 
     * @ClassName HttpClient
     * @Description acpsdk发送后台http请求类
     * @date 2016-7-22 下午4:03:25
     *
     */
    public class HttpClient {
    	/**
    	 * 目标地址
    	 */
    	private URL url;
    
    	/**
    	 * 通信连接超时时间
    	 */
    	private int connectionTimeout;
    
    	/**
    	 * 通信读超时时间
    	 */
    	private int readTimeOut;
    
    	/**
    	 * 通信结果
    	 */
    	private String result;
    
    	/**
    	 * 获取通信结果
    	 * @return
    	 */
    	public String getResult() {
    		return result;
    	}
    
    	/**
    	 * 设置通信结果
    	 * @param result
    	 */
    	public void setResult(String result) {
    		this.result = result;
    	}
    
    	/**
    	 * 构造函数
    	 * @param url 目标地址
    	 * @param connectionTimeout HTTP连接超时时间
    	 * @param readTimeOut HTTP读写超时时间
    	 */
    	public HttpClient(String url, int connectionTimeout, int readTimeOut) {
    		try {
    			this.url = new URL(url);
    			this.connectionTimeout = connectionTimeout;
    			this.readTimeOut = readTimeOut;
    		} catch (MalformedURLException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    	}
    
    	/**
    	 * 发送信息到服务端
    	 * @param data
    	 * @param encoding
    	 * @return
    	 * @throws Exception
    	 */
    	public int send(Map<String, String> data, String encoding) throws Exception {
    		try {
    			HttpURLConnection httpURLConnection = createConnection(encoding);
    			if (null == httpURLConnection) {
    				throw new Exception("Create httpURLConnection Failure");
    			}
    			String sendData = this.getRequestParamString(data, encoding);
    			LogUtil.writeLog("请求报文:[" + sendData + "]");
    			this.requestServer(httpURLConnection, sendData,
    					encoding);
    			this.result = this.response(httpURLConnection, encoding);
    			LogUtil.writeLog("Response message:[" + result + "]");
    			return httpURLConnection.getResponseCode();
    		} catch (Exception e) {
    			throw e;
    		}
    	}
    
    	/**
    	 * 发送信息到服务端 GET方式
    	 * @param encoding
    	 * @return
    	 * @throws Exception
    	 */
    	public int sendGet(String encoding) throws Exception {
    		try {
    			HttpURLConnection httpURLConnection = createConnectionGet(encoding);
    			if(null == httpURLConnection){
    				throw new Exception("创建联接失败");
    			}
    			this.result = this.response(httpURLConnection, encoding);
    			LogUtil.writeLog("同步返回报文:[" + result + "]");
    			return httpURLConnection.getResponseCode();
    		} catch (Exception e) {
    			throw e;
    		}
    	}
    
    	
    	/**
    	 * HTTP Post发送消息
    	 *
    	 * @param connection
    	 * @param message
    	 * @throws IOException
    	 */
    	private void requestServer(final URLConnection connection, String message, String encoder)
    			throws Exception {
    		PrintStream out = null;
    		try {
    			connection.connect();
    			out = new PrintStream(connection.getOutputStream(), false, encoder);
    			out.print(message);
    			out.flush();
    		} catch (Exception e) {
    			throw e;
    		} finally {
    			if (null != out) {
    				out.close();
    			}
    		}
    	}
    
    	/**
    	 * 显示Response消息
    	 *
    	 * @param connection
    	 * @param encoding
    	 * @return
    	 * @throws URISyntaxException
    	 * @throws IOException
    	 */
    	private String response(final HttpURLConnection connection, String encoding)
    			throws URISyntaxException, IOException, Exception {
    		InputStream in = null;
    		StringBuilder sb = new StringBuilder(1024);
    		BufferedReader br = null;
    		try {
    			if (200 == connection.getResponseCode()) {
    				in = connection.getInputStream();
    				sb.append(new String(read(in), encoding));
    			} else {
    				in = connection.getErrorStream();
    				sb.append(new String(read(in), encoding));
    			}
    			LogUtil.writeLog("HTTP Return Status-Code:["
    					+ connection.getResponseCode() + "]");
    			return sb.toString();
    		} catch (Exception e) {
    			throw e;
    		} finally {
    			if (null != br) {
    				br.close();
    			}
    			if (null != in) {
    				in.close();
    			}
    			if (null != connection) {
    				connection.disconnect();
    			}
    		}
    	}
    	
    	public static byte[] read(InputStream in) throws IOException {
    		byte[] buf = new byte[1024];
    		int length = 0;
    		ByteArrayOutputStream bout = new ByteArrayOutputStream();
    		while ((length = in.read(buf, 0, buf.length)) > 0) {
    			bout.write(buf, 0, length);
    		}
    		bout.flush();
    		return bout.toByteArray();
    	}
    	
    	/**
    	 * 创建连接
    	 *
    	 * @return
    	 * @throws ProtocolException
    	 */
    	private HttpURLConnection createConnection(String encoding) throws ProtocolException {
    		HttpURLConnection httpURLConnection = null;
    		try {
    			httpURLConnection = (HttpURLConnection) url.openConnection();
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return null;
    		}
    		httpURLConnection.setConnectTimeout(this.connectionTimeout);// 连接超时时间
    		httpURLConnection.setReadTimeout(this.readTimeOut);// 读取结果超时时间
    		httpURLConnection.setDoInput(true); // 可读
    		httpURLConnection.setDoOutput(true); // 可写
    		httpURLConnection.setUseCaches(false);// 取消缓存
    		httpURLConnection.setRequestProperty("Content-type",
    				"application/x-www-form-urlencoded;charset=" + encoding);
    		httpURLConnection.setRequestMethod("POST");
    		if ("https".equalsIgnoreCase(url.getProtocol())) {
    			HttpsURLConnection husn = (HttpsURLConnection) httpURLConnection;
    			//是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false
    			if(!SDKConfig.getConfig().isIfValidateRemoteCert()){
    				husn.setSSLSocketFactory(new BaseHttpSSLSocketFactory());
    				husn.setHostnameVerifier(new BaseHttpSSLSocketFactory.TrustAnyHostnameVerifier());//解决由于服务器证书问题导致HTTPS无法访问的情况
    			}
    			return husn;
    		}
    		return httpURLConnection;
    	}
    
    	/**
    	 * 创建连接
    	 *
    	 * @return
    	 * @throws ProtocolException
    	 */
    	private HttpURLConnection createConnectionGet(String encoding) throws ProtocolException {
    		HttpURLConnection httpURLConnection = null;
    		try {
    			httpURLConnection = (HttpURLConnection) url.openConnection();
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return null;
    		}
    		httpURLConnection.setConnectTimeout(this.connectionTimeout);// 连接超时时间
    		httpURLConnection.setReadTimeout(this.readTimeOut);// 读取结果超时时间
    		httpURLConnection.setUseCaches(false);// 取消缓存
    		httpURLConnection.setRequestProperty("Content-type",
    				"application/x-www-form-urlencoded;charset=" + encoding);
    		httpURLConnection.setRequestMethod("GET");
    		if ("https".equalsIgnoreCase(url.getProtocol())) {
    			HttpsURLConnection husn = (HttpsURLConnection) httpURLConnection;
    			//是否验证https证书,测试环境请设置false,生产环境建议优先尝试true,不行再false
    			if(!SDKConfig.getConfig().isIfValidateRemoteCert()){
    				husn.setSSLSocketFactory(new BaseHttpSSLSocketFactory());
    				husn.setHostnameVerifier(new BaseHttpSSLSocketFactory.TrustAnyHostnameVerifier());//解决由于服务器证书问题导致HTTPS无法访问的情况
    			}
    			return husn;
    		}
    		return httpURLConnection;
    	}
    	
    	/**
    	 * 将Map存储的对象,转换为key=value&key=value的字符
    	 *
    	 * @param requestParam
    	 * @param coder
    	 * @return
    	 */
    	private String getRequestParamString(Map<String, String> requestParam, String coder) {
    		if (null == coder || "".equals(coder)) {
    			coder = "UTF-8";
    		}
    		StringBuffer sf = new StringBuffer("");
    		String reqstr = "";
    		if (null != requestParam && 0 != requestParam.size()) {
    			for (Entry<String, String> en : requestParam.entrySet()) {
    				try {
    					sf.append(en.getKey()
    							+ "="
    							+ (null == en.getValue() || "".equals(en.getValue()) ? "" : URLEncoder
    									.encode(en.getValue(), coder)) + "&");
    				} catch (UnsupportedEncodingException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    					return "";
    				}
    			}
    			reqstr = sf.substring(0, sf.length() - 1);
    		}
    		LogUtil.writeLog("Request Message:[" + reqstr + "]");
    		return reqstr;
    	}
    
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28       证书工具类.
     * =============================================================================
     */
    package com.bt.star.util;
    
    import com.bt.star.config.SDKConfig;
    import com.bt.star.properties.SDKConstants;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    import java.io.*;
    import java.math.BigInteger;
    import java.security.*;
    import java.security.cert.*;
    import java.security.spec.RSAPublicKeySpec;
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    /**
     * @ClassName: CertUtil
     * @Description: acpsdk证书工具类,主要用于对证书的加载和使用
     * @date 2016-7-22 下午2:46:20
     *
     */
    @Slf4j
    public class CertUtil {
    	/** 证书容器,存储对商户请求报文签名私钥证书. */
    	private static KeyStore keyStore = null;
    	/** 敏感信息加密公钥证书 */
    	private static X509Certificate encryptCert = null;
    	/** 磁道加密公钥 */
    	private static PublicKey encryptTrackKey = null;
    	/** 验证银联返回报文签名证书. */
    	private static X509Certificate validateCert = null;
    	/** 验签中级证书 */
    	private static X509Certificate middleCert = null;
    	/** 验签根证书 */
    	private static X509Certificate rootCert = null;
    	/** 验证银联返回报文签名的公钥证书存储Map. */
    	private static Map<String, X509Certificate> certMap = new HashMap<String, X509Certificate>();
    	/** 商户私钥存储Map */
    	private final static Map<String, KeyStore> keyStoreMap = new ConcurrentHashMap<String, KeyStore>();
    
    	
    	/**
    	 * 初始化所有证书.
    	 */
    	public static void init() {
    		try {
    			addProvider();//向系统添加BC provider
    			initSignCert();//初始化签名私钥证书
    			initMiddleCert();//初始化验签证书的中级证书
    			initRootCert();//初始化验签证书的根证书
    			initEncryptCert();//初始化加密公钥
    			initTrackKey();//构建磁道加密公钥
    			initValidateCertFromDir();//初始化所有的验签证书
    		} catch (Exception e) {
    			log.error("init失败。(如果是用对称密钥签名的可无视此异常。)", e);
    		}
    	}
    	
    	/**
    	 * 添加签名,验签,加密算法提供者
    	 */
    	private static void addProvider(){
    		if (Security.getProvider("BC") == null) {
    			log.info("add BC provider");
    			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    		} else {
    			Security.removeProvider("BC"); //解决eclipse调试时tomcat自动重新加载时,BC存在不明原因异常的问题。
    			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    			log.info("re-add BC provider");
    		}
    		printSysInfo();
    	}
    	
    	/**
    	 * 用配置文件acp_sdk.properties中配置的私钥路径和密码 加载签名证书
    	 */
    	private static void initSignCert() {
    		if(!"01".equals(SDKConfig.getConfig().getSignMethod())){
    			log.info("非rsa签名方式,不加载签名证书。");
    			return;
    		}
    		if (SDKConfig.getConfig().getSignCertPath() == null
    				|| SDKConfig.getConfig().getSignCertPwd() == null
    				|| SDKConfig.getConfig().getSignCertType() == null) {
    			log.error("WARN: " + SDKConfig.SDK_SIGNCERT_PATH + "或" + SDKConfig.SDK_SIGNCERT_PWD 
    					+ "或" + SDKConfig.SDK_SIGNCERT_TYPE + "为空。 停止加载签名证书。");
    			return;
    		}
    		if (null != keyStore) {
    			keyStore = null;
    		}
    		try {
    			keyStore = getKeyInfo(SDKConfig.getConfig().getSignCertPath(),
    					SDKConfig.getConfig().getSignCertPwd(), SDKConfig
    							.getConfig().getSignCertType());
    			log.info("InitSignCert Successful. CertId=["
    					+ getSignCertId() + "]");
    		} catch (IOException e) {
    			log.error("InitSignCert Error", e);
    		}
    	}
    
    	/**
    	 * 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书
    	 */
    	private static void initMiddleCert() {
    		log.info("加载中级证书==>"+SDKConfig.getConfig().getMiddleCertPath());
    		if (!SDKUtil.isEmpty(SDKConfig.getConfig().getMiddleCertPath())) {
    			middleCert = initCert(SDKConfig.getConfig().getMiddleCertPath());
    			log.info("Load MiddleCert Successful");
    		} else {
    			log.info("WARN: acpsdk.middle.path is empty");
    		}
    	}
    
    	/**
    	 * 用配置文件acp_sdk.properties配置路径 加载敏感信息加密证书
    	 */
    	private static void initRootCert() {
    		log.info("加载根证书==>"+SDKConfig.getConfig().getRootCertPath());
    		if (!SDKUtil.isEmpty(SDKConfig.getConfig().getRootCertPath())) {
    			rootCert = initCert(SDKConfig.getConfig().getRootCertPath());
    			log.info("Load RootCert Successful");
    		} else {
    			log.info("WARN: acpsdk.rootCert.path is empty");
    		}
    	}
    	
    	/**
    	 * 用配置文件acp_sdk.properties配置路径 加载银联公钥上级证书(中级证书)
    	 */
    	private static void initEncryptCert() {
    		log.info("加载敏感信息加密证书==>"+SDKConfig.getConfig().getEncryptCertPath());
    		if (!SDKUtil.isEmpty(SDKConfig.getConfig().getEncryptCertPath())) {
    			encryptCert = initCert(SDKConfig.getConfig().getEncryptCertPath());
    			log.info("Load EncryptCert Successful");
    		} else {
    			log.info("WARN: acpsdk.encryptCert.path is empty");
    		}
    	}
    	
    	/**
    	 * 用配置文件acp_sdk.properties配置路径 加载磁道公钥
    	 */
    	private static void initTrackKey() {
    		if (!SDKUtil.isEmpty(SDKConfig.getConfig().getEncryptTrackKeyModulus())
    				&& !SDKUtil.isEmpty(SDKConfig.getConfig().getEncryptTrackKeyExponent())) {
    			encryptTrackKey = getPublicKey(SDKConfig.getConfig().getEncryptTrackKeyModulus(), 
    					SDKConfig.getConfig().getEncryptTrackKeyExponent());
    			log.info("LoadEncryptTrackKey Successful");
    		} else {
    			log.info("WARN: acpsdk.encryptTrackKey.modulus or acpsdk.encryptTrackKey.exponent is empty");
    		}
    	}
    
    	/**
    	 * 用配置文件acp_sdk.properties配置路径 加载验证签名证书
    	 */
    	private static void initValidateCertFromDir() {
    		if(!"01".equals(SDKConfig.getConfig().getSignMethod())){
    			log.info("非rsa签名方式,不加载验签证书。");
    			return;
    		}
    		certMap.clear();
    		String dir = SDKConfig.getConfig().getValidateCertDir();
    		log.info("加载验证签名证书目录==>" + dir +" 注:如果请求报文中version=5.1.0那么此验签证书目录使用不到,可以不需要设置(version=5.0.0必须设置)。");
    		if (SDKUtil.isEmpty(dir)) {
    			log.error("WARN: acpsdk.validateCert.dir is empty");
    			return;
    		}
    		CertificateFactory cf = null;
    		FileInputStream in = null;
    		try {
    			cf = CertificateFactory.getInstance("X.509", "BC");
    			File fileDir = new File(dir);
    			File[] files = fileDir.listFiles(new CerFilter());
    			for (int i = 0; i < files.length; i++) {
    				File file = files[i];
    				in = new FileInputStream(file.getAbsolutePath());
    				validateCert = (X509Certificate) cf.generateCertificate(in);
    				certMap.put(validateCert.getSerialNumber().toString(),
    						validateCert);
    				// 打印证书加载信息,供测试阶段调试
    				log.info("[" + file.getAbsolutePath() + "][CertId="
    						+ validateCert.getSerialNumber().toString() + "]");
    			}
    			log.info("LoadVerifyCert Successful");
    		} catch (CertificateException e) {
    			log.error("LoadVerifyCert Error", e);
    		} catch (FileNotFoundException e) {
    			log.error("LoadVerifyCert Error File Not Found", e);
    		} catch (NoSuchProviderException e) {
    			log.error("LoadVerifyCert Error No BC Provider", e);
    		} finally {
    			if (null != in) {
    				try {
    					in.close();
    				} catch (IOException e) {
    					log.error(e.toString());
    				}
    			}
    		}
    	}
    
    	/**
    	 * 用给定的路径和密码 加载签名证书,并保存到certKeyStoreMap
    	 * 
    	 * @param certFilePath
    	 * @param certPwd
    	 */
    	private static void loadSignCert(String certFilePath, String certPwd) {
    		KeyStore keyStore = null;
    		try {
    			keyStore = getKeyInfo(certFilePath, certPwd, "PKCS12");
    			keyStoreMap.put(certFilePath, keyStore);
    			log.info("LoadRsaCert Successful");
    		} catch (IOException e) {
    			log.error("LoadRsaCert Error", e);
    		}
    	}
    
    	/**
    	 * 通过证书路径初始化为公钥证书
    	 * @param path
    	 * @return
    	 */
    	private static X509Certificate initCert(String path) {
    		X509Certificate encryptCertTemp = null;
    		CertificateFactory cf = null;
    		InputStream in = null;
    		//相对路径变为绝对路径
    		try {
    			cf = CertificateFactory.getInstance("X.509", "BC");
    			Resource resource = new ClassPathResource(path);
    			in = resource.getInputStream();
    			encryptCertTemp = (X509Certificate) cf.generateCertificate(in);
    			// 打印证书加载信息,供测试阶段调试
    			log.info("[" + path + "][CertId="
    					+ encryptCertTemp.getSerialNumber().toString() + "]");
    		} catch (CertificateException e) {
    			log.error("InitCert Error", e);
    		} catch (FileNotFoundException e) {
    			log.error("InitCert Error File Not Found", e);
    		} catch (NoSuchProviderException e) {
    			log.error("LoadVerifyCert Error No BC Provider", e);
    		} catch (IOException e) {
    			e.printStackTrace();
    		} finally {
    			if (null != in) {
    				try {
    					in.close();
    				} catch (IOException e) {
    					log.error(e.toString());
    				}
    			}
    		}
    		return encryptCertTemp;
    	}
    	
    	/**
    	 * 通过keyStore 获取私钥签名证书PrivateKey对象
    	 * 
    	 * @return
    	 */
    	public static PrivateKey getSignCertPrivateKey() {
    		try {
    			Enumeration<String> aliasenum = keyStore.aliases();
    			String keyAlias = null;
    			if (aliasenum.hasMoreElements()) {
    				keyAlias = aliasenum.nextElement();
    			}
    			PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias,
    					SDKConfig.getConfig().getSignCertPwd().toCharArray());
    			return privateKey;
    		} catch (KeyStoreException e) {
    			log.error("getSignCertPrivateKey Error", e);
    			return null;
    		} catch (UnrecoverableKeyException e) {
    			log.error("getSignCertPrivateKey Error", e);
    			return null;
    		} catch (NoSuchAlgorithmException e) {
    			log.error("getSignCertPrivateKey Error", e);
    			return null;
    		}
    	}
    	/**
    	 * 通过指定路径的私钥证书  获取PrivateKey对象
    	 * 
    	 * @return
    	 */
    	public static PrivateKey getSignCertPrivateKeyByStoreMap(String certPath,
    			String certPwd) {
    		if (!keyStoreMap.containsKey(certPath)) {
    			loadSignCert(certPath, certPwd);
    		}
    		try {
    			Enumeration<String> aliasenum = keyStoreMap.get(certPath)
    					.aliases();
    			String keyAlias = null;
    			if (aliasenum.hasMoreElements()) {
    				keyAlias = aliasenum.nextElement();
    			}
    			PrivateKey privateKey = (PrivateKey) keyStoreMap.get(certPath)
    					.getKey(keyAlias, certPwd.toCharArray());
    			return privateKey;
    		} catch (KeyStoreException e) {
    			log.error("getSignCertPrivateKeyByStoreMap Error", e);
    			return null;
    		} catch (UnrecoverableKeyException e) {
    			log.error("getSignCertPrivateKeyByStoreMap Error", e);
    			return null;
    		} catch (NoSuchAlgorithmException e) {
    			log.error("getSignCertPrivateKeyByStoreMap Error", e);
    			return null;
    		}
    	}
    
    	/**
    	 * 获取敏感信息加密证书PublicKey
    	 * 
    	 * @return
    	 */
    	public static PublicKey getEncryptCertPublicKey() {
    		if (null == encryptCert) {
    			String path = SDKConfig.getConfig().getEncryptCertPath();
    			if (!SDKUtil.isEmpty(path)) {
    				encryptCert = initCert(path);
    				return encryptCert.getPublicKey();
    			} else {
    				log.error("acpsdk.encryptCert.path is empty");
    				return null;
    			}
    		} else {
    			return encryptCert.getPublicKey();
    		}
    	}
    	
    	/**
    	 * 重置敏感信息加密证书公钥
    	 */
    	public static void resetEncryptCertPublicKey() {
    		encryptCert = null;
    	}
    	
    	/**
    	 * 获取磁道加密证书PublicKey
    	 * 
    	 * @return
    	 */
    	public static PublicKey getEncryptTrackPublicKey() {
    		if (null == encryptTrackKey) {
    			initTrackKey();
    		}
    		return encryptTrackKey;
    	}
    	
    	/**
    	 * 通过certId获取验签证书Map中对应证书PublicKey
    	 * 
    	 * @param certId 证书物理序号
    	 * @return 通过证书编号获取到的公钥
    	 */
    	public static PublicKey getValidatePublicKey(String certId) {
    		X509Certificate cf = null;
    		if (certMap.containsKey(certId)) {
    			// 存在certId对应的证书对象
    			cf = certMap.get(certId);
    			return cf.getPublicKey();
    		} else {
    			// 不存在则重新Load证书文件目录
    			initValidateCertFromDir();
    			if (certMap.containsKey(certId)) {
    				// 存在certId对应的证书对象
    				cf = certMap.get(certId);
    				return cf.getPublicKey();
    			} else {
    				log.error("缺少certId=[" + certId + "]对应的验签证书.");
    				return null;
    			}
    		}
    	}
    	
    	/**
    	 * 获取配置文件acp_sdk.properties中配置的签名私钥证书certId
    	 * 
    	 * @return 证书的物理编号
    	 */
    	public static String getSignCertId() {
    		try {
    			Enumeration<String> aliasenum = keyStore.aliases();
    			String keyAlias = null;
    			if (aliasenum.hasMoreElements()) {
    				keyAlias = aliasenum.nextElement();
    			}
    			X509Certificate cert = (X509Certificate) keyStore
    					.getCertificate(keyAlias);
    			return cert.getSerialNumber().toString();
    		} catch (Exception e) {
    			log.error("getSignCertId Error", e);
    			return null;
    		}
    	}
    
    	/**
    	 * 获取敏感信息加密证书的certId
    	 * 
    	 * @return
    	 */
    	public static String getEncryptCertId() {
    		if (null == encryptCert) {
    			String path = SDKConfig.getConfig().getEncryptCertPath();
    			if (!SDKUtil.isEmpty(path)) {
    				encryptCert = initCert(path);
    				return encryptCert.getSerialNumber().toString();
    			} else {
    				log.error("acpsdk.encryptCert.path is empty");
    				return null;
    			}
    		} else {
    			return encryptCert.getSerialNumber().toString();
    		}
    	}
    
    	/**
    	 * 将签名私钥证书文件读取为证书存储对象
    	 * 
    	 * @param pfxkeyfile
    	 *            证书文件名
    	 * @param keypwd
    	 *            证书密码
    	 * @param type
    	 *            证书类型
    	 * @return 证书对象
    	 * @throws IOException 
    	 */
    	private static KeyStore getKeyInfo(String pfxkeyfile, String keypwd,
    			String type) throws IOException {
    		log.info("加载签名证书==>" + pfxkeyfile);
    		InputStream fis = null;
    		try {
    			KeyStore ks = KeyStore.getInstance(type, "BC");
    			log.info("Load RSA CertPath=[" + pfxkeyfile + "],Pwd=["+ keypwd + "],type=["+type+"]");
    
    			//File file=new File(getRealCertPath() + pfxkeyfile);
    			Resource resource = new ClassPathResource(pfxkeyfile);
    			fis = resource.getInputStream();
    			char[] nPassword = null;
    			nPassword = null == keypwd || "".equals(keypwd.trim()) ? null: keypwd.toCharArray();
    			if (null != ks) {
    				ks.load(fis, nPassword);
    			}
    			return ks;
    		} catch (Exception e) {
    			log.error("getKeyInfo Error", e);
    			return null;
    		} finally {
    			if(null!=fis)
    				fis.close();
    		}
    	}
    	
    	/**
    	 * 通过签名私钥证书路径,密码获取私钥证书certId
    	 * @param certPath
    	 * @param certPwd
    	 * @return
    	 */
    	public static String getCertIdByKeyStoreMap(String certPath, String certPwd) {
    		if (!keyStoreMap.containsKey(certPath)) {
    			// 缓存中未查询到,则加载RSA证书
    			loadSignCert(certPath, certPwd);
    		}
    		return getCertIdIdByStore(keyStoreMap.get(certPath));
    	}
    	
    	/**
    	 * 通过keystore获取私钥证书的certId值
    	 * @param keyStore
    	 * @return
    	 */
    	private static String getCertIdIdByStore(KeyStore keyStore) {
    		Enumeration<String> aliasenum = null;
    		try {
    			aliasenum = keyStore.aliases();
    			String keyAlias = null;
    			if (aliasenum.hasMoreElements()) {
    				keyAlias = aliasenum.nextElement();
    			}
    			X509Certificate cert = (X509Certificate) keyStore
    					.getCertificate(keyAlias);
    			return cert.getSerialNumber().toString();
    		} catch (KeyStoreException e) {
    			log.error("getCertIdIdByStore Error", e);
    			return null;
    		}
    	}
    	
    	/**
    	 * 使用模和指数生成RSA公钥 注意:此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同
    	 * 
    	 * @param modulus
    	 *            模
    	 * @param exponent
    	 *            指数
    	 * @return
    	 */
    	private static PublicKey getPublicKey(String modulus, String exponent) {
    		try {
    			BigInteger b1 = new BigInteger(modulus);
    			BigInteger b2 = new BigInteger(exponent);
    			KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
    			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
    			return keyFactory.generatePublic(keySpec);
    		} catch (Exception e) {
    			log.error("构造RSA公钥失败:" + e);
    			return null;
    		}
    	}
    	
    	/**
    	 * 将字符串转换为X509Certificate对象.
    	 * 
    	 * @param x509CertString
    	 * @return
    	 */
    	public static X509Certificate genCertificateByStr(String x509CertString) {
    		X509Certificate x509Cert = null;
    		try {
    			CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); 
    			InputStream tIn = new ByteArrayInputStream(
    					x509CertString.getBytes("ISO-8859-1"));
    			x509Cert = (X509Certificate) cf.generateCertificate(tIn);
    		} catch (Exception e) {
    			log.error("gen certificate error", e);			
    		}
    		return x509Cert;
    	}
    	
    	/**
    	 * 从配置文件acp_sdk.properties中获取验签公钥使用的中级证书
    	 * @return
    	 */
    	public static X509Certificate getMiddleCert() {
    		if (null == middleCert) {
    			String path = SDKConfig.getConfig().getMiddleCertPath();
    			if (!SDKUtil.isEmpty(path)) {
    				initMiddleCert();
    			} else {
    				log.error(SDKConfig.SDK_MIDDLECERT_PATH + " not set in " + SDKConfig.FILE_NAME);
    				return null;
    			}
    		}
    		return middleCert;
    	}
    	
    	/**
    	 * 从配置文件acp_sdk.properties中获取验签公钥使用的根证书
    	 * @return
    	 */
    	public static X509Certificate getRootCert() {
    		if (null == rootCert) {
    			String path = SDKConfig.getConfig().getRootCertPath();
    			if (!SDKUtil.isEmpty(path)) {
    				initRootCert();
    			} else {
    				log.error(SDKConfig.SDK_ROOTCERT_PATH + " not set in " + SDKConfig.FILE_NAME);
    				return null;
    			}
    		}
    		return rootCert;
    	}
    
    	/**
    	 * 获取证书的CN
    	 * @param aCert
    	 * @return
    	 */
    	private static String getIdentitiesFromCertficate(X509Certificate aCert) {
    		String tDN = aCert.getSubjectDN().toString(); 
    		String tPart = "";
    		if ((tDN != null)) {
    			String tSplitStr[] = tDN.substring(tDN.indexOf("CN=")).split("@");
    			if (tSplitStr != null && tSplitStr.length > 2
    					&& tSplitStr[2] != null)
    				tPart = tSplitStr[2];
    		}
    		return tPart;
    	}
    	
    	/**
    	 * 验证书链。
    	 * @param cert
    	 * @return
    	 */
    	private static boolean verifyCertificateChain(X509Certificate cert){
    		
    		if ( null == cert) {
    			log.error("cert must Not null");
    			return false;
    		}
    		
    		X509Certificate middleCert = CertUtil.getMiddleCert();
    		if (null == middleCert) {
    			log.error("middleCert must Not null");
    			return false;
    		}
    		
    		X509Certificate rootCert = CertUtil.getRootCert();
    		if (null == rootCert) {
    			log.error("rootCert or cert must Not null");
    			return false;
    		}
    		
    		try {
    		
    	        X509CertSelector selector = new X509CertSelector();
    	        selector.setCertificate(cert);
    	        
    	        Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
    	        trustAnchors.add(new TrustAnchor(rootCert, null));
    	        PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(
    			        trustAnchors, selector);
    	
    	        Set<X509Certificate> intermediateCerts = new HashSet<X509Certificate>();
    	        intermediateCerts.add(rootCert);
    	        intermediateCerts.add(middleCert);
    	        intermediateCerts.add(cert);
    	        
    	        pkixParams.setRevocationEnabled(false);
    	
    	        CertStore intermediateCertStore = CertStore.getInstance("Collection",
    	                new CollectionCertStoreParameters(intermediateCerts), "BC");
    	        pkixParams.addCertStore(intermediateCertStore);
    	
    	        CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC");
    	        
            	@SuppressWarnings("unused")
    			PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) builder
                    .build(pkixParams);
    			log.info("verify certificate chain succeed.");
    			return true;
            } catch (CertPathBuilderException e){
    			log.error("verify certificate chain fail.", e);
    		} catch (Exception e) {
    			log.error("verify certificate chain exception: ", e);
    		}
    		return false;
    	}
    	
    	/**
    	 * 检查证书链
    	 * 
    	 *  rootCerts
    	 *  根证书
    	 * @param cert
    	 *            待验证的证书
    	 * @return
    	 */
    	public static boolean verifyCertificate(X509Certificate cert) {
    		
    		if ( null == cert) {
    			log.error("cert must Not null");
    			return false;
    		}
    		try {
    			cert.checkValidity();//验证有效期
    //			cert.verify(middleCert.getPublicKey());
    			if(!verifyCertificateChain(cert)){
    				return false;
    			}
    		} catch (Exception e) {
    			log.error("verifyCertificate fail", e);
    			return false;
    		}
    		
    		if(SDKConfig.getConfig().isIfValidateCNName()){
    			// 验证公钥是否属于银联
    			if(!SDKConstants.UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert))) {
    				log.error("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert));
    				return false;
    			}
    		} else {
    			// 验证公钥是否属于银联
    			if(!SDKConstants.UNIONPAY_CNNAME.equals(CertUtil.getIdentitiesFromCertficate(cert))
    					&& !"00040000:SIGN".equals(CertUtil.getIdentitiesFromCertficate(cert))) {
    				log.error("cer owner is not CUP:" + CertUtil.getIdentitiesFromCertficate(cert));
    				return false;
    			}
    		}
    		return true;		
    	}
    
    	/**
    	 * 打印系统环境信息
    	 */
    	private static void printSysInfo() {
    		log.info("================= SYS INFO begin====================");
    		log.info("os_name:" + System.getProperty("os.name"));
    		log.info("os_arch:" + System.getProperty("os.arch"));
    		log.info("os_version:" + System.getProperty("os.version"));
    		log.info("java_vm_specification_version:"
    				+ System.getProperty("java.vm.specification.version"));
    		log.info("java_vm_specification_vendor:"
    				+ System.getProperty("java.vm.specification.vendor"));
    		log.info("java_vm_specification_name:"
    				+ System.getProperty("java.vm.specification.name"));
    		log.info("java_vm_version:"
    				+ System.getProperty("java.vm.version"));
    		log.info("java_vm_name:" + System.getProperty("java.vm.name"));
    		log.info("java.version:" + System.getProperty("java.version"));
    		log.info("java.vm.vendor=[" + System.getProperty("java.vm.vendor") + "]");
    		log.info("java.version=[" + System.getProperty("java.version") + "]");
    		printProviders();
    		log.info("================= SYS INFO end=====================");
    	}
    	
    	/**
    	 * 打jre中印算法提供者列表
    	 */
    	private static void printProviders() {
    		log.info("Providers List:");
    		Provider[] providers = Security.getProviders();
    		for (int i = 0; i < providers.length; i++) {
    			log.info(i + 1 + "." + providers[i].getName());
    		}
    	}
    
    	/**
    	 * 证书文件过滤器
    	 * 
    	 */
    	static class CerFilter implements FilenameFilter {
    		public boolean isCer(String name) {
    			if (name.toLowerCase().endsWith(".cer")) {
    				return true;
    			} else {
    				return false;
    			}
    		}
    		public boolean accept(File dir, String name) {
    			return isCer(name);
    		}
    	}
    
    	private static String getRealCertPath(){
    		String clazzPath=Thread.currentThread().getContextClassLoader().getResource("").getPath();
    		clazzPath=clazzPath.replace("test-classes","classes");
    		clazzPath=clazzPath.replace("/classes/","/classes");
    		return clazzPath;
    	}
    }
    
    package com.example.demo.union.service;
    
    
    import com.example.demo.union.constants.SDKConstants;
    import com.example.demo.union.util.*;
    
    import java.io.*;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * @ClassName AcpService
     * @Description acpsdk接口服务类,接入商户集成请可以直接参考使用本类中的方法
     * @date 2016-7-22 下午2:44:37
     */
    public class AcpService {
    
    	/**
    	 * 请求报文签名(使用配置文件中配置的私钥证书或者对称密钥签名)<br>
    	 * 功能:对请求报文进行签名,并计算赋值certid,signature字段并返回<br>
    	 * @param reqData 请求报文map<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return 签名后的map对象<br>
    	 */
    	public static Map<String, String> sign(Map<String, String> reqData,String encoding) {
    		reqData = SDKUtil.filterBlank(reqData);
    		SDKUtil.sign(reqData, encoding);
    		return reqData;
    	}
    	
    	/**
    	 * 同signByCertInfo<br>
    	 * @param reqData
    	 * @param certPath
    	 * @param certPwd
    	 * @param encoding
    	 * @return
    	 * @deprecated
    	 */
    	public static Map<String, String> sign(Map<String, String> reqData, String certPath, 
    			String certPwd,String encoding) {
    		reqData = SDKUtil.filterBlank(reqData);
    		SDKUtil.signByCertInfo(reqData,certPath,certPwd,encoding);
    		return reqData;
    	}
    	
    	/**
    	 * 多证书签名(通过传入私钥证书路径和密码签名)<br>
    	 * 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
    	 * @param reqData 请求报文map<br>
    	 * @param certPath 签名私钥文件(带路径)<br>
    	 * @param certPwd 签名私钥密码<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return 签名后的map对象<br>
    	 */
    	public static Map<String, String> signByCertInfo(Map<String, String> reqData, String certPath, 
    			String certPwd,String encoding) {
    		reqData = SDKUtil.filterBlank(reqData);
    		SDKUtil.signByCertInfo(reqData,certPath,certPwd,encoding);
    		return reqData;
    	}
    	
    	/**
    	 * 多密钥签名(通过传入密钥签名)<br>
    	 * 功能:如果有多个商户号接入银联,每个商户号对应不同的证书可以使用此方法:传入私钥证书和密码(并且在acp_sdk.properties中 配置 acpsdk.singleMode=false)<br>
    	 * @param reqData 请求报文map<br>
    	 * @param secureKey 签名对称密钥<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return 签名后的map对象<br>
    	 */
    	public static Map<String, String> signBySecureKey(Map<String, String> reqData, String secureKey, String encoding) {
    		reqData = SDKUtil.filterBlank(reqData);
    		SDKUtil.signBySecureKey(reqData, secureKey, encoding);
    		return reqData;
    	}
    	
    	/**
    	 * 验证签名(SHA-1摘要算法)<br>
    	 * @param rspData 返回报文数据<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return true 通过 false 未通过<br>
    	 */
    	public static boolean validate(Map<String, String> rspData, String encoding) {
    		return SDKUtil.validate(rspData, encoding);
    	}
    	
    	/**
    	 * 多密钥验签(通过传入密钥签名)<br>
    	 * @param rspData 返回报文数据<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return true 通过 false 未通过<br>
    	 */
    	public static boolean validateBySecureKey(Map<String, String> rspData, String secureKey, String encoding) {
    		return SDKUtil.validateBySecureKey(rspData, secureKey, encoding);
    	}
    	
    
    	/**
    	 * @deprecated 5.1.0开发包已删除此方法,请直接参考5.1.0开发包中的VerifyAppData.java验签。
    	 * 对控件支付成功返回的结果信息中data域进行验签(控件端获取的应答信息)<br>
    	 * @param jsonData json格式数据,例如:{"sign" : "J6rPLClQ64szrdXCOtV1ccOMzUmpiOKllp9cseBuRqJ71pBKPPkZ1FallzW18gyP7CvKh1RxfNNJ66AyXNMFJi1OSOsteAAFjF5GZp0Xsfm3LeHaN3j/N7p86k3B1GrSPvSnSw1LqnYuIBmebBkC1OD0Qi7qaYUJosyA1E8Ld8oGRZT5RR2gLGBoiAVraDiz9sci5zwQcLtmfpT5KFk/eTy4+W9SsC0M/2sVj43R9ePENlEvF8UpmZBqakyg5FO8+JMBz3kZ4fwnutI5pWPdYIWdVrloBpOa+N4pzhVRKD4eWJ0CoiD+joMS7+C0aPIEymYFLBNYQCjM0KV7N726LA==",  "data" : "pay_result=success&tn=201602141008032671528&cert_id=68759585097"}
    	 * @return 是否成功
    	 */
    	public static boolean validateAppResponse(String jsonData, String encoding) {
    		LogUtil.writeLog("控件应答信息验签处理开始:[" + jsonData + "]");
    		if (SDKUtil.isEmpty(encoding)) {
    			encoding = "UTF-8";
    		}
    
            Pattern p = Pattern.compile("\\s*\"sign\"\\s*:\\s*\"([^\"]*)\"\\s*");
    		Matcher m = p.matcher(jsonData);
    		if(!m.find()) return false;
    		String sign = m.group(1);
    
    		p = Pattern.compile("\\s*\"data\"\\s*:\\s*\"([^\"]*)\"\\s*");
    		m = p.matcher(jsonData);
    		if(!m.find()) return false;
    		String data = m.group(1);
    
    		p = Pattern.compile("cert_id=(\\d*)");
    		m = p.matcher(jsonData);
    		if(!m.find()) return false;
    		String certId = m.group(1);
    
    		try {
    			// 验证签名需要用银联发给商户的公钥证书.
    			return SecureUtil.validateSignBySoft(CertUtil
    					.getValidatePublicKey(certId), SecureUtil.base64Decode(sign
    					.getBytes(encoding)), SecureUtil.sha1X16(data,
    					encoding));
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return false;
    	}
    	
    	/**
    	 * 功能:后台交易提交请求报文并接收同步应答报文<br>
    	 * @param reqData 请求报文<br>
    	 * @param reqUrl  请求地址<br>
    	 * @param encoding<br>
    	 * @return 应答http 200返回true ,其他false<br>
    	 */
    	public static Map<String,String> post(
    			Map<String, String> reqData,String reqUrl,String encoding) {
    		Map<String, String> rspData = new HashMap<String,String>();
    		LogUtil.writeLog("请求银联地址:" + reqUrl);
    		//发送后台请求数据
    		HttpClient hc = new HttpClient(reqUrl, 30000, 30000);
    		try {
    			int status = hc.send(reqData, encoding);
    			if (200 == status) {
    				String resultString = hc.getResult();
    				if (null != resultString && !"".equals(resultString)) {
    					// 将返回结果转换为map
    					Map<String,String> tmpRspData  = SDKUtil.convertResultStringToMap(resultString);
    					rspData.putAll(tmpRspData);
    				}
    			}else{
    				LogUtil.writeLog("返回http状态码["+status+"],请检查请求报文或者请求地址是否正确");
    			}
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return rspData;
    	}
    	
    	/**
    	 * 功能:http Get方法 便民缴费产品中使用<br>
    	 * @param reqUrl 请求地址<br>
    	 * @param encoding<br>
    	 * @return
    	 */
    	public static String get(String reqUrl,String encoding) {
    		
    		LogUtil.writeLog("请求银联地址:" + reqUrl);
    		//发送后台请求数据
    		HttpClient hc = new HttpClient(reqUrl, 30000, 30000);
    		try {
    			int status = hc.sendGet(encoding);
    			if (200 == status) {
    				String resultString = hc.getResult();
    				if (null != resultString && !"".equals(resultString)) {
    					return resultString;
    				}
    			}else{
    				LogUtil.writeLog("返回http状态码["+status+"],请检查请求报文或者请求地址是否正确");
    			}
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return null;
    	}
    	
    	
    	/**
    	 * 功能:前台交易构造HTTP POST自动提交表单<br>
    	 * @param reqUrl 表单提交地址<br>
    	 * @param hiddens 以MAP形式存储的表单键值<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>
    	 * @return 构造好的HTTP POST交易表单<br>
    	 */
    	public static String createAutoFormHtml(String reqUrl, Map<String, String> hiddens,String encoding) {
    		StringBuffer sf = new StringBuffer();
    		sf.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset="+encoding+"\"/></head><body>");
    		sf.append("<form id = \"pay_form\" action=\"" + reqUrl
    				+ "\" method=\"post\">");
    		if (null != hiddens && 0 != hiddens.size()) {
    			Set<Entry<String, String>> set = hiddens.entrySet();
    			Iterator<Entry<String, String>> it = set.iterator();
    			while (it.hasNext()) {
    				Entry<String, String> ey = it.next();
    				String key = ey.getKey();
    				String value = ey.getValue();
    				sf.append("<input type=\"hidden\" name=\"" + key + "\" id=\""
    						+ key + "\" value=\"" + value + "\"/>");
    			}
    		}
    		sf.append("</form>");
    		sf.append("</body>");
    		sf.append("<script type=\"text/javascript\">");
    		sf.append("document.all.pay_form.submit();");
    		sf.append("</script>");
    		sf.append("</html>");
    		return sf.toString();
    	}
    
    	
    	/**
    	 * 功能:将批量文件内容使用DEFLATE压缩算法压缩,Base64编码生成字符串并返回<br>
    	 * 适用到的交易:批量代付,批量代收,批量退货<br>
    	 * @param filePath 批量文件-全路径文件名<br>
    	 * @return
    	 */
    	public static String enCodeFileContent(String filePath,String encoding){
    		String baseFileContent = "";
    		
    		File file = new File(filePath);
    		if (!file.exists()) {
    			try {
    				file.createNewFile();
    			} catch (IOException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			}
    		}
    		InputStream in = null;
    		try {
    			in = new FileInputStream(file);
    			int fl = in.available();
    			if (null != in) {
    				byte[] s = new byte[fl];
    				in.read(s, 0, fl);
    				// 压缩编码.
    				baseFileContent = new String(SecureUtil.base64Encode(SDKUtil.deflater(s)),encoding);
    			}
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} finally {
    			if (null != in) {
    				try {
    					in.close();
    				} catch (IOException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				}
    			}
    		}
    		return baseFileContent;
    	}
    	
    	/**
    	 * 功能:解析交易返回的fileContent字符串并落地 ( 解base64,解DEFLATE压缩并落地)<br>
    	 * 适用到的交易:对账文件下载,批量交易状态查询<br>
    	 * @param resData 返回报文map<br>
    	 * @param fileDirectory 落地的文件目录(绝对路径)
    	 * @param encoding 上送请求报文域encoding字段的值<br>	
    	 */
    	public static String deCodeFileContent(Map<String, String> resData,String fileDirectory,String encoding) {
    		// 解析返回文件
    		String filePath = null;
    		String fileContent = resData.get(SDKConstants.param_fileContent);
    		if (null != fileContent && !"".equals(fileContent)) {
    			FileOutputStream out = null;
    			try {
    				byte[] fileArray = SDKUtil.inflater(SecureUtil
    						.base64Decode(fileContent.getBytes(encoding)));
    				if (SDKUtil.isEmpty(resData.get("fileName"))) {
    					filePath = fileDirectory + File.separator + resData.get("merId")
    							+ "_" + resData.get("batchNo") + "_"
    							+ resData.get("txnTime") + ".txt";
    				} else {
    					filePath = fileDirectory + File.separator + resData.get("fileName");
    				}
    				File file = new File(filePath);
    				if (file.exists()) {
    					file.delete();
    				}
    				file.createNewFile();
    			    out = new FileOutputStream(file);
    				out.write(fileArray, 0, fileArray.length);
    				out.flush();
    			} catch (UnsupportedEncodingException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			} catch (IOException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			}finally{
    				try {
    					out.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    		return filePath;
    	}
    
    	/**
    	 * 功能:将结果文件内容 转换成明文字符串:解base64,解压缩<br>
    	 * 适用到的交易:批量交易状态查询<br>
    	 * @param fileContent 批量交易状态查询返回的文件内容<br>
    	 * @return 内容明文<br>
    	 */
    	public static String getFileContent(String fileContent,String encoding){
    		String fc = "";
    		try {
    			fc = new String(SDKUtil.inflater(SecureUtil.base64Decode(fileContent.getBytes())),encoding);
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return fc;
    	}
    	
    	
    	/**
    	 * 功能:持卡人信息域customerInfo构造<br>
    	 * 说明:不勾选对敏感信息加密权限使用旧的构造customerInfo域方式,不对敏感信息进行加密(对 phoneNo,cvn2, expired不加密),但如果送pin的话则加密<br>
    	 * @param customerInfoMap 信息域请求参数 key送域名value送值,必送<br>
    	 *        例如:customerInfoMap.put("certifTp", "01");					//证件类型<br>
    				  customerInfoMap.put("certifId", "341126197709218366");	//证件号码<br>
    				  customerInfoMap.put("customerNm", "互联网");				//姓名<br>
    				  customerInfoMap.put("phoneNo", "13552535506");			//手机号<br>
    				  customerInfoMap.put("smsCode", "123456");					//短信验证码<br>
    				  customerInfoMap.put("pin", "111111");						//密码(加密)<br>
    				  customerInfoMap.put("cvn2", "123");           			//卡背面的cvn2三位数字(不加密)<br>
    				  customerInfoMap.put("expired", "1711");  				    //有效期 年在前月在后(不加密)<br>
    	 * @param accNo  customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码pin,此字段可以不送<br>
    	 * @param encoding 上送请求报文域encoding字段的值<br>				  
    	 * @return base64后的持卡人信息域字段<br>
    	 */
    	public static String getCustomerInfo(Map<String,String> customerInfoMap,String accNo,String encoding) {
    		
    		if(customerInfoMap.isEmpty())
    			return "{}";
    		StringBuffer sf = new StringBuffer("{");
    		for(Iterator<String> it = customerInfoMap.keySet().iterator(); it.hasNext();){
    			String key = it.next();
    			String value = customerInfoMap.get(key);
    			if(key.equals("pin")){
    				if(null == accNo || "".equals(accNo.trim())){
    					LogUtil.writeLog("送了密码(PIN),必须在getCustomerInfo参数中上传卡号");
    					throw new RuntimeException("加密PIN没送卡号无法后续处理");
    				}else{
    					value = encryptPin(accNo,value,encoding);
    				}
    			}
    			sf.append(key).append(SDKConstants.EQUAL).append(value);
    			if(it.hasNext())
    				sf.append(SDKConstants.AMPERSAND);
    		}
    		String customerInfo = sf.append("}").toString();
    		LogUtil.writeLog("组装的customerInfo明文:"+customerInfo);
    		try {
    			return new String(SecureUtil.base64Encode(sf.toString().getBytes(
    					encoding)),encoding);
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return customerInfo;
    	}
    	
    	/**
    	 * 功能:持卡人信息域customerInfo构造,勾选对敏感信息加密权限 适用新加密规范,对pin和phoneNo,cvn2,expired加密 <br>
    	 * 适用到的交易: <br>
    	 * @param customerInfoMap 信息域请求参数 key送域名value送值,必送 <br>
    	 *        例如:customerInfoMap.put("certifTp", "01");					//证件类型 <br>
    				  customerInfoMap.put("certifId", "341126197709218366");	//证件号码 <br>
    				  customerInfoMap.put("customerNm", "互联网");				//姓名 <br>
    				  customerInfoMap.put("smsCode", "123456");					//短信验证码 <br>
    				  customerInfoMap.put("pin", "111111");						//密码(加密) <br>
    				  customerInfoMap.put("phoneNo", "13552535506");			//手机号(加密) <br>
    				  customerInfoMap.put("cvn2", "123");           			//卡背面的cvn2三位数字(加密) <br>
    				  customerInfoMap.put("expired", "1711");  				    //有效期 年在前月在后(加密) <br>
    	 * @param accNo  customerInfoMap送了密码那么卡号必送,如果customerInfoMap未送密码PIN,此字段可以不送<br>
    	 * @param encoding 上送请求报文域encoding字段的值
    	 * @return base64后的持卡人信息域字段 <br>
    	 */
    	public static String getCustomerInfoWithEncrypt(Map<String,String> customerInfoMap,String accNo,String encoding) {
    		if(customerInfoMap.isEmpty())
    			return "{}";
    		StringBuffer sf = new StringBuffer("{");
    		//敏感信息加密域
    		StringBuffer encryptedInfoSb = new StringBuffer("");
    		
    		for(Iterator<String> it = customerInfoMap.keySet().iterator(); it.hasNext();){
    			String key = it.next();
    			String value = customerInfoMap.get(key);
    			if(key.equals("phoneNo") || key.equals("cvn2") || key.equals("expired")){
    				encryptedInfoSb.append(key).append(SDKConstants.EQUAL).append(value).append(SDKConstants.AMPERSAND);
    			}else{
    				if(key.equals("pin")){
    					if(null == accNo || "".equals(accNo.trim())){
    						LogUtil.writeLog("送了密码(PIN),必须在getCustomerInfoWithEncrypt参数中上传卡号");
    						throw new RuntimeException("加密PIN没送卡号无法后续处理");
    					}else{
    						value = encryptPin(accNo,value,encoding);
    					}
    				}
    				sf.append(key).append(SDKConstants.EQUAL).append(value).append(SDKConstants.AMPERSAND);
    			}
    		}
    		
    		if(!encryptedInfoSb.toString().equals("")){
    			encryptedInfoSb.setLength(encryptedInfoSb.length()-1);//去掉最后一个&符号
    			LogUtil.writeLog("组装的customerInfo encryptedInfo明文:"+ encryptedInfoSb.toString());
    			sf.append("encryptedInfo").append(SDKConstants.EQUAL).append(encryptData(encryptedInfoSb.toString(), encoding));
    		}else{
    			sf.setLength(sf.length()-1);
    		}
    		
    		String customerInfo = sf.append("}").toString();
    		LogUtil.writeLog("组装的customerInfo明文:"+customerInfo);
    		try {
    			return new String(SecureUtil.base64Encode(sf.toString().getBytes(encoding)),encoding);
    		} catch (UnsupportedEncodingException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		}
    		return customerInfo;
    	}
    	
    	/**
    	 * 解析返回报文(后台通知)中的customerInfo域:<br>
    	 * 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
    	 * @param customerInfo<br>
    	 * @param encoding<br>
    	 * @return
    	 */
    	public static Map<String,String> parseCustomerInfo(String customerInfo,String encoding){
    		Map<String,String> customerInfoMap = null;
    		try {
    				byte[] b = SecureUtil.base64Decode(customerInfo.getBytes(encoding));
    				String customerInfoNoBase64 = new String(b,encoding);
    				LogUtil.writeLog("解base64后===>" +customerInfoNoBase64);
    				//去掉前后的{}
    				customerInfoNoBase64 = customerInfoNoBase64.substring(1, customerInfoNoBase64.length()-1);
    				customerInfoMap = SDKUtil.parseQString(customerInfoNoBase64);
    				if(customerInfoMap.containsKey("encryptedInfo")){
    					String encInfoStr = customerInfoMap.get("encryptedInfo");
    					customerInfoMap.remove("encryptedInfo");
    					String encryptedInfoStr = decryptData(encInfoStr, encoding);
    					Map<String,String> encryptedInfoMap = SDKUtil.parseQString(encryptedInfoStr);
    					customerInfoMap.putAll(encryptedInfoMap);
    				}
    			} catch (UnsupportedEncodingException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			} catch (IOException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			}
    		return customerInfoMap;
    	}
    	
    	/**
    	 * 解析返回报文(后台通知)中的customerInfo域:<br>
    	 * 解base64,如果带敏感信息加密 encryptedInfo 则将其解密并将 encryptedInfo中的域放到customerInfoMap返回<br>
    	 * @param customerInfo<br>
    	 * @param encoding<br>
    	 * @return
    	 */
    	public static Map<String,String> parseCustomerInfo(String customerInfo, String certPath, 
    			String certPwd, String encoding){
    		Map<String,String> customerInfoMap = null;
    		try {
    				byte[] b = SecureUtil.base64Decode(customerInfo.getBytes(encoding));
    				String customerInfoNoBase64 = new String(b,encoding);
    				LogUtil.writeLog("解base64后===>" +customerInfoNoBase64);
    				//去掉前后的{}
    				customerInfoNoBase64 = customerInfoNoBase64.substring(1, customerInfoNoBase64.length()-1);
    				customerInfoMap = SDKUtil.parseQString(customerInfoNoBase64);
    				if(customerInfoMap.containsKey("encryptedInfo")){
    					String encInfoStr = customerInfoMap.get("encryptedInfo");
    					customerInfoMap.remove("encryptedInfo");
    					String encryptedInfoStr = decryptData(encInfoStr, certPath, certPwd, encoding);
    					Map<String,String> encryptedInfoMap = SDKUtil.parseQString(encryptedInfoStr);
    					customerInfoMap.putAll(encryptedInfoMap);
    				}
    			} catch (UnsupportedEncodingException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			} catch (IOException e) {
    				LogUtil.writeErrorLog(e.getMessage(), e);
    			}
    		return customerInfoMap;
    	}
    
    	/**
    	 * 密码加密并做base64<br>
    	 * @param accNo 卡号<br>
    	 * @param pin 密码<br>
    	 * @param encoding<br>
    	 * @return 加密的内容<br>
    	 */
    	public static String encryptPin(String accNo, String pin, String encoding) {
    		return SecureUtil.encryptPin(accNo, pin, encoding, CertUtil
    				.getEncryptCertPublicKey());
    	}
    	
    	/**
    	 * 敏感信息加密并做base64(卡号,手机号,cvn2,有效期)<br>
    	 * @param data 送 phoneNo,cvn2,有效期<br>
    	 * @param encoding<br>
    	 * @return 加密的密文<br>
    	 */
    	public static String encryptData(String data, String encoding) {
    		return SecureUtil.encryptData(data, encoding, CertUtil
    				.getEncryptCertPublicKey());
    	}
    	
    	/**
    	 * 敏感信息解密,使用配置文件acp_sdk.properties解密<br>
    	 * @param base64EncryptedInfo 加密信息<br>
    	 * @param encoding<br>
    	 * @return 解密后的明文<br>
    	 */
    	public static String decryptData(String base64EncryptedInfo, String encoding) {
    		return SecureUtil.decryptData(base64EncryptedInfo, encoding, CertUtil
    				.getSignCertPrivateKey());
    	}
    	
    	/**
    	 * 敏感信息解密,通过传入的私钥解密<br>
    	 * @param base64EncryptedInfo 加密信息<br>
    	 * @param certPath 私钥文件(带全路径)<br>
    	 * @param certPwd 私钥密码<br>
    	 * @param encoding<br>
    	 * @return
    	 */
    	public static String decryptData(String base64EncryptedInfo, String certPath, 
    			String certPwd, String encoding) {
    		return SecureUtil.decryptData(base64EncryptedInfo, encoding, CertUtil
    				.getSignCertPrivateKeyByStoreMap(certPath, certPwd));
    	}
    
    	/**
    	 * 5.0.0加密磁道信息,5.1.0接口请勿使用<br>
    	 * @param trackData 待加密磁道数据<br>
    	 * @param encoding 编码格式<br>
    	 * @return 加密的密文<br>
    	 * @deprecated
    	 */
    	public static String encryptTrack(String trackData, String encoding) {
    		return SecureUtil.encryptData(trackData, encoding,
    				CertUtil.getEncryptTrackPublicKey());
    	}
    	
    	/**
    	 * 获取敏感信息加密证书的物理序列号<br>
    	 * @return
    	 */
    	public static String getEncryptCertId(){
    		return CertUtil.getEncryptCertId();
    	}
    	
    	/**
    	 * 对字符串做base64<br>
    	 * @param rawStr<br>
    	 * @param encoding<br>
    	 * @return<br>
    	 * @throws IOException
    	 */
    	public static String base64Encode(String rawStr,String encoding) throws IOException{
    		byte [] rawByte = rawStr.getBytes(encoding);
    		return new String(SecureUtil.base64Encode(rawByte),encoding);
    	}
    	/**
    	 * 对base64的字符串解base64<br>
    	 * @param base64Str<br>
    	 * @param encoding<br>
    	 * @return<br>
    	 * @throws IOException
    	 */
    	public static String base64Decode(String base64Str,String encoding) throws IOException{
    		byte [] rawByte = base64Str.getBytes(encoding);
    		return new String(SecureUtil.base64Decode(rawByte),encoding);	
    	}
    
    
    	/**
    	 * 
    	 * 有卡交易信息域(cardTransData)构造<br>
    	 * 所有子域需用“{}”包含,子域间以“&”符号链接。格式如下:{子域名1=值&子域名2=值&子域名3=值}<br>
    	 * 说明:本示例仅供参考,开发时请根据接口文档中的报文要素组装<br>
    	 * 
    	 * @param cardTransDataMap cardTransData的数据<br>
    	 * @param requestData 必须包含merId、orderId、txnTime、txnAmt,磁道加密时需要使用<br>
    	 * @param encoding 编码<br>
    	 * @return
    	 */
    	public static String getCardTransData(Map<String, String> cardTransDataMap, 
    			Map<String, String> requestData,
    			String encoding) { {
    
    		StringBuffer cardTransDataBuffer = new StringBuffer();
    		
    		if(cardTransDataMap.containsKey("track2Data")){
    			StringBuffer track2Buffer = new StringBuffer();
    			track2Buffer.append(requestData.get("merId"))
    					.append(SDKConstants.COLON).append(requestData.get("orderId"))
    					.append(SDKConstants.COLON).append(requestData.get("txnTime"))
    					.append(SDKConstants.COLON).append(requestData.get("txnAmt")==null?0:requestData.get("txnAmt"))
    					.append(SDKConstants.COLON).append(cardTransDataMap.get("track2Data"));
    			cardTransDataMap.put("track2Data", 
    					AcpService.encryptData(track2Buffer.toString(),	encoding));
    		}
    		
    		if(cardTransDataMap.containsKey("track3Data")){
    			StringBuffer track3Buffer = new StringBuffer();
    			track3Buffer.append(requestData.get("merId"))
    				.append(SDKConstants.COLON).append(requestData.get("orderId"))
    				.append(SDKConstants.COLON).append(requestData.get("txnTime"))
    				.append(SDKConstants.COLON).append(requestData.get("txnAmt")==null?0:requestData.get("txnAmt"))
    				.append(SDKConstants.COLON).append(cardTransDataMap.get("track3Data"));
    			cardTransDataMap.put("track3Data", 
    					AcpService.encryptData(track3Buffer.toString(),	encoding));
    		}
    
    		return cardTransDataBuffer.append(SDKConstants.LEFT_BRACE)
    				.append(SDKUtil.coverMap2String(cardTransDataMap))
    				.append(SDKConstants.RIGHT_BRACE).toString();
    		}
    	
    	}
    	
    	/**
    	 * 获取应答报文中的加密公钥证书,并存储到本地,备份原始证书,并自动替换证书<br>
    	 * 更新成功则返回1,无更新返回0,失败异常返回-1<br>
    	 * @param resData 返回报文
    	 * @param encoding
    	 * @return
    	 */
    	public static int updateEncryptCert(Map<String, String> resData,
    			String encoding) {
    		return SDKUtil.getEncryptCert(resData, encoding);
    	}
    	
    	/**
    	 * 获取
    	 * @param number
    	 * @return
    	 */
    	public static int genLuhn(String number){
    		return SecureUtil.genLuhn(number);
    	}
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28     SSLSocket 链接工具类(用于https)
     * =============================================================================
     */
    package com.example.demo.union.service;
    
    
    import com.example.demo.union.util.LogUtil;
    
    import javax.net.ssl.*;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.security.cert.X509Certificate;
    
    /**
     * 
     * @ClassName BaseHttpSSLSocketFactory
     * @Description 忽略验证ssl证书
     * @date 2016-7-22 下午4:10:14
     *
     */
    public class BaseHttpSSLSocketFactory extends SSLSocketFactory {
    	private SSLContext getSSLContext() {
    		return createEasySSLContext();
    	}
    
    	@Override
    	public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2,
    			int arg3) throws IOException {
    		return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
    				arg2, arg3);
    	}
    
    	@Override
    	public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3)
    			throws IOException, UnknownHostException {
    		return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
    				arg2, arg3);
    	}
    
    	@Override
    	public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
    		return getSSLContext().getSocketFactory().createSocket(arg0, arg1);
    	}
    
    	@Override
    	public Socket createSocket(String arg0, int arg1) throws IOException,
    			UnknownHostException {
    		return getSSLContext().getSocketFactory().createSocket(arg0, arg1);
    	}
    
    	@Override
    	public String[] getSupportedCipherSuites() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public String[] getDefaultCipherSuites() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3)
    			throws IOException {
    		return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
    				arg2, arg3);
    	}
    
    	private SSLContext createEasySSLContext() {
    		try {
    			SSLContext context = SSLContext.getInstance("SSL");
    			context.init(null,
    					new TrustManager[] { MyX509TrustManager.manger }, null);
    			return context;
    		} catch (Exception e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    			return null;
    		}
    	}
    
    	public static class MyX509TrustManager implements X509TrustManager {
    
    		static MyX509TrustManager manger = new MyX509TrustManager();
    
    		public MyX509TrustManager() {
    		}
    
    		public X509Certificate[] getAcceptedIssuers() {
    			return null;
    		}
    
    		public void checkClientTrusted(X509Certificate[] chain, String authType) {
    		}
    
    		public void checkServerTrusted(X509Certificate[] chain, String authType) {
    		}
    	}
    
    	/**
    	 * 解决由于服务器证书问题导致HTTPS无法访问的情况 PS:HTTPS hostname wrong: should be <localhost>
    	 */
    	public static class TrustAnyHostnameVerifier implements HostnameVerifier {
    		public boolean verify(String hostname, SSLSession session) {
    			//直接返回true
    			return true;
    		}
    	}
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28       MPI插件包常量定义
     * =============================================================================
     */
    package com.example.demo.union.constants;
    /**
     * 
     * @ClassName SDKConstants
     * @Description acpsdk常量类
     * @date 2016-7-22 下午4:05:54
     *
     */
    public class SDKConstants {
    
    	public final static String COLUMN_DEFAULT = "-";
    
    	public final static String KEY_DELIMITER = "#";
    
    	/** memeber variable: blank. */
    	public static final String BLANK = "";
    
    	/** member variabel: space. */
    	public static final String SPACE = " ";
    
    	/** memeber variable: unline. */
    	public static final String UNLINE = "_";
    
    	/** memeber varibale: star. */
    	public static final String STAR = "*";
    
    	/** memeber variable: line. */
    	public static final String LINE = "-";
    
    	/** memeber variable: add. */
    	public static final String ADD = "+";
    
    	/** memeber variable: colon. */
    	public final static String COLON = "|";
    
    	/** memeber variable: point. */
    	public final static String POINT = ".";
    
    	/** memeber variable: comma. */
    	public final static String COMMA = ",";
    
    	/** memeber variable: slash. */
    	public final static String SLASH = "/";
    
    	/** memeber variable: div. */
    	public final static String DIV = "/";
    
    	/** memeber variable: left . */
    	public final static String LB = "(";
    
    	/** memeber variable: right. */
    	public final static String RB = ")";
    
    	/** memeber variable: rmb. */
    	public final static String CUR_RMB = "RMB";
    
    	/** memeber variable: .page size */
    	public static final int PAGE_SIZE = 10;
    
    	/** memeber variable: String ONE. */
    	public static final String ONE = "1";
    
    	/** memeber variable: String ZERO. */
    	public static final String ZERO = "0";
    
    	/** memeber variable: number six. */
    	public static final int NUM_SIX = 6;
    
    	/** memeber variable: equal mark. */
    	public static final String EQUAL = "=";
    
    	/** memeber variable: operation ne. */
    	public static final String NE = "!=";
    
    	/** memeber variable: operation le. */
    	public static final String LE = "<=";
    
    	/** memeber variable: operation ge. */
    	public static final String GE = ">=";
    
    	/** memeber variable: operation lt. */
    	public static final String LT = "<";
    
    	/** memeber variable: operation gt. */
    	public static final String GT = ">";
    
    	/** memeber variable: list separator. */
    	public static final String SEP = "./";
    
    	/** memeber variable: Y. */
    	public static final String Y = "Y";
    
    	/** memeber variable: AMPERSAND. */
    	public static final String AMPERSAND = "&";
    
    	/** memeber variable: SQL_LIKE_TAG. */
    	public static final String SQL_LIKE_TAG = "%";
    
    	/** memeber variable: @. */
    	public static final String MAIL = "@";
    
    	/** memeber variable: number zero. */
    	public static final int NZERO = 0;
    
    	public static final String LEFT_BRACE = "{";
    
    	public static final String RIGHT_BRACE = "}";
    
    	/** memeber variable: string true. */
    	public static final String TRUE_STRING = "true";
    	/** memeber variable: string false. */
    	public static final String FALSE_STRING = "false";
    
    	/** memeber variable: forward success. */
    	public static final String SUCCESS = "success";
    	/** memeber variable: forward fail. */
    	public static final String FAIL = "fail";
    	/** memeber variable: global forward success. */
    	public static final String GLOBAL_SUCCESS = "$success";
    	/** memeber variable: global forward fail. */
    	public static final String GLOBAL_FAIL = "$fail";
    
    	public static final String UTF_8_ENCODING = "UTF-8";
    	public static final String GBK_ENCODING = "GBK";
    	public static final String CONTENT_TYPE = "Content-type";
    	public static final String APP_XML_TYPE = "application/xml;charset=utf-8";
    	public static final String APP_FORM_TYPE = "application/x-www-form-urlencoded;charset=";
    	
    	public static final String VERSION_1_0_0 = "1.0.0";
    	public static final String VERSION_5_0_0 = "5.0.0";
    	public static final String VERSION_5_0_1 = "5.0.1";
    	public static final String VERSION_5_1_0 = "5.1.0";
    	public static final String SIGNMETHOD_RSA = "01";
    	public static final String SIGNMETHOD_SHA256 = "11";
    	public static final String SIGNMETHOD_SM3 = "12";
    	public static final String UNIONPAY_CNNAME = "中国银联股份有限公司";
    	public static final String CERTTYPE_01 = "01";// 敏感信息加密公钥
    	public static final String CERTTYPE_02 = "02";// 磁道加密公钥
    
    	/******************************************** 5.0报文接口定义 ********************************************/
    	/** 版本号. */
    	public static final String param_version = "version";
    	/** 证书ID. */
    	public static final String param_certId = "certId";
    	/** 签名. */
    	public static final String param_signature = "signature";
    	/** 签名方法. */
    	public static final String param_signMethod = "signMethod";
    	/** 编码方式. */
    	public static final String param_encoding = "encoding";
    	/** 交易类型. */
    	public static final String param_txnType = "txnType";
    	/** 交易子类. */
    	public static final String param_txnSubType = "txnSubType";
    	/** 业务类型. */
    	public static final String param_bizType = "bizType";
    	/** 前台通知地址 . */
    	public static final String param_frontUrl = "frontUrl";
    	/** 后台通知地址. */
    	public static final String param_backUrl = "backUrl";
    	/** 接入类型. */
    	public static final String param_accessType = "accessType";
    	/** 收单机构代码. */
    	public static final String param_acqInsCode = "acqInsCode";
    	/** 商户类别. */
    	public static final String param_merCatCode = "merCatCode";
    	/** 商户类型. */
    	public static final String param_merType = "merType";
    	/** 商户代码. */
    	public static final String param_merId = "merId";
    	/** 商户名称. */
    	public static final String param_merName = "merName";
    	/** 商户简称. */
    	public static final String param_merAbbr = "merAbbr";
    	/** 二级商户代码. */
    	public static final String param_subMerId = "subMerId";
    	/** 二级商户名称. */
    	public static final String param_subMerName = "subMerName";
    	/** 二级商户简称. */
    	public static final String param_subMerAbbr = "subMerAbbr";
    	/** Cupsecure 商户代码. */
    	public static final String param_csMerId = "csMerId";
    	/** 商户订单号. */
    	public static final String param_orderId = "orderId";
    	/** 交易时间. */
    	public static final String param_txnTime = "txnTime";
    	/** 发送时间. */
    	public static final String param_txnSendTime = "txnSendTime";
    	/** 订单超时时间间隔. */
    	public static final String param_orderTimeoutInterval = "orderTimeoutInterval";
    	/** 支付超时时间. */
    	public static final String param_payTimeoutTime = "payTimeoutTime";
    	/** 默认支付方式. */
    	public static final String param_defaultPayType = "defaultPayType";
    	/** 支持支付方式. */
    	public static final String param_supPayType = "supPayType";
    	/** 支付方式. */
    	public static final String param_payType = "payType";
    	/** 自定义支付方式. */
    	public static final String param_customPayType = "customPayType";
    	/** 物流标识. */
    	public static final String param_shippingFlag = "shippingFlag";
    	/** 收货地址-国家. */
    	public static final String param_shippingCountryCode = "shippingCountryCode";
    	/** 收货地址-省. */
    	public static final String param_shippingProvinceCode = "shippingProvinceCode";
    	/** 收货地址-市. */
    	public static final String param_shippingCityCode = "shippingCityCode";
    	/** 收货地址-地区. */
    	public static final String param_shippingDistrictCode = "shippingDistrictCode";
    	/** 收货地址-详细. */
    	public static final String param_shippingStreet = "shippingStreet";
    	/** 商品总类. */
    	public static final String param_commodityCategory = "commodityCategory";
    	/** 商品名称. */
    	public static final String param_commodityName = "commodityName";
    	/** 商品URL. */
    	public static final String param_commodityUrl = "commodityUrl";
    	/** 商品单价. */
    	public static final String param_commodityUnitPrice = "commodityUnitPrice";
    	/** 商品数量. */
    	public static final String param_commodityQty = "commodityQty";
    	/** 是否预授权. */
    	public static final String param_isPreAuth = "isPreAuth";
    	/** 币种. */
    	public static final String param_currencyCode = "currencyCode";
    	/** 账户类型. */
    	public static final String param_accType = "accType";
    	/** 账号. */
    	public static final String param_accNo = "accNo";
    	/** 支付卡类型. */
    	public static final String param_payCardType = "payCardType";
    	/** 发卡机构代码. */
    	public static final String param_issInsCode = "issInsCode";
    	/** 持卡人信息. */
    	public static final String param_customerInfo = "customerInfo";
    	/** 交易金额. */
    	public static final String param_txnAmt = "txnAmt";
    	/** 余额. */
    	public static final String param_balance = "balance";
    	/** 地区代码. */
    	public static final String param_districtCode = "districtCode";
    	/** 附加地区代码. */
    	public static final String param_additionalDistrictCode = "additionalDistrictCode";
    	/** 账单类型. */
    	public static final String param_billType = "billType";
    	/** 账单号码. */
    	public static final String param_billNo = "billNo";
    	/** 账单月份. */
    	public static final String param_billMonth = "billMonth";
    	/** 账单查询要素. */
    	public static final String param_billQueryInfo = "billQueryInfo";
    	/** 账单详情. */
    	public static final String param_billDetailInfo = "billDetailInfo";
    	/** 账单金额. */
    	public static final String param_billAmt = "billAmt";
    	/** 账单金额符号. */
    	public static final String param_billAmtSign = "billAmtSign";
    	/** 绑定标识号. */
    	public static final String param_bindId = "bindId";
    	/** 风险级别. */
    	public static final String param_riskLevel = "riskLevel";
    	/** 绑定信息条数. */
    	public static final String param_bindInfoQty = "bindInfoQty";
    	/** 绑定信息集. */
    	public static final String param_bindInfoList = "bindInfoList";
    	/** 批次号. */
    	public static final String param_batchNo = "batchNo";
    	/** 总笔数. */
    	public static final String param_totalQty = "totalQty";
    	/** 总金额. */
    	public static final String param_totalAmt = "totalAmt";
    	/** 文件类型. */
    	public static final String param_fileType = "fileType";
    	/** 文件名称. */
    	public static final String param_fileName = "fileName";
    	/** 批量文件内容. */
    	public static final String param_fileContent = "fileContent";
    	/** 商户摘要. */
    	public static final String param_merNote = "merNote";
    	/** 商户自定义域. */
    	// public static final String param_merReserved = "merReserved";//接口变更删除
    	/** 请求方保留域. */
    	public static final String param_reqReserved = "reqReserved";// 新增接口
    	/** 保留域. */
    	public static final String param_reserved = "reserved";
    	/** 终端号. */
    	public static final String param_termId = "termId";
    	/** 终端类型. */
    	public static final String param_termType = "termType";
    	/** 交互模式. */
    	public static final String param_interactMode = "interactMode";
    	/** 发卡机构识别模式. */
    	// public static final String param_recognitionMode = "recognitionMode";
    	public static final String param_issuerIdentifyMode = "issuerIdentifyMode";// 接口名称变更
    	/** 商户端用户号. */
    	public static final String param_merUserId = "merUserId";
    	/** 持卡人IP. */
    	public static final String param_customerIp = "customerIp";
    	/** 查询流水号. */
    	public static final String param_queryId = "queryId";
    	/** 原交易查询流水号. */
    	public static final String param_origQryId = "origQryId";
    	/** 系统跟踪号. */
    	public static final String param_traceNo = "traceNo";
    	/** 交易传输时间. */
    	public static final String param_traceTime = "traceTime";
    	/** 清算日期. */
    	public static final String param_settleDate = "settleDate";
    	/** 清算币种. */
    	public static final String param_settleCurrencyCode = "settleCurrencyCode";
    	/** 清算金额. */
    	public static final String param_settleAmt = "settleAmt";
    	/** 清算汇率. */
    	public static final String param_exchangeRate = "exchangeRate";
    	/** 兑换日期. */
    	public static final String param_exchangeDate = "exchangeDate";
    	/** 响应时间. */
    	public static final String param_respTime = "respTime";
    	/** 原交易应答码. */
    	public static final String param_origRespCode = "origRespCode";
    	/** 原交易应答信息. */
    	public static final String param_origRespMsg = "origRespMsg";
    	/** 应答码. */
    	public static final String param_respCode = "respCode";
    	/** 应答码信息. */
    	public static final String param_respMsg = "respMsg";
    	// 新增四个报文字段merUserRegDt merUserEmail checkFlag activateStatus
    	/** 商户端用户注册时间. */
    	public static final String param_merUserRegDt = "merUserRegDt";
    	/** 商户端用户注册邮箱. */
    	public static final String param_merUserEmail = "merUserEmail";
    	/** 验证标识. */
    	public static final String param_checkFlag = "checkFlag";
    	/** 开通状态. */
    	public static final String param_activateStatus = "activateStatus";
    	/** 加密证书ID. */
    	public static final String param_encryptCertId = "encryptCertId";
    	/** 用户MAC、IMEI串号、SSID. */
    	public static final String param_userMac = "userMac";
    	/** 关联交易. */
    	// public static final String param_relationTxnType = "relationTxnType";
    	/** 短信类型 */
    	public static final String param_smsType = "smsType";
    
    	/** 风控信息域 */
    	public static final String param_riskCtrlInfo = "riskCtrlInfo";
    
    	/** IC卡交易信息域 */
    	public static final String param_ICTransData = "ICTransData";
    
    	/** VPC交易信息域 */
    	public static final String param_VPCTransData = "VPCTransData";
    
    	/** 安全类型 */
    	public static final String param_securityType = "securityType";
    
    	/** 银联订单号 */
    	public static final String param_tn = "tn";
    
    	/** 分期付款手续费率 */
    	public static final String param_instalRate = "instalRate";
    
    	/** 分期付款手续费率 */
    	public static final String param_mchntFeeSubsidy = "mchntFeeSubsidy";
    	
    	/** 签名公钥证书 */
    	public static final String param_signPubKeyCert = "signPubKeyCert";
    
    	/** 加密公钥证书 */
    	public static final String param_encryptPubKeyCert = "encryptPubKeyCert";
    	
    	/** 证书类型 */
    	public static final String param_certType = "certType";
    
    }
    
    /**
     *
     * Licensed Property to China UnionPay Co., Ltd.
     * 
     * (C) Copyright of China UnionPay Co., Ltd. 2010
     *     All Rights Reserved.
     *
     * 
     * Modification History:
     * =============================================================================
     *   Author         Date          Description
     *   ------------ ---------- ---------------------------------------------------
     *   xshu       2014-05-28       MPI基本参数工具类
     * =============================================================================
     */
    package com.example.demo.union.config;
    
    import com.example.demo.union.constants.SDKConstants;
    import com.example.demo.union.util.LogUtil;
    import com.example.demo.union.util.SDKUtil;
    import org.apache.commons.lang.StringUtils;
    
    import java.io.*;
    import java.util.Properties;
    
    /**
     * 
     * @ClassName SDKConfig
     * @Description acpsdk配置文件acp_sdk.properties配置信息类
     * @date 2016-7-22 下午4:04:55
     *
     */
    public class SDKConfig {
    	public static final String FILE_NAME = "properties/acp_sdk.properties";
    	/** 前台请求URL. */
    	private String frontRequestUrl;
    	/** 后台请求URL. */
    	private String backRequestUrl;
    	/** 单笔查询 */
    	private String singleQueryUrl;
    	/** 批量查询 */
    	private String batchQueryUrl;
    	/** 批量交易 */
    	private String batchTransUrl;
    	/** 文件传输 */
    	private String fileTransUrl;
    	/** 签名证书路径. */
    	private String signCertPath;
    	/** 签名证书密码. */
    	private String signCertPwd;
    	/** 签名证书类型. */
    	private String signCertType;
    	/** 加密公钥证书路径. */
    	private String encryptCertPath;
    	/** 验证签名公钥证书目录. */
    	private String validateCertDir;
    	/** 按照商户代码读取指定签名证书目录. */
    	private String signCertDir;
    	/** 磁道加密证书路径. */
    	private String encryptTrackCertPath;
    	/** 磁道加密公钥模数. */
    	private String encryptTrackKeyModulus;
    	/** 磁道加密公钥指数. */
    	private String encryptTrackKeyExponent;
    	/** 有卡交易. */
    	private String cardRequestUrl;
    	/** app交易 */
    	private String appRequestUrl;
    	/** 证书使用模式(单证书/多证书) */
    	private String singleMode;
    	/** 安全密钥(SHA256和SM3计算时使用) */
    	private String secureKey;
    	/** 中级证书路径  */
    	private String middleCertPath;
    	/** 根证书路径  */
    	private String rootCertPath;
    	/** 是否验证验签证书CN,除了false都验  */
    	private boolean ifValidateCNName = true;
    	/** 是否验证https证书,默认都不验  */
    	private boolean ifValidateRemoteCert = false;
    	/** signMethod,没配按01吧  */
    	private String signMethod = "01";
    	/** version,没配按5.0.0  */
    	private String version = "5.0.0";
    	/** frontUrl  */
    	private String frontUrl;
    	/** backUrl  */
    	private String backUrl;
    
    	/*缴费相关地址*/
    	private String jfFrontRequestUrl;
    	private String jfBackRequestUrl;
    	private String jfSingleQueryUrl;
    	private String jfCardRequestUrl;
    	private String jfAppRequestUrl;
    	
    	private String qrcBackTransUrl;
    	private String qrcB2cIssBackTransUrl;
    	private String qrcB2cMerBackTransUrl;
    
    	/** 配置文件中的前台URL常量. */
    	public static final String SDK_FRONT_URL = "acpsdk.frontTransUrl";
    	/** 配置文件中的后台URL常量. */
    	public static final String SDK_BACK_URL = "acpsdk.backTransUrl";
    	/** 配置文件中的单笔交易查询URL常量. */
    	public static final String SDK_SIGNQ_URL = "acpsdk.singleQueryUrl";
    	/** 配置文件中的批量交易查询URL常量. */
    	public static final String SDK_BATQ_URL = "acpsdk.batchQueryUrl";
    	/** 配置文件中的批量交易URL常量. */
    	public static final String SDK_BATTRANS_URL = "acpsdk.batchTransUrl";
    	/** 配置文件中的文件类交易URL常量. */
    	public static final String SDK_FILETRANS_URL = "acpsdk.fileTransUrl";
    	/** 配置文件中的有卡交易URL常量. */
    	public static final String SDK_CARD_URL = "acpsdk.cardTransUrl";
    	/** 配置文件中的app交易URL常量. */
    	public static final String SDK_APP_URL = "acpsdk.appTransUrl";
    
    	/** 以下缴费产品使用,其余产品用不到,无视即可 */
    	// 前台请求地址
    	public static final String JF_SDK_FRONT_TRANS_URL= "acpsdk.jfFrontTransUrl";
    	// 后台请求地址
    	public static final String JF_SDK_BACK_TRANS_URL="acpsdk.jfBackTransUrl";
    	// 单笔查询请求地址
    	public static final String JF_SDK_SINGLE_QUERY_URL="acpsdk.jfSingleQueryUrl";
    	// 有卡交易地址
    	public static final String JF_SDK_CARD_TRANS_URL="acpsdk.jfCardTransUrl";
    	// App交易地址
    	public static final String JF_SDK_APP_TRANS_URL="acpsdk.jfAppTransUrl";
    	// 人到人
    	public static final String QRC_BACK_TRANS_URL="acpsdk.qrcBackTransUrl";
    	// 人到人
    	public static final String QRC_B2C_ISS_BACK_TRANS_URL="acpsdk.qrcB2cIssBackTransUrl";
    	// 人到人
    	public static final String QRC_B2C_MER_BACK_TRANS_URL="acpsdk.qrcB2cMerBackTransUrl";
    	
    	
    	/** 配置文件中签名证书路径常量. */
    	public static final String SDK_SIGNCERT_PATH = "acpsdk.signCert.path";
    	/** 配置文件中签名证书密码常量. */
    	public static final String SDK_SIGNCERT_PWD = "acpsdk.signCert.pwd";
    	/** 配置文件中签名证书类型常量. */
    	public static final String SDK_SIGNCERT_TYPE = "acpsdk.signCert.type";
    	/** 配置文件中密码加密证书路径常量. */
    	public static final String SDK_ENCRYPTCERT_PATH = "acpsdk.encryptCert.path";
    	/** 配置文件中磁道加密证书路径常量. */
    	public static final String SDK_ENCRYPTTRACKCERT_PATH = "acpsdk.encryptTrackCert.path";
    	/** 配置文件中磁道加密公钥模数常量. */
    	public static final String SDK_ENCRYPTTRACKKEY_MODULUS = "acpsdk.encryptTrackKey.modulus";
    	/** 配置文件中磁道加密公钥指数常量. */
    	public static final String SDK_ENCRYPTTRACKKEY_EXPONENT = "acpsdk.encryptTrackKey.exponent";
    	/** 配置文件中验证签名证书目录常量. */
    	public static final String SDK_VALIDATECERT_DIR = "acpsdk.validateCert.dir";
    
    	/** 配置文件中是否加密cvn2常量. */
    	public static final String SDK_CVN_ENC = "acpsdk.cvn2.enc";
    	/** 配置文件中是否加密cvn2有效期常量. */
    	public static final String SDK_DATE_ENC = "acpsdk.date.enc";
    	/** 配置文件中是否加密卡号常量. */
    	public static final String SDK_PAN_ENC = "acpsdk.pan.enc";
    	/** 配置文件中证书使用模式 */
    	public static final String SDK_SINGLEMODE = "acpsdk.singleMode";
    	/** 配置文件中安全密钥 */
    	public static final String SDK_SECURITYKEY = "acpsdk.secureKey";
    	/** 配置文件中根证书路径常量  */
    	public static final String SDK_ROOTCERT_PATH = "acpsdk.rootCert.path";
    	/** 配置文件中根证书路径常量  */
    	public static final String SDK_MIDDLECERT_PATH = "acpsdk.middleCert.path";
    	/** 配置是否需要验证验签证书CN,除了false之外的值都当true处理 */
    	public static final String SDK_IF_VALIDATE_CN_NAME = "acpsdk.ifValidateCNName";
    	/** 配置是否需要验证https证书,除了true之外的值都当false处理 */
    	public static final String SDK_IF_VALIDATE_REMOTE_CERT = "acpsdk.ifValidateRemoteCert";
    	/** signmethod */
    	public static final String SDK_SIGN_METHOD ="acpsdk.signMethod";
    	/** version */
    	public static final String SDK_VERSION = "acpsdk.version";
    	/** 后台通知地址  */
    	public static final String SDK_BACKURL = "acpsdk.backUrl";
    	/** 前台通知地址  */
    	public static final String SDK_FRONTURL = "acpsdk.frontUrl";
    	/** 操作对象. */
    	private static SDKConfig config = new SDKConfig();
    	/** 属性文件对象. */
    	private Properties properties;
    
    	private SDKConfig() {
    		super();
    	}
    
    	/**
    	 * 获取config对象.
    	 * @return
    	 */
    	public static SDKConfig getConfig() {
    		return config;
    	}
    
    	/**
    	 * 从properties文件加载
    	 * 
    	 * @param rootPath
    	 *            不包含文件名的目录.
    	 */
    	public void loadPropertiesFromPath(String rootPath) {
    		if (StringUtils.isNotBlank(rootPath)) {
    			LogUtil.writeLog("从路径读取配置文件: " + rootPath+File.separator+FILE_NAME);
    			File file = new File(rootPath + File.separator + FILE_NAME);
    			InputStream in = null;
    			if (file.exists()) {
    				try {
    					in = new FileInputStream(file);
    					properties = new Properties();
    					properties.load(in);
    					loadProperties(properties);
    				} catch (FileNotFoundException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				} catch (IOException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				} finally {
    					if (null != in) {
    						try {
    							in.close();
    						} catch (IOException e) {
    							LogUtil.writeErrorLog(e.getMessage(), e);
    						}
    					}
    				}
    			} else {
    				// 由于此时可能还没有完成LOG的加载,因此采用标准输出来打印日志信息
    				LogUtil.writeErrorLog(rootPath + FILE_NAME + "不存在,加载参数失败");
    			}
    		} else {
    			loadPropertiesFromSrc();
    		}
    
    	}
    
    	/**
    	 * 从classpath路径下加载配置参数
    	 */
    	public void loadPropertiesFromSrc() {
    		InputStream in = null;
    		try {
    			LogUtil.writeLog("从classpath: " +SDKConfig.class.getClassLoader().getResource("").getPath()+" 获取属性文件"+FILE_NAME);
    			in = this.getClass().getClassLoader().getResourceAsStream(FILE_NAME);
    			if (null != in) {
    				properties = new Properties();
    				try {
    					properties.load(in);
    				} catch (IOException e) {
    					throw e;
    				}
    			} else {
    				LogUtil.writeErrorLog(FILE_NAME + "属性文件未能在classpath指定的目录下 "+SDKConfig.class.getClassLoader().getResource("").getPath()+" 找到!");
    				return;
    			}
    			loadProperties(properties);
    		} catch (IOException e) {
    			LogUtil.writeErrorLog(e.getMessage(), e);
    		} finally {
    			if (null != in) {
    				try {
    					in.close();
    				} catch (IOException e) {
    					LogUtil.writeErrorLog(e.getMessage(), e);
    				}
    			}
    		}
    	}
    
    	/**
    	 * 根据传入的 {@link #(Properties)}对象设置配置参数
    	 * 
    	 * @param pro
    	 */
    	public void loadProperties(Properties pro) {
    		LogUtil.writeLog("开始从属性文件中加载配置项");
    		String value = null;
    		
    		value = pro.getProperty(SDK_SIGNCERT_PATH);
    		if (!SDKUtil.isEmpty(value)) {
    			this.signCertPath = value.trim();
    			LogUtil.writeLog("配置项:私钥签名证书路径==>"+SDK_SIGNCERT_PATH +"==>"+ value+" 已加载");
    		}
    		value = pro.getProperty(SDK_SIGNCERT_PWD);
    		if (!SDKUtil.isEmpty(value)) {
    			this.signCertPwd = value.trim();
    			LogUtil.writeLog("配置项:私钥签名证书密码==>"+SDK_SIGNCERT_PWD +" 已加载");
    		}
    		value = pro.getProperty(SDK_SIGNCERT_TYPE);
    		if (!SDKUtil.isEmpty(value)) {
    			this.signCertType = value.trim();
    			LogUtil.writeLog("配置项:私钥签名证书类型==>"+SDK_SIGNCERT_TYPE +"==>"+ value+" 已加载");
    		}
    		value = pro.getProperty(SDK_ENCRYPTCERT_PATH);
    		if (!SDKUtil.isEmpty(value)) {
    			this.encryptCertPath = value.trim();
    			LogUtil.writeLog("配置项:敏感信息加密证书==>"+SDK_ENCRYPTCERT_PATH +"==>"+ value+" 已加载");
    		}
    		value = pro.getProperty(SDK_VALIDATECERT_DIR);
    		if (!SDKUtil.isEmpty(value)) {
    			this.validateCertDir = value.trim();
    			LogUtil.writeLog("配置项:验证签名证书路径(这里配置的是目录,不要指定到公钥文件)==>"+SDK_VALIDATECERT_DIR +"==>"+ value+" 已加载");
    		}
    		value = pro.getProperty(SDK_FRONT_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.frontRequestUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_BACK_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.backRequestUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_BATQ_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.batchQueryUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_BATTRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.batchTransUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_FILETRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.fileTransUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_SIGNQ_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.singleQueryUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_CARD_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.cardRequestUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_APP_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.appRequestUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_ENCRYPTTRACKCERT_PATH);
    		if (!SDKUtil.isEmpty(value)) {
    			this.encryptTrackCertPath = value.trim();
    		}
    
    		value = pro.getProperty(SDK_SECURITYKEY);
    		if (!SDKUtil.isEmpty(value)) {
    			this.secureKey = value.trim();
    		}
    		value = pro.getProperty(SDK_ROOTCERT_PATH);
    		if (!SDKUtil.isEmpty(value)) {
    			this.rootCertPath = value.trim();
    		}
    		value = pro.getProperty(SDK_MIDDLECERT_PATH);
    		if (!SDKUtil.isEmpty(value)) {
    			this.middleCertPath = value.trim();
    		}
    
    		/**缴费部分**/
    		value = pro.getProperty(JF_SDK_FRONT_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.jfFrontRequestUrl = value.trim();
    		}
    
    		value = pro.getProperty(JF_SDK_BACK_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.jfBackRequestUrl = value.trim();
    		}
    		
    		value = pro.getProperty(JF_SDK_SINGLE_QUERY_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.jfSingleQueryUrl = value.trim();
    		}
    		
    		value = pro.getProperty(JF_SDK_CARD_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.jfCardRequestUrl = value.trim();
    		}
    		
    		value = pro.getProperty(JF_SDK_APP_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.jfAppRequestUrl = value.trim();
    		}
    		
    		value = pro.getProperty(QRC_BACK_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.qrcBackTransUrl = value.trim();
    		}
    		
    		value = pro.getProperty(QRC_B2C_ISS_BACK_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.qrcB2cIssBackTransUrl = value.trim();
    		}
    		
    		value = pro.getProperty(QRC_B2C_MER_BACK_TRANS_URL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.qrcB2cMerBackTransUrl = value.trim();
    		}
    
    		value = pro.getProperty(SDK_ENCRYPTTRACKKEY_EXPONENT);
    		if (!SDKUtil.isEmpty(value)) {
    			this.encryptTrackKeyExponent = value.trim();
    		}
    
    		value = pro.getProperty(SDK_ENCRYPTTRACKKEY_MODULUS);
    		if (!SDKUtil.isEmpty(value)) {
    			this.encryptTrackKeyModulus = value.trim();
    		}
    		
    		value = pro.getProperty(SDK_IF_VALIDATE_CN_NAME);
    		if (!SDKUtil.isEmpty(value)) {
    			if( SDKConstants.FALSE_STRING.equals(value.trim()))
    					this.ifValidateCNName = false;
    		}
    		
    		value = pro.getProperty(SDK_IF_VALIDATE_REMOTE_CERT);
    		if (!SDKUtil.isEmpty(value)) {
    			if( SDKConstants.TRUE_STRING.equals(value.trim()))
    					this.ifValidateRemoteCert = true;
    		}
    		
    		value = pro.getProperty(SDK_SIGN_METHOD);
    		if (!SDKUtil.isEmpty(value)) {
    			this.signMethod = value.trim();
    		}
    		
    		value = pro.getProperty(SDK_SIGN_METHOD);
    		if (!SDKUtil.isEmpty(value)) {
    			this.signMethod = value.trim();
    		}
    		value = pro.getProperty(SDK_VERSION);
    		if (!SDKUtil.isEmpty(value)) {
    			this.version = value.trim();
    		}
    		value = pro.getProperty(SDK_FRONTURL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.frontUrl = value.trim();
    		}
    		value = pro.getProperty(SDK_BACKURL);
    		if (!SDKUtil.isEmpty(value)) {
    			this.backUrl = value.trim();
    		}
    	}
    
    
    	public String getFrontRequestUrl() {
    		return frontRequestUrl;
    	}
    
    	public void setFrontRequestUrl(String frontRequestUrl) {
    		this.frontRequestUrl = frontRequestUrl;
    	}
    
    	public String getBackRequestUrl() {
    		return backRequestUrl;
    	}
    
    	public void setBackRequestUrl(String backRequestUrl) {
    		this.backRequestUrl = backRequestUrl;
    	}
    
    	public String getSignCertPath() {
    		return signCertPath;
    	}
    
    	public void setSignCertPath(String signCertPath) {
    		this.signCertPath = signCertPath;
    	}
    
    	public String getSignCertPwd() {
    		return signCertPwd;
    	}
    
    	public void setSignCertPwd(String signCertPwd) {
    		this.signCertPwd = signCertPwd;
    	}
    
    	public String getSignCertType() {
    		return signCertType;
    	}
    
    	public void setSignCertType(String signCertType) {
    		this.signCertType = signCertType;
    	}
    
    	public String getEncryptCertPath() {
    		return encryptCertPath;
    	}
    
    	public void setEncryptCertPath(String encryptCertPath) {
    		this.encryptCertPath = encryptCertPath;
    	}
    	
    	public String getValidateCertDir() {
    		return validateCertDir;
    	}
    
    	public void setValidateCertDir(String validateCertDir) {
    		this.validateCertDir = validateCertDir;
    	}
    
    	public String getSingleQueryUrl() {
    		return singleQueryUrl;
    	}
    
    	public void setSingleQueryUrl(String singleQueryUrl) {
    		this.singleQueryUrl = singleQueryUrl;
    	}
    
    	public String getBatchQueryUrl() {
    		return batchQueryUrl;
    	}
    
    	public void setBatchQueryUrl(String batchQueryUrl) {
    		this.batchQueryUrl = batchQueryUrl;
    	}
    
    	public String getBatchTransUrl() {
    		return batchTransUrl;
    	}
    
    	public void setBatchTransUrl(String batchTransUrl) {
    		this.batchTransUrl = batchTransUrl;
    	}
    
    	public String getFileTransUrl() {
    		return fileTransUrl;
    	}
    
    	public void setFileTransUrl(String fileTransUrl) {
    		this.fileTransUrl = fileTransUrl;
    	}
    
    	public String getSignCertDir() {
    		return signCertDir;
    	}
    
    	public void setSignCertDir(String signCertDir) {
    		this.signCertDir = signCertDir;
    	}
    
    	public Properties getProperties() {
    		return properties;
    	}
    
    	public void setProperties(Properties properties) {
    		this.properties = properties;
    	}
    
    	public String getCardRequestUrl() {
    		return cardRequestUrl;
    	}
    
    	public void setCardRequestUrl(String cardRequestUrl) {
    		this.cardRequestUrl = cardRequestUrl;
    	}
    
    	public String getAppRequestUrl() {
    		return appRequestUrl;
    	}
    
    	public void setAppRequestUrl(String appRequestUrl) {
    		this.appRequestUrl = appRequestUrl;
    	}
    	
    	public String getEncryptTrackCertPath() {
    		return encryptTrackCertPath;
    	}
    
    	public void setEncryptTrackCertPath(String encryptTrackCertPath) {
    		this.encryptTrackCertPath = encryptTrackCertPath;
    	}
    	
    	public String getJfFrontRequestUrl() {
    		return jfFrontRequestUrl;
    	}
    
    	public void setJfFrontRequestUrl(String jfFrontRequestUrl) {
    		this.jfFrontRequestUrl = jfFrontRequestUrl;
    	}
    
    	public String getJfBackRequestUrl() {
    		return jfBackRequestUrl;
    	}
    
    	public void setJfBackRequestUrl(String jfBackRequestUrl) {
    		this.jfBackRequestUrl = jfBackRequestUrl;
    	}
    
    	public String getJfSingleQueryUrl() {
    		return jfSingleQueryUrl;
    	}
    
    	public void setJfSingleQueryUrl(String jfSingleQueryUrl) {
    		this.jfSingleQueryUrl = jfSingleQueryUrl;
    	}
    
    	public String getJfCardRequestUrl() {
    		return jfCardRequestUrl;
    	}
    
    	public void setJfCardRequestUrl(String jfCardRequestUrl) {
    		this.jfCardRequestUrl = jfCardRequestUrl;
    	}
    
    	public String getJfAppRequestUrl() {
    		return jfAppRequestUrl;
    	}
    
    	public void setJfAppRequestUrl(String jfAppRequestUrl) {
    		this.jfAppRequestUrl = jfAppRequestUrl;
    	}
    
    	public String getSingleMode() {
    		return singleMode;
    	}
    
    	public void setSingleMode(String singleMode) {
    		this.singleMode = singleMode;
    	}
    
    	public String getEncryptTrackKeyExponent() {
    		return encryptTrackKeyExponent;
    	}
    
    	public void setEncryptTrackKeyExponent(String encryptTrackKeyExponent) {
    		this.encryptTrackKeyExponent = encryptTrackKeyExponent;
    	}
    
    	public String getEncryptTrackKeyModulus() {
    		return encryptTrackKeyModulus;
    	}
    
    	public void setEncryptTrackKeyModulus(String encryptTrackKeyModulus) {
    		this.encryptTrackKeyModulus = encryptTrackKeyModulus;
    	}
    	
    	public String getSecureKey() {
    		return secureKey;
    	}
    
    	public void setSecureKey(String securityKey) {
    		this.secureKey = securityKey;
    	}
    	
    	public String getMiddleCertPath() {
    		return middleCertPath;
    	}
    
    	public void setMiddleCertPath(String middleCertPath) {
    		this.middleCertPath = middleCertPath;
    	}
    	
    	public boolean isIfValidateCNName() {
    		return ifValidateCNName;
    	}
    
    	public void setIfValidateCNName(boolean ifValidateCNName) {
    		this.ifValidateCNName = ifValidateCNName;
    	}
    
    	public boolean isIfValidateRemoteCert() {
    		return ifValidateRemoteCert;
    	}
    
    	public void setIfValidateRemoteCert(boolean ifValidateRemoteCert) {
    		this.ifValidateRemoteCert = ifValidateRemoteCert;
    	}
    
    	public String getSignMethod() {
    		return signMethod;
    	}
    
    	public void setSignMethod(String signMethod) {
    		this.signMethod = signMethod;
    	}
    	public String getQrcBackTransUrl() {
    		return qrcBackTransUrl;
    	}
    
    	public void setQrcBackTransUrl(String qrcBackTransUrl) {
    		this.qrcBackTransUrl = qrcBackTransUrl;
    	}
    
    	public String getQrcB2cIssBackTransUrl() {
    		return qrcB2cIssBackTransUrl;
    	}
    
    	public void setQrcB2cIssBackTransUrl(String qrcB2cIssBackTransUrl) {
    		this.qrcB2cIssBackTransUrl = qrcB2cIssBackTransUrl;
    	}
    
    	public String getQrcB2cMerBackTransUrl() {
    		return qrcB2cMerBackTransUrl;
    	}
    
    	public void setQrcB2cMerBackTransUrl(String qrcB2cMerBackTransUrl) {
    		this.qrcB2cMerBackTransUrl = qrcB2cMerBackTransUrl;
    	}
    
    	public String getVersion() {
    		return version;
    	}
    
    	public void setVersion(String version) {
    		this.version = version;
    	}
    
    	public String getFrontUrl() {
    		return frontUrl;
    	}
    
    	public void setFrontUrl(String frontUrl) {
    		this.frontUrl = frontUrl;
    	}
    
    	public String getBackUrl() {
    		return backUrl;
    	}
    
    	public void setBackUrl(String backUrl) {
    		this.backUrl = backUrl;
    	}
    
    	public String getRootCertPath() {
    		return rootCertPath;
    	}
    
    	public void setRootCertPath(String rootCertPath) {
    		this.rootCertPath = rootCertPath;
    	}
    	
    }
    

     

     

    展开全文
  • 资源名称:Java开发在线支付平台视频教程(12集)资源目录:【】5ef07ee1f2be2ba9fc9a035b3cbfb662【】95991ea4a0da032178437c1d8221a25e【】ad9e2901d56b94a342958c52ed5aa4eb【】java开发教程_01_在线支付_在线...
  • 开发官网:银联支付开发平台 支付流程: 正常的支付流程都是一样, 2 是支付请求,将返回的支付结果html在浏览器打开返回给用户 5 是同步支付结果写入(这里是完成支付后点击返回商户按钮触发) 6 是异步支付结果...

    开发官网:银联支付开发平台

    支付流程:

    正常的支付流程都是一样,

    2 是支付请求,将返回的支付结果html在浏览器打开返回给用户

    5 是同步支付结果写入(这里是完成支付后点击返回商户按钮触发)

    6 是异步支付结果写入(这里是完成支付后银联自动发起)

    在若支付结果写入异常时,可以主动发起结果查询接口,查询支付状态。

    心得:

    1.银联支付也是可以用到测试环境的,可以直接用,而且在开发平台带有支付教程视频可以参考

    2.下载demo后,要将相对应的测试证书也下载下来,并将对应的路径写入到配置文件中。

    3.在运行demo是要注意对应的jdk版本是否一致,否则会报错不能运行。

    4.在遇到问题不能解决时,可以到开发平台的社区中提问,一般隔天回复,也直接加客服QQ提问

    文章来源:
    https://www.cnblogs.com/LiLiliang/p/8574670.html

    展开全文
  • 通过银联测试Demo学习在线支付流程,以后对接其他的在线支付大概都是这个流程
  • Java银联卡支付小系统

    2021-11-11 17:17:37
    //银联支付卡 //获取余额 //取钱 //检查密码 public interface UnionPay { // 获取余额 public double getYE(); // 取钱功能 public boolean getMoney(double money); // 检查密码 public boolean checkPwd...

    接口:

    1----------

    package cn.edu.sqxy.day12.UnionPay;
    //银联支付卡
    //获取余额
    //取钱
    //检查密码
    public interface UnionPay {
    //    获取余额
        public double getYE();
    //    取钱功能
        public boolean getMoney(double money);
    //    检查密码
        public boolean checkPwd(String pwd);
    }

    2----------

    package cn.edu.sqxy.day12.UnionPay;
    //工商银行接口
    public interface ICBC extends UnionPay{
    //    在线支付
        public boolean drawOnline(double money);
    }

    3----------

    package cn.edu.sqxy.day12.UnionPay;
    //农业银行
    public interface ABC extends UnionPay{
    //    电话支付
        public boolean phoneMoney(String phone,String pwd,double money);
    }

    class:

    package cn.edu.sqxy.day12.UnionPay;
    
    import java.util.Scanner;
    
    //工商银行的实现类
    public  class ICBCImpl implements ICBC{
        public double usermoney = 2000000;
    
        @Override
        public boolean drawOnline(double money) {
    //        在线支付
            return false;
        }
    
        @Override
        public double getYE() {
    //        获取余额
            System.out.println("查询余额");
            return usermoney;
        }
    
        @Override
        public boolean getMoney(double money) {
    //        取款,判断是否余额不足
            if (usermoney >= money){
                System.out.println("有钱人");
                usermoney -= money;
                return true;
            }
    
            return false;
        }
    
        @Override
        public boolean checkPwd(String pwd) {
    //        判断密码是否正确
            if ("123".equals(pwd)){
                System.out.println("密码正确");
                return true;
            }
    
            return false;
        }
    }
    class ICBCTest{
        public static void main(String[] args) {
    //        设置输入函数
            Scanner scanner=new Scanner(System.in);
    //        提示用户输入密码
            System.out.println("请输入您的密码");
            String userPwd =scanner.next();
    //        创建ICBC实现类对象
            ICBCImpl ic =new ICBCImpl();
    //调用检查密码功能
            if(ic.checkPwd(userPwd)){
                System.out.println("请输入取款金额");
                double number =scanner.nextDouble();
                if (ic.getMoney(number)){
                    System.out.println("取款成功");
                }else {
                    System.out.println("余额不足");
                }
    //            查询余额
                System.out.println("余额是"+ic.getYE());
            }
    //        关闭输入函数
            scanner.close();
        }
    }

    展开全文
  • 使用Java完成网上支付(1. 银联

    千次阅读 2017-05-03 11:38:19
    4. 下载:网关支付产品技术开发包 5. 代码结构 6. 下载证书和密钥 7. 在D盘新建文件夹certs,把工程src/assets/测试环境证书 里面的文件拷贝到刚才新建的文件夹里 8. 把下载的...
  • 最新银联支付接口文档 + demo(JAVA

    热门讨论 2012-09-11 17:14:17
    最新银联支付接口,包括JAVA版实现和3个参考文档,包含接入方式说明,接口说明,字段说明,支付流程说明;涵盖了有卡支付,无卡支付等在线支付业务。基本上有你需要的!如果里面还没有你想要的,请发私信给我。
  • 由于公司App开发支付需求,需要后台用Java来完成银联支付接入接口。首先你要先进入银联开发登录地址open.unionpay.com找到手机控件支付模块,完成相应的入网步骤准备工作做完之后银联会对你发放相应的技术文档这里...
  • java开发微信支付源码

    2016-08-19 14:36:14
    基于java开发的微信支付源码,直接上干货,下载直接运行
  • 对接银联支付接口详解java版mac开发

    千次阅读 2018-02-14 11:44:00
    首先,这是一篇工具类的文章了,也是为了备忘,需求就是微信公众号的开发后台对接支付,有银联,支付宝,微信等,我负责写银联的接口。明天大年三十,今天在公司码完字也要灰走了,祝大家新年快乐,发大财。 先说...
  • 二、环境:(以银联支付目前的要求): 1、JDK1.6以上; 2、Tomcat6.0以上。 获取证书和代码 第一步: 注册登录银联支付银联支付开放平台官网链接 第二步: 进入在线网关支付下载官方支付代码,操作如下: ...
  • 银联二维码支付java 实现

    千次阅读 2017-12-13 18:28:26
    1. 准备工作  首先在银联开放平台注册一个测试账号,地址https://open.unionpay.com/ajweb/index  注册完成后可以根据自己所用的编程语言选择对应的demo下载,我下载了java通用版。...import java.io.IOExcepti
  • 银联商务支付接口DEMO

    2020-09-30 08:53:43
    包含公众号支付和H5支付示例,公众号支付参考连接:https://blog.csdn.net/weixin_44936767/article/details/106896362
  • 百度银联支付,基本在喷银联代码烂,要不就是拿官方的代码贴上来,都没有仔细的说集成过程,用处实在不大 这里记录我集成过程,希望能帮到大家 官方demo 都说银联代码没有规范,文档也烂。但是人家挺用心的,...
  • 3.根据需求(这里我们肯定使用JAVA)选择不同的开发包,导入到项目中 4.修改 Java Version SDK (通用版)\ACPSample_B2C\src 文件中acp_sdk.propertites 证书以及配置回调的地址,源码压缩包中有测试需要使用的证书 ...
  • 银联在线Java接口开发

    千次阅读 2016-06-13 11:34:59
    这几天在做chinapay的接口整合,银联的文档写得太烂,代码规范也不行,给用户带来不便就不多说,废话少说了,整理一下碰到的一些文档中没有强调的问题或者容易忽视的问题。 一、注册ChinaPay.dll这个文件 如果...
  • chinapay 银联支付 java

    2018-09-12 16:06:54
    chinapay银联支付基础代码 和文档,参考文档 和代码 ,注意是chinapay 不是 unionpay
  • java对接银联商务扫码支付

    千次阅读 热门讨论 2020-01-16 09:06:52
    java实现银联商务扫码支付----微信、支付宝 本文对接银联商务扫码支付,实现支付下单、订单查询、订单退款、退款查询和订单关闭几个功能,使用到银联商务的公众+服务窗支付接口规范,请自行百度下载。 一、接入前...
  • 注:原文来源与 《 Java 银联支付官网demo测试及项目整合代码 》银联支付(网关支付B2C) 一、测试官网demo a)下载官网开发包,导入eclipse等待修改(下载的开发包没有servlet jar包自己在Tomcat找一个) b)...
  • Java实现支付宝、微信、银联支付项目实例源码,支持新手项目学习
  • 银联java相关开发

    2016-03-24 17:02:44
    银联java相关开发

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,038
精华内容 815
关键字:

java银联支付开发

java 订阅