From: Tang Cheng Date: Thu, 18 Jul 2019 11:51:30 +0000 (+0800) Subject: 改进下载对账文件的方案 X-Git-Tag: 1.0.0^2~21 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=3a1bfb111265b706e5e432aeb5caab055442fe6b;p=epayment%2Ffood_payapi.git 改进下载对账文件的方案 --- diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties index 52289cef..8e2b45ea 100644 --- a/config/application-devel-pg.properties +++ b/config/application-devel-pg.properties @@ -10,7 +10,7 @@ spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/payapidev spring.datasource.username=payapi spring.datasource.password=123456 spring.datasource.continue-on-error=true -#spring.datasource.initialization-mode=always +spring.datasource.initialization-mode=always # Redis settings #spring.redis.host=ykt.supwisdom.com spring.redis.host=172.28.201.101 diff --git a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java index e2042d95..d68a2385 100644 --- a/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java +++ b/payapi-sdk/src/main/java/com/supwisdom/dlpay/paysdk/proxy/CitizenCardPayProxy.java @@ -13,7 +13,6 @@ import javax.validation.Valid; @FeignClient(value = "citizenCardPay", url = "${payapi.url}") public interface CitizenCardPayProxy { @RequestMapping(value = "/api/consume/citizencard/payinit", method = RequestMethod.GET) - @Valid CitizenPayResponse citizencardPayinit(@RequestBody CitizenCardPayinitParam param); @RequestMapping(value = "/api/consume/citizencard/payfinish", method = RequestMethod.GET) diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java index 191697e9..88e7e1b5 100644 --- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java +++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/ParamServiceImpl.java @@ -164,7 +164,7 @@ public class ParamServiceImpl implements ParamService { } @Override - @Cacheable(cacheNames = "dictionary_cache", key = "#{@tenantHolder.genKey('sourcetype', #sourceType)}") + @Cacheable(cacheNames = "dictionary_cache", key = "@tenantHolder.genKey('sourcetype', #sourceType)") public TSourceType getSourceType(String sourceType) { if (!StringUtil.isEmpty(sourceType)) { return sourceTypeDao.getBySourceType(sourceType.trim()); diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt index 4139d9e6..5b9745ac 100644 --- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt +++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/async_tasks.kt @@ -2,7 +2,6 @@ package com.supwisdom.dlpay.api import com.supwisdom.dlpay.agent.AgentCode import com.supwisdom.dlpay.agent.DtlStatus - import com.supwisdom.dlpay.agent.citizencard.YnrccUtil import com.supwisdom.dlpay.api.domain.TDtlQuery import com.supwisdom.dlpay.api.domain.TTransactionMain @@ -129,8 +128,9 @@ class AgentQueryResultTask { } AgentCode.REFNO_NOT_EXISTS -> transactionService.fail(transaction.refno, "银行流水不存在") //银行返回流水不存在 - AgentCode.REQUIRE_QUERY -> + AgentCode.REQUIRE_QUERY -> { queryResult(transaction, qcnt + 1) //查询次数加1 + } else -> { //其他明确错误,查询失败 logger.error("查询refno=[${transaction.refno}]流水结果返回失败:code=[${resp.agentCode}],message=[${resp.agentMsg}]") diff --git a/ynrcc-agent/build.gradle b/ynrcc-agent/build.gradle index a46f4d77..a00c65d9 100644 --- a/ynrcc-agent/build.gradle +++ b/ynrcc-agent/build.gradle @@ -49,6 +49,7 @@ dependencies { implementation group: 'taglibs', name: 'standard', version: '1.1.2' implementation group: 'commons-codec', name: 'commons-codec', version: '1.6' implementation 'org.dom4j:dom4j:2.1.1' + implementation 'commons-beanutils:commons-beanutils:1.9.3' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:3.3.0' diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java new file mode 100644 index 00000000..d19df54c --- /dev/null +++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileHeader.java @@ -0,0 +1,76 @@ +package com.supwisdom.agent.api.bean; + +/** + * 第一行:总笔数|总金额|代扣总笔数|代扣总金额|退款总笔数|退款总金额| + */ +public class CheckFileHeader { + private int totalCount; + private int totalAmount; + private int payCount; + private int payAmount; + private int refundCount; + private int refundAmount; + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(int totalAmount) { + this.totalAmount = totalAmount; + } + + public int getPayCount() { + return payCount; + } + + public void setPayCount(int payCount) { + this.payCount = payCount; + } + + public int getPayAmount() { + return payAmount; + } + + public void setPayAmount(int payAmount) { + this.payAmount = payAmount; + } + + public int getRefundCount() { + return refundCount; + } + + public void setRefundCount(int refundCount) { + this.refundCount = refundCount; + } + + public int getRefundAmount() { + return refundAmount; + } + + public void setRefundAmount(int refundAmount) { + this.refundAmount = refundAmount; + } + + public boolean isZero() { + return (totalAmount == 0 && totalCount == 0 + && payAmount == 0 && payCount == 0 && refundAmount == 0 && refundCount == 0); + } + + @Override + public String toString() { + return totalCount + + ", " + totalAmount + + ", " + payCount + + ", " + payAmount + + ", " + refundCount + + ", " + refundAmount; + } +} diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java new file mode 100644 index 00000000..e3d9b692 --- /dev/null +++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/bean/CheckFileLine.java @@ -0,0 +1,100 @@ +package com.supwisdom.agent.api.bean; + +/** + * * 第二行及以后:交易日期|交易时间|报文业务类型|业务系统流水号|银行流水号|付款银行卡号|收款商户银行卡号|核心记账日期|交易金额|交易摘要| + *

