銀連網關支付,退款java實現

來源:互聯網
上載者:User
    曆時兩周,終於把銀聯支付退款搞定了。由於沒人指導,走了不少彎路,博主在此貼出相關代碼,希望能幫到像我一樣沒人指導的小夥伴。
銀聯支付 1:支付,退款流程。


2:支付的相關準備 去官網下載sdk,官網相關地址會在本文結尾出提供 下載官網的測試組態檔案acp_sdk.properties,測試相關認證acp_test_enc.cer,acp_test_sign.pfx,修改acp_sdk.properties後放在classpath下,如果要用生產環境,相關認證檔案有四個,設定檔也有對應的生產環境認證。 如果支付成功後是跳轉頁面,則需要準備相關頁面,如果是java代碼拼接字串,需要準備相關的java類,用來動態生產html頁面。 3:支付,退款相關代碼

1:代碼結構

2:AutoLoadServlet

 import com.kemile.common.pay.chinapay.sdk.SDKConfig;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;/** * 功能:從應用的classpath下載入acp_sdk.properties屬性檔案並將該屬性檔案中的索引值對賦值到SDKConfig類中 <br> *  */public class AutoLoadServlet extends HttpServlet {    @Override    public void init(ServletConfig config) throws ServletException {        SDKConfig.getConfig().loadPropertiesFromSrc();        super.init();    }}

3:CharsetEncodingFilter

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

4:ChinapayConfig

