在grails中实现excel导入的有效方法

在grails中实现excel导入的有效方法,excel,grails,groovy,apache-poi,Excel,Grails,Groovy,Apache Poi,这段代码应该放在代码评审中,但我不会在那里得到快速的回答,那里只有两个groovy问题。 我有以下代码用于将数据从excel导入grails应用程序。问题是我没有在excel文件中测试>1000行,所以当我的客户端试图上传13k行时,我的应用程序冻结了。我已检查stacktrace.log应用程序是否正在生产中,但没有异常。系统管理员认为jvm内存不足。我们增加了堆内存的大小。然而,我想问,是否有更好的方法来实现这一点。我正在使用ApachePOI并在从excel读取每一行时创建域对象。之后,我

这段代码应该放在代码评审中,但我不会在那里得到快速的回答,那里只有两个groovy问题。 我有以下代码用于将数据从excel导入grails应用程序。问题是我没有在excel文件中测试>1000行,所以当我的客户端试图上传13k行时,我的应用程序冻结了。我已检查stacktrace.log应用程序是否正在生产中,但没有异常。系统管理员认为jvm内存不足。我们增加了堆内存的大小。然而,我想问,是否有更好的方法来实现这一点。我正在使用ApachePOI并在从excel读取每一行时创建域对象。之后,我将对象列表传递给控制器,控制器验证并将它们保存在数据库中。我是否应该告诉我的客户限制一次导入的项目数量?有没有更好的方法来编写此代码


使用插件将是一个更好的选择。
我使用这个插件-

使用插件将是一个更好的选择。
我使用这个插件-

Hibernate和GORM在处理批量导入时需要一些调整。两项建议:

遵循这里找到的技术:编写时考虑到MySQL,但是这些概念与任何RDBMS都相关

不要使用集合来映射Inventory和InventoryItem之间的关系。从Inventory中删除items集合,而是将Inventory字段添加到InventoryItem类中。Burt Beckwith在这里详细介绍了这一点:


在处理批量导入时,Hibernate和GORM需要一些调整。两项建议:

遵循这里找到的技术:编写时考虑到MySQL,但是这些概念与任何RDBMS都相关

不要使用集合来映射Inventory和InventoryItem之间的关系。从Inventory中删除items集合,而是将Inventory字段添加到InventoryItem类中。Burt Beckwith在这里详细介绍了这一点:


我有一些问题。这就是为什么我写我的。然而,您以前是否在大于13k行的大型数据集上使用过它?@unekwu不太可能。我不得不进口不超过几百件。你能报告这个问题吗我有一些问题。这就是为什么我写我的。然而,您以前是否在大于13k行的大型数据集上使用过它?@unekwu不太可能。我不得不进口不超过几百件。你能报告这个问题吗您认为使用GPAR并行实现它是一个好主意吗?这可能是有益的,取决于可用的CPU资源,但我不会从这里开始。我认为,在遵循上述建议后,您将看到显著的性能提升。您认为使用GPAR并行实现它是一个好主意吗?这可能是有益的,具体取决于可用的CPU资源,但我不会从这里开始。我认为在遵循上述建议后,您将看到显著的性能提升。
def importData(file, user){
    def rows = []
    def keywords = Keyword.list()
    int inventoryCount = Inventory.findAllByUser(user).size()

    def inventory = new Inventory(name:"Inventory ${inventoryCount +1}", user:user)

    Workbook workbook = WorkbookFactory.create(file)
    Sheet sheet = workbook.getSheetAt(0)

    int rowStart = 1;
    int rowEnd = sheet.getLastRowNum() + 1 ;
    for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
        Row r = sheet.getRow(rowNum);

        if(r != null && r?.getCell(0, Row.RETURN_BLANK_AS_NULL)!=null ){
            def rowData =[:]
            int lastColumn = 8;
            for (int cn = 0; cn < lastColumn; cn++) {
                Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
                if (c == null) {
                    return new ExcelFormatException("Empty cell not allowed",rowNum+1, cn+1)
                } else {

                    def field = properties[cn+1]
                    if(field.type==c.getCellType()){
                        if(c.getCellType()==text){

                            rowData<<[(field.name):c.getStringCellValue().toString()]
                        }else if(c.getCellType()==numeric){
                            if(field.name.equalsIgnoreCase("price") ){
                                rowData<<[(field.name):c.getNumericCellValue().toDouble()]
                            }else{
                                rowData<<[(field.name):c.getNumericCellValue().toInteger()]
                            }
                        }
                    }else{
                        return new ExcelFormatException("Invalid value found", rowNum+1, cn+1)
                    }
                }

            }

            def item = new InventoryItem(rowData)
            String keyword = retrieveKeyword(item.description, keywords)
            String criticality = keyword?"Critical":"Not known"
            int proposedMin = getProposedMin(item.usagePerYear)
            int proposedMax = getProposedMax(proposedMin, item.price, item.usagePerYear, item?.currentMin)
            String inventoryLevel = getInventoryLevel(item.usagePerYear, item.quantity, proposedMin, item.currentMin) 

            item.proposedMin = proposedMin
            item.proposedMax = proposedMax
            item.inventoryLevel = inventoryLevel
            item.keyword = keyword 
            item.criticality = criticality

            inventory.addToItems(item)
        }

    }

    return inventory
}
def retrieveKeyword(desc, keywords){
    def keyword
    for (key in keywords){
        if(desc.toLowerCase().contains(key.name.toLowerCase())){
            keyword = key.name
            break
        }
    }
    return keyword
}
int getProposedMin(int usage){
    (int) ((((usage/12)/30) *7) + 1)
}


int getProposedMax(int pmin, double price, int usage, int cmin){
    int c = price == 0? 1: ((Math.sqrt((24 * (usage/12)*5)/(0.15*price))) + (pmin - 1))
    if(cmin >= c){
        return pmin
    }
    return c
}

String getInventoryLevel(int usage, int qty, int proposedMin, int currentMin){
    if(qty != 0){
        double c = usage/qty
        if(usage==0)
            return "Excess"
        if(c<0.75){
            return "Inactive"
        }else if(proposedMin<currentMin){
            return "Excess"
        }else if(c>=0.75){
            return "Active"
        }
    }else if(usage==0 && qty == 0){
        return "Not used"
    }else if(usage>3 && qty ==0){
        return "Insufficient"
    }else if(proposedMin > currentMin){
        return "Insufficient"
    }

}
def importData(){
    if(request.post){
        def file = request.getFile("excelFile")

        //validate file
        def file_types = ["application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]

        if(!file_types.contains(file.getContentType())){
            render view:"importData", model:[error:"Invalid File type"]
            return
        }

        def inv = excelService.importData(file.getInputStream(),User.get(principal.id))
        if(inv){
            if(inv instanceof ExcelFormatException){
                def err = (ExcelFormatException) inv
                render view:"importData", model:[error:err.message +". Error occurred at: Row: "+err.row+" Col: "+err.col]
                return
            }else{
                render view:"viewData", model:[inventory:inv]
                return
            }
        }
    }


}