建行对接微信支付

1、获取配置信息,基础代码设置

1.1 建行支付、退款需要商户提供以下信息:

商户代码 支付使用
商户柜台代码 支付使用
分行代码 支付使用
公钥 外联平台使用、支付使用
操作员号 外联平台使用
操作员号交易密码 外联平台使用
证书 外联平台使用
证书密码 外联平台使用

1.2 创建工具类、实体类

1.2.1 映射信息

public class Const {
	//建行币种
    public static final String CCB_RMB= "01";//币种 01 人民币
    //建行交易码
    public static final String CCB_CODE= "530590";//由建行统一分配为 530590
    //建行接口类型
    public static final String CCB_METHOD_TYPE= "1";//1- 防钓鱼接口
    //建行语言
    public static final String CCB_LANGUAGE_CN= "CN";
    //建行支付方式
    public static final String CCB_TRADE_TYPE_JSAPI= "JSAPI";//JSAPI-- 公 众 号 支 付
    public static final String CCB_TRADE_TYPE_MINIPRO= "MINIPRO";//MINIPRO--小程序

    public static final String CCB_5W1001 = "5W1001";//商户连接交易
    public static final String CCB_5W1002 = "5W1002";//商户支付流水查询
    public static final String CCB_5W1003 = "5W1003";//商户退款流水查询
    public static final String CCB_5W1004 = "5W1004";//商户单笔退款交易
    public static final String CCB_5W1005 = "5W1005";//商户流水文件下载
    public static final String CCB_5W1006 = "5W1006";//E付通授权信息查询
    public static final String CCB_5W1007 = "5W1007";//外卡收单商户端mpi
    public static final String CCB_5W1015 = "5W1015";//历史订单退款交易
    public static final String CCB_5W1016 = "5W1016";//历史订单退款结果查询
    public static final String CCB_5W1024 = "5W1024";//线上集团商户单笔退款
    public static final String CCB_520200 = "520200";//商户支付交易
}

1.2.2 支付查询

