TTInfoDetailServiceImpl.java 9.7 KB
package com.bsth.service.schedule;

import com.bsth.entity.schedule.TTInfoDetail;
import com.bsth.repository.schedule.TTInfoDetailRepository;
import com.bsth.service.impl.BaseServiceImpl;
import com.bsth.service.schedule.utils.DataImportExportService;
import com.bsth.service.schedule.utils.DataToolsProperties;
import jxl.Sheet;
import jxl.Workbook;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.pentaho.di.core.logging.LogLevel;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by xu on 16/7/2.
 */
@Service
@EnableConfigurationProperties(DataToolsProperties.class)
public class TTInfoDetailServiceImpl extends BaseServiceImpl<TTInfoDetail, Long> implements TTInfoDetailService {
    @Autowired
    private DataImportExportService dataImportExportService;
    @Autowired
    private DataToolsProperties dataToolsProperties;
    @Autowired
    private TTInfoDetailRepository ttInfoDetailRepository;

    /**
     * 发车信息内部类。
     */
    public static class FcInfo {
        /** 时刻明细id */
        private Long ttdid;
        /** 发车时间 */
        private String fcsj;
        /** 班次类型 */
        private String bc_type;

        public FcInfo() {
        }

        public FcInfo(Long ttdid, String bc_type, String fcsj) {
            this.ttdid = ttdid;
            this.bc_type = bc_type;
            this.fcsj = fcsj;
        }

        public Long getTtdid() {
            return ttdid;
        }

        public void setTtdid(Long ttdid) {
            this.ttdid = ttdid;
        }

        public String getFcsj() {
            return fcsj;
        }

        public void setFcsj(String fcsj) {
            this.fcsj = fcsj;
        }

        public String getBc_type() {
            return bc_type;
        }

        public void setBc_type(String bc_type) {
            this.bc_type = bc_type;
        }
    }

    /**
     * 时刻表编辑用的返回数据。
     */
    public static class EditInfo {
        /** 标题数据 */
        private List<String> header = new ArrayList<>();
        /** 内容数据 */
        private List<List<FcInfo>> contents = new ArrayList<>();

        public List<String> getHeader() {
            return header;
        }

        public void setHeader(List<String> header) {
            this.header = header;
        }

        public List<List<FcInfo>> getContents() {
            return contents;
        }

        public void setContents(List<List<FcInfo>> contents) {
            this.contents = contents;
        }
    }

    /**
     * 获取待编辑的数据。
     * @param xlid 线路id
     * @param ttid 时刻表id
     * @return
     */
    public EditInfo getEditInfo(Integer xlid, Long ttid) throws Exception {
        // 1、使用ktr转换获取输出文件
        // 1.1、获取转换用ktr
        File ktrFile = new File(this.getClass().getResource(
                dataToolsProperties.getTtinfodetailForeditktr()).toURI());
        TransMeta transMeta = new TransMeta(ktrFile.getAbsolutePath());
        Trans trans = new Trans(transMeta);
        trans.setLogLevel(LogLevel.DEBUG);
        // 1.2、设定命名参数,TODO:之后还要添加其他命名参数
        String outputFilePath = "ttinfodetail_" + new DateTime().toString("yyyy-MM-dd_HH-mm-ss");
        trans.setParameterValue("tempfilepath", dataToolsProperties.getTransTempdir() + File.separator + outputFilePath); // 数据输出文件路径
        trans.setParameterValue("xlid", String.valueOf(xlid));
        trans.setParameterValue("ttid", String.valueOf(ttid));
        // 1.3、执行转换
        trans.execute(null);
        // 1.4、等待转换结束
        trans.waitUntilFinished();

        // 1.5、判定ktr错误数,注意这种错误代表部分数据错误,不会终止转换执行,一般设计ktr的时候,会有错误输出文件,TODO:以后考虑使用日志实时输出
        if (trans.getErrors() > 0) {
            throw new Exception("转换数据部分错误,请查看相关错误输出文件!");
        }

        // 1.6、获取最大的发车数,用于输出数据的数量
        Long maxfcno = ttInfoDetailRepository.findMaxFcno(xlid, ttid);
        if (maxfcno == null)
            return new EditInfo();

        // 2、读取ktr生成的excel数据,组织编辑用数据返回
        // 2-1、读取Excel文件
        Workbook book = Workbook.getWorkbook(new File(dataToolsProperties.getTransTempdir() +
                File.separator + outputFilePath + ".xls"));
        Sheet sheet = book.getSheet(0);
        EditInfo editInfo = new EditInfo();
        // 2-2、处理数据
        String[] headarrays = new String[maxfcno.intValue() + 1];
        headarrays[0] = "路牌";
        for (int r = 1; r < sheet.getRows(); r++) {
            List<FcInfo> fcInfos = new ArrayList<>();
            // 每行第一列都是路牌
            fcInfos.add(new FcInfo(null, null, sheet.getCell(0, r).getContents())); // 用fcsj放置路牌显示
            for (int c = 1; c <= maxfcno * 4; ) {
                Long ttdid = StringUtils.isEmpty(sheet.getCell(c, r).getContents()) ? null :
                        Long.valueOf(sheet.getCell(c, r).getContents());
                String fcsj = sheet.getCell(c + 1, r).getContents();
                String fzdname = sheet.getCell(c + 2, r).getContents();
                String bctype = sheet.getCell(c + 3, r).getContents();

                FcInfo fcInfo = new FcInfo(ttdid, bctype, fcsj);

                if (StringUtils.isNotEmpty(fzdname  ))
                    headarrays[(int)(c / 4) + 1] = fzdname;
                fcInfos.add(fcInfo);

                c += 4;
            }
            editInfo.getContents().add(fcInfos);
        }
        editInfo.getHeader().addAll(Arrays.asList(headarrays));

        return editInfo;
    }

