基於XML的接口參數校驗的一種方式

公司的接口又臭又長,同事提供了一個思路,採用xml進行不涉及業務的參數的校驗。

可以在excel上編輯,然後生成xml,校驗器會自動對每個參數進行長度、數值、正則、必填等校驗。解放雙手,

公司不怎麼提倡創新,估計只有這一個項目會使用吧,不過有十幾個接口,夠用了。。。

請求->Business->校驗公共參數-》初始化校驗器->校驗非業務->校驗業務。。。

 

首先定義參數的屬性 

RemoteParam

然後書寫校驗器

RemoteParamValidator

準備xml文件 

spicii-1...

準備dtd約束(可以忽略)

rules.dtd

接口抽象類公共調用

AbstractN9ServerBusiness

 

package com.nstc.aims.model;

import com.nstc.util.CastUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.xml.sax.Attributes;

/**
 * <p>Title: RemoteParam.java</p>
 * <p>Description: 接口參數</p>
 * <p>Company: 北京九恆星科技股份有限公司</p>
 *
 * @author luhao
 * @since 2020-03-14 11:13
 */
public class RemoteParam {
    private String name;
    private String remark;
    private Integer length;
    //小數位數
    private Integer decimalDigits;
    //類型 NUMBER/NUMBER(X,X)/INTEGER/VARCHAR2(XX)/DATE
    private String type;
    //必填
    private Integer require;
    private String reg;
    private String fieldName;

    private final static String NAME_TAG = "name";
    private final static String REMARK_TAG = "remark";
    private final static String TYPE_TAG = "type";
    private final static String REQUIRE_TAG = "require";
    private final static String REG_TAG = "reg";
    private final static String FIELD_NAME = "fieldName";
    private final static Integer YES = 1;
    private final static String INTEGER_REG = "^-?\\d+$";
    private final static String DATE_REG = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|" +
            "((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|" +
            "((0[48]|[2468][048]|[3579][26])00))-02-29)$";

    private String getDoubleReg() {
        return "^[-\\+]?\\d{1," + length + "}(\\.\\d{0," + decimalDigits + "})?|\\.\\d{1," + decimalDigits + "}$";
    }

    public RemoteParam(Attributes attributes) {
        name = attributes.getValue(NAME_TAG);
        remark = attributes.getValue(REMARK_TAG);
        type = attributes.getValue(TYPE_TAG);
        require = CastUtil.toInteger(attributes.getValue(REQUIRE_TAG));
        reg = CastUtil.toNotEmptyString(attributes.getValue(REG_TAG));
        fieldName = CastUtil.toNotEmptyString(attributes.getValue(FIELD_NAME));
        setLength(type);
    }

    public void setLength(String type) {
        if ("D".equals(type)) {
            length = 10;
            decimalDigits = null;
        } else if (type.startsWith("C")) {
            length = CastUtil.toInteger(type.replace("C", ""));
            decimalDigits = null;
        } else if (type.startsWith("N") && type.contains(",")) {
            String[] strArr = type.replace("N", "").split(",");
            length = CastUtil.toInteger(strArr[0]);
            decimalDigits = CastUtil.toInteger(strArr[1]);
        } else if (type.startsWith("N") && !type.contains(",")) {
            length = CastUtil.toInteger(type.replace("N", ""));
            decimalDigits = null;
        }
    }

    public void validate(Object obj, String sign) {
        if (obj == null) {
            Validate.isTrue(!YES.equals(require), notice(sign) + "不能爲空!");
        }
        String value = (String) obj;
        if (StringUtils.isBlank(value)) {
            Validate.isTrue(!YES.equals(require), notice(sign)  + "不能爲空!");
        } else {
            if (type.startsWith("C")) {
                Validate.isTrue(value.length() <= length, notice(sign)  + "長度不可大於" + length + ":" + obj);
            } else if ("N".equals(type) && decimalDigits == null) {
                Validate.isTrue(value.matches(INTEGER_REG), notice(sign)  + "不滿足整數規則!" + ":" + obj);
                Validate.isTrue(value.length() <= length, notice(sign)  + "長度不可大於" + length + ":" + obj);

            } else if (decimalDigits != null) {
                Validate.isTrue(value.matches(getDoubleReg()), notice(sign)  + "必須爲浮點數類型,且整數位不可超過" + length + ",小數位不可超過" + decimalDigits + ":" + obj);
            } else if ("D".equals(type)) {
                Validate.isTrue(value.matches(DATE_REG), notice(sign) + "不符合日期格式!" + ":" + obj);
            }
            if (StringUtils.isNotBlank(reg)) {
                Validate.isTrue(value.matches(reg), notice(sign)  + "參數值不合法!" + ":" + obj);
            }
        }

    }

    /**
     * 提示信息
     * @param sign 標記錯誤的未知
     * @return
     */
    private String notice(String sign){
        return sign + remark + "(" + name + ")";
    }

