Java操作表格数据

今日内容

  • 出货表的导入导出
  • 使用模板导出出货表
  • 百万数据报表技术
  • EasyPOI
  • 定时任务

第一章 出货表导出(练习)

1. 跳转出货表页面

ContractController中添加下面方法

/**
	 * 跳转出货表页面
	 */
	@RequestMapping(value = "/print", name = "跳转出货表页面")
	public String print() {
		return "/cargo/print/contract-print";
	}

2. 需求分析

2.1 需求说明

要求可以按照按照条件导出指定月份的出货表

 

 

2.2 sql语句分析

SELECT  c.`custom_name` AS customName,
	c.`contract_no` AS contractNo,
	cp.`product_no` AS productNo,
	cp.`cnumber` AS cnumber,
	cp.`factory_name` AS factoryName,
	c.`delivery_period` AS deliveryPeriod,
	c.`ship_time` AS shipTime,
	c.`trade_terms` AS tradeTerms 

	FROM `co_contract` c 
	JOIN `co_contract_product` cp ON c.id = cp.`contract_id`
	WHERE DATE_FORMAT(c.`ship_time`,"%Y-%m") = '2015-01' 
	AND c.`company_id` = '1'

3. 基础代码

3.1 ContractProductVo 实体类

导入 :export_domain\src\main\java\com\itheima\vo\ContractProductVo.java

@Data
public class ContractProductVo implements Serializable {
    private String customName;    //客户名称
    private String contractNo;    //合同号,订单号
    private String productNo;     //货号
    private Integer cnumber;      //数量
    private String factoryName;       //厂家名称
    private Date deliveryPeriod;   //交货期限
    private Date shipTime;       //船期
    private String tradeTerms;    //贸易条款
}

3.2 DownloadUtil

导入工具类 export_commons\src\main\java\com\itheima\utils\DownloadUtil.java