    /**
     * 上传并导入数据,和DataImportExportService的同名方法有差别。
     * @param datafile form上传文件
     * @param xlmc 线路名称
     * @param ttinfoname 时刻表名字
     * @param tccname 停车场名字
     * @throws Exception
     */
    public void fileDataImport(MultipartFile datafile,
                               String xlmc,
                               String ttinfoname,
                               String tccname) throws Exception {
        // 1、上传数据文件
        File uploadFile = dataImportExportService.uploadFile(datafile);

        System.out.println("线路名称:" + xlmc);
        System.out.println("时刻表名称:" + ttinfoname);
        System.out.println("停车场名字:" + tccname);
        System.out.println("时刻表明细上传文件:" + uploadFile);

        // 2、jexcelapi读取excel文件
        Workbook book = Workbook.getWorkbook(uploadFile);
        Sheet sheet = book.getSheet(0);
        List<String> columnames = new ArrayList<>();
        for (int i = 0; i < sheet.getColumns(); i++) { // 获取第一行,数据,作为列名
            columnames.add(sheet.getCell(i, 0).getContents());
        }

        System.out.println("表头1:" + StringUtils.join(columnames.toArray(), ","));

        // 2、使用kettle运行封装数据导入逻辑的ktr转换文件
        // 2.1、初始化kettle(组件初始化已经做了)
        // 2.2、创建转换元数据,转换
        File ktrFile = new File(this.getClass().getResource(
                dataToolsProperties.getTtinfodetailMetadatainputktr()).toURI());
        File ktrFile2 = new File(this.getClass().getResource(
                dataToolsProperties.getTtinfodetailDatainputktr()).toURI());
        TransMeta transMeta = new TransMeta(ktrFile.getAbsolutePath());
        Trans trans = new Trans(transMeta);
        // 2.3、设定命名参数,用于指定数据文件,注意每个ktr必须都有以下指定的命名参数
        trans.setParameterValue("injectktrfile", ktrFile2.getAbsolutePath()); // 注入元数据的ktr文件
        trans.setParameterValue("filepath", uploadFile.getAbsolutePath()); // 指定导入数据文件的位置
        trans.setParameterValue("erroroutputdir", dataToolsProperties.getTransErrordir()); // ktr转换错误输出目录
        trans.setParameterValue("xlname", xlmc); // 线路名称
        trans.setParameterValue("ttinfoname", ttinfoname); // 时刻表名称
        trans.setParameterValue("tccname", tccname); // 停车场名字
        trans.setParameterValue("excelfieldnames", StringUtils.join(columnames.toArray(), ",")); // 时刻表excel输入字段名,以逗号连接
        columnames.remove(0);
        trans.setParameterValue("normalizefieldnames", StringUtils.join(columnames.toArray(), ",")); // 数据范式化字段名,以逗号连接

        // TODO:可以考虑设定日志输出
        // 2.4、执行转换
        trans.execute(null);
        // 2.5、等待转换结束
        trans.waitUntilFinished();

        // 3、判定ktr错误数,注意这种错误代表部分数据错误,不会终止转换执行,一般设计ktr的时候,会有错误输出文件,TODO:以后考虑使用日志实时输出
        if (trans.getErrors() > 0) {
            throw new Exception("转换数据部分错误,请查看相关错误输出文件!");
        }
    }
}