关于多条件检索和数据导出word表格及合并

1.项目搭建

1.1 框架生成

采用的是renren-fast的后台脚手架框架,是人人开源社区采用Spring、MyBatis、Shiro编写的;

1.1.1 建立数据库表

​ 搭建完成后,先需要建立好数据库的所有数据表,以便代码生成器生成

1.1.2 代码生成器

​ 随后利用代码生成器生成相应实体的controller,service,dao,entity实体以及mapper中的xml映射文件。

1.1.3 业务层修改

​ 基本的增删改查具有了,接下来就根据实际的业务需求修改代码(主要针对业务逻辑层)

2.列表查询(检索)

2.1 内容梳理

表内容组成

​ 产品配方主表 P:(物料suppliesCode,原膜memType,产品名称productName,id)

​ 字表 S:配方子表(颜色color,对应区域fileUrl,header_id)

​ 字表 S2:配色明细(厂家inkFactor,油墨inkName,型号model,配比propertion,header_id)

2.1.1 建立关系

​ 建立好主表和相应字表间的关系,字表作为成员变量存放在主表中

2.1.2 处理

​ 点击进入详情,传入主表id,找到对应的S表,再利用S表id找到S2表,逐层封装,最后返回给前端

​ 条件搜索,能够确定唯一的产品

2.2 思路解决

关于多条件检索和数据导出word表格及合并_第1张图片

​ 因为最后的配方列表需要将s2表的内容组装起来,所以先将产品名称-p表颜色-s表对应区域-s表进行表连接,然后再将s2表中的数据拼接为配方需要的字符串信息,再将两张表拼接起来。

2.2.2 sql语句
-- 先尝试将s2的信息拼接成功,成一张新表
SELECT
	header_id,
	GROUP_CONCAT( model, '(', ink_name, '):', proportion, '%' ) AS info 
FROM
	bo_packprint_recp_s2 
GROUP BY
	header_id
	
-- 再将新表和产品、颜色、对应区域部分进行拼接,即可达到上图的检索效果
SELECT
p.product_name,
s.color,
s.file_url,
pf.info
FROM
bo_packprint_recp_p AS p
LEFT JOIN bo_packprint_recp_s AS s ON p.id = s.header_id
LEFT JOIN bo_packprint_recp_s2 AS s2 ON s.id = s2.header_id
LEFT JOIN (
SELECT
	header_id,
	GROUP_CONCAT( model, '(', ink_name, '):', proportion, '%' ) AS info 
FROM
	bo_packprint_recp_s2 
GROUP BY
	header_id) AS pf ON s.id = pf.header_id
WHERE
s.color LIKE '%蓝%' AND
s2.ink_name LIKE '%原蓝%' AND
p.product_name LIKE '%苏打水%' AND
p.mem_type LIKE '%透明膜%'

3.word表格的文档导出功能

3.1 导出要求梳理

效果图中涉及到数据的替换,动态插入数据和图片,根据要求合并单元格。

3.1.1 绘制模板

​ 首先,进行模板的绘制,将固定替换的位置标注出来。

关于多条件检索和数据导出word表格及合并_第2张图片

3.1.2 替换表格里固定位置的变量

​ 将表格的内容进行遍历,如果表格单元格中的内容包含${},则执行替换的操作

3.1.3 进行动态数据的插入

​ 根据实际数据个数,增加模板行数。

​ 插入数据,图片转换为字节输入流保存,先插入数据,再进行判断合并。

动态添加数据和图片,并进行合并单元格操作的代码部分:

模板:

 private static void insertTable(XWPFTable table, List<String[]> tableList, Integer matrListSize) {
        //创建行,根据需要插入的数据添加新行,不处理表头
        for (int i = 0; i < tableList.size(); i++) {
            setTableStyle(table);
            XWPFTableRow row = table.createRow();
            for (int k = 1; k < tableList.get(0).length; k++) {
                row.createCell();//根据String数组第一条数据的长度动态创建列
            }
        }
        //遍历表格插入数据
        List<XWPFTableRow> rows = table.getRows();
        int length = table.getRows().size();
        for (int i = 3; i < length; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                if (j == 2) {
                    List<XWPFParagraph> paragraphs = cell.getParagraphs();
                    XWPFParagraph newPara = paragraphs.get(0);
                    XWPFRun imageCellRunn = newPara.createRun();
                    try {
                        String fileName = tableList.get(i - 3)[j];
                        File file = new File(fileName);
                        FileInputStream is = new FileInputStream(file);
                        imageCellRunn.addPicture(is, getPictureType(fileName), file.getName(), Units.toEMU(70), Units.toEMU(30));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                    CTTc cttc = cell.getCTTc();
                    CTP ctp = cttc.getPList().get(0);
                    CTPPr ctpPr = ctp.getPPr();
                    if (ctpPr == null) {
                        ctpPr = ctp.addNewPPr();
                    }
                    CTJc ctJc = ctpPr.getJc();
                    if (ctJc == null) {
                        ctJc = ctpPr.addNewJc();
                    }
                    ctJc.setVal(STJc.CENTER);
                    String s = tableList.get(i - 3)[j];
                    cell.setText(s);
                }
            }

        }
        //合并单元格(对每一行的进行遍历,根据相同的条件进行合并)
        for (int n = matrListSize; n < tableList.size(); ) {
            //获取到tableList里面的序号,如果序号相同就可以进行合并
            String[] strings = tableList.get(n);
            String index = strings[0];
            // 定义可以合并的单元行数
            int mergeNumber = 0;
            for (String[] strings1 : tableList) {
                String s = strings1[0];
                if (index.equals(s)) {
                    mergeNumber += 1;
                }
            }
            // col:指定列   fromRow:从第几行开始    toRow:从第几行结束
            mergeCellsVertically(table, 0, 3 + n, 3 + n + mergeNumber - 1);
            mergeCellsVertically(table, 1, 3 + n, 3 + n + mergeNumber - 1);
            mergeCellsVertically(table, 2, 3 + n, 3 + n + mergeNumber - 1);
            n = n + mergeNumber;
        }
    }

效果图:
关于多条件检索和数据导出word表格及合并_第3张图片NI~1\AppData\Local\Temp\1591692057388.png)]

4.总结点

4.1 关于遍历中的遇到的问题

****

for: 最原始的循环方式,基于索引来实现;

​ 它的内容垃圾比foreach少,在遍历的过程中能对元素本身进行增删改的操作。

foreach:实现便捷,基于迭代器实现(实现Iterator集合类 ),能快速循环取出元素;

​ 由于底层实现原理导致不能在遍历的过程中操作元素(增删改),否则会抛出ConcurrentModificationException的异常,但可以对元素的已有属性进行更改;

​ 其中有两种情况可以在foreach中实现部分修改(自己操作过),在try…catch的情况下可以进行增删的操作,有结果但也报错;除此之外,没有catch的情况下删除需要保证元素只有两个,否则报错(没意义…哈哈)

4.2 通常使用的注解的作用

@ExplicitConstraint注解

​ 这各注解是一种数组方式的下拉框约束,(source={“aa”,“bb”})指定该注解修饰的字段在导出excel后能进行下拉框内容的选择。

@Api开头的注解作用

​ 通常是用做接口文档Swagger的生成,在控制层,方法,实体类上添加相应注解完成接口文档的各个部分:

@Api(tags = "产品配方主表")		//  作用在类上,说明具体针对哪个实体进行操作
@ApiOperation("查询/新增/删除产品配方主表")  	//  作用在方法上,具体说明方法的作用
@ApiImplicitParams({			//	执行方法时需要的多个参数说明(名称,含义,参数作用,数据类型)
      @ApiImplicitParam(name = "memType", value = "原膜类型", paramType = "query", dataType = "String"),					
      @ApiImplicitParam(name = "suppliesCode", value = "物料代码", paramType = "query", dataType = "String")
    })