package com.itheima.utils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class DownloadUtil {

    /**
     * @param filePath   要下载的文件路径
     * @param returnName 返回的文件名
     * @param response   HttpServletResponse
     * @param delFlag    是否删除文件
     */
    protected static void download(String filePath, String returnName, HttpServletResponse response, boolean delFlag) {
        prototypeDownload(new File(filePath), returnName, response, delFlag);
    }


    /**
     * @param file       要下载的文件
     * @param returnName 返回的文件名
     * @param response   HttpServletResponse
     * @param delFlag    是否删除文件
     */
    protected static void download(File file, String returnName, HttpServletResponse response, boolean delFlag) {
        prototypeDownload(file, returnName, response, delFlag);
    }

    /**
     * @param file       要下载的文件
     * @param returnName 返回的文件名
     * @param response   HttpServletResponse
     * @param delFlag    是否删除文件
     */
    public static void prototypeDownload(File file, String returnName, HttpServletResponse response, boolean delFlag) {
        // 下载文件
        FileInputStream inputStream = null;
        ServletOutputStream outputStream = null;
        try {
            if (!file.exists()) return;
            response.reset();
            //设置响应类型   PDF文件为"application/pdf",WORD文件为:"application/msword", EXCEL文件为:"application/vnd.ms-excel"。
            response.setContentType("application/octet-stream;charset=utf-8");

            //设置响应的文件名称,并转换成中文编码
            //returnName = URLEncoder.encode(returnName,"UTF-8");

            //保存的文件名,必须和页面编码一致,否则乱码
            returnName = response.encodeURL(new String(returnName.getBytes(), "iso8859-1"));

            //attachment作为附件下载;inline客户端机器有安装匹配程序,则直接打开;注意改变配置,清除缓存,否则可能不能看到效果
            response.addHeader("Content-Disposition", "attachment;filename=" + returnName);

            //将文件读入响应流
            inputStream = new FileInputStream(file);
            outputStream = response.getOutputStream();
            int length = 1024;
            int readLength = 0;
            byte buf[] = new byte[1024];
            readLength = inputStream.read(buf, 0, length);
            while (readLength != -1) {
                outputStream.write(buf, 0, readLength);
                readLength = inputStream.read(buf, 0, length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //删除原文件

            if (delFlag) {
                file.delete();
            }
        }
    }

    public static void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) throws IOException {
        response.setContentType("application/octet-stream;charset=utf-8");
        //保存的文件名,必须和页面编码一致,否则乱码
        returnName = response.encodeURL(new String(returnName.getBytes(), "iso8859-1"));
        response.addHeader("Content-Disposition", "attachment;filename=" + returnName);
        response.setContentLength(byteArrayOutputStream.size());
        //取得输出流
        ServletOutputStream outputstream = response.getOutputStream();
        //写到输出流
        byteArrayOutputStream.writeTo(outputstream);
        //关闭
        byteArrayOutputStream.close();
        //刷数据
        outputstream.flush();
    }
}

4. 代码编写

4.1 ContractPrintController

创建一个新的Controller文件,编写关于printExcel相关的

package com.itheima.web.controller.cargo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.service.cargo.ContractService;
import com.itheima.utils.DownloadUtil;
import com.itheima.vo.ContractProductVo;
import com.itheima.web.controller.BaseController;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;

@Controller
@RequestMapping("/cargo/contract")
public class ContractPrintController extends BaseController {

	@Reference
	private ContractService contractService;



	/**
	 * 跳转出货表页面
	 */
	@RequestMapping(value = "/print", name = "跳转出货表页面")
	public String print() {
		return "/cargo/print/contract-print";
	}
	/**
	 * 导出商品
	 */
	@RequestMapping(value = "/printExcel", name = "导出商品")
	public void printExcel(String inputDate) throws IOException {
		// 根据传输的参数查询数据库
		List<ContractProductVo> list=contractService.findContractProductVo(inputDate,getCompanyId());
		// 创建一个工作簿
		Workbook workbook = new XSSFWorkbook();
		// 根据工作簿创建一个工作表
		Sheet sheet = workbook.createSheet();

		/**
		 * @author mryhl
		 * 合并单元格
		 *  CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol)
		 */
		sheet.addMergedRegion(new CellRangeAddress(0,0,1,8));
		// 设置列宽
		for (int i = 1; i < 9; i++) {
			sheet.setColumnWidth(i,15 * 256);
		}


		// 创建第0行
		Row row0 = sheet.createRow(0);
		for (int i = 1; i < 9; i++) {
			Cell cell = row0.createCell(i);
			// 添加样式
			cell.setCellStyle(bigTitleStyle(workbook));
		}
		// 替换出入文件的格式
		String s = inputDate.replaceAll("-0", "年").replaceAll("-", "年") + "月份出货表";
		// 设置第一行的内容
		row0.getCell(1).setCellValue(s);
		// 创建数组,保存字段名
		String[] objs = {"客户","合同号","货号","数量","工厂","工厂交期","船期","贸易条款"};
		// 创建第1行		
		Row row1 = sheet.createRow(1);
		for (int i = 1; i < 9; i++) {
			Cell cell = row1.createCell(i);
			// 出入数据
			cell.setCellValue(objs[i-1]);
			// 添加样式
			cell.setCellStyle(littleTitleStyle(workbook));
		}
		
		// 使用查询到的数据创建第n行
		int n = 2;
		for (ContractProductVo contractProductVo : list) {
			// 使用行创建单元格
			Row row = sheet.createRow(n++);
			for (int i = 1; i < 9; i++) {
				Cell cell = row.createCell(i);
				//  添加样式
				cell.setCellStyle(textStyle(workbook));
			}
			// 添加数据
			row.getCell(1).setCellValue(contractProductVo.getCustomName());
			row.getCell(2).setCellValue(contractProductVo.getContractNo());
			row.getCell(3).setCellValue(contractProductVo.getProductNo());
			row.getCell(4).setCellValue(contractProductVo.getCnumber());
			row.getCell(5).setCellValue(contractProductVo.getFactoryName());
			row.getCell(6).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getDeliveryPeriod()));
			row.getCell(7).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getShipTime()));
			row.getCell(8).setCellValue(contractProductVo.getTradeTerms());

		}


		// 文件下载
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		workbook.write(outputStream);
		DownloadUtil.download(outputStream, response, "出货表.xlsx");
	}

	//大标题的样式
	public CellStyle bigTitleStyle(Workbook wb) {
		CellStyle style = wb.createCellStyle();
		Font font = wb.createFont();
		font.setFontName("宋体");
		font.setFontHeightInPoints((short) 16);
		font.setBold(true);//字体加粗
		style.setFont(font);
		style.setAlignment(HorizontalAlignment.CENTER);                //横向居中
		style.setVerticalAlignment(VerticalAlignment.CENTER);        //纵向居中
		return style;
	}

	//小标题的样式
	public CellStyle littleTitleStyle(Workbook wb) {
		CellStyle style = wb.createCellStyle();
		Font font = wb.createFont();
		font.setFontName("黑体");
		font.setFontHeightInPoints((short) 12);
		style.setFont(font);
		style.setAlignment(HorizontalAlignment.CENTER);                //横向居中
		style.setVerticalAlignment(VerticalAlignment.CENTER);        //纵向居中
		style.setBorderTop(BorderStyle.THIN);                        //上细线
		style.setBorderBottom(BorderStyle.THIN);                    //下细线
		style.setBorderLeft(BorderStyle.THIN);                        //左细线
		style.setBorderRight(BorderStyle.THIN);                        //右细线
		return style;
	}

	//文字样式
	public CellStyle textStyle(Workbook wb) {
		CellStyle style = wb.createCellStyle();
		Font font = wb.createFont();
		font.setFontName("Times New Roman");
		font.setFontHeightInPoints((short) 10);
		style.setFont(font);
		style.setAlignment(HorizontalAlignment.LEFT);                //横向居左
		style.setVerticalAlignment(VerticalAlignment.CENTER);        //纵向居中
		style.setBorderTop(BorderStyle.THIN);                        //上细线
		style.setBorderBottom(BorderStyle.THIN);                    //下细线
		style.setBorderLeft(BorderStyle.THIN);                        //左细线
		style.setBorderRight(BorderStyle.THIN);                        //右细线

		return style;
	}

}