    @Override
    public String toString() {
        return "RemoteParam{" +
                "name='" + name + '\'' +
                ", remark='" + remark + '\'' +
                ", length=" + length +
                ", decimalDigits=" + decimalDigits +
                ", type='" + type + '\'' +
                ", require=" + require +
                ", reg='" + reg + '\'' +
                ", fieldName='" + fieldName + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Integer getLength() {
        return length;
    }

    public void setLength(Integer length) {
        this.length = length;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Integer getRequire() {
        return require;
    }

    public void setRequire(Integer require) {
        this.require = require;
    }

    public String getReg() {
        return reg;
    }

    public void setReg(String reg) {
        this.reg = reg;
    }

    public Integer getDecimalDigits() {
        return decimalDigits;
    }

    public void setDecimalDigits(Integer decimalDigits) {
        this.decimalDigits = decimalDigits;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
}
package com.nstc.aims.service.remote.n9server;

import com.nstc.aims.constants.SpicRemoteIIConstants;
import com.nstc.aims.model.RemoteParam;
import com.nstc.aims.option.SpicServerRemoteIIEnum;
import com.nstc.aims.util.ResourceLoader;
import com.nstc.util.CastUtil;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.Validate;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>Title: RemoteParamValidator.java</p>
 * <p>Description: 接口參數校驗器</p>
 * <p>Company: 北京九恆星科技股份有限公司</p>
 *
 * @author luhao
 * @since 2020-03-14 11:16
 */
public class RemoteParamValidator extends DefaultHandler {

    private HashMap<String, List<RemoteParam>> remoteParamsMap;

    private List<RemoteParam> remoteParamList;

    private RemoteParam remoteParam;

    private final static String RULES = "rules";
    private final static String LIST_TAG = "remoteParams";
    private final static String PARAM_TAG = "remoteParam";
    public final static String RULES_DIR = "AIMS-CFG" + File.separator + "SPIC_REMOTE_RULES" + File.separator;

    private static RemoteParamValidator remoteParamValidator = null;

    private RemoteParamValidator() {
    }

    /**
     * 構建保存模型
     *
     * @param map
     * @param spicServerRemoteIIEnum
     * @return
     */
    public Object buildModel(Map<String, Object> map, SpicServerRemoteIIEnum spicServerRemoteIIEnum) {
        Validate.notNull(map, "參數列表爲空!");
        List<RemoteParam> remoteParams = remoteParamsMap.get(spicServerRemoteIIEnum.getCode());
        if (remoteParams == null) {
            init();
        }
        Validate.notNull(remoteParams, "初始化校驗器失敗!接口:" + spicServerRemoteIIEnum);
        Object model = null;
        try {
            model = spicServerRemoteIIEnum.getClazz().newInstance();
            for (RemoteParam param : remoteParams) {
                //Field field = spicServerRemoteIIEnum.getClazz().getDeclaredField(param.getFieldName());
                //field.setAccessible(true);
                Object value = null;
                if (param.getType().startsWith("D")) {
                    value = CastUtil.toDate(map.get(param.getName()));
                } else if ((param.getType().startsWith("N") && param.getDecimalDigits() == null)) {
                    value = CastUtil.toInteger(map.get(param.getName()));
                } else if (param.getType().startsWith("N") && param.getDecimalDigits() != null) {
                    value = CastUtil.toDouble(map.get(param.getName()));
                } else {
                    value = CastUtil.toNotEmptyString(map.get(param.getName()));
                }
                PropertyUtils.setProperty(model,param.getFieldName(),value);
                //field.set(model, value);

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return model;
    }

    public static RemoteParamValidator getInstance() {
        if (remoteParamValidator == null) {
            remoteParamValidator = new RemoteParamValidator();
            remoteParamValidator.init();
        }
        return remoteParamValidator;
    }

    /**
     * 校驗Map類型的參數
     *
     * @param interfaceKey
     * @param map
     * @param sign
     */
    public void validate(String interfaceKey, Map<String, Object> map, String sign) {
        Validate.notEmpty(map, "參數列表不可爲空!");
        List<RemoteParam> rules = rules(interfaceKey);
        Validate.notNull(rules, "無法找到接口" + interfaceKey);
        if (map.containsKey(SpicRemoteIIConstants.DATA_LIST)) {
            List<Map<String, Object>> list = (List) (map.get(SpicRemoteIIConstants.DATA_LIST));
            validate(interfaceKey, list);
        } else {
            for (RemoteParam param : rules) {
                param.validate(map.get(param.getName()), sign);
            }
        }

    }

    /**
     * 校驗List類型的參數
     *
     * @param intefaceKey
     * @param list
     */
    public void validate(String intefaceKey, List<Map<String, Object>> list) {
        Validate.noNullElements(list, "參數列表不可爲空!");
        for (int i = 0; i < list.size(); i++) {
            Map<String, Object> map = list.get(i);
            validate(intefaceKey, map, "第" + (i + 1) + "行");
        }
    }

    private List<RemoteParam> rules(String interfaceKey) {
        List<RemoteParam> rules = remoteParamsMap.get(interfaceKey);
        if (rules == null) {
            init();
        }
        rules = remoteParamsMap.get(interfaceKey);
        Validate.notNull(rules, "未定義的接口:" + interfaceKey);
        return rules;
    }

    /**
     * 初始化
     */
    public void init() {
        //1.獲取SAXParserFactory實例
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //2.獲取SAXparser實例
        SAXParser saxParser = null;
        try {
            saxParser = factory.newSAXParser();
            File dir = new File(ResourceLoader.getResource(RemoteParamValidator.RULES_DIR).getPath());
            if (dir != null && dir.isDirectory()) {
                File[] files = dir.listFiles(new FilenameFilter() {
                    @Override
                    public boolean accept(File dir, String name) {
                        return name.toLowerCase().endsWith(".xml");
                    }
                });
                for (File file : files) {
                    saxParser.parse(file, remoteParamValidator);
                }
            }

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        if (RULES.equals(qName)) {
            remoteParamsMap = remoteParamsMap == null ? new HashMap<String, List<RemoteParam>>() : remoteParamsMap;
        } else if (LIST_TAG.equals(qName)) {
            remoteParamList = new ArrayList<RemoteParam>();
            remoteParamsMap.put(attributes.getValue(0), remoteParamList);
        } else if (PARAM_TAG.equals(qName)) {
            remoteParam = new RemoteParam(attributes);
            remoteParamList.add(remoteParam);
        }
    }

    public HashMap<String, List<RemoteParam>> getRemoteParamsMap() {
        return remoteParamsMap;
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE rules SYSTEM "rules.dtd">
<rules>
    <remoteParams name="SPICII-1-1">
        <remoteParam name="ACCOUNTNO" remark="賬號" type="C32" require="1" reg="" fieldName="accountNo"/>
        <remoteParam name="APPLYID" remark="賬戶申請流水號" type="N38" require="" reg="" fieldName="applyId"/>
        <remoteParam name="CLTNO" remark="單位編號" type="C32" require="1" reg="" fieldName="cltNo"/>
        <remoteParam name="CLT_NAME" remark="單位名稱" type="C64" require="1" reg="" fieldName="cltName" />
        <remoteParam name="ASSBANKNAME" remark="合作金融網點名稱" type="C128" require="1" reg="" fieldName="assBankName" />
        <remoteParam name="ISABROAD" remark="境內外" type="C1" require="" reg="0|1" fieldName="isAbroad" />
        <remoteParam name="AREAID" remark="區域編碼" type="N38" require="" reg="" fieldName="areaId" />
        <remoteParam name="OPENACCOUNTDATE" remark="開戶日期" type="D" require="1" reg="" fieldName="openAccountDate" />
        <remoteParam name="ACCOUNTNAME" remark="戶名" type="C128" require="1" reg="" fieldName="accountName" />
        <remoteParam name="MEMORYNAME" remark="助記名" type="C128" require="" reg="" fieldName="memoryName" />
        <remoteParam name="CURRENCYNO" remark="幣種" type="C3" require="1" reg="" fieldName="currencyNo" />
        <remoteParam name="CTNAME" remark="賬戶性質" type="C32" require="1" reg="" fieldName="type" />
        <remoteParam name="NATURENAME" remark="賬戶用途" type="C32" require="1" reg="" fieldName="natureName" />
        <remoteParam name="FOREIGNTYPE" remark="外匯業務類型" type="N1" require="" reg="1|2" fieldName="foreignType" />
        <remoteParam name="ASSOCIATEFLAG" remark="聯網方式" type="C1" require="1" reg="0|1|2" fieldName="associateFlag" />
        <remoteParam name="ARRDESS" remark="單位/項目地址" type="C256" require="1" reg="" fieldName="arrdess" />
        <remoteParam name="CNREMARK" remark="備註" type="C500" require="" reg="" fieldName="cnreMark" />
        <remoteParam name="ACNTSTATE" remark="賬戶狀態" type="N2" require="1" reg="0|1|-1|-2" fieldName="acntState" />
        <remoteParam name="EACCOUNT" remark="實體賬戶賬號" type="C32" require="" reg="" fieldName="eAccount" />
        <remoteParam name="PUBLIC_TELEPHONE" remark="對公電話" type="C20" require="" reg="" fieldName="publicTelephone" />
        <remoteParam name="CUSTOMER_MANAGER" remark="客戶經理" type="C60" require="" reg="" fieldName="customerManager" />
        <remoteParam name="CM_TELEPHONE" remark="客戶經理電話" type="C20" require="" reg="" fieldName="cmTelephone" />
        <remoteParam name="CM_MAIL" remark="客戶經理郵箱" type="C60" require="" reg="" fieldName="cmMail" />
        <remoteParam name="IS_DEDUCT" remark="是否扣減賬戶:0不是;1是" type="N1" require="" reg="0|1" fieldName="isDeduct" />
        <remoteParam name="IS_ESCROWACCOUNT" remark="是否監管賬戶(0-否 1-是)" type="N1" require="" reg="0|1" fieldName="isEscrowAccount" />
        <remoteParam name="NEED_ONLINE" remark="是否申請上線" type="N1" require="" reg="0|1" fieldName="needOnline" />
        <remoteParam name="CONTACT_PERSON" remark="聯繫人" type="C32" require="1" reg="" fieldName="contactPerson" />
        <remoteParam name="CONTACT_TEL" remark="聯繫人電話" type="C32" require="1" reg="" fieldName="contactTel" />
        <remoteParam name="BASIC_ACCOUNT_NO" remark="基本戶賬戶" type="C32" require="" reg="" fieldName="basicAccountNo" />
        <remoteParam name="BASIC_ACCOUNT_BANKNAME" remark="基本戶開戶行" type="C64" require="" reg="" fieldName="basicAccountBankname" />
        <remoteParam name="AUTHORIZED_PERSON_NAME" remark="被授權人姓名" type="C32" require="1" reg="" fieldName="authorizedPersonName" />
        <remoteParam name="AUTHORIZED_PERSON_ID" remark="被授權人身份證號" type="C32" require="1" reg="" fieldName="authorizedPersonId" />
        <remoteParam name="LEGAL_PERSON" remark="法人姓名" type="C32" require="" reg="" fieldName="legalPerson" />
        <remoteParam name="LEGAL_ID_CARD" remark="法人身份證號" type="C32" require="" reg="" fieldName="legalIdCard" />
        <remoteParam name="NAMES_SEAL" remark="印鑑人名章名稱" type="C100" require="" reg="" fieldName="namesSeal" />
        <remoteParam name="FINANCIAL_SEAL" remark="印鑑財務章名稱" type="C128" require="" reg="" fieldName="financialSeal" />
        <remoteParam name="OFFICIAL_SEAL" remark="公章名稱" type="C128" require="" reg="" fieldName="officialSeal" />
        <remoteParam name="ADMIN_AREA" remark="行政區劃" type="C32" require="" reg="" fieldName="adminArea" />
        <remoteParam name="ACTUAL_OFFICE_ADDRESS" remark="實際辦公地址" type="C100" require="1" reg="" fieldName="actualOfficeAddress" />
        <remoteParam name="IS_SEAL_LEGAL_PERSON" remark="預留印鑑是否爲法人" type="N1" require="1" reg="0|1" fieldName="isSealLegalPerson" />
        <remoteParam name="BELONG_FTA" remark="是否屬於自貿區" type="N1" require="1" reg="0|1" fieldName="belongFta" />
        <remoteParam name="IS_OPEN_REMIND" remark="是否開通提醒" type="N1" require="1" reg="0|1" fieldName="isOpenRemind" />
        <remoteParam name="SMS_REMIND" remark="是否短信提醒" type="N1" require="1" reg="0|1" fieldName="smsRemind" />
        <remoteParam name="TEL_REMIND" remark="是否電話提醒" type="N1" require="1" reg="0|1" fieldName="telRemind" />
        <remoteParam name="LARGE_AMOUNT_REMIND" remark="是否大額提醒" type="N1" require="" reg="0|1" fieldName="largeAmountRemind" />
        <remoteParam name="DUE_DATE" remark="賬戶到期日" type="D" require="" reg="" fieldName="dueDate" />
    </remoteParams>

    <remoteParams name="SPICII-1-2">
        <remoteParam name="ACCOUNTNO" remark="賬號" type="C32" require="1" reg="" fieldName="accountNo" />
        <remoteParam name="CHANGE_REASON" remark="變更原因" type="C128" require="1" reg="" fieldName="changeReason" />
        <remoteParam name="CHANGE_DATE" remark="變更日期" type="D" require="1" reg="" fieldName="changeDate" />
        <remoteParam name="CHANGE_APPLY_ID" remark="變更申請ID" type="N38" require="1" reg="" fieldName="changeApplyId" />
        <remoteParam name="CLTNO" remark="單位編號" type="C32" require="" reg="" fieldName="cltNo" />
        <remoteParam name="CLT_NAME" remark="單位名稱" type="C64" require="" reg="" fieldName="cltName" />
        <remoteParam name="ASSBANKNAME" remark="合作金融網點名稱" type="C128" require="" reg="" fieldName="assBankName" />
        <remoteParam name="ISABROAD" remark="境內外" type="C1" require="" reg="0|1" fieldName="isAbroad" />
        <remoteParam name="AREAID" remark="區域編碼" type="N38" require="" reg="" fieldName="areaId" />
        <remoteParam name="OPENACCOUNTDATE" remark="開戶日期" type="D" require="" reg="" fieldName="openAccountDate" />
        <remoteParam name="ACCOUNTNAME" remark="戶名" type="C128" require="" reg="" fieldName="accountName" />
        <remoteParam name="MEMORYNAME" remark="助記名" type="C128" require="" reg="" fieldName="memoryName" />
        <remoteParam name="CURRENCYNO" remark="幣種" type="C3" require="" reg="" fieldName="currencyNo" />
        <remoteParam name="CTNAME" remark="賬戶性質" type="C32" require="" reg="" fieldName="type" />
        <remoteParam name="NATURENAME" remark="賬戶用途" type="C32" require="" reg="" fieldName="natureName" />
        <remoteParam name="FOREIGNTYPE" remark="外匯業務類型" type="N38" require="" reg="1|2" fieldName="foreignType" />
        <remoteParam name="ASSOCIATEFLAG" remark="聯網方式" type="C1" require="" reg="0|1|2" fieldName="associateFlag" />
        <remoteParam name="ARRDESS" remark="單位/項目地址" type="C256" require="" reg="" fieldName="arrdess" />
        <remoteParam name="CNREMARK" remark="備註" type="C500" require="" reg="" fieldName="cnreMark" />
        <remoteParam name="ACNTSTATE" remark="賬戶狀態" type="N38" require="" reg="0|1|-1|-2" fieldName="acntState" />
        <remoteParam name="EACCOUNT" remark="實體賬戶賬號" type="C32" require="" reg="" fieldName="eAccount" />
        <remoteParam name="PUBLIC_TELEPHONE" remark="對公電話" type="C20" require="" reg="" fieldName="publicTelephone" />
        <remoteParam name="CUSTOMER_MANAGER" remark="客戶經理" type="C60" require="" reg="" fieldName="customerManager" />
        <remoteParam name="CM_TELEPHONE" remark="客戶經理電話" type="C20" require="" reg="" fieldName="cmTelephone" />
        <remoteParam name="CM_MAIL" remark="客戶經理郵箱" type="C60" require="" reg="" fieldName="cmMail" />
        <remoteParam name="IS_DEDUCT" remark="是否扣減賬戶:0不是;1是" type="N38" require="" reg="0|1" fieldName="isDeduct" />
        <remoteParam name="IS_ESCROWACCOUNT" remark="是否監管賬戶(0-否 1-是)" type="N38" require="" reg="0|1" fieldName="isEscrowAccount" />
        <remoteParam name="NEED_ONLINE" remark="是否申請上線" type="N38" require="" reg="0|1" fieldName="needOnline" />
        <remoteParam name="CONTACT_PERSON" remark="聯繫人" type="C32" require="" reg="" fieldName="contactPerson" />
        <remoteParam name="CONTACT_TEL" remark="聯繫人電話" type="C32" require="" reg="" fieldName="contactTel" />
        <remoteParam name="BASIC_ACCOUNT_NO" remark="基本戶賬戶" type="C32" require="" reg="" fieldName="basicAccountNo" />
        <remoteParam name="BASIC_ACCOUNT_BANKNAME" remark="基本戶開戶行" type="C64" require="" reg="" fieldName="basicAccountBankname" />
        <remoteParam name="AUTHORIZED_PERSON_NAME" remark="被授權人姓名" type="C32" require="" reg="" fieldName="authorizedPersonName" />
        <remoteParam name="AUTHORIZED_PERSON_ID" remark="被授權人身份證號" type="C32" require="" reg="" fieldName="authorizedPersonId" />
        <remoteParam name="LEGAL_PERSON" remark="法人姓名" type="C32" require="" reg="" fieldName="legalPerson" />
        <remoteParam name="LEGAL_ID_CARD" remark="法人身份證號" type="C32" require="" reg="" fieldName="legalIdCard" />
        <remoteParam name="NAMES_SEAL" remark="印鑑人名章名稱" type="C100" require="" reg="" fieldName="namesSeal" />
        <remoteParam name="FINANCIAL_SEAL" remark="印鑑財務章名稱" type="C128" require="" reg="" fieldName="financialSeal" />
        <remoteParam name="OFFICIAL_SEAL" remark="公章名稱" type="C128" require="" reg="" fieldName="officialSeal" />
        <remoteParam name="ADMIN_AREA" remark="行政區劃" type="C32" require="" reg="" fieldName="adminArea" />
        <remoteParam name="ACTUAL_OFFICE_ADDRESS" remark="實際辦公地址" type="C100" require="" reg="" fieldName="actualOfficeAddress" />
        <remoteParam name="IS_SEAL_LEGAL_PERSON" remark="預留印鑑是否爲法人" type="N38" require="" reg="0|1" fieldName="isSealLegalPerson" />
        <remoteParam name="BELONG_FTA" remark="是否屬於自貿區" type="N38" require="" reg="0|1" fieldName="belongFta" />
        <remoteParam name="IS_OPEN_REMIND" remark="是否開通提醒" type="N38" require="" reg="0|1" fieldName="isOpenRemind" />
        <remoteParam name="SMS_REMIND" remark="是否短信提醒" type="N38" require="" reg="0|1" fieldName="smsRemind" />
        <remoteParam name="TEL_REMIND" remark="是否電話提醒" type="N38" require="" reg="0|1" fieldName="telRemind" />
        <remoteParam name="LARGE_AMOUNT_REMIND" remark="是否大額提醒" type="N38" require="" reg="0|1" fieldName="largeAmountRemind" />
        <remoteParam name="DUE_DATE" remark="賬戶到期日" type="D" require="" reg="" fieldName="dueDate" />
    </remoteParams>

    <remoteParams name="SPICII-1-3">
        <remoteParam name="ACCOUNTNO" remark="賬號" type="C32" require="1" reg="" fieldName="accountNo" />
        <remoteParam name="APPLYID" remark="銷戶申請流水號" type="N38" require="1" reg="" fieldName="applyId" />
        <remoteParam name="CANCELDATE" remark="銷戶日期" type="D" require="1" reg="" fieldName="cancelDate" />
        <remoteParam name="CANCELREMARK" remark="銷戶備註" type="C500" require="" reg="" fieldName="cancelRemark" />
        <remoteParam name="CANCELREASON" remark="銷戶原因" type="C500" require="" reg="" fieldName="cancelReason" />
    </remoteParams>

    <remoteParams name="SPICII-1-4">
        <remoteParam name="ACCOUNTNO" remark="賬號" type="C32" require="1" reg="" fieldName="accountNo" />
        <remoteParam name="CLTNO" remark="單位編號" type="C32" require="" reg="" fieldName="cltNo" />
        <remoteParam name="CLT_NAME" remark="單位名稱" type="C64" require="" reg="" fieldName="cltName" />
        <remoteParam name="ASSBANKNAME" remark="合作金融網點名稱" type="C128" require="" reg="" fieldName="assBankName" />
        <remoteParam name="ISABROAD" remark="境內外" type="C1" require="" reg="0|1" fieldName="isAbroad" />
        <remoteParam name="AREAID" remark="區域編碼" type="N38" require="" reg="" fieldName="areaId" />
        <remoteParam name="OPENACCOUNTDATE" remark="開戶日期" type="D" require="" reg="" fieldName="openAccountDate" />
        <remoteParam name="ACCOUNTNAME" remark="戶名" type="C128" require="" reg="" fieldName="accountName" />
        <remoteParam name="MEMORYNAME" remark="助記名" type="C128" require="" reg="" fieldName="memoryName" />
        <remoteParam name="CURRENCYNO" remark="幣種" type="C3" require="" reg="" fieldName="currencyNo" />
        <remoteParam name="CTNAME" remark="賬戶性質" type="C32" require="" reg="" fieldName="type" />
        <remoteParam name="NATURENAME" remark="賬戶用途" type="C32" require="" reg="" fieldName="natureName" />
        <remoteParam name="FOREIGNTYPE" remark="外匯業務類型" type="N38" require="" reg="1|2" fieldName="foreignType" />
        <remoteParam name="ASSOCIATEFLAG" remark="聯網方式" type="C1" require="" reg="0|1|2" fieldName="associateFlag" />
        <remoteParam name="ARRDESS" remark="單位/項目地址" type="C256" require="" reg="" fieldName="arrdess" />
        <remoteParam name="CNREMARK" remark="備註" type="C500" require="" reg="" fieldName="cnreMark" />
        <remoteParam name="ACNTSTATE" remark="賬戶狀態" type="N38" require="" reg="0|1|-1|-2" fieldName="acntState" />
        <remoteParam name="EACCOUNT" remark="實體賬戶賬號" type="C32" require="" reg="" fieldName="eAccount" />
        <remoteParam name="PUBLIC_TELEPHONE" remark="對公電話" type="C20" require="" reg="" fieldName="publicTelephone" />
        <remoteParam name="CUSTOMER_MANAGER" remark="客戶經理" type="C60" require="" reg="" fieldName="customerManager" />
        <remoteParam name="CM_TELEPHONE" remark="客戶經理電話" type="C20" require="" reg="" fieldName="cmTelephone" />
        <remoteParam name="CM_MAIL" remark="客戶經理郵箱" type="C60" require="" reg="" fieldName="cmMail" />
        <remoteParam name="IS_DEDUCT" remark="是否扣減賬戶:0不是;1是" type="N38" require="" reg="0|1" fieldName="isDeduct" />
        <remoteParam name="IS_ESCROWACCOUNT" remark="是否監管賬戶(0-否 1-是)" type="N38" require="" reg="0|1" fieldName="isEscrowAccount" />
        <remoteParam name="NEED_ONLINE" remark="是否申請上線" type="N38" require="" reg="0|1" fieldName="needOnline" />
        <remoteParam name="CONTACT_PERSON" remark="聯繫人" type="C32" require="" reg="" fieldName="contactPerson" />
        <remoteParam name="CONTACT_TEL" remark="聯繫人電話" type="C32" require="" reg="" fieldName="contactTel" />
        <remoteParam name="BASIC_ACCOUNT_NO" remark="基本戶賬戶" type="C32" require="" reg="" fieldName="basicAccountNo" />
        <remoteParam name="BASIC_ACCOUNT_BANKNAME" remark="基本戶開戶行" type="C64" require="" reg="" fieldName="basicAccountBankname" />
        <remoteParam name="AUTHORIZED_PERSON_NAME" remark="被授權人姓名" type="C32" require="" reg="" fieldName="authorizedPersonName" />
        <remoteParam name="AUTHORIZED_PERSON_ID" remark="被授權人身份證號" type="C32" require="" reg="" fieldName="authorizedPersonId" />
        <remoteParam name="LEGAL_PERSON" remark="法人姓名" type="C32" require="" reg="" fieldName="legalPerson" />
        <remoteParam name="LEGAL_ID_CARD" remark="法人身份證號" type="C32" require="" reg="" fieldName="legalIdCard" />
        <remoteParam name="NAMES_SEAL" remark="印鑑人名章名稱" type="C100" require="" reg="" fieldName="namesSeal" />
        <remoteParam name="FINANCIAL_SEAL" remark="印鑑財務章名稱" type="C128" require="" reg="" fieldName="financialSeal" />
        <remoteParam name="OFFICIAL_SEAL" remark="公章名稱" type="C128" require="" reg="" fieldName="officialSeal" />
        <remoteParam name="ADMIN_AREA" remark="行政區劃" type="C32" require="" reg="" fieldName="adminArea" />
        <remoteParam name="ACTUAL_OFFICE_ADDRESS" remark="實際辦公地址" type="C100" require="" reg="" fieldName="actualOfficeAddress" />
        <remoteParam name="IS_SEAL_LEGAL_PERSON" remark="預留印鑑是否爲法人" type="N38" require="" reg="0|1" fieldName="isSealLegalPerson" />
        <remoteParam name="BELONG_FTA" remark="是否屬於自貿區" type="N38" require="" reg="0|1" fieldName="belongFta" />
        <remoteParam name="IS_OPEN_REMIND" remark="是否開通提醒" type="N38" require="" reg="0|1" fieldName="isOpenRemind" />
        <remoteParam name="SMS_REMIND" remark="是否短信提醒" type="N38" require="" reg="0|1" fieldName="smsRemind" />
        <remoteParam name="TEL_REMIND" remark="是否電話提醒" type="N38" require="" reg="0|1" fieldName="telRemind" />
        <remoteParam name="LARGE_AMOUNT_REMIND" remark="是否大額提醒" type="N38" require="" reg="0|1" fieldName="largeAmountRemind" />
        <remoteParam name="DUE_DATE" remark="賬戶到期日" type="D" require="" reg="" fieldName="dueDate" />
    </remoteParams>
</rules>
<?xml version="1.0" encoding="utf-8" ?>
<!ELEMENT rules (remoteParams+)>
<!ELEMENT remoteParams (remoteParam+)>
<!ELEMENT remoteParam EMPTY>
<!ATTLIST remoteParams
        name ID #REQUIRED
        >
<!ATTLIST remoteParam
        name CDATA #REQUIRED
        remark CDATA #REQUIRED
        type CDATA #REQUIRED
        require CDATA #REQUIRED
        reg CDATA #IMPLIED
        fieldName CDATA #IMPLIED
        >
package com.nstc.aims.service.remote.n9server;

import com.nstc.aims.constants.SpicCommonConstants;
import com.nstc.aims.constants.SpicRemoteIIConstants;
import com.nstc.aims.controller.builder.RemoteLogBuilder;
import com.nstc.aims.model.RemoteLog;
import com.nstc.aims.option.SpicServerRemoteIIEnum;
import com.nstc.aims.service.ServerLocator;
import com.nstc.aims.service.remote.server.AbstractExternalBaseServiceImpl;
import com.nstc.framework.core.Profile;
import com.nstc.framework.web.util.FrameworkUtil;
import com.nstc.smartform.pub.business.BaseBusiness;
import com.nstc.util.CastUtil;
import com.nstc.util.StringUtils;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>Title: AbstractN9ServerBusiness.java</p>
 * <p>Description: G6集團賬戶服務端接口 抽象類</p>
 * <p>Company: 北京九恆星科技股份有限公司</p>
 *
 * @author luhao
 * @since 2020-03-12 15:06
 */
public abstract class AbstractN9ServerBusiness extends BaseBusiness {

    public static boolean DEBUG_MOD = true;

    /**
     * 入參
     */
    private Map<String, Object> attituteMap;

    private Profile profile;

    private String successMsg = "調用成功!";

    private RemoteLog remoteLog;

    private static final Logger logger = LoggerFactory.getLogger(AbstractExternalBaseServiceImpl.class);

    /**
     * 接口類型
     */
    protected SpicServerRemoteIIEnum spicServerRemoteIIEnum;

    /**
     * 獲取服務類門面
     *
     * @return
     */
    public ServerLocator getServiceLocator() {
        return (ServerLocator) FrameworkUtil.getServiceLocator(SpicCommonConstants.AIMS);
    }

    /**
     * 遠程接口服務基礎實現類,在此完成以下功能
     * 1 解析參數
     * 2 統一獲取異常,返回結果
     * 3 組裝返回結果樣式
     *
     * @return
     */
    public void execute() {
        //SPIC-INTERFACE-ENTRY
        logger.info("====== aims remote spic interface entry======");
        result = new HashMap();
        try {
            // 校驗公共參數
            validateCommonParam();
            // 初始化接口信息
            init();
            // 調用前參數合法性校驗
            validateParam();
            //調用前業務校驗
            validateAndBuildBuss();
            // 各個接口實現類實現此接口進行業務處理
            doExecute();
            result.put(SpicCommonConstants.RET_CODE, SpicCommonConstants.SUCCESS);
            result.put(SpicCommonConstants.RET_MSG, successMsg);
        } catch (IllegalArgumentException ae) {
            result.put(SpicCommonConstants.RET_CODE, SpicCommonConstants.FAILED);
            result.put(SpicCommonConstants.RET_MSG, ae.getMessage());
        } catch (RuntimeException e) {
            e.printStackTrace();
            String msg = e.getMessage();
            if (StringUtils.isBlank(msg)) {
                String erroinfo = e.getStackTrace() == null ? "" : ":" + e.getStackTrace()[0];
                msg = e.getClass().getSimpleName() + erroinfo;
            }
            result.put(SpicCommonConstants.RET_CODE, SpicCommonConstants.FAILED);
            result.put(SpicCommonConstants.RET_MSG, msg);
        } finally {
            unbindResource();
        }

        // 日誌參數組裝
        remoteLog = RemoteLogBuilder.buildLog(getAttituteMap(),
                result.get(SpicCommonConstants.RET_CODE), result.get(SpicCommonConstants.RET_MSG));
        getServiceLocator().getRemoteService().saveRemoteLog(remoteLog);

        setResult(result);
        logger.info("======aims remote spic interface result:" + result + "======");
        logger.info("======aims remote spic interface end======");
    }

    protected abstract void validateAndBuildBuss();

    /**
     * 公共參數校驗
     */
    private void validateCommonParam() {
        Map map = bizEvent.getAttributes();
        Validate.notEmpty(map, "參數列表不能爲空!");
        Validate.notNull(map.get(SpicRemoteIIConstants.CLIENT_SOURCE), SpicRemoteIIConstants.CLIENT_MESSAGE + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
        Validate.notNull(map.get(SpicRemoteIIConstants.CLIENT_MESSAGE), SpicRemoteIIConstants.CLIENT_MESSAGE + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
        Validate.notNull(map.get(SpicRemoteIIConstants.CLIENT_INPUTOR), SpicRemoteIIConstants.CLIENT_MESSAGE + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
        Validate.notNull(map.get(SpicRemoteIIConstants.CLIENT_CLTNO), SpicRemoteIIConstants.CLIENT_CLTNO + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
        Validate.notNull(map.get(SpicRemoteIIConstants.SYNC_TYPE), SpicRemoteIIConstants.CLIENT_MESSAGE + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
        Validate.notNull(map.get(SpicRemoteIIConstants.DATA_LIST), SpicRemoteIIConstants.CLIENT_MESSAGE + SpicRemoteIIConstants.NULL_ERRO_MESSAGE);
    }

    /**
     * 執行業務動作
     */
    protected abstract void doExecute();

    /**
     * 參數合法性校驗
     */
    private void validateParam() {
        RemoteParamValidator remoteParamValidator = RemoteParamValidator.getInstance();
        if (DEBUG_MOD) {
            long t1 = System.currentTimeMillis();
            remoteParamValidator.init();
            long t2 = System.currentTimeMillis();
            logger.info("調試階段接口參數校驗器初始化耗時:" + (t2 - t1));
        }

        remoteParamValidator.validate(spicServerRemoteIIEnum.getCode(), getAttituteMap(), "");
    }

    /**
     * 初始化
     */
    public void init() {
        initProfile();
        bindResource();
        setSpicServerRemoteIIEnum();

        logger.info("====== aims remote spic interface init complet ======");
    }

    /**
     * 設置接口類型
     */
    protected void setSpicServerRemoteIIEnum() {
        String code = CastUtil.toNotEmptyString(getAttituteMap().get(SpicRemoteIIConstants.SYNC_TYPE));
        spicServerRemoteIIEnum = SpicServerRemoteIIEnum.getSpicRemoteEnum(code);
        Validate.notNull(spicServerRemoteIIEnum, "無法獲得" + SpicRemoteIIConstants.SYNC_TYPE);
    }

    /**
     * 初始化Profile
     */
    public void initProfile() {
        profile = null;
        if (getCaller() == null || getCaller().getProfile() == null) {
            profile = new Profile();
        } else {
            profile = getCaller().getProfile();
        }
        //此處可以獲得N9的用戶和單位
        profile.setUserNo(CastUtil.toNotNullString(getAttituteMap().get(SpicRemoteIIConstants.CLIENT_INPUTOR)));
        String cltNo = CastUtil.toNotNullString(getAttituteMap().get(SpicRemoteIIConstants.CLIENT_CLTNO));
        profile.setCustNo(cltNo);
//        profile.setUserNo("機制");
//        profile.setCustName("機制");
    }

    /**
     * 綁定線程變量
     */
    public void bindResource() {
        com.nstc.framework.util.ThreadResources.bindResource(profile.getClass().getName(), profile);
        com.nstc.framework.util.ThreadResources.bindResource("CurThreadAppNo", SpicCommonConstants.AIMS);
        com.nstc.waf.util.ThreadResources.bindResource(profile.getClass().getName(), profile);
        com.nstc.waf.util.ThreadResources.bindResource("CurThreadAppNo", SpicCommonConstants.AIMS);
    }

    /**
     * 解綁線程變量
     */
    private void unbindResource() {
        if (profile != null) {
            com.nstc.framework.util.ThreadResources.unbindResource(profile.getClass().getName());
            com.nstc.framework.util.ThreadResources.unbindResource("CurThreadAppNo");
            com.nstc.waf.util.ThreadResources.unbindResource(profile.getClass().getName());
            com.nstc.waf.util.ThreadResources.unbindResource("CurThreadAppNo");
        }
    }

    public Profile getProfile() {
        return profile;
    }

    public Map<String, Object> getAttituteMap() {
        if (attituteMap == null) {
            attituteMap = bizEvent.getAttributes();
        }
        return attituteMap;
    }

    public void onSuccess() {
    }

    public void onFailure() {
        onSuccess();
    }

    public String getSuccessMsg() {
        return successMsg;
    }

    public void setSuccessMsg(String successMsg) {
        this.successMsg = successMsg;
    }
}

一個基於js的dtd約束文件的檢查工具

<html>
<head>
    <script language="javascript">
        for (var i = 1; i <= 9; i++) {
            checkXml("SPICII-" + i + ".xml");
        }

        function checkXml(path) {
            // 創建xml文檔解析器對象
            var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
            // 開啓xml校驗
            xmldoc.validateOnParse = "true";
            // 裝載xml文檔,即指定校驗哪個XML文件
            xmldoc.load(path);
            document.writeln(path + ":" + "<br>");
            document.writeln("\t錯誤信息:" + xmldoc.parseError.reason + "<br>");
            document.writeln("\t錯誤行號:" + xmldoc.parseError.line + "<br>");
            document.writeln("<br />")
        }
    </script>

</head>
<body>

</body>
</html>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章