天天看點

scala應用開發

上一篇知識儲備的文章。

https://blog.csdn.net/qq_33792843/article/details/82735787

Scala項目代碼結構

關于代碼結構,我想說項目的主題部分吧。一步一步來。

因為簽署了隐私協定,是以具體需求不能透露,以及涉及到業務的圖檔、代碼都将被打上馬賽克。

首先來看看主體akka部分代碼。

scala應用開發

以上為主題工程入口。

可以看到,在內建App類後,case Class JobTake就可以比對到JobTaker中的receive方法。開始doStart

doStart為主要代碼入口,但是在此之前,我們需要擷取目标檔案夾下檔案的清單,來看該工具類。

package utils

import java.io.File

import common.Constants
import org.slf4j.LoggerFactory
import transform.AkkaActor

import scala.collection.mutable.ListBuffer


/**
  * 檔案
  * @author shouzhuang.li on 2018/09/11
  */
class FileUtils {

  val logger = LoggerFactory.getLogger(AkkaActor.getClass.getName)

  /**
    * 擷取指定路徑下檔案
    * @return
    */
  def getFileList():ListBuffer[File]= {
    val nowPath = System.getProperty(Constants.USER_IDR) //user.dir指定了目前的路徑
    val list = subdir(new File(nowPath + Constants.INPUT_PATH))
    if(null == list) return null else if (list.isEmpty) {new MsgBoxUtils().sendWrongMsg(Constants.LOG_ERROR + "輸入檔案内沒有可用檔案,請檢查.");return null}
//    list.foreach{x=>logger.info("即将處理檔案 : {} ",x.getAbsolutePath)}
    logger.info("即将處理檔案 : {} ",list.mkString("[",", ","]"))

    list
  }


  /**
    * 擷取指定目錄下所有檔案,過濾檔案夾
    * @param dir
    * @return
    */
  def subdir(dir:File):  ListBuffer[File]={
    val listFiles:Array[File]=dir.listFiles()
    val list = new ListBuffer[File]
    try{
      for (file <- listFiles if file.isFile;if file.getName.contains(Constants.SALARY_EXCEL_FLAG)) list.append(file)
    }catch {
      case e:NullPointerException=>new MsgBoxUtils().sendWrongMsg(Constants.LOG_ERROR + " 輸入檔案目錄不存在,請仔細檢查!");return null
      case e:Exception=> new MsgBoxUtils().sendWrongMsg(e.getMessage);;return null
    }
    list
  }

}
           

在剛才的akkaActor擷取list後,如果也沒有異常,就會進入具體方法。

代碼邏輯如下。

package transform

import java.io.File

import common.Constants
import org.slf4j.LoggerFactory
import utils.{MsgBoxUtils, TimeUtils}

class HandlerJob {
  val logger = LoggerFactory.getLogger(AkkaActor.getClass.getName)


  /**
    * 開啟線程run方法
    * @param file
    */
  def doStart(file: File): Unit = {
    logger.info(Constants.LOG_START_FLAG ,file.getName)

    /* 1.校驗所有sheet完備性 */
    logger.info(Constants.LOG_STEP1_FLAG)
    val validXlsx = new ValidXlsx()
    val validFlagString = validXlsx.reedXlsxAndValid(file.getPath)
    if (validFlagString.length!=Constants.ZERO_INDEX) {new MsgBoxUtils().sendWrongMsg(validFlagString);return }


    logger.info(Constants.LOG_STEP2_FLAG)
    val getExcelData = new GetExcelData()
    val allPersonMap = getExcelData.getExcelDataMethod(file.getPath)
    if(null == allPersonMap || allPersonMap.isEmpty){ new MsgBoxUtils().sendWrongMsg("解析内容為空,請檢查輸入内容.");return }


    logger.info(Constants.LOG_STEP3_FLAG)
    val company = new CombineDeptAndCom().combineDeptsAndCom(allPersonMap)


    logger.info(Constants.LOG_STEP4_FLAG)
    new Calculate().calculate(company)


    try{
      logger.info(Constants.LOG_STEP5_FLAG)
      val outputPath = file.getParent.replace(Constants.SALARY_FILE_INPUT, Constants.SALARY_FILE_OUTPUT)
      logger.info(Constants.OUTPUT_FILEPATH ,outputPath)
      val filenameUnFilter = file.getName.replace(".xlsx", "")
      val filename = Constants.LOG_FILENAME_STRING.format(filenameUnFilter, (new TimeUtils).getTimestamps())
      logger.info(Constants.LOG_OUTPUT_STRING ,filename)
      new WriteExcel().writeExcel(company, outputPath, filename)

    }catch {
      case e:Exception=>{
        logger.error(Constants.LOG_ERROR+e.getMessage)
        new MsgBoxUtils().sendWrongMsg(e.getMessage)
      }
    }

    logger.info(Constants.LOG_END)
  }
}
           

第一步,校驗excel的完整性。

package transform

import java.io.{FileInputStream, FileNotFoundException}

import common.Constants
import org.apache.poi.ss.usermodel.{Sheet, Workbook}
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.slf4j.LoggerFactory
import utils.CommonUtils

/**
  * 校驗excel子產品
  *
  * @author shouzhuang.li on 2018/09/11
  */
class ValidXlsx {

  val logger = LoggerFactory.getLogger(AkkaActor.getClass.getName)

