上一篇知識儲備的文章。
https://blog.csdn.net/qq_33792843/article/details/82735787
Scala項目代碼結構
關于代碼結構,我想說項目的主題部分吧。一步一步來。
因為簽署了隐私協定,是以具體需求不能透露,以及涉及到業務的圖檔、代碼都将被打上馬賽克。
首先來看看主體akka部分代碼。

以上為主題工程入口。
可以看到,在內建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應用完了,後續還會有更多的Java、python、scala應用,開發hadoop、spark做離線,實時處理,敬請期待。
你與我一同進步,成為那改變世界的人。