4.2 ContractService

List<ContractProductVo> findContractProductVo(String inputDate, String companyId);
@Override
public List<ContractProductVo> findContractProductVo(String inputDate, String companyId) {
    return contractDao.findContractProductVo(inputDate, companyId);
}

4.3 ContractDao

List<ContractProductVo> findContractProductVo(@Param("inputDate") String inputDate, @Param("companyId") String companyId);
<select id="findContractProductVo" resultType="com.itheima.vo.ContractProductVo">
    SELECT  c.`custom_name` AS customName,
        c.`contract_no` AS contractNo,
        cp.`product_no` AS productNo,
        cp.`cnumber` AS cnumber,
        cp.`factory_name` AS factoryName,
        c.`delivery_period` AS deliveryPeriod,
        c.`ship_time` AS shipTime,
        c.`trade_terms` AS tradeTerms

        FROM `co_contract` c
        JOIN `co_contract_product` cp ON c.id = cp.`contract_id`
        WHERE DATE_FORMAT(c.`ship_time`,"%Y-%m") = #{inputDate}
        AND c.`company_id` = #{companyId}
</select>

第二章 使用模板导出出货表(重点)

1. 需求说明

自定义生成Excel报表文件是非常复杂的,特别是针对复杂报表头,单元格样式,字体等操作。

为了简便,我们可以使用已经准备好的Excel模板,将模板读到程序中, 然后设置上数据即可。

2. 步骤分析

 

操作步骤:

  1. 制作模版文件(一般是由设计人员或者项目经理完成)

  2. 加载模版文件,从而得到一个工作簿

  3. 读取工作表

  4. 读取行,此时发现其实表中的前两行是固定内容, 所以不用处理

  5. 直接读取第三行中的每个单元格的样式信息,存储在一个数组中,备用

  6. 接下来开始遍历创建行,设置每行中单元格的文字和样式(使用上步读到的样式)

3. 代码编写

3.1 jsp页面调整

修改\webapp\WEB-INF\pages\cargo\print\contract-print.jsp中的内容

3.1.1 第一步:复制一个form表单

<form role="form" action="/cargo/contract/printExcelWithTemplate.do">
         <div class="input-group input-group-sm" >
             <div class="input-group-addon">
                 <i class="fa fa-calendar"></i>
             </div>
             <input type="text" name="inputDate" class="form-control pull-right" id="datepicker1">
             <span class="input-group-btn">
                 <button type="submit"   class="btn btn-info btn-flat">模板导出</button>
             </span>
         </div>
     </form>

3.1.2第二步:在js中添加

$('#datepicker1').datepicker({
     language: "zh-CN",
     autoclose: true,
     format: 'yyyy-mm',
     startView: 'months', //开始视图层,为月视图层
     maxViewMode:'years', //最大视图层,为年视图层
     minViewMode:'months', //最小视图层,为月视图层
 });

3.1.3页面效果如下:

 

3.2 ContractController

