zoukankan      html  css  js  c++  java
  • 生成对账文件_实现

    我方每天在服务器上生成对账文件, 第三方来取.

     

    1.需求:

    2.思路

    生成对账文件的程序是一个定时任务: 凌晨2点运行此程序
    1.设置好 对账文件存放的路径(工程部门给外部平台一个地址,他们自己过来取)
    2.在这个路径下新建一个文件 .  格式是.txt
    3. 连接数据库,查询支付表(可能多表查询), 查询前一天的数据. 按照接口文档需要的字段  查询到对应字段 ,并拼接
    4.把查出来的数据(eg:101486120190325083431|20190325|10.00|0|1|0042930413|SWShopMall),  放到  .txt文件里
     
     
     
    3.代码
    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 = "
    
    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 || '|' || '"
                                    + getGconfigure().getFileConfigure().getMerchantCode() + "'
    "
                                    + "from payment_item where pay_time between '" + beginTime + "' and '" + endTime
                                    + "'  and  gateway_id = '" + getGconfigure().getFileConfigure().getGateway_id()
                                    + "'  and channel_id = '" + getGconfigure().getFileConfigure().getChannel_id() + "' 
    "
                                    + "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 || '|' || '"
                                    + getGconfigure().getFileConfigure().getMerchantCode() + "'
    "
                                    + "from refund_item r,payment_item p   
    "
                                    + "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() + "'
    ";
                            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) + "
    ").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);
                }
            }
        }
    }

    控制台运行此程序,对账文件生成

    .........................

    ......................

     去这个路径下看看,发现对账文件已经生成了

    有bug--回头看发现程序里面需要一个回车符

    4.补充

    这个程序重点:

    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:时间格式 /   金额显示格式(保留几位小数) /  只显示渠道的支付记录/   等等

  • 相关阅读:
    Android 开发笔记___存储方式__共享参数__sharedprefences
    Android 开发笔记___登陆app
    Android 开发笔记___alertDialog
    Android 开发笔记___Intent的使用
    Android 开发笔记___Activity的生命周期
    Android 开发笔记___AutoComplateTextView__自动完成文本框
    单例模式
    程序设计模式六大原则--个人理解
    简单理解适配器模式
    呱呱乐
  • 原文地址:https://www.cnblogs.com/PinkPink/p/10607853.html
Copyright © 2011-2022 走看看