//支付查询
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountPayJournalRequest {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *操作员号
     */
    @XmlElement(name = "USER_ID")
    public String USER_ID;
    /**
     *密码
     */
    @XmlElement(name = "PASSWORD")
    public String PASSWORD;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

    @XmlElement(name = "TX_INFO")
    public Body body;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class Body{
        /**
         *起始日期
         */
        public String START;
        /**
         *开始小时
         */
        public String STARTHOUR;
        /**
         *开始分钟
         */
        public String STARTMIN;
        /**
         *截止日期
         */
        public String END;
        /**
         *结束小时
         */
        public String ENDHOUR;
        /**
         *结束分钟
         */
        public String ENDMIN;
        /**
         *流水类型
         */
        public String KIND;
        /**
         *订单号
         */
        public String ORDER;
        /**
         *结算账户号
         */
        public String ACCOUNT;
        /**
         *文件类型
         */
        public String DEXCEL;
        /**
         *金额
         */
        public BigDecimal MONEY;
        /**
         *排序
         */
        public String NORDERBY;
        /**
         *当前页次
         */
        public int PAGE;
        /**
         *柜台号
         */
        public String POS_CODE;
        /**
         *流水状态
         */
        public String STATUS;
        /**
         *子商户号
         */
        public String Mrch_No;
    }

}
//支付查询响应
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountPayJournalResponse {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *响应码
     */
    @XmlElement(name = "RETURN_CODE")
    public String RETURN_CODE;
    /**
     *交易响应信息
     */
    @XmlElement(name = "RETURN_MSG")
    public String RETURN_MSG;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

//    @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
    @XmlElement(name = "TX_INFO")
    public Body body;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Body{
        /**
         *总页次
         */
        public int TPAGE;
        /**
         *当前页次
         */
        public int CUR_PAGE;
        /**
         *提示
         */
        public String NOTICE;

        @XmlElementWrapper(name = "LIST")
        public List<ListInfo> listInfoList;

        @XmlRootElement(name="LIST")
        @XmlAccessorType(XmlAccessType.FIELD)
        @Data
        public static class ListInfo{
            public String TRAN_DATE; //交易日期
            public String ACC_DATE; //记账日期
            public String ORDER; //订单号
            public String ACCOUNT; //付款方账号
            public String ACC_NAME; //付款方户名
            public BigDecimal PAYMENT_MONEY; //支付金额
            public BigDecimal REFUND_MONEY; //退款金额
            public String POS_ID; //柜台号
            public String REM1; //备注1public String
            public String REM2; //备注2
            public String ORDER_STATUS; //订单状态
            public String PAY_MODE; //支付方式
            public BigDecimal Orig_Amt; //订单金额
            public BigDecimal Txn_ClrgAmt; //结算金额
            public BigDecimal MrchCmsn_Amt; //手续费金额
            public BigDecimal Discount_Amt; //优惠金额
            public String OriOvrlsttnEV_Trck_No; //银行流水号
            public String MsgRp_Jrnl_No; //商户流水号
            public String OnlnPcsgInd_1_Bmp_ECD; //交易标志位图编码
            public String TxnAmt; //交易金额
            public String Cst_Tp_Prft_Dsc; //客户类型优惠描述
            public String Jrnl_TpCd; //流水类型代码
            public String CrCrd_Instm_Prd_Num; //信用卡分期期数
            public String Crd_Attr_Bmp_Def_ID; //卡属性位图
            public String DstCrd_IssuBnk_InsNo; //发卡行机构号
         }
}

1.2.3 单笔退款申请

//退款申请
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class OneRefundRequest {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *操作员号
     */
    @XmlElement(name = "USER_ID")
    public String USER_ID;
    /**
     *密码
     */
    @XmlElement(name = "PASSWORD")
    public String PASSWORD;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

    //    @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
    @XmlElement(name = "TX_INFO")
    public Body body;
    /**
     *签名信息
     */
    @XmlElement(name = "SIGN_INFO")
    public String SIGN_INFO;

    /**
     *签名CA信息
     */
    @XmlElement(name = "SIGNCERT")
    public String SIGNCERT;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class Body{
        /**
         * 退款金额
         */
        public String MONEY;
        /**
         * 订单号
         */
        public String ORDER;
        /**
         * 退款流水号
         * 可不填,商户可根据需要填写,退款流水号由商户的系统生成
         */
        public String REFUND_CODE;
    }
}
//退款响应
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class OneRefundResponse {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *响应码
     */
    @XmlElement(name = "RETURN_CODE")
    public String RETURN_CODE;
    /**
     *交易响应信息
     */
    @XmlElement(name = "RETURN_MSG")
    public String RETURN_MSG;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

    //    @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
    @XmlElement(name = "TX_INFO")
    public Body body;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class Body{
        public String ORDER_NUM; //订单号
        public String PAY_AMOUNT; //支付金额
        public String AMOUNT; //退款金额
        public String REM1; //备注1
        public String REM2; //备注2
        public String PAY_MODE; //退款方式  ZFB:支付宝;CFT:微信;其他返回空
        public String MRCH_ACCENTRAMT; //商户实际退款金额。  PAY_MODE=ZFB或CFT时有效,否则返回空值
        public String CASH_REFUND_FEE; //买家退款金额  PAY_MODE=ZFB或CFT时有效,否则返回空值
        public String COUPON_REFUND_FEE; //代金券退款金额  PAY_MODE=CFT时有效,否则返回空值
        public String PRESENT_REFUND_DISCOUNT; //平台优惠退款金额   PAY_MODE=CFT时有效,否则返回空值
        public String PRESENT_REFUND_MDISCOUNT_AMOUNT; //商家优惠退款金额   PAY_MODE=CFT时有效,否则返回空值
        public String REFUND_FEE; //申请退款总金额  PAY_MODE=ZFB或CFT时有效,否则返回空值
        public String TXNAMT; //交易金额  折后金额 龙支付优惠退货,该字段返回实际退卡金额。
        /**
         * 龙支付优惠退货的情况返回:
         * 交易操作的权益位图(1-操作,0-不操作)
         * 第1位:建行综合积分
         * 第2位:客户回馈优惠券
         * 第3位:客户回馈优惠活动
         * 第4位:ELP优惠活动
         * 第5位:预付卡
         * 第6位:商户优惠券
         * 第7位:预留(银联优惠)
         * 第8位:预留(微信优惠)
         * 第9位:预留(支付宝优惠)
         * 第10位:激励金
         * 注:该字段仅对有需要的商户返回
         */
        public String ONLNPCSGIND_1_BMP_ECD; //联机处理标志一位图编码
    }
}

1.2.3 退款查询

//退款查询
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountRefundJournalRequest {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *操作员号
     */
    @XmlElement(name = "USER_ID")
    public String USER_ID;
    /**
     *密码
     */
    @XmlElement(name = "PASSWORD")
    public String PASSWORD;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

//    @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
    @XmlElement(name = "TX_INFO")
    public Body body;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    @Data
    public static class Body{
        /**
         *起始日期
         */
        public String START;
        /**
         *开始小时
         */
        public String STARTHOUR;
        /**
         *开始分钟
         */
        public String STARTMIN;
        /**
         *截止日期
         */
        public String END;
        /**
         *结束小时
         */
        public String ENDHOUR;
        /**
         *结束分钟
         */
        public String ENDMIN;
        /**
         *流水类型
         */
        public String KIND;
        /**
         *订单号
         */
        public String ORDER;
        /**
         *结算账户号
         */
        public String ACCOUNT;
        /**
         *金额
         */
        public BigDecimal MONEY;
        /**
         *排序
         */
        public String NORDERBY;
        /**
         *当前页次
         */
        public int PAGE;
        /**
         *柜台号
         */
        public String POS_CODE;
        /**
         *流水状态
         */
        public String STATUS;
        /**
         *子商户号
         */
        public String Mrch_No;
    }
}
//退款查询响应
@XmlRootElement(name="TX")  // 父节点名称
@XmlAccessorType(XmlAccessType.FIELD) //定义这个类中的何种类型需要映射到XML
@Data
public class AccountRefundJournalResponse {
    /**
     *请求序列号  只可以使用数字
     */
    @XmlElement(name = "REQUEST_SN")
    public String REQUEST_SN;
    /**
     *商户号
     */
    @XmlElement(name = "CUST_ID")
    public String CUST_ID;
    /**
     *交易码
     */
    @XmlElement(name = "TX_CODE")
    public String TX_CODE;
    /**
     *响应码
     */
    @XmlElement(name = "RETURN_CODE")
    public String RETURN_CODE;
    /**
     *交易响应信息
     */
    @XmlElement(name = "RETURN_MSG")
    public String RETURN_MSG;
    /**
     *语言
     */
    @XmlElement(name = "LANGUAGE")
    public String LANGUAGE;

//    @XmlElementWrapper(name = "TX_INFO") // 数组或集合节点名称
    @XmlElement(name = "TX_INFO")
    public Body body;

    @XmlRootElement(name="TX_INFO")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Body{
        /**
         *总页次
         */
        public int TPAGE;
        /**
         *当前页次
         */
        public int CUR_PAGE;
        /**
         *提示
         */
        public String NOTICE;

        @XmlElementWrapper(name = "LIST")
        public List<ListInfo> listInfoList;

        @XmlRootElement(name="LIST")
        @XmlAccessorType(XmlAccessType.FIELD)
        @Data
        public static class ListInfo{
            public String TRAN_DATE; //交易日期
            public String REFUND_DATE; //退款日期
            public String ORDER_NUMBER; //订单号
            public String REFUND_ACCOUNT; //退款账号
            public BigDecimal PAY_AMOUNT; //支付金额
            public BigDecimal REFUNDEMENT_AMOUNT; //退款金额
            public String POS_CODE; //柜台号
            public String USERID; //操作员
            public String STATUS; //订单状态
            public String REFUND_CODE; //退款流水号
            public String REM1; //备注1
            public String REM2; //备注2
            public String PAY_MODE; //支付方式
            public BigDecimal Orig_Amt; //订单金额
            public BigDecimal Txn_ClrgAmt; //退款结算金额
            public BigDecimal MrchCmsn_Amt; //退款手续费金额
            public String OriOvrlsttnEV_Trck_No; //银行流水号
            public String MsgRp_Jrnl_No; //商户流水号
            public String Crd_Attr_Bmp_Def_ID; //卡属性位图
            public String DstCrd_IssuBnk_InsNo; //发卡行机构号
            public String OnlnPcsgInd_1_Bmp_ECD; //交易标志位图编码
            public String TxnAmt; //交易金额
            public String Cst_Tp_Prft_Dsc; //客户类型优惠描述
            public String Jrnl_TpCd; //流水类型代码
        }
 }

1.2.4 XML映射工具

public class XmlUtil {
    protected static Logger logger = LoggerFactory.getLogger(XmlUtil.class);

    private static final Map<String,Class> clazzMap = new HashMap<String,Class>(){{
        this.put(AccountRefundJournalRequest.class.getName(), AccountRefundJournalRequest.class);//商户支付流水查询 商户退款流水查询
        this.put(OneRefundRequest.class.getName(),OneRefundRequest.class);//商户单笔退款交易
        this.put(AccountPayJournalResponse.class.getName(), AccountPayJournalResponse.class);//商户退款流水查询响应
        this.put(OneRefundResponse.class.getName(),OneRefundResponse.class);//商户单笔退款交易响应
    }};

    /**
     * 将对象转为流程XML
     *
     * @param graphModel
     * @return
     * @throws JAXBException
     */
    /**
     * 将对象转为流程XML
     *
     * @return
     * @throws JAXBException
     */
    public static String convertToXML(Object entry) throws JAXBException,RuntimeException {
        if(entry instanceof AccountRefundJournalRequest){
            return convertToClazz(AccountRefundJournalRequest.class,entry);
        }else if(entry instanceof OneRefundRequest){
            return convertToClazz(OneRefundRequest.class,entry);
        }else if(entry instanceof AccountPayJournalRequest){
            return convertToClazz(AccountPayJournalRequest.class,entry);
        }else {
            throw new RuntimeException("class not found, can not convert to xml");
        }
    }

    private static String convertToClazz(Class clazz,Object entry) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
        StringWriter writer = new StringWriter();
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.marshal(entry, writer);
        String xmlStr = writer.toString();
        //建行编码方式是GB2312
        if(StringUtils.isNotBlank(xmlStr) && xmlStr.contains("encoding=\"UTF-8\"")){
            xmlStr = xmlStr.replace("encoding=\"UTF-8\"","encoding=\"GB2312\"");
        }
        xmlStr = StringUtils.replace(xmlStr, """, "'");
        return xmlStr;
    }
    public static Object convertToClass(String xml,Class clazz){
        Object xmlObject = null;
        Reader reader = null;
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
            // xml转为对象的接口 反序列化
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            reader = new StringReader(xml);
            xmlObject = unmarshaller.unmarshal(reader);
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return xmlObject;
    }
}

1.2.5 网络请求工具

public class HttpClientUtil {
    public static String httpPostCCB(String url, Map paramMap) {
        return HttpClientUtil.httpPost(url, paramMap, "UTF-8");
    }
    public static String httpPost(String url, Map paramMap, String code) {
        String content = null;
        if (url == null || url.trim().length() == 0 || paramMap == null || paramMap.isEmpty()) return null;
        HttpClient httpClient = new HttpClient();
        httpClient.getParams().setParameter(HttpMethodParams.USER_AGENT,"Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.1.2) Gecko/20090803 Fedora/3.5.2-2.fc11 Firefox/3.5.2");//
        PostMethod method = new PostMethod(url);
        Iterator it = paramMap.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next() + "";
            Object o = paramMap.get(key);
            if (o != null && o instanceof String) {
                method.addParameter(new org.apache.commons.httpclient.NameValuePair(key, o.toString()));
            }
            if (o != null && o instanceof String[]) {
                String[] s = (String[]) o;
                if (s != null)
                    for (int i = 0; i < s.length; i++) {
                        method.addParameter(new org.apache.commons.httpclient.NameValuePair(key, s[i]));
                    }
            }
        }
        try {
            int statusCode = httpClient.executeMethod(method);
            content = new String(method.getResponseBody(), code);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(method!=null)method.releaseConnection();
            method = null;
            httpClient = null;
        }
        return content;

    }
	public static String sendHttpRequest(String ipAdress, int nPort,String sRequest) {
        String sResult = "";
        OutputStream out = null;
        BufferedReader in = null;
        try {
            String encoding = "GB18030"; // ��ϵͳʹ��UTF-8���룬�轫������ת��ΪGB18030
            String params = "requestXml=" + sRequest;  //ע�⣺�����ı������requestXml������
            String path = "http://" + ipAdress + ":" + nPort;
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(10 * 1000); // �������ӳ�ʱʱ��
            conn.setDoOutput(true); // �� doOutput ��־����Ϊ true��ָʾӦ�ó���Ҫ������д�� URL
            conn.setDoInput(true); // //�� doInput ��־����Ϊ true��ָʾӦ�ó���Ҫ�� URL
            conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
            conn.setRequestProperty("Content-Length",String.valueOf(params.length()));
            conn.setRequestProperty("Connection", "close");
            out = conn.getOutputStream();
            out.write(params.getBytes(encoding));
            out.flush();
            out.close();
            if (conn.getResponseCode() == 200) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), encoding));
            } else {
                in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), encoding));
            }
            String sLine = null;
            StringBuffer sb = new StringBuffer();
            while ((sLine = in.readLine()) != null) {
                sb.append(sLine);
            }
            sResult = sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
                if (out != null)
                    out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sResult;
    }

}

2、开启外联平台

2.1 下载外联平台

建行对接微信支付_第1张图片

2.2 将证书 存放在 cert 目录下

建行对接微信支付_第2张图片

2.3 修改设置,bin目录下启动 设置.bat

建行对接微信支付_第3张图片
建行对接微信支付_第4张图片
将 1.1 中配置信息填进去后,点击确定

2.4 启动外联平台服务

建行对接微信支付_第5张图片
建行对接微信支付_第6张图片
建行对接微信支付_第7张图片

3、支付

3.1 充值

    public static void main(String[] args) {
        String MERCHANTID = "1111111111111";//商户代码
        String POSID = "1111111";//商户柜台代码
        String BRANCHID = "11111111";//分行代码
        String PUB = "1111111111111111111111";//公钥后 30 位
        String ORDERID = "12aadsda2dsad944443";//定单号
        String PAYMENT = "0.01";//付款金额
        String CURCODE = Const.CCB_RMB;//币种
        String TXCODE = "530590";//交易码
        String REMARK1 = "";//备注 1
        String REMARK2 = "";//备注 2
        String TYPE = Const.CCB_METHOD_TYPE;//接口类型
        String GATEWAY = "0";//网关类型 默认0
        String CLIENTIP = "";//客户端 IP
        String REGINFO = "";//客户注册信息
        String PROINFO = "";//商品信息
        String REFERER = "";//商户 URL
        String TRADE_TYPE = Const.CCB_TRADE_TYPE_JSAPI;//交易类型
        String SUB_APPID = "";//微信公共号id
        String SUB_OPENID = "";//微信用户id
        String bankURL="https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6";//发送的url

        Map<String,String> map = new HashMap();
        map.put("MERCHANTID",MERCHANTID);
        map.put("POSID",POSID);
        map.put("BRANCHID",BRANCHID);
        map.put("ORDERID",ORDERID);
        map.put("PAYMENT",PAYMENT);
        map.put("CURCODE",CURCODE);
        map.put("TXCODE",TXCODE);
        map.put("REMARK1",REMARK1);
        map.put("REMARK2",REMARK2);
        map.put("TYPE",TYPE);
        map.put("PUB",PUB);
        map.put("GATEWAY",GATEWAY);
        map.put("CLIENTIP",CLIENTIP);
        map.put("REGINFO",REGINFO);
        map.put("PROINFO",PROINFO);
        map.put("REFERER",REFERER);
        map.put("TRADE_TYPE",TRADE_TYPE);
        map.put("SUB_APPID",SUB_APPID);
        map.put("SUB_OPENID",SUB_OPENID);

        String param = "MERCHANTID=" + MERCHANTID + "&POSID=" + POSID + "&BRANCHID=" + BRANCHID + "&ORDERID=" + ORDERID  + "&PAYMENT=" + PAYMENT + "&CURCODE=" + CURCODE +
                "&TXCODE=" + TXCODE +"&REMARK1=" + REMARK1 +"&REMARK2=" + REMARK2 + "&TYPE=" + TYPE + "&PUB=" + PUB + "&GATEWAY=" + GATEWAY
                + "&CLIENTIP=" + CLIENTIP +"®INFO=" + REGINFO+"&PROINFO=" + PROINFO+"&REFERER=" + REFERER
                + "&TRADE_TYPE=" + TRADE_TYPE + "&SUB_APPID=" + SUB_APPID +
                "&SUB_OPENID=" + SUB_OPENID;
        map.put("MAC", MD5Util.MD5Encode(param,"UTF-8"));
        String ret = HttpClientUtil.httpPostCCB(bankURL, map);
        System.out.println(ret);
    }

3.2 充值回调

//为了安全情况下,需要把参数,进行校验,一下方法简写,忽略校验了

	@ApiOperation("建行服务器支付回调")
    @PostMapping("bank/callback")
    public String bankCallBack(HttpServletRequest request) {
		 Map<String, String> map = new HashMap<String, String>();
         Enumeration<String> parameterNames = request.getParameterNames();
         StringBuilder data = new StringBuilder();
         while (parameterNames.hasMoreElements()) {
             String name = (String) parameterNames.nextElement();
             String value = request.getParameter(name);
             map.put(name, value);
             data.append(name).append("=").append(value).append("&");
         }
         log.info("bank callBack data : {}",data);
         if (StringUtils.isBlank(map.get("BRANCHID")) || StringUtils.isBlank(map.get("POSID"))){
             return null;
         }
         String orderid = map.get("ORDERID");
         if (StringUtils.isBlank(orderid)){
             return null;
         }
         if ("Y".equals(map.get("SUCCESS"))) {//表示支付成功
         	
         }
         return "";
	}

4、退款

public static void main(String[] args) {
	OneRefundRequest oneRefundRequest = new OneRefundRequest();
        oneRefundRequest.setREQUEST_SN("1111111111");//交易单号
        oneRefundRequest.setCUST_ID("1111111111111");//商户号
        oneRefundRequest.setUSER_ID("1111111111111-003");//操作员号
        oneRefundRequest.setPASSWORD("11111111");//操作员密码
        oneRefundRequest.setTX_CODE(Const.CCB_5W1004);//交易码
        oneRefundRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
        OneRefundRequest.Body body = new OneRefundRequest.Body();
        body.setMONEY("30.00");//退款金额
        body.setORDER("12aadsda2dsad944443");//订单号
        oneRefundRequest.setBody(body);
        String xmlMsg = null;
        try {
            xmlMsg = XmlUtil.convertToXML(oneRefundRequest);
        } catch (JAXBException e) {
            throw new RuntimeException(e.getMessage());
        }
        System.out.println(xmlMsg);
        String oneRefundRsponseStr = "";
        try {
        	//外联平台的ip和端口
            oneRefundRsponseStr = HttpClientUtil.sendHttpRequest("127.0.0.1",12345, xmlMsg);
        }catch (Exception e){
        }
        System.out.println(oneRefundRsponseStr);
}

5、查询

5.1 充值查询

public static void main(String[] args) {
	   AccountPayJournalRequest accountPayJournalRequest = new AccountPayJournalRequest();
       accountPayJournalRequest.setREQUEST_SN("1111111111111");
       accountPayJournalRequest.setCUST_ID("1111111111111");//商户号
       accountPayJournalRequest.setUSER_ID("1111111111111-003");//操作员号
       accountPayJournalRequest.setPASSWORD("111111");//操作员面
       accountPayJournalRequest.setTX_CODE(Const.CCB_5W1002);//交易码
       accountPayJournalRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
       AccountPayJournalRequest.Body body = new AccountPayJournalRequest.Body();
       accountPayJournalRequest.setBody(body);
       body.setKIND("1");//0:未结流水,1:已结流水
       body.setORDER("0001000026821683267596082");//按订单号查询时,时间段不起作用
       body.setDEXCEL("1");//默认为“1”,1:不压缩,2.压缩成zip文件
       body.setNORDERBY("2");//排序 1:交易日期,2:订单号
       body.setPAGE(1);//当前页次
       body.setSTATUS("1");//0:交易失败,1:交易成功,2:待银行确认(针对未结流水查询);3:全部
       String xmlMsg = null;
       try {
           xmlMsg = XmlUtil.convertToXML(accountPayJournalRequest);
       } catch (JAXBException e) {
           throw new RuntimeException(e.getMessage());
       }
       String accountJournalRequestStr = "";
       try {
           accountJournalRequestStr = HttpClientUtil.sendHttpRequest("localhost",12345, xmlMsg);
       }catch (Exception e){
       }
       System.out.println(accountJournalRequestStr);
}

5.2 退款查询

public static void main(String[] args) {
	AccountRefundJournalRequest oneRefundRequest = new AccountRefundJournalRequest();
    oneRefundRequest.setREQUEST_SN("111111111");//交易单号
    oneRefundRequest.setCUST_ID("1111111111111");//商户号
    oneRefundRequest.setUSER_ID("1111111111111-003");//操作员号
    oneRefundRequest.setPASSWORD("11111111");//操作员密码
    oneRefundRequest.setTX_CODE(Const.CCB_5W1003);//交易码
    oneRefundRequest.setLANGUAGE(Const.CCB_LANGUAGE_CN);//语言
    AccountRefundJournalRequest.Body body = new AccountRefundJournalRequest.Body();
    body.setORDER("0001000026821683267596082");//订单号
    body.setSTATUS("3");
    body.setPAGE(0);
    body.setNORDERBY("2");
    body.setKIND("1");
    oneRefundRequest.setBody(body);
    String xmlMsg = null;
    try {
        xmlMsg = XmlUtil.convertToXML(oneRefundRequest);
    } catch (JAXBException e) {
        throw new RuntimeException(e.getMessage());
    }
    System.out.println(xmlMsg);
    String oneRefundRsponseStr = "";
    try {
        oneRefundRsponseStr = HttpClientUtil.sendHttpRequest("localhost",12345, xmlMsg);
    }catch (Exception e){
    }
    System.out.println(oneRefundRsponseStr);
}

6、 外联平台发布k8s

为了方便可以在本地将证书添加到外联品台里,或者使用pv挂载

6.1 将文件打成压缩包

ccb_web_connect.zip

6.2 构建Dockerfile

FROM java:8
ADD ccb_web_connect.zip ./
RUN unzip ccb_web_connect.zip && chmod 755 /ccb_web_connect/bin/startService.sh
WORKDIR /ccb_web_connect/bin
## 参数依次为------- 商户号  操作员号  操作员密码  证书密码  端口号
ENTRYPOINT ["sh","-c","./startService.sh 1111111111111 1111111111111-003 111111 123456 12345"]

6.3 构建无状态服务

kubectl create -f 文件名称

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "12"
  labels:
    app: ccb-connect-test
  name: ccb-connect-test
  namespace: cloud-test
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: ccb-connect-test
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: ccb-connect-test
    spec:
      containers:
      - image: 192.168.32.14/prihub/ccb_connect:test
        imagePullPolicy: Always
        name: ccb-connect-dkxpw
        ports:
        - containerPort: 12345
          name: 12345aa
          protocol: TCP
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      terminationGracePeriodSeconds: 30

7、 帮助指导

YDCA02910001 流水记录不存在 查询成功
0250E0200001 流水记录不存在 查询成功
YFCP1001A00D 通讯故障 查询失败 建议重发查询交易
YALA02910002 查询过于频繁,请稍后再试 查询失败 减少不必要的查询
0130Z1109064 操作员已被冻结,不能进行交易。请向主管咨询有关情况 查询失败 找商户主管解冻操作员
0130Z1101018 您输入的信息不正确,请重新输入。 查询失败 “1、商户主管不能发外联交易,要使用操作员 2、PC端用操作员登书登录一次商户服务平台(https://merchant.ccb.com/MCMain.htm)”
0130Z1101002 您输入的交易要素格式或范围不正确,请重新输入。 查询失败 发送报文参数有误,请核验报文与接口字段
0130Z1101021 您输入的密码不正确,请重新输入。 查询失败 检查报文交易密码是否正确
YBLA06412001 子商户与主商户信息不匹配 查询失败 检查主子商户关系
YBLP1MERCX01 子商户与主商户信息不匹配 查询失败 联系银行维护集团商户关系
YBLP1MERCX02 ***(主商户号)无查询权限 查询失败 联系银行维护商户集团使用目的
YBLP1MERCX05 ***(子商户号)不是集团商户的子商户 查询失败 联系银行维护集团商户关系
YBLA02910011 不符合规则 查询失败 发送报文参数有误,请核验报文与接口字段
YBLA02910003 商户已经注销 查询失败 联系银行处理
0130Z0100001 暂时未能处理您的请求,请稍后再试。【交易超时】 状态不确定 先调用5W1003退款查询,返回退款记录,则无需发起退款;无退款记录返回,则在120秒后再发起5W1003退款查询;
ZTLAP101AL03 未知错误,@@20000Service Currently Unavailableaop.ACQ.SYSTEM_ERROR~~系统异常@@ 状态不确定 建议商户核实商户账处理状态后再发起退款
ZBLAP101WX03 未知报错,@@SYSTEMERROR~~请求平台数据返回异常,请稍后再试@@ 状态不确定 建议商户隔段时间重试
YBLP1MERTH01 此笔订单正在退款中,不可以重复退款 退款失败 不要重复退款
0130Z0100002 暂时未能处理您的请求,请稍后再试。【通讯故障】 退款失败 建议重发退款交易
YFCP1001A00E 暂时未能处理您的请求,请稍后再试。 退款失败 建议重发退款交易
YALA02910002 查询过于频繁,请稍后再试 查询失败 建议降低退款频率后,重发退款交易
YBLA02910008 终端【***(终端号)】不允许退货 退款失败 联系银行开通退款功能
YBLA02910010 金额不足. 退款失败
YBLA02910011 退款金额与原交易的订单金额不一致,交易拒绝 退款失败 该交易仅支持全额退款,建议检查退款金额后重发退款交易
YBLA02910014 累计退款金额超限,交易拒绝 退款失败
ZBLAP101WX01 支付不成功,@@ERROR~~您的请求参数与订单信息不一致@@ 扣商户账成功,入客户账失败 需核实退款中上送的微信商户信息(如channel_id上送是否正确),若正确还报此类错误,则需要提供相关信息,找微信排查下。
XFCF40100001 超出流量限制 退款失败
0130Z110C064 没有查询到符合条件的记录。 退款失败
0130Z110C405 退款金额不能大于原支付金额。 退款失败
0130Z110C032 退款金额不能大于原交易金额。 退款失败
0130Z110W001 序列号错误 退款失败 不能用同一序列号发两次退款
YBLA06412001 未查询到相关数据 退款失败 退款对应的支付订单不存在
YBLP1MERCX05 ***(子商户号)不是集团商户的子商户 退款失败 联系银行维护集团商户关系

你可能感兴趣的:(支付,微信,java,spring,boot,spring,cloud,kubernetes)