[Day 19] - 初探永丰银行线上收款API - 订单查询及其他(1)

继续昨天的内容,在建立订单後,如果是信用卡订单,api会回给一个付款页面,
https://ithelp.ithome.com.tw/upload/images/20211004/20128973PXXaSKh8ir.png
在这个页面用测试资料付款完成後,页面会跳转到当初打api时,我所设定的ReturnUrl,
https://ithelp.ithome.com.tw/upload/images/20211004/20128973JyJlidPikO.png
在测试时我塞google.com,
付完款果然转到google了,并且不是只是单纯转址,是以Post的方式附带了PayToken
https://ithelp.ithome.com.tw/upload/images/20211004/20128973sloVfKvJbL.png

这个PayToken可以拿来发到api的另一个功能OrderPayQuery,查询单笔订单的详细状态。
也就是说,一个完整的信用卡订单流程会是
下订→跳转永丰交易页面→跳转回自己的ReturnUrl,
这个returnUrl页面要处理PayToken,藉此查询客户的该笔订单,再show给客户看

那麽就来实作OrderPayQuery的串接吧

一样照着规格书写出req跟res的Data Object:

import lombok.Data;

@Data
public class OrderPayQueryReq {
    private String ShopNo;
    private String PayToken;
}
import lombok.Data;

@Data
public class OrderPayQueryRes {

    public enum Status { S, F };
    public enum APType { PayOut, CaptureOut, RegularOut, RegularEnd };
    public enum PayType { A, C };

    @Data
    public class TSResultContent{
        private APType APType;
        private String TSNo;
        private String OrderNo;
        private String ShopNo;
        private PayType PayType;
        private Integer Amount;
        private Status Status;
        private String Description;
        private String Param1;
        private String Param2;
        private String Param3;
        private String LeftCCNo;
        private String RightCCNo;
        private String CCExpDate;
        private String CCToken;
        private String PayDate;
        private String MasterOrderNo;
    }

    private String ShopNo;
    private String PayToken;
    private String Date;
    private String Status;
    private String Description;
    private TSResultContent TSResultContent;

}

照着之前的orderCreate方法复制贴上稍微改一下,又是一条好汉
骗谁啊/images/emoticon/emoticon20.gif
目前都是以能跑为目的在写code,说实在写得很烂/images/emoticon/emoticon02.gif
这个call api的方法应该还有更好的写法,之後再调整

public String orderPayQuery(OrderPayQueryReq orderPayQueryReq)throws IOException{
    //1.nonce
    String nonce=getNonce();
    //2.hashID
    String hashID=getHashID();
    //3.iv
    String iv = getIV(nonce);
    ObjectMapper mapper = new ObjectMapper();
    mapper.setPropertyNamingStrategy(new QpayPropNamingStrategy());
    Map<String, Object> map = 
    mapper.convertValue(orderPayQueryReq, new TypeReference<TreeMap<String, Object>>() {});
    //remove null
    map.values().removeIf(Objects::isNull);
    map.forEach((k, v) -> {
        if(v.getClass().equals(java.util.LinkedHashMap.class)){
            LinkedHashMap<Object,Object>m =(LinkedHashMap<Object, Object>) v;
            m.values().removeIf(Objects::isNull);
            map.replace(k, v, m);
        }
    });

    //4.message
    String jsonContent ="";
    jsonContent = new ObjectMapper().writeValueAsString(map);

    String message = "";
        try {
            message= encryptUtil.encrypt(jsonContent, hashID, iv);
        } catch (IOException | GeneralSecurityException e) {
            e.printStackTrace();
        }

    //5.sign
    String sign = getSign(map,nonce,hashID);

    //send to api
    Map<String,String> request = new HashMap<String,String>();
    request.put("Version", "1.0.0");
    request.put("ShopNo", "NA0001_001");
    request.put("APIService", "OrderPayQuery");
    request.put("Sign", sign);        
    request.put("Nonce", nonce);
    request.put("Message", message);

    String reqJson="";
    reqJson = new ObjectMapper().writeValueAsString(request);

    String res="";
    try {
        res=util.post("https://apisbx.sinopac.com/funBIZ/QPay.WebAPI/api/Order", reqJson);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Map<String, String> resMap =new HashMap<String,String>();
    resMap = mapper.readValue(res, new TypeReference<HashMap<String, String>>() {});

    String resSign =resMap.get("Sign");
    String resNonce =resMap.get("Nonce");
    String resMessage =resMap.get("Message");

    String resiv= getIV(resNonce);

    try {
        resMessage=encryptUtil.decrypt(resMessage, hashID, resiv);
    } catch (IOException | GeneralSecurityException | DecoderException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Map<String, Object> resMessageMap =new TreeMap<String,Object>();
    resMessageMap = mapper.readValue(resMessage, new TypeReference<TreeMap<String, Object>>() {});

    resMessageMap.forEach((k, v) ->System.out.println(k+":"+v));

    String resForUser = "";
    String signCheck = getSign(resMessageMap, resNonce, hashID);

    if(signCheck.equals(resSign)){
        System.out.println("Sign Check OK:"+signCheck);
    }else{
        resForUser="永丰回传签章验证失败"+"\nA:"+signCheck+"\nresSign:"+resSign;
        return resForUser;
    }

    if(resMessageMap.containsKey("Description")){
        resForUser=resMessageMap.get("Description").toString();
    }else{
        resForUser="待续";
    }

    return resForUser;

}   


<<:  IT 铁人赛 k8s 入门30天 -- day20 k8s Logging Architecture

>>:  Day19# Leetcode - Palindrome Number

Burp Suite 已经提供给你了最便利的 C2 Server

虽然是写C2 Server, 但实际上我们并不是真的要从这个Server发送指令出去, 我们只是要让...

「认知」是你观望世界的窗,不时擦拭,光线才能穿透。

「认知」是你观望世界的窗,不时擦拭,光线才能穿透。 Your assumptions are you...

DAY4: Visual Code 的第一个Node.js与 Node一开始系统无法执行的解决办法

上一篇介绍了安装步骤与执行环境,接下来今天要撰写人生第一个Node.js。因为接下来要介绍的或是要展...

[重构倒数第12天] - Vue3 directive 与 Skeleton 实战组合应用

前言 该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系...

[iT铁人赛Day1]JAVA下载与执行

JAVA是一个大家既熟悉又陌生的程序语言 稍微知道怎麽编写但会写错,也可能写还不知道怎麽储存,还有不...