我方天天在服務器上生成對帳文件, 第三方來取.java
1.需求:git
2.思路sql
1.設置好 對帳文件存放的路徑(工程部門給外部平臺一個地址,他們本身過來取) 2.在這個路徑下新建一個文件 . 格式是.txt 3. 鏈接數據庫,查詢支付表(可能多表查詢), 查詢前一天的數據. 按照接口文檔須要的字段 查詢到對應字段 ,並拼接 4.把查出來的數據(eg:101486120190325083431|20190325|10.00|0|1|0042930413|SWShopMall), 放到 .txt文件裏
package com.seaway.open.open_bank_luoyang_check; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.yaml.snakeyaml.Yaml; import com.seaway.open.open_bank_luoyang_check.configure.Configure; import io.vertx.core.AbstractVerticle; import io.vertx.core.Vertx; import io.vertx.core.cli.Argument; import io.vertx.core.cli.CLI; import io.vertx.core.cli.TypedOption; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.ext.jdbc.JDBCClient; import io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider; import io.vertx.ext.sql.ResultSet; import io.vertx.ext.sql.SQLConnection; public class Runner extends AbstractVerticle { private static final Logger logger = LogManager.getLogger(Runner.class); private Configure gconfigure = null; private JDBCClient jdbcClient = null; // Vertx vertx = Vertx.vertx(); public Configure getGconfigure() { return gconfigure; } public void setGconfigure(Configure gconfigure) { this.gconfigure = gconfigure; } public synchronized JDBCClient getJdbcClientInstance() { if (jdbcClient == null) { try { HikariCPDataSourceProvider HikariCPDataSource = new HikariCPDataSourceProvider(); JsonObject jdbcobject = JsonObject.mapFrom(getGconfigure().getJdbcConfig()); jdbcobject.put("autoCommit", true); jdbcClient = JDBCClient.create(vertx, HikariCPDataSource.getDataSource(jdbcobject)); logger.info("初始化數據庫鏈接池成功 {}", jdbcobject.toString()); } catch (SQLException e) { logger.error("鏈接數據庫失敗:{}", e); } } return jdbcClient; } public static void main(String[] args) { Runner runner = new Runner(); Vertx vertx = Vertx.vertx(); runner.start(vertx); } private void initConfigure() { CLI cli = CLI.create("open_bank_luoyang_check").setSummary("開放平臺xx銀行對帳文件生成程序") .addOption(new TypedOption<Boolean>().setType(Boolean.class).setLongName("configure") .setShortName("cfg").setDescription("指定配置文件").setFlag(true).setRequired(true)) .addArgument(new Argument().setDescription("文件絕對路徑(yaml格式)").setArgName("filename").setRequired(true)); StringBuilder builder = new StringBuilder(); cli.usage(builder); String ConfigureFile = null; // int liFile = this.context.processArgs().indexOf("-cfg"); // if (liFile == -1) { // // logger.error("指定配置文件: [-cfg <filename>]"); // logger.error(builder); // stop(); // } // try { // ConfigureFile = this.context.processArgs().get(liFile + 1); // if (!new File(ConfigureFile).exists()) { // // logger.error("配置文件[" + ConfigureFile + "]不存在"); // logger.error(builder); // stop(); // } // } catch (Exception e) { // // logger.error("指定配置文件: [-cfg <filename>]",e); // logger.error(builder); // stop(); // // } Yaml yaml = new Yaml(); ConfigureFile = "F:/Users/Administrator/git/open6/open_bank_check/open_bank_luoyang_check/src/main/resources/open_bank_luoyang_check.yaml"; try { InputStream in = new FileInputStream(new File(ConfigureFile)); setGconfigure(yaml.loadAs(in, Configure.class)); logger.info("讀取配置文件[" + ConfigureFile + "]:[" + getGconfigure() + "]"); } catch (Exception e) { logger.error("解析文件錯誤", e); stop(); } } @Override public void stop() { logger.info("關閉系統!"); vertx.close(); System.exit(0); } // @Override public void start(Vertx vertx) { initConfigure(); HikariCPDataSourceProvider HikariCPDataSource = new HikariCPDataSourceProvider(); try { JsonObject jdbcobject = JsonObject.mapFrom(getGconfigure().getJdbcConfig()); jdbcobject.put("autoCommit", true); jdbcClient = JDBCClient.create(vertx, HikariCPDataSource.getDataSource(jdbcobject)); logger.info("初始化數據庫鏈接池成功 {}", jdbcobject.toString()); } catch (SQLException e) { logger.error("鏈接數據庫失敗:", e); } /** * 功能描述: 當天對前一天生活圈發生的支付或退款交易進行校對和清算 對帳文件的文件名:SWShopMall_yyyyMMdd.txt 文件內容格式: 訂單號 * |交易日期|金額|交易狀態|交易類型|客戶號 |商戶號 20160602 |20190218|9.01| 0 | 1 | 037894566 * |SWShopMall 文件格式是.txt 文件中不能出現空格,空行 天天早上7點以前必須將前一天的對帳文件放置服務器上,不然將影響對帳交易 交易狀態 * 0:成功1:失敗 交易類型 1:付款2:退款; */ // 每晚2點生成 vertx.setTimer(getGconfigure().getFileConfigure().getTaskTime(), id1 -> { executeTask(); vertx.setPeriodic(getGconfigure().getFileConfigure().getCycleTaskTime(), id2 -> { executeTask(); }); vertx.cancelTimer(id1); }); } private void executeTask() { logger.info("定時任務開始"); String dateTime = LocalDateTime.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMdd")); // 若是dateTime日期20190324時間小於設置的時間,則取配置時間 if (!getGconfigure().getCheckConfigure().getCheckDate().equals("00000000")) dateTime = getGconfigure().getCheckConfigure().getCheckDate(); String checkPath = getGconfigure().getCheckConfigure().getCheckPath(); String filePath = checkPath + "/SWShopMall_" + dateTime + ".txt"; logger.info("filePath: {}", filePath); File file = new File(filePath); if (file.exists()) { logger.info("文件已經生成 退出"); return; } else { logger.info("文件不存在 新建文件"); try { file.createNewFile(); logger.info("建立成功"); if (jdbcClient == null) { logger.info("jdbcClient is null getJdbcClientInstance"); jdbcClient = getJdbcClientInstance(); } else { logger.info("jdbcClient not null"); } String times = dateTime; jdbcClient.getConnection(jdbcConnect -> { if (jdbcConnect.failed()) { logger.error("鏈接出錯: {}", jdbcConnect.cause().getMessage()); return; } else { final SQLConnection connection = jdbcConnect.result(); logger.info("取得鏈接"); // 查詢數據庫 String beginTime = times + "000000"; String endTime = times + "235959"; // 金額保留兩位小數,多餘舍掉 cast(trunc(pay_amount/10000,2) AS NUMBER (10, 2)) // 金額保留兩位小數,四捨五入 to_char(pa.pay_amount/10000,'fm99,999,990.00') // 該sql金額會至少保留兩位小數(單位元) String querySql = "\n\nselect pay_id || '|' || substr(pay_time, 0, 8) || '|' || \n" + "case \n" + " when substr(to_char(pay_amount/10000,'fm99,999,990.0000'),-2) > 00\n" + " then\n" + " to_char(pay_amount/10000,'fm99,999,990.0000')\n" + " else\n" + " to_char(pay_amount/10000,'fm99,999,990.00')\n" + " end \n" + " || '|' ||\n" + "case when stats in(3,5,9) then\n" + " 0\n" + " else\n" + " 1\n" + " end || '|' || 1 || '|' || user_id || '|' || '" + getGconfigure().getFileConfigure().getMerchantCode() + "'\n" + "from payment_item where pay_time between '" + beginTime + "' and '" + endTime + "' and gateway_id = '" + getGconfigure().getFileConfigure().getGateway_id() + "' and channel_id = '" + getGconfigure().getFileConfigure().getChannel_id() + "' \n" + "union all\n" + "select r.refund_id || '|' || substr(r.refund_time, 0, 8)|| '|' || \n" + "case \n" + " when substr(to_char(r.refund_amount/10000,'fm99,999,990.0000'),-2) > 00\n" + " then\n" + " to_char(r.refund_amount/10000,'fm99,999,990.0000')\n" + " else\n" + " to_char(r.refund_amount/10000,'fm99,999,990.00')\n" + " end \n" + "|| '|' ||\n" + "case r.stats \n" + " when 1 then\n" + " 0\n" + " when 2 then\n" + " 1\n" + " else\n" + " 1\n" + " end || '|' || 2 || '|' || p.user_id || '|' || '" + getGconfigure().getFileConfigure().getMerchantCode() + "'\n" + "from refund_item r,payment_item p \n" + "where r.pay_id = p.pay_id and r.refund_time between '" + beginTime + "' and '" + endTime + "' and r.gateway_id = '" + getGconfigure().getFileConfigure().getGateway_id() + "' and r.channel_id = '" + getGconfigure().getFileConfigure().getChannel_id() + "'\n"; logger.info("querySql: {}", querySql); connection.query(querySql, queryresult -> { if (queryresult.succeeded()) { connection.close(); logger.info("queryresult succeeded"); ResultSet queryResultSet = queryresult.result(); List<JsonArray> jsonArraysList = queryResultSet.getResults(); // logger.info("jsonArraysList: {}", jsonArraysList); FileOutputStream outSTr = null; BufferedOutputStream buff = null; try { outSTr = new FileOutputStream(file); } catch (FileNotFoundException e1) { logger.error(e1); } buff = new BufferedOutputStream(outSTr); logger.info("size: " + jsonArraysList.size()); for (int i = 0; i < jsonArraysList.size(); i++) { /*** 把數據寫入到磁盤 */ try { buff.write((jsonArraysList.get(i).getString(0) + "\n").getBytes()); // 每多少次清理一次 緩衝區 if (i % getGconfigure().getFileConfigure().getFlushCount() == 0 && buff != null) { buff.flush(); logger.info("flush: " + i); } } catch (IOException e) { logger.error("寫入磁盤出錯", e); } } if (buff != null) { try { buff.flush(); buff.close(); } catch (IOException e) { logger.error("關閉出錯", e); } } logger.info("{}日對帳文件寫入磁盤成功,共{}條", times, jsonArraysList.size()); } else { connection.close(); logger.error("執行查詢錯誤,關閉鏈接: {}", queryresult.cause().getMessage()); } }); } }); } catch (IOException e) { logger.error("程序異常: ", e); } } } }
控制檯運行此程序,對帳文件生成數據庫
.........................apache
......................json
去這個路徑下看看,發現對帳文件已經生成了服務器
有bug--回頭看發現程序裏面須要一個回車符oracle
4.補充ide
這個程序重點:函數
1.要熟悉java基礎.(建文件 /往文件寫數據)
2.sql函數的運用.
公司數據庫用的是oracle數據庫. 下面是把生成對帳文件內容的sql 從程序裏摘出來.你們能夠學習下
select pay_id || '|' || substr(pay_time, 0, 8) || '|' || case when substr(to_char(pay_amount/10000,'fm99,999,990.0000'),-2) > 00 then to_char(pay_amount/10000,'fm99,999,990.0000') else to_char(pay_amount/10000,'fm99,999,990.00') end || '|' || case when stats in(3,5,9) then 0 else 1 end || '|' || 1 || '|' || user_id || '|' || 'SWShopMall' from payment_item where pay_time between '20190326000000' and '20190326235959' and gateway_id = '10' and channel_id = '1' union all select r.refund_id || '|' || substr(r.refund_time, 0, 8)|| '|' || case when substr(to_char(r.refund_amount/10000,'fm99,999,990.0000'),-2) > 00 then to_char(r.refund_amount/10000,'fm99,999,990.0000') else to_char(r.refund_amount/10000,'fm99,999,990.00') end || '|' || case r.stats when 1 then 0 when 2 then 1 else 1 end || '|' || 2 || '|' || p.user_id || '|' || 'SWShopMall' from refund_item r,payment_item p where r.pay_id = p.pay_id and r.refund_time between '20190326000000' and '20190326235959' and r.gateway_id = '10' and r.channel_id = '1'
在數據庫運行該sql, 這個就是對帳文件裏面放的內容. 已經用sql拼接好了.
多加思考,多加訓練.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~補充二~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
上面的sql太長了, 是怎麼要達到我想要的內容呢
1.先查出接口文檔中字段(對帳文件須要的字段).
標準的文件內容格式:
20160602|20190218|9.01|0|1|037894566|SWShopMal
2.而後再根據需求 改. 加函數/ 加判斷
eg:時間格式 / 金額顯示格式(保留幾位小數) / 只顯示渠道的支付記錄/ 等等