@ApiModel(value="产品配方主表")		//	说明实体类的含义,作用在具体的实体上面
@ApiModelProperty(value = "原膜类型")	//	作用在实体类的属性上,说明实体的属性代表含义

//   其他常用注释
@Excel  	//  报表技术常用的一种注释,用于导出表格(创建人,id,更新时间和更新人的id不要加注释!!!)
@ExplicitConstraint(source = {"PVC","PET透明膜","PET白膜","BOPP","珠光膜","PE"})
    		//  在导出excel表格后,要求能在该字段下进行多选操作,则需要该注释,source里放入多选项。
@TableId	//  修饰主键id
@TableName("bo_packprint_recp_p")	//	对应的数据库中的表
@TableField("order_id")				//	表中的字段和实际使用的字段(orderId)是不一致的

4.3 数据类型和方法的使用

1、BigDecimal数据类型的特性?

​ 是用于高精度计算的数据类型,有两类:BigInteger(针对大整数的处理类)和BigDecimal(针对大小数的处理类),他们创建的是对象,不能用普通的运算符计算,需调用对应的方法,方法的参数也必须一致。

:add :subtract :multiply :divide

推荐初始化时参数string,保证精度。BigDecimal decimal = new BigDecimal(“100”)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LisGxpyS-1591749647656)(C:\Users\ADMINI~1\AppData\Local\Temp\1591020963111.png)]

2、==和equals, compareTo的使用?

	== 比较的是值是否相等,对于基本类型数据的变量,则直接比较值是否相等;对引用类型的变量则比较指向对象的地址。

	equals 方法是不能作用于基本数据类型的变量的,equals方法继承自objec类,比较的是否为统一对象,没有重写的情况下比较的是引用类型的变量所指向的地址;但是String、Date类对equals方法重写,所以比较的是内容。

	compareTo:用于对象的比较和字符串的比较,大于比较对象则返回正数,小于返回负数,等于返回0;

4.4 获得相应的路径

获得文件路径:this.getClass().getClassLoader().getResource("")

this.getClass().getClassLoader().getResource("").getPath()  
    // 获取src资源文件编译后的路径(即classes路径) 
    getClass():获得当前对象所属的Class对象
    getClassLoader():获得Class对象的类加载器
   	// 输出:  /D:/06-hs/packprint/target/classes/

4.5、在lambda表达式中关于变量的声明和使用?

	lambda表达式不能访问非final修饰的局部变量,因为实例变量存在堆中,而局部变量存放在栈上,lambda表达是在另外的线程上进行执行的,所以当该线程访问局部变量的时候,该局部变量可能已经销毁了.
	final类型的局部变量则是作为原变量的拷贝副本来使用。
	jdk8中不需要显示的声明,在表达式(匿名类)中访问了就会强制加上final属性,后面就无法进行赋值等修改操作了;其中实例和静态变量是不受限制的。

4.6、代码管理工具的使用?

​ pull:将服务器上的代码拉取到本地仓库,每次推送代码前拉取一次代码,保证代码是最新的。

​ commit:把修改好的代码提交到本地仓库,在此之前还有个add添加操作也就是添加到暂存区。

​ push:将本地仓库的代码接着推送到服务器上面,也就是主(master)从分支上面。

4.6、代码管理工具的使用?

​ pull:将服务器上的代码拉取到本地仓库,每次推送代码前拉取一次代码,保证代码是最新的。

​ commit:把修改好的代码提交到本地仓库,在此之前还有个add添加操作也就是添加到暂存区。

​ push:将本地仓库的代码接着推送到服务器上面,也就是主(master)从分支上面。

你可能感兴趣的:(java,ssm,SQL)