import java.text.SimpleDateFormat;import java.util.Date;public class ChinapayConfig {    //商家號    //public static String MERID = "777290058137116";//填自己網站相關的商家號    //前台請求地址    public static String FRONTURL = "fontrev";    //後台請求地址    public static String BACKURL = "backrev";    //預設配置的是UTF-8    public static String encoding_UTF8 = "UTF-8";    //  public static String encoding_GBK = "GBK";    //全渠道固定值    public static String version = "5.0.0";    // 商戶發送交易時間 格式: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());    }    /**     招商銀行借記卡:6226090000000048     手機號:18100000000     密碼:111101     簡訊驗證碼:123456(手機)/111111(PC)(先點擷取驗證碼之後再輸入)     證件類型:01     證件號:510265790128303     姓名:張三     */}

5:CYChinaPayController

@Controller@RequestMapping(value = "/CYChinapay")public class CYChinaPayController {    Logger logger = Logger.getLogger(AliPayController.class);    @Autowired    private IMobileCyDishorderService mobileCyDishorderService;//注入service    @Autowired    private IMobileServiceStyleService mobileServiceStyleService;    //支付    @RequestMapping("/{order_nbr}")    public String pay(@PathVariable String order_nbr, HttpServletRequest request, HttpServletResponse response) {        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();        CyDishorderEntity order = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", order_nbr);        Map<String, String> requestData = new HashMap<String, String>();        requestData.put("version", ChinapayConfig.version);              //版本號碼,全渠道預設值        requestData.put("encoding", ChinapayConfig.encoding_UTF8);              //字元集編碼,可以使用UTF-8,GBK兩種方式        requestData.put("signMethod", "01");                          //簽名方法,只支援 01:RSA方式認證加密        requestData.put("txnType", "01");                          //交易類型 ,01:消費        requestData.put("txnSubType", "01");                          //交易子類型, 01:自助消費        requestData.put("bizType", "000201");                      //業務類型,B2C網關支付,手機wap支付        requestData.put("channelType", "08");                      //渠道類型,這個欄位區分B2C網關支付和手機wap支付;07:PC,平板  08:手機        /***商戶接入參數***/        requestData.put("merId", ChinapayConfig.MERID);                  //商戶號碼,請改成自己申請的正式商戶號或者open上註冊得來的777測試商戶號        requestData.put("accessType", "0");                          //接入類型,0:直連商戶        requestData.put("orderId", order_nbr);             //商戶訂單號,8-40位元字字母,不能含“-”或“_”,可以自行定製規則        requestData.put("txnTime", ChinapayConfig.getCurrentTime());        //訂單發送時間,取系統時間,格式為YYYYMMDDhhmmss,必須取目前時間,否則會報txnTime無效        requestData.put("currencyCode", "156");                      //交易幣種(境內商戶一般是156 人民幣)        BigDecimal totPrice = null;        //==========價格計算=========        totPrice = new BigDecimal(order.getPayMoney());//查詢價格        requestData.put("txnAmt", String.valueOf((totPrice.multiply(new BigDecimal(100))).longValue())); //交易金額,單位分,不要帶小數點        try {            //===============================                //:TODO:            //=============================            requestData.put("frontUrl", basePath + "/CYChinapay/" + ChinapayConfig.FRONTURL); //前台請求地址            requestData.put("backUrl", basePath + "/CYChinapay/" + ChinapayConfig.BACKURL);  //後台請求地址            logger.info("回調地址"+basePath + "/CYChinapay/" + ChinapayConfig.FRONTURL);            logger.info("回調地址"+basePath + "/CYChinapay/" + ChinapayConfig.BACKURL);            Map<String, String> submitFromData = AcpService.sign(requestData, ChinapayConfig.encoding_UTF8); //簽名            String requestFrontUrl = SDKConfig.getConfig().getFrontRequestUrl();  //擷取請求銀聯的前台地址:對應屬性檔案acp_sdk.properties檔案中的acpsdk.frontTransUrl            String html = AcpService.createAutoFormHtml(requestFrontUrl, submitFromData, ChinapayConfig.encoding_UTF8);   //產生自動跳轉的Html表單            //將產生的html寫到瀏覽器中完成自動跳轉開啟銀聯支付頁面;這裡調用signData之後,將html寫到瀏覽器跳轉到銀聯頁面之前均不能對html中的表單項的名稱和值進行修改,如果修改會導致驗簽不通過            response.getWriter().write(html);        } catch (Exception e) {            e.printStackTrace();        }        return null;    }    private static Map<String, String> valideData(HttpServletRequest req, HttpServletResponse resp) throws IOException {        String encoding = req.getParameter(SDKConstants.param_encoding);        // 擷取銀聯通知伺服器發送的後台通知參數        Map<String, String> reqParam = getAllRequestParam(req);        Map<String, String> valideData = null;        if (null != reqParam && !reqParam.isEmpty()) {            Iterator<Map.Entry<String, String>> it = reqParam.entrySet().iterator();            valideData = new HashMap<String, String>(reqParam.size());            while (it.hasNext()) {                Map.Entry<String, String> e = it.next();                String key = (String) e.getKey();                String value = (String) e.getValue();                value = new String(value.getBytes(encoding), encoding);                valideData.put(key, value);            }        }        return valideData;    }    //後台請求地址    @RequestMapping(value = "/backrev")    public void BackRcv(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //Map<String,String> map=getAllRequestParam(request);        logger.info("[進入銀聯支付回調方法]");        String encoding = req.getParameter(SDKConstants.param_encoding);        // 擷取銀聯通知伺服器發送的後台通知參數        Map<String, String> reqParam = getAllRequestParam(req);        //   LogUtil.printRequestLog(reqParam);        Map<String, String> valideData = valideData(req, resp);        PrintWriter out = null;        out = resp.getWriter();        //重要。驗證簽名前不要修改reqParam中的索引值對的內容,否則會驗簽不過        if (!AcpService.validate(valideData, encoding)) {            logger.info("驗證簽名結果[失敗].");            out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "驗證簽名失敗", Const.validateFaliUrl));        } else {            logger.info("驗證簽名結果[成功].");            //【註:為了安全驗簽成功才應該寫商戶的成功處理邏輯】交易成功,更新商戶訂單狀態            String respCode = valideData.get("respCode");            if ("00".equals(respCode)) {//銀聯返回00代表支付成功               //:TODO:該方法在使用者支付成功後銀聯自動非同步回調。此處可以寫訂單支付成功後的商務邏輯                if (訂單支付成功後) {                    resp.getWriter().print("ok");//這裡一定要寫響應。否則銀聯會認為商戶後台沒有收到回調資訊。                }            }        }        LogUtil.writeLog("BackRcvResponse接收後台通知結束");    }    //前台請求地址    @RequestMapping("/fontrev")    public void fontrev(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        response.setCharacterEncoding("utf-8");        response.setContentType("text/html; charset=utf-8");//設定編碼        PrintWriter out = null;        out = response.getWriter();//擷取響應輸出資料流        logger.info("FrontRcvResponse前台接收報文返回開始");        String encoding = request.getParameter(SDKConstants.param_encoding);        logger.info("返回報文中encoding=[" + encoding + "]");        Map<String, String> respParam = getAllRequestParam(request);//擷取銀聯回調的參數        // 列印請求報文        LogUtil.printRequestLog(respParam);        Map<String, String> valideData = valideData(request, response);//驗證簽名        if (!AcpService.validate(valideData, encoding)) {//驗證簽名失敗            logger.info("驗證簽名結果[失敗].");//            return "redirect:/pay-failed.html";            out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "驗證簽名失敗", Const.validateFaliUrl));        } else {            String respCode = valideData.get("respCode");//驗證成功後擷取銀聯響應碼            if ("00".equals(respCode)) {//響應碼為00表示支付成功。                logger.info("驗證簽名結果[成功]");                //=====================               //TODO:這個方法在使用者支付成功後點擊返回商戶時,銀聯回調,這裡寫回調成功後的一些商務邏輯。            } else {                out.write(CyReturnPayEndHtml.failedHtml(valideData.get("orderId"), "銀聯支付失敗", Const.validateFaliUrl));            }        }        out.flush();        out.close();    }    /**     * 更新訂單資料(狀態)此方法根據自己的業務需求編寫,最後要返回驗證簽名後的訂單編號。     *     * @param valideData     * @return     */    private String updateOrder(Map<String, String> valideData) {        return valideData.get("orderId");//返回驗證簽名成功後的訂單編號    }    //退款    @ResponseBody    @RequestMapping("/Refund/{order_nbr}")    public String doPost(@PathVariable String order_nbr, HttpServletRequest req, HttpServletResponse resp)            throws ServletException, IOException {        String basePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort();        CyDishorderEntity order = (CyDishorderEntity) mobileCyDishorderService.findOne("orderNum", order_nbr);        Map<String, String> data = new HashMap<String, String>();        /***銀聯全渠道系統,產品參數 ,除了encoding自行選擇外其他不需修改***/        data.put("version", ChinapayConfig.version);               //版本號碼        data.put("encoding", ChinapayConfig.encoding_UTF8);             //字元集編碼 可以使用UTF-8,GBK兩種方式        data.put("signMethod", "01");                        //簽名方法 目前只支援01-RSA方式認證加密        data.put("txnType", "04");                           //交易類型 04-退貨        data.put("txnSubType", "00");                        //交易子類型  預設00        data.put("bizType", "000201");                       //業務類型 B2C網關支付,手機wap支付        data.put("channelType", "07");                       //渠道類型,07-PC,08-手機        /***商戶接入參數***/ /*ChinapayConfig.MERID*/        data.put("merId", ChinapayConfig.MERID);                //商戶號碼,請改成自己申請的商戶號或者open上註冊得來的777商戶號測試        data.put("accessType", "0");                         //接入類型,商戶接入固定填0,不需修改        data

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.