+ * private static final String[]chkFileColumnList=new String[]{"transdate","transtime","flag","refno","agentrefno", + * "payerid","payeeid","agentdate","amount","summary"}; + */ +public class CheckFileLine { + private String transdate; + private String transtime; + private String flag; + private String refno; + private String agentrefno; + private String payerid; + private String payeeid; + private String agentdate; + private Integer amount; + private String summary; + + public String getTransdate() { + return transdate; + } + + public void setTransdate(String transdate) { + this.transdate = transdate; + } + + public String getTranstime() { + return transtime; + } + + public void setTranstime(String transtime) { + this.transtime = transtime; + } + + public String getFlag() { + return flag; + } + + public void setFlag(String flag) { + this.flag = flag; + } + + public String getRefno() { + return refno; + } + + public void setRefno(String refno) { + this.refno = refno; + } + + public String getAgentrefno() { + return agentrefno; + } + + public void setAgentrefno(String agentrefno) { + this.agentrefno = agentrefno; + } + + public String getPayerid() { + return payerid; + } + + public void setPayerid(String payerid) { + this.payerid = payerid; + } + + public String getPayeeid() { + return payeeid; + } + + public void setPayeeid(String payeeid) { + this.payeeid = payeeid; + } + + public String getAgentdate() { + return agentdate; + } + + public void setAgentdate(String agentdate) { + this.agentdate = agentdate; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getSummary() { + return summary; + } + + public void setSummary(String summary) { + this.summary = summary; + } +} diff --git a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java index 8c229d33..52fa611b 100644 --- a/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java +++ b/ynrcc-agent/src/main/java/com/supwisdom/agent/api/controller/YnrccApiController.java @@ -4,18 +4,24 @@ import com.supwisdom.agent.Util.BussinessException; import com.supwisdom.agent.Util.DlpayUtil; import com.supwisdom.agent.Util.ErrorCode; import com.supwisdom.agent.Util.StringUtil; +import com.supwisdom.agent.api.bean.CheckFileHeader; +import com.supwisdom.agent.api.bean.CheckFileLine; import com.supwisdom.agent.api.bean.DlpayReq; import com.supwisdom.agent.api.bean.DlpayResp; import com.supwisdom.agent.api.service.YnrccApiService; import com.supwisdom.agent.api.service.YnrccParamCheckService; +import org.apache.commons.beanutils.BeanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletResponse; import javax.ws.rs.FormParam; +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -28,6 +34,18 @@ public class YnrccApiController { @Autowired private YnrccParamCheckService ynrccParamCheckService; + /** + * 第一行:总笔数|总金额|代扣总笔数|代扣总金额|退款总笔数|退款总金额| + * 第二行及以后:交易日期|交易时间|报文业务类型|业务系统流水号|银行流水号|付款银行卡号|收款商户银行卡号|核心记账日期|交易金额|交易摘要| + */ + private static final String[] chkFileColumnList = new String[]{"transdate", "transtime", "flag", "refno", "agentrefno", + "payerid", "payeeid", "agentdate", "amount", "summary"}; + private static final String[] chkFileHeaderColumnList = new String[]{"totalCount", "totalAmount", "payCount", + "payAmount", "refundCount", "refundAmount"}; + private static final String chkFileDelimiter = "|"; + private static final String FLAG_WITHHOLD = "BC5512"; + private static final String FLAG_REFUND = "BC5513"; + private static final Logger logger = LoggerFactory.getLogger(YnrccApiController.class); private boolean checkYnrccSign(Map params, DlpayResp resp) { @@ -375,5 +393,106 @@ public class YnrccApiController { } } + private void populate(String[] fields, String[] column, T bean) { + if (fields.length != column.length) { + throw new IllegalArgumentException("错误的列定义"); + } + try { + Map data = new HashMap<>(); + for (int col = 0; col < column.length; ++col) { + data.put(column[col], fields[col]); + } + BeanUtils.populate(bean, data); + } catch (InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + throw new IllegalArgumentException("错误的列定义"); + } + private T populate(String[] fields, String[] column, Class beanClass) { + try { + T bean = beanClass.newInstance(); + populate(fields, column, bean); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + throw new IllegalArgumentException("错误的列定义"); + } + + private void writeLine(OutputStream output, String delimiter, Object... columns) throws IOException { + for (Object item : columns) { + output.write(item.toString().getBytes(StandardCharsets.UTF_8)); + output.write(delimiter.getBytes()); + } + output.write("\n".getBytes()); + } + + private void parseFile(String filePath, OutputStream output) { + int lineno = 1; + try { + BufferedReader reader = new BufferedReader( + new InputStreamReader( + new FileInputStream(filePath), "GBK")); + String header = reader.readLine(); + if (header == null) { + throw new IllegalArgumentException("数据文件内容为空"); + } + + CheckFileHeader fileHeader = populate(chkFileHeaderColumnList, + header.split(chkFileDelimiter), CheckFileHeader.class); + + + CheckFileLine record = new CheckFileLine(); + writeLine(output, ",", "refno", "agentrefno", "agentdate", "flag", "payerid", + "payeeid", "amount", "summary"); + while (true) { + String line = reader.readLine(); + if (line == null) { + break; + } + lineno++; + String[] field = line.split(chkFileDelimiter); + populate(chkFileColumnList, field, record); + int amount; + String flag; + if (FLAG_WITHHOLD.equals(record.getFlag())) { + amount = -record.getAmount(); + flag = "pay"; + fileHeader.setPayCount(fileHeader.getPayCount() - 1); + fileHeader.setPayAmount(fileHeader.getPayAmount() - record.getAmount()); + } else if (FLAG_REFUND.equals(record.getFlag())) { + amount = +record.getAmount(); + flag = "refund"; + fileHeader.setRefundCount(fileHeader.getRefundCount() - 1); + fileHeader.setRefundAmount(fileHeader.getRefundAmount() - record.getAmount()); + } else { + throw new IllegalArgumentException("对账文件【报文业务类型】错误,行数 " + lineno + " 。"); + } + fileHeader.setTotalCount(fileHeader.getTotalCount() - 1); + fileHeader.setTotalAmount(fileHeader.getTotalAmount() - record.getAmount()); + writeLine(output, ",", record.getRefno(), + record.getAgentrefno(), record.getAgentdate(), + flag, record.getPayerid(), record.getPayeeid(), + amount, record.getSummary()); + } + if (!fileHeader.isZero()) { + throw new IllegalArgumentException("对账文件总金额与笔数与明细不符"); + } + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException("对账文件数据格式错误,行数 " + lineno + " 。"); + } + } + + @GetMapping("/download") + public void downloadFile(@RequestParam("file") String file, HttpServletResponse response) throws IOException { + try { + parseFile(file, response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + response.sendError(HttpStatus.SERVICE_UNAVAILABLE.value(), e.getMessage()); + } + } }