  /**
    * 讀取Excel,相容 Excel 2003/2007/2010
    *
    * @param path
    * @return List<String>
    */
  def reedXlsxAndValid(path: String): String = {
    try{val is = new FileInputStream(path)

    if (null == is) return Constants.ERROR_FLAG


    val workbook = new XSSFWorkbook(is)
    if (null == workbook) return Constants.ERROR_FLAG

    /* 輸入檔案總校驗 */
    val validExcel = doVilidExcel(workbook)
    if (validExcel == null || validExcel.length > Constants.ZERO_INDEX) return validExcel

    //校驗sheet1表頭
    val sheet0 = workbook.getSheetAt(Constants.ZERO_INDEX)
    val sheet0StandardHead = Constants.SHEET0_LIST_STANDARD_STR.split(Constants.STRING_SPLITION).size
    val excelHeadSheet1 = validExcelHead(sheet0,sheet0StandardHead, Constants.SHEET0_LIST_STANDARD_STR)
    if(excelHeadSheet1.length != Constants.ZERO_INDEX) return excelHeadSheet1

    //校驗sheet2表頭
    val sheet1 = workbook.getSheetAt(Constants.ONE_INDEX)
    val sheet1StandardHead = Constants.SHEET1_LIST_STANDARD_STR.split(Constants.STRING_SPLITION).size
    val excelHeadSheet2 = validExcelHead(sheet1,sheet1StandardHead, Constants.SHEET1_LIST_STANDARD_STR)
    if(excelHeadSheet2.length != Constants.ZERO_INDEX) return excelHeadSheet2

    }catch {
      case e :FileNotFoundException=> return e.getMessage
    }

    ""
  }


  /**
    * 校驗表頭字段是否齊整
    *
    * @param sheet
    * @return
    */
  def validExcelHead(sheet: Sheet, column: Int, listStand: String): String = {
    val sheetListStand = listStand.split(Constants.STRING_SPLITION, -1).toList
    val row = sheet.getRow(Constants.ZERO_INDEX)
    //總列數
    val columnNum = row.getPhysicalNumberOfCells
    if (columnNum < column) return "該sheet : %s  内列字段不夠,缺少必要字段,請檢查!".format(sheet.getSheetName)


    //為了擷取标準字段以及所給excel字段是否涵蓋
    var listExcelString = ""
    for (i <- 0 until columnNum) {
      val cellValue = new CommonUtils().getCellValue(row.getCell(i))
      if (columnNum - 1 == i) listExcelString = listExcelString + cellValue else listExcelString = listExcelString + cellValue + Constants.STRING_SPLITION
    }
    val listExcel = listExcelString.split(Constants.STRING_SPLITION, -1).toList
    if (listExcel.isEmpty) return "該sheet : %s  内列字段不夠,缺少必要字段,請檢查!".format(sheet.getSheetName)  //如果excel中沒有表頭資料


    //這裡是為了校驗兩個list的自己關系
    val initBoolean = list1containslist2(listExcel, sheetListStand)
    if (!initBoolean) {
      val excelHeadName = findList1containslist2(listExcel, sheetListStand)
      if (null != excelHeadName && !"".equalsIgnoreCase(excelHeadName)) return sheet.getSheetName + Constants.SHORT_OF_COLUMNNAME + sheet.getSheetName + " : " + excelHeadName
      return Constants.ERROR_FLAG
    }

    ""
  }


  /**
    * 為了校驗:
    * 1.workbook不為空
    * 2.sheet不為空
    * 3.sheet名稱
    * 4.row記錄數是否為空
    *
    * @param workbook
    * @return
    */
  def doVilidExcel(workbook: Workbook): String = {
    var message = validSheet(Constants.ZERO_INDEX, workbook)
    if(message.length > Constants.ZERO_INDEX) return message
    message = validSheet(Constants.ONE_INDEX, workbook)
    message
  }


  /**
    * 根據具體的sheet類型,處理其中校驗
    * @param sheetType
    * @param workbook
    * @param m
    * @return
    */
  def validSheet(sheetType: Int, workbook: Workbook): String = {
    var message,sheetName = ""
    if (Constants.ZERO_INDEX == sheetType) sheetName = Constants.SHEET1_NAME_STRING else sheetName = Constants.SHEET2_NAME_STRING

    if(workbook.getNumberOfSheets <2 ) return "該excel數小于2,請檢查!"
    val sheet = workbook.getSheetAt(sheetType) //擷取sheet

    if (!sheetName.equalsIgnoreCase(sheet.getSheetName)) {
      message += sheetName + Constants.SHEET_NAME_UNVILID
    } else {
      //擷取總行數
      if (sheet.getPhysicalNumberOfRows() < 2)  message += sheetName + Constants.SHEET_DATA_EMPTY
    }
    message
  }


  /**
    * 判斷是否标準集合在給入集合裡面沒有
    * 子集判斷方法
    *
    * @param list1
    * @param list2
    * @return
    */
  def list1containslist2(list1: Seq[String], list2: Seq[String]): Boolean = {
    var trueOrFalse = true
    list2.foreach { x =>  if (!list1.contains(x)) trueOrFalse = false}
    trueOrFalse
  }


  /**
    * 該方法用于傳回是哪些字段沒有
    *
    * @param list1
    * @param list2
    * @return
    */
  def findList1containslist2(list1: Seq[String], list2: Seq[String]): String = {
    var unHaveExcelHead = ""
    list2.foreach { x =>  if (!list1.contains(x)) unHaveExcelHead = unHaveExcelHead + x + " "  }
    unHaveExcelHead
  }


}
           

校驗完了之後,來到最精彩的建構環節。

scala應用開發

然後是輸出了。

scala應用開發

可以看到代碼非常的簡潔,沒有任何的拖泥帶水。

scala應用開發

總體感覺非常優雅,好了。我的第一個即将投産的scala應用完了,後續還會有更多的Java、python、scala應用,開發hadoop、spark做離線,實時處理,敬請期待。

你與我一同進步,成為那改變世界的人。