/**
	 * 按照模板导出商品
	 */
	@RequestMapping(value = "/printExcelWithTemplate", name = "按照模板导出商品")
	public void printExcelWithTemplate(String inputDate) throws IOException {
		// 根据传输的参数查询数据库
		List<ContractProductVo> list=contractService.findContractProductVo(inputDate,getCompanyId());
		// 读取模板
		String realPath = session.getServletContext().getRealPath("/make/xlsprint/tOUTPRODUCT.xlsx");
		// 通过读入模板文件创建一个工作簿
		Workbook workbook = new XSSFWorkbook(new FileInputStream(realPath));
		// 根据工作簿创建一个工作表
		Sheet sheet = workbook.getSheetAt(0);





		// 替换出入文件的格式
		String s = inputDate.replaceAll("-0", "年").replaceAll("-", "年") + "月份出货表";
		// 设置第一行的内容
		sheet.getRow(0).getCell(1).setCellValue(s);

		// 读取第2行
		Row row2 = sheet.getRow(2);
		// 创建样式数组
		CellStyle[] cellStyles = new CellStyle[8];
		// 向数组中写入数据
		for (int i = 0; i < 8; i++) {
			cellStyles[i] = row2.getCell(i+ 1).getCellStyle();
		}

		// 使用查询到的数据创建第n行
		int n = 2;
		for (ContractProductVo contractProductVo : list) {
			// 使用行创建单元格
			Row row = sheet.createRow(n++);
			for (int i = 1; i < 9; i++) {
				Cell cell = row.createCell(i);
				//  添加样式
				cell.setCellStyle(textStyle(workbook));
				cell.setCellStyle(cellStyles[i-1]);

			}
			// 添加数据
			row.getCell(1).setCellValue(contractProductVo.getCustomName());
			row.getCell(2).setCellValue(contractProductVo.getContractNo());
			row.getCell(3).setCellValue(contractProductVo.getProductNo());
			row.getCell(4).setCellValue(contractProductVo.getCnumber());
			row.getCell(5).setCellValue(contractProductVo.getFactoryName());
			row.getCell(6).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getDeliveryPeriod()));
			row.getCell(7).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getShipTime()));
			row.getCell(8).setCellValue(contractProductVo.getTradeTerms());

		}


		// 文件下载
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		workbook.write(outputStream);
		DownloadUtil.download(outputStream, response, "出货表.xlsx");
	}

4. 效果展示

 

第三章 百万级别数据报表技术(了解 面试)

1. 概述

对于百万数据量的Excel导入导出,只讨论基于Excel2007的解决方法。Excel2007的数据结构是XML,操作XML有两种模式:

  • 用户模式:基于dom4j的解析, 一次性加载xml文件再解析(XSSF对象底层用的就是dom4j,它的缺点是当数据量过大时,会导致内存溢出)
  • 事件模式:基于SAX方式解析XML,逐行加载,逐行解析(SXSSF对象底层用的是SAX,它的缺点是不能使用模板,并且不支持过多的CellStyle[62000])

2. Jvisualvm

Jvisualvm是JDK自带的一个Java程序性能检测工具。基于它可以监视程序的运行情况,包括CUP,垃圾回收,内存的分配和使用情况。

此软件放在jdk的安装目录下的bin目录下,名字叫jvisualvm.exe。

 

双击即可启动图形化检测界面,找到我们的tomcat,点击就可以看到其运行详情。

 

概述:可以看到进程的启动参数。

监视:左上:cpu利用率,gc状态的监控,右上:堆利用率,永久内存区的利用率,左下:类的监控,右下:线程的监控

线程:能够显示线程的名称和运行的状态,在调试多线程时必不可少,而且可以点进一个线程查看这个线程的详细运行情况

3. 百万级别数据导出

3.1 jsp页面调整

3.1.1第一步:复制一个form表单

<form role="form" action="/cargo/contract/printExcelMillion.do">
    <div class="input-group input-group-sm" >
        <div class="input-group-addon">
            <i class="fa fa-calendar"></i>
        </div>
        <input type="text" name="inputDate" class="form-control pull-right" id="datepicker2">
        <span class="input-group-btn">
            <button type="submit" class="btn btn-info btn-flat">百万级别数据导出</button>
        </span>
    </div>
</form>

3.1.2 第二步:在js中添加

$('#datepicker2').datepicker({
    language: "zh-CN",
    autoclose: true,
    format: 'yyyy-mm',
    startView: 'months', //开始视图层,为月视图层
    maxViewMode:'years', //最大视图层,为年视图层
    minViewMode:'months', //最小视图层,为月视图层
});

3.1.3页面效果如下:

 

3.2 ContractController代码调整

