上一篇知识储备的文章。
https://blog.youkuaiyun.com/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做离线,实时处理,敬请期待。
你与我一同进步,成为那改变世界的人。