Spring Boot的validation套件提供豐富的資料檢核annotation,包括@Pattern支援Regex,不過秉持少引用一個套件就少一份處理弱掃的風險,加上有的檢核還真的是複雜,所以不引用validation自己手工做一個。
因此,一開始我就弱化了Controller角色,所有method都將@RequestBody當作字串處理,回應一律用Object,方便Value Object轉成JSON。
@RestController
@Slf4j
@RequiredArgsConstructor
public class CRMController {
    @Autowired
    private CRMService crmService;
    @PostMapping(value = "/getOldCust_Period", consumes = MediaType.APPLICATION_JSON_VALUE, produces = "application/json;charset=UTF-8")
    public ResponseEntity<Object> getOldCust_Period(@RequestBody String inputVO) {
        Object outputVO = this.crmService.getOldCust_Period(inputVO);
        return ResponseEntity.ok(outputVO);
    }
}
在客戶的弱掃軟體是Micro Focus,測試案例如下,會要求不得回覆HTTP Status 500。另一款弱掃軟體AppScan遇到以下測試個案例,會要求一律回HTTP Status 500
{"is_admin": true}
第一個validateJSON的檢核就包括了長度、JSON格式、JSON Key是否合法
private List<String> AFields = Arrays.asList(new String[]{"CUST_ID", "PROD_TYPE", "SEQ", "AMT"});
/**
 * 檢核A電文JSON字串有無失當
 * @param jsonStr
 * @return 回null表示正常
 */
private ESBErrorVO validateJSON(String jsonStr) {
    if (jsonStr != null && jsonStr.length() >= 2048) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT(DenominatorService.EMSGTXT + ", 長度太長");
        return errorVO;
    }
    ObjectMapper mapper = new ObjectMapper();
    boolean valid = true;
    try {
        JsonNode rootNode = mapper.readTree(jsonStr);
        Iterator<String> fieldNames = rootNode.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            if (!AFields.contains(fieldName)) {
                valid = false;
            }
        }
    } catch (Exception errJson) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("非JSON格式");
        return errorVO;
    }
    if (!valid) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("帶不合法欄位");
        return errorVO;
    }
    return null;
}
第二個檢核就針對每個欄位的value進行檢核,這時的ESBInputVO是透過Spring Boot的Jackson套件轉換,這原本是可以在Controller就可以透過@RequestBody ESBInputVO inputVO做掉:
ObjectMapper mapper = new ObjectMapper();
ESBInputVO inputVO = mapper.readValue(jsonStr, ESBInputVO.class);
validateInputVO的內容,其中checkIDType這個method是Day 1的內容,檢核客戶ID是哪一種類型,這需求就無法使用validation套件的@Pattern
/**
 * 檢核A上行電文欄位有無不當
 * @param inputVO
 * @return null表示沒錯誤
 */
private ESBErrorVO validateInputVO(ESBInputVO inputVO) {
    ESBErrorVO errorVO = new ESBErrorVO();
    StringBuffer sbErr = new StringBuffer();
    if (inputVO == null) {
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("上行電文為空");
        return errorVO;
    }
    String custId = inputVO.getCUST_ID();
    if (this.checkIDType(custId) == null) {
        sbErr.append("CUST_ID[").append(custId).append("]");
    }
    String prodType = inputVO.getPROD_TYPE();
    if (prodType == null || !prodType.matches("[1-6]")) {
        sbErr.append("PROD_TYPE[").append(prodType).append("]");
    }
    String amt = inputVO.getAMT();
    if (amt == null || !amt.matches("[0-9]{1,16}")) {
        sbErr.append("AMT[").append(amt).append("]");
    }
    String seq = inputVO.getSEQ();
    if (seq == null || !seq.matches("([0-9A-Za-z]){7,20}")) {
        sbErr.append("SEQ[").append(seq).append("]");
    }
    if (sbErr.length() > 0) {
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("上行電文欄位有誤:" + sbErr.toString());
        return errorVO;
    }
    return null;
}