修改内容:

  • new XSSFWorkbook(); —>改为 new SXSSFWorkbook();

  • 导出数据那里模拟一个8000次的循环

  • 去掉所有样式设置

    @RequestMapping(value = "/printExcelMillion", name = "出货表导出")
    public void printExcelMillion(String inputDate) throws IOException {
        //1. 根据输入的参数查询货物列表
        List<ContractProductVo> list = contractService.findContractProductVo(inputDate, getCompanyId());
    
        //2. 封装列表为一个工作簿
        //2-1) 创建一个工作簿
        Workbook workbook = new SXSSFWorkbook();
    
        //2-2) 使用工作簿创建工作表
        Sheet sheet = workbook.createSheet();
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 1, 8));//合并单元格
        for (int i = 1; i < 9; i++) {
            sheet.setColumnWidth(i, 15 * 256);//设置列宽
        }
    
        //2-3) 使用工作表创建第0行
        Row row0 = sheet.createRow(0);
        for (int i = 1; i < 9; i++) {
            Cell cell = row0.createCell(i);
        }
        String title = inputDate.replaceAll("-0", "年").replaceAll("-", "年");
        row0.getCell(1).setCellValue(title + "月份出货表");
    
        //2-4) 使用工作表创建第1行
        Row row1 = sheet.createRow(1);
        for (int i = 1; i < 9; i++) {
            Cell cell = row1.createCell(i);
        }
        row1.getCell(1).setCellValue("客户");
        row1.getCell(2).setCellValue("合同号");
        row1.getCell(3).setCellValue("货号");
        row1.getCell(4).setCellValue("数量");
        row1.getCell(5).setCellValue("工厂");
        row1.getCell(6).setCellValue("工厂交期");
        row1.getCell(7).setCellValue("船期");
        row1.getCell(8).setCellValue("贸易条款");
    
        //2-5) 使用工作表创建第n行
        int n = 2;
        for (ContractProductVo contractProductVo : list) {
            for (int x = 0; x < 8000; x++) {
                //2-6) 使用行创建单元格
                Row rown = sheet.createRow(n++);
                for (int i = 1; i < 9; i++) {
                    Cell cell = rown.createCell(i);
                }
    
                //2-7) 向单元格中设置数据(样式)
                rown.getCell(1).setCellValue(contractProductVo.getCustomName());
                rown.getCell(2).setCellValue(contractProductVo.getContractNo());
                rown.getCell(3).setCellValue(contractProductVo.getProductNo());
                rown.getCell(4).setCellValue(contractProductVo.getCnumber());
                rown.getCell(5).setCellValue(contractProductVo.getFactoryName());
                rown.getCell(6).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getDeliveryPeriod()));
                rown.getCell(7).setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(contractProductVo.getShipTime()));
                rown.getCell(8).setCellValue(contractProductVo.getTradeTerms());
            }
        }
    
        //3. 文件下载
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workbook.write(outputStream);
        DownloadUtil.download(outputStream, response, "出货表.xlsx");
    }
    

4. 百万级别数据导入

4.1 自定义处理器(直接复制)

package com.itheima.poi;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.InputStream;

//用于处理百万级别数据
//需要我们做的是在SheetHandler中自定义处理逻辑
public class ExcelParse {

    public static void parse(String path) throws Exception {
        //解析器
        SheetHandler hl = new SheetHandler();

        //1.根据 Excel 获取 OPCPackage 对象
        OPCPackage pkg = OPCPackage.open(path, PackageAccess.READ);
        try {
            //2.创建 XSSFReader 对象
            XSSFReader reader = new XSSFReader(pkg);
            //3.获取 SharedStringsTable 对象
            SharedStringsTable sst = reader.getSharedStringsTable();
            //4.获取 StylesTable 对象
            StylesTable styles = reader.getStylesTable();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            // 处理公共属性
            parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, hl, false));
            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();

            //逐行读取逐行解析
            while (sheets.hasNext()) {
                InputStream sheetstream = sheets.next();
                InputSource sheetSource = new InputSource(sheetstream);
                try {
                    parser.parse(sheetSource);
                } finally {
                    sheetstream.close();
                }
            }
        } finally {
            pkg.close();
        }
    }

    public static void main(String[] args) throws Exception {
        parse("c:/upload/data.xlsx");
    }
}

4.2 自定义解析器

package com.itheima.poi;

import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;

import java.util.ArrayList;
import java.util.List;

