[Day 21] - 初探永丰银行线上收款API - 实作我的收款API

昨晚在测试时遇到一个问题找了好久,就是我的QpayHelper这支程序里明明有用constructor injection
执行时却报nullpointer的错
开debug mode发现,我autowired的Bean是null...

找了好久都不知道哪边有问题,结果发现原来是因为我在另一支程序在call QpayHelper时
是用new的方式新增实例,
原来这麽做会导致里面没有被autowired到...又学到了一课/images/emoticon/emoticon20.gif

今天要来实作要拿来给我的网站使用的API

因为永丰的API在建立订单时,需要不重复的订单编号,而在MongoDB似乎没有get Sequence的功能
因此我打算先建立一个取流水号的功能,

首先,一样先建立一个Data Object

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.Data;

@Data
@Document
public class NextNum {
    @Id
    private String id;
    private long no;
}

再来是repostory

import com.rei1997.vault.model.entity.NextNum;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface NextNumRepo extends MongoRepository<NextNum,String>{
}

最後再建一个service就完成了

@RequiredArgsConstructor
@Service
public class NextNumService {
    
    private final NextNumRepo nextNumRepo;
    public long getNum(){
        Optional<NextNum> num=nextNumRepo.findById("no");
        long nextNum=0;
        if(num.isPresent()){
            nextNum=num.get().getNo()+1;
            num.get().setNo(nextNum);
            nextNumRepo.save(num.get());;
        }else{
            NextNum n=new NextNum();
            n.setId("no");
            n.setNo(1);
            nextNum=n.getNo();
            nextNumRepo.save(n);
        }
        return nextNum;
    }

这麽做是建立一个document来专忙放我的编号,
并且在每次取号後都+1,不过我不确定这麽做是不是个好作法...
搞不好会有重复取号的问题呢...晚点再回来看看有没有更好的做法

因为我觉得之前做好的QpayHelper就等於是Service了
接下来就来直接实作Controller

我後来先把QpayHelper的qpayHelper方法回传值改成String,直接回传json字串,要取哪些栏位来呈现就由前端去操作吧!
因为确定都只回传json字串,所以我在PostMapping直接加上了
produces = MediaType.APPLICATION_JSON_VALUE
也就是告诉浏览器 回传的资料是application/json格式

import com.rei1997.vault.api.Qpay.QpayHelper;
import com.rei1997.vault.api.Qpay.OrderCreate.OrderCreateReq;
import com.rei1997.vault.api.Qpay.OrderPayQuery.OrderPayQueryReq;
import com.rei1997.vault.service.NextNumService;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.MediaType;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping(value="api/v1/Qpay",produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class QpayController {
    private final QpayHelper qpayHelper;
    private final NextNumService service;
    
    @PostMapping("/")
    public String orderCreate(@RequestBody OrderCreateReq orderCreateReq){
//有些value由後端控制
        cardParam.setAutoBilling(AutoBilling.Y);
        orderCreateReq.setShopNo("NA0249_001");
        orderCreateReq.setOrderNo(String.valueOf(service.getNum()));
        orderCreateReq.setCurrencyID("TWD");
        orderCreateReq.setCardParam(cardParam);
        orderCreateReq.setReturnURL("http://localhost:8080/demo/api/v1/Qpay/query");
        String jsonRes="";
        try {
            jsonRes=qpayHelper.qpayHelper(orderCreateReq, "OrderCreate");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.err.println(e.toString());
        }
        return jsonRes;


    }

    @PostMapping("/query")
    public String orderPayQuery(@RequestBody OrderPayQueryReq orderPayQueryReq){

        String jsonRes="";
        try {
            jsonRes=qpayHelper.qpayHelper(orderPayQueryReq, "OrderPayQuery");
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println(e.toString());
        }
        return jsonRes;
    }
}

好,验收!
https://ithelp.ithome.com.tw/upload/images/20211007/20128973MvhLu6aRXa.png

拿取得的url来贴浏览器
成功来到付款页https://ithelp.ithome.com.tw/upload/images/20211007/20128973HATDZxUy1D.png

本来付款完成後预计是会跳转到付款结果的api
结果
https://ithelp.ithome.com.tw/upload/images/20211007/20128973ZpVqltCM5Z.png
发现原来因为永丰跳转时post到我的api的值是用post param的格式,而非json
我用的@ReuestBody没办法接收
因此改成@RequestParam

    @PostMapping("/query")
    public String orderPayQuery(@RequestParam Map<String,String>params){
    ...略

害我又要再用ObjectMapper转一次...

        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(Include.NON_NULL);
        OrderPayQueryReq orderPayQueryReq=
        mapper.convertValue(params, OrderPayQueryReq.class);
        String jsonRes="";

又发现因为永丰给的key是大写开头,Objectmapper无法识别,
找到一个方法是再加上
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
让转换时不要区分大小写

@PostMapping("/query")
public String orderPayQuery(@RequestParam Map<String,String>params){

    ObjectMapper mapper = new ObjectMapper();
    mapper.setSerializationInclusion(Include.NON_NULL);
    mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
    OrderPayQueryReq orderPayQueryReq=
    mapper.convertValue(params, OrderPayQueryReq.class);
    String jsonRes="";
    try {
        jsonRes=qpayHelper.qpayHelper(orderPayQueryReq, "OrderPayQuery");
    } catch (Exception e) {
        e.printStackTrace();
        System.err.println(e.toString());
    }
    return jsonRes;
}

https://ithelp.ithome.com.tw/upload/images/20211007/201289731afb8ICL6d.png

拖了这麽多天终於成功啦/images/emoticon/emoticon02.gif


<<:  【领域展开 21 式】 Menu 修炼持续进行中

>>:  JS 21 - 资料太多看得心很累?用 9 行程序码将资料转换为表格吧!

以Postgresql为主,再聊聊资料库 width_bucket() 的介绍

前天的趣味SQL, 经过大家热烈的响应,有提到 width_bucket() https://ith...

Day-19 Button

本篇内容要介绍Button元件, 除了认识Button的语法、属性外, 同时也要为按钮设置监听及触发...

【D11】避免重复交易资料汇入:使用PK和Unique key

前言 用了前面的范例,尤其是历史资料,会发现有可能重复输入的状况,或是重复资料输入不进去。这是我故意...

[ Day 08 ] 元件的资料传递 - Props

在 Day 06 和 Day 07 中,我们认识了 React.js 的两个 Components...

Day31 - Windows 提权(2)-AlwaysInstallElevated、Unattended Installs、Bypassing UAC

AlwaysInstallElevated 设定 在 Windows 当中有一种设定可以让非管理权限...