//自定义解析器,负责每行代码的处理
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {

    ContractProductVo contractProductVo = null;
    List<ContractProductVo> list = new ArrayList<ContractProductVo>();

    //rowIndex 行索引
    public void startRow(int rowIndex) {

        System.out.println("进入了第" + rowIndex + "行");
        contractProductVo =  new ContractProductVo();

    }

    //每个单元格中要做的操作
    //cellName  单元格名称   C2
    //cellValue 单元格中的值
    //xssfComment  单元格批注
    public void cell(String cellName, String cellValue, XSSFComment xssfComment) {
        System.out.print(cellName + ":" + cellValue+"   ");
        if (cellName.startsWith("B")){
            contractProductVo.setCustomName(cellValue);
        }else if (cellName.startsWith("C")){
            contractProductVo.setContractNo(cellValue);
        }
    }

    public void endRow(int rowIndex) {
        System.out.println("离开了第" + rowIndex + "行");
        //
        
        list.add(contractProductVo);

        System.out.println(list);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

第四章 EasyPOI(扩展)

1. 简介

​ easypoi主打的功能就是容易,让一个没见接触过poi的人员,就可以方便的写出Excel导出和导入功能,它通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法。

官方文档:http://easypoi.mydoc.io/

2. 快速入门

2.1 环境搭建

<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>3.2.0</version>
</dependency>

2.2 定义实体

public class ContractProductVo implements Serializable {
    @Excel(name = "客户")
    private String customName;        //客户名称
    @Excel(name = "合同号")
    private String contractNo;        //合同号,订单号
    @Excel(name = "货号")
    private String productNo;        //货号
    @Excel(name = "数量",type = 10)
    private Integer cnumber;        //数量
    @Excel(name = "工厂")
    private String factoryName;        //厂家名称
    @Excel(name = "工厂交期", format = "yyyy-MM-dd",width = 15)
    private Date deliveryPeriod;    //交货期限
    @Excel(name = "船期", format = "yyyy-MM-dd",width = 15)
    private Date shipTime;            //船期
    @Excel(name = "贸易条款")
    private String tradeTerms;        //贸易条款

    public String getCustomName() {
        return customName;
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public String getContractNo() {
        return contractNo;
    }

    public void setContractNo(String contractNo) {
        this.contractNo = contractNo;
    }

    public String getProductNo() {
        return productNo;
    }

    public void setProductNo(String productNo) {
        this.productNo = productNo;
    }

    public Integer getCnumber() {
        return cnumber;
    }

    public void setCnumber(Integer cnumber) {
        this.cnumber = cnumber;
    }

    public String getFactoryName() {
        return factoryName;
    }

    public void setFactoryName(String factoryName) {
        this.factoryName = factoryName;
    }

    public Date getDeliveryPeriod() {
        return deliveryPeriod;
    }

    public void setDeliveryPeriod(Date deliveryPeriod) {
        this.deliveryPeriod = deliveryPeriod;
    }

    public Date getShipTime() {
        return shipTime;
    }

    public void setShipTime(Date shipTime) {
        this.shipTime = shipTime;
    }

    public String getTradeTerms() {
        return tradeTerms;
    }

    public void setTradeTerms(String tradeTerms) {
        this.tradeTerms = tradeTerms;
    }

    @Override
    public String toString() {
        return "ContractProductVo{" +
                "customName='" + customName + '\'' +
                ", contractNo='" + contractNo + '\'' +
                ", productNo='" + productNo + '\'' +
                ", cnumber=" + cnumber +
                ", factoryName='" + factoryName + '\'' +
                ", deliveryPeriod=" + deliveryPeriod +
                ", shipTime=" + shipTime +
                ", tradeTerms='" + tradeTerms + '\'' +
                '}';
    }
}

2.3 创建excel

public class CreateExcel {

    public static void main(String[] args)throws Exception {
        // 1.定义excel配置
        ExportParams exportParams = new ExportParams();
        exportParams.setSheetName("Sheet1");// 页名称
        exportParams.setTitle("2015年01月份出货表");// 大标题
        exportParams.setType(ExcelType.XSSF);// 07及以上版本
        // 2.创建workbook对象
        Workbook wb = ExcelExportUtil.exportExcel(exportParams, ContractProductVo.class, getData());
        // 3.导出到文件
        FileOutputStream out = new FileOutputStream("d:/demo.xlsx");
        wb.write(out);
        wb.close();
    }

    //从数据库中查找了数据
    public static List<ContractProductVo> getData() {
        List<ContractProductVo> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            ContractProductVo vo = new ContractProductVo();
            vo.setCustomName("客户"+i);
            vo.setContractNo("合同号"+i);
            vo.setProductNo("货号"+i);
            vo.setCnumber(i);
            vo.setFactoryName("工厂"+i);
            vo.setDeliveryPeriod(new Date());
            vo.setShipTime(new Date());
            vo.setTradeTerms("条款"+i);
            list.add(vo);
        }
        return list;
    }
}

2.4 解析excel

public class ParseExcel {
    public static void main(String[] args) {
        // 1.解析excel的配置参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1); // 大标题行数
        params.setHeadRows(1); //  列标题行数

        // 2.实现解析
        List<ContractProductVo> list = ExcelImportUtil.importExcel(new File("D:/demo.xlsx"), ContractProductVo.class, params);

        // 3.遍历输出
        for (ContractProductVo contractProductVo : list) {
            System.out.println(contractProductVo);
        }
    }
}

第五章 定时任务(重点)

1. 简介

定时任务:按照配置的时间规则,自动执行java类中的方法

实现框架:Quartz、Spring Task

应用场景

  • 某些网站会定时发送优惠邮件
  • 银行系统还款日信用卡催收款短信
  • 某些应用的生日祝福短信等

Quartz 是一个完全由 Java 编写的开源任务调度框架,为在 Java 应用程序中进行任务调度提供了简单却强大的机制。

官网地址:http://www.quartz-scheduler.org/

2. 核心组件

Quartz 定时任务调度框架(按照配置的时间规则,自动执行java中的方法)

  • Job:需要执行的java类

  • JobDetail:任务细节,用来指定java类和具体执行的方法

  • Trigger:触发器,配置时间规则和JobDetail

  • Scheduler:调度器,统一调度并管理所有的Trigger

     

3. 快速入门

需求:每间隔五秒,向控制台输出当前时间

3.1 创建一个新工程,导入依赖

<dependencies>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!-- 设置编译版本为1.8 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

3.2 创建Job类,创建JobDetail方法

import java.util.Date;

/**
 * @description:
 * @author: mryhl
 * @date: Created in 2020/10/18 17:36
 * @version:
 */
public class myjob {
   public void sendMail(){
      System.out.println("发邮件了 " + new Date().toLocaleString());
   }
}

3.3 添加一个配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context.xsd">


    <!--1.配置Job:自定义java类 -->
    <bean id="myjob" class="myjob"></bean>
   
   
    <!--2.配置JobDetail:执行任务来的方法-->
    <bean id="myJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <!--1.确定任务类-->
        <property name="targetObject" ref="myjob"/>
        <!--2.确认任务的方法-->
        <property name="targetMethod" value="sendMail"></property>
    </bean>
   
   
    <!--3.配置Trigger:根据时间规则,触发方法执行-->
    <bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <!--1.指定时间规则-->
        <property name="cronExpression" value="*/5 * * * * ?"></property>
        <!--2.指定JobDetail-->
        <property name="jobDetail" ref="myJobDetail"></property>
    </bean>
   
    <!--4.配置Scheduler:统一管理配置trigger-->
    <bean id="myScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <array>
                <ref bean="myTrigger"></ref>
            </array>
        </property>
    </bean>

</beans>

3.4 测试

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;

/**
 * @description:
 * @author: mryhl
 * @date: Created in 2020/10/18 17:40
 * @version:
 */
public class QuartzStart {
   public static void main(String[] args) throws IOException {
      ClassPathXmlApplicationContext act
            = new ClassPathXmlApplicationContext("applicationContext-quartz.xml");

      act.start();

      System.in.read();
   }
}

4. Cron表达式【重点】(7子)

Cron表达式简单来说就是一个字符串,有如下两种语法格式:

  • Seconds Minutes Hours DayofMonth Month DayofWeek Year(七个域)
  • Seconds Minutes Hours DayofMonth Month DayofWeek(六个域)
cron  时间表达式(配置时间规则)
	秒           分           时         日          月              周             年
	0-59      	0-59         0-23       1-31        1-12            1-7           1970-2099	
	*/5          *            *          5W           *               3L              *
                                      
常用的符号
	*:表示任意,例如在Minutes域使用,即表示每分钟都会触发
	?:表示忽略,只能用在DayofMonth和DayofWeek两个域
	-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次 
	/:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着在5分钟触发一次,而25,45等分别触发一次. 
	,:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。 
	L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。 
	W: 表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。
		例如:在DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。
			 如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。 另外一点,W的最近寻找不会跨过月份。
	LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。 
	#:用于确定第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

常用表达式例子
	0 0 2 1 * ? *   表示在每月的1日的凌晨2点调整任务
	0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
	0 15 10 ? * 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
	0 0 10,14,16 * * ?   每天上午10点,下午2点,4点 
	0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时 
	0 0 12 ? * WED    表示每个星期三中午12点 
	0 0 12 * * ?   每天中午12点触发 
	0 15 10 ? * *    每天上午10:15触发 
	0 15 10 * * ?     每天上午10:15触发 
	0 15 10 * * ? *    每天上午10:15触发 
	0 15 10 * * ? 2005    2005年的每天上午10:15触发 
	0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发 
	0 0/5 14 * * ?    在每天下午2点到下午2:55期间的每5分钟触发 
	0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
	0 0-5 14 * * ?    在每天下午2点到下午2:05期间的每1分钟触发 
	0 10,44 14 ? 3 WED    每年三月的星期三的下午2:10和2:44触发 
	0 15 10 ? * MON-FRI    周一至周五的上午10:15触发 
	0 15 10 15 * ?    每月15日上午10:15触发 
	0 15 10 L * ?    每月最后一日的上午10:15触发 
	0 15 10 ? * 6L    每月的最后一个星期五上午10:15触发 
	0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发 
	0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
一个免费的表格控件,相当强大 reportX支持预览和打印、支持公式、支持表格模版、支持导出excel、支持单元格锁定及格式、支持图表和条码等,不支持数据源、单元格边框单独改色,至2.6版本时仍有些BUG如:OnCellChanging事件无效,只能用API getfocus()取当前输入框句柄然后取该控件的标题即是正在输入的内容。 发布只要regsvr32注册ReportX.ocx即可。 1、常用属性及方法: setcellvalue()置单元格文本、getcellvalue()取单元格文本、Explain...()计算刷新单元格公式、OpenReport()载入表格模版、Colcount和Rowcount属性设置或取得表格行列数、 GetSelectCell方法的参数应使用变量而不是变量值以便该方法将选择范围返回给变量、TopRow属性为当前表格可见行首行号、Sortcol()对指定列进行排序、sortrow()对指定行排序、PageHeader...Text和PageFooter...Text属性设置页眉页脚其中@number表示当前面@Count表示总页数、 GetCellHAlignment取横向对齐方式GetCellVAlignment纵向SetCellHAlignment设置0左1中2右、ExplainCellExpression计算单元格公式(单元格公式不会自动计算,只能在程序中调用执行)、ExportExcel导出到excel。 2、BottomHeight和RightWidth设为0则reportX没有滚动条,PoleHeight和PoleWidth设为0则表格没有固定标题行列。 3、reportx单元格首列和首行号均为1 4、setpoletext()和getpoletext 参数一为标杆方向横向为0,纵向为1,参数二位置从1开始(即最左上角标杆格无法设置任何数据) 5、MergeCell()合并单元格必须用合并后的最前的行列进行读写,或用SplitCell拆分单元格。 6、VB对其setfocus()无效(易语言支持setfocus),可使用控件本身的SetSelectCell方法代替。 7、AppendRow和AppendCol方法增加指定的行数或列数,DeleteCol删除指定列数。 8、reportx.SetColWidth col, reportx.GetColBestWidth(col) + 9 '填充完数据后,用此语句设置最佳列宽。 9、copycell和paste方法可以复制,粘贴区域,包含格式(但不含分页符),可以粘贴到另一个Rpt对象中。 10、大量写表格数据时,设置InvalidatePaint()使表格刷新无效,写好数据后使用ValidatePaint()使报表刷新有效并刷新,这样可以加快写的速度。如果这样还是太慢或内存不足,则只能用分页分册的方式了。 速度上比VsFlex的还是要差很多,但支持图表,支持打印,支持套打模版等等,更主要的是免费,支持原作者!
要在Java中导出动态表格数据,可以使用Apache POI来实现。首先,需要在项目中引入Apache POI的相关依赖。然后,可以按照以下步骤进行操作: 1. 创建一个Workbook对象,可以选择创建XSSFWorkbook(针对.xlsx格式)或HSSFWorkbook(针对.xls格式)。 2. 在Workbook对象中创建一个Sheet对象,使用createSheet方法即可。 3. 创建表头,并将表头数据填充到Sheet对象中。 4. 遍历动态表格数据,将数据逐行填充到Sheet对象中。 5. 最后,将数据写入到输出流中,可以通过FileOutputStream或ServletOutputStream来实现。 以下是一个简单的示例代码: ```java // 创建Workbook对象 Workbook workbook = new XSSFWorkbook(); // 创建Sheet对象 Sheet sheet = workbook.createSheet("动态表格数据"); // 创建表头 Row headerRow = sheet.createRow(0); headerRow.createCell(0).setCellValue("列1"); headerRow.createCell(1).setCellValue("列2"); headerRow.createCell(2).setCellValue("列3"); // 填充表格数据 List<List<Object>> dynamicData = getDynamicData(); // 获取动态表格数据 int rowNum = 1; for(List<Object> rowData : dynamicData) { Row row = sheet.createRow(rowNum++); int cellNum = 0; for(Object cellData : rowData) { row.createCell(cellNum++).setCellValue(cellData.toString()); } } // 将数据写入输出流 try (FileOutputStream fileOut = new FileOutputStream("dynamic_table_data.xlsx")) { workbook.write(fileOut); } ``` 通过以上步骤,就可以在Java中实现导出动态表格数据的功能。在实际应用中,可以根据需求对表格样式、数据格式等进行更多的定制化操作

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.YHL

谢谢您的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值