Excel报表简介:
POI:POI是apache的项目,可对微软的Word,Excel,PPT进行操作,包括office2003和2007,Excle2003和2007。poi现在一直有更新。所以现在主流使用POI。
工作簿 : WorkBook (HSSFWordBook : 2003版本,XSSFWorkBook : 2007级以上)
工作表 : Sheet (HSSFSheet : 2003版本,XSSFSheet : 2007级以上)
行 : Row (HSSFRow : 2003版本,XSSFRow : 2007级以上)
单元格 : Cell (HSSFCell : 2003版本,XSSFCell : 2007级以上)
单元格样式:Style(HSSFCellStyle:2003版本,XSSFCellStyle:2007级以上)
Excel报表数据导出与导入:
导出时样式的设置:
HSSFCellStyle contentStyle = book.createCellStyle();
contentStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);//底线
contentStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//顶部线
contentStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左侧线
contentStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右侧线
//合并单元格 起始行, 结束行, 起始列, 结束列
sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));
sheet.getRow(1).setHeight((short)500);
//内容部分的样式
style_content.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_content.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中
HSSFFont font = book.createFont();//创建字体
font.setFontName("宋体");//设置字体名称
font.setFontHeightInPoints((short)11);//设置字体大小
style_content.setFont(font);//对样式设置字体
//标题样式
HSSFCellStyle style_title = book.createCellStyle();//创建标题样式
style_title.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_title.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中
HSSFFont titleFont = book.createFont();//设置标题字体
titleFont.setFontName("黑体");
titleFont.setBold(true);//加粗
titleFont.setFontHeightInPoints((short)18);//字体大小
style_title.setFont(titleFont);//将标题字体设置到标题样式
sheet.getRow(0).getCell(0).setCellStyle(style_title);//单元格设置标题样式
POI高级操作:
基于模板导出列表数据:
导出数据带图片:
// 先创建一个字节输出流
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
// BufferedImage是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中
BufferedImage bufferImg = ImageIO.read(new File(rootPath + user.getPhoto()));
// 把读取到图像放入到输出流中
ImageIO.write(bufferImg, "jpg", byteArrayOut);
// 创建一个绘图控制类,负责画图
Drawing patriarch = sheet.createDrawingPatriarch();
// 指定把图片放到哪个位置
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 2, 1, 4, 5);
// 开始把图片写入到sheet指定的位置
patriarch.createPicture(anchor, workbook.addPicture(
byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG));
导出公式:
自定义导出详细数据的引擎:
百万数据导出:
我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下:
①Excel 2003:在POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量。这时对于百万级别数据,Excel肯定容纳不了。
②Excel 2007:当POI升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近百万条数据。但实际运行时还可能存在问题,原因是执行POI报表所产生的行对象,单元格对象,字体对象,他们都不会销毁,这就导致OOM的风险。
解决方案分析:对于百万数据量的Excel导入导出,只讨论基于Excel2007的解决方法。在ApachePoi 官方提供了对操作大数据量的导入导出的工具和解决办法,操作Excel2007使用XSSF对象,可以分为三种模式:
①java代码解析xml
②dom4j:一次性加载xml文件再解析
③SAX:逐行加载,逐行解析
解决方案:
①用户模式:用户模式有许多封装好的方法操作简单,但创建太多的对象,非常耗内存。加载并读取Excel时,是通过一次性的将所有数据加载到内存中再去解析每个单元格内容。当Excel数据量较大时,由于不同的运行环境可能会造成内存不足甚至OOM异常。
<1>java代码解析xml
<2>dom4j:一次性加载xml文件再解析
②事件模式:基于SAX方式解析XML,SAX全称Simple API for XML,它是一个接口,也是一个软件包。它是一种XML解析的替代方法,不同于DOM解析XML文档时把所有内容一次性加载到内存中的方式,它逐行扫描文档,一边扫描,一边解析。
<1>SAX:逐行加载,逐行解析
SXSSF对象:是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excel
原理分析 :
①在实例化SXSSFWorkBook这个对象时,可以指定在内存中所产生的POI导出相关对象的数量(默认100),一旦内存中的对象的个数达到这个指定值时,就将内存中的这些对象的内容写入到磁盘中(XML的文件格式),就可以将这些对象从内存中销毁,以后只要达到这个值,就会以类似的处理方式处理,直至Excel导出完成。
思路分析:
①导出时使用的是SXSSFWorkBook这个类,一个工作表sheet最多只能放1048576行数据, 当我们的业务数据已超过100万了,一个sheet就不够用了,必须拆分到多个工作表。
②导出百万数据时有两个弊端:
<1>不能使用模板
<2>不能使用太多的样式
③也就是说导出的数据太多时必须要放弃一些。
步骤分析:
①设置POI的事件模式:
<1>根据Excel获取文件流
<2>根据文件流创建OPCPackage 用来组合读取到的xml 组合出来的数据占用的空间更小
<3>创建XSSFReader对象
②Sax解析:
<1>自定义Sheet处理器
<2>创建Sax的XmlReader对象
<3>设置Sheet的事件处理器
<4>逐行读取
--------自定义处理器---------
public class SheetHandler implements XSSFSheetXMLHandler.SheetContentsHandler {
// 编号 用户名 手机号 入职日期 现住址
private User user=null;
@Override
public void startRow(int rowIndex) { //每一行的开始 rowIndex代表的是每一个sheet的行索引
if(rowIndex==0){
user = null;
}else{
user = new User();
}
}
@Override //处理每一行的所有单元格
public void cell(String cellName, String cellValue, XSSFComment comment) {
if(user!=null){
String letter = cellName.substring(0, 1); //每个单元名称的首字母 A B C
switch (letter){
case "A":{
user.setId(Long.parseLong(cellValue));
break;
}
case "B":{
user.setUserName(cellValue);
break;
}
}
}
}
@Override
public void endRow(int rowIndex) { //每一行的结束
if(rowIndex!=0){
System.out.println(user);
}
}
}
--------自定义解析---------
public class ExcelParser {
public void parse (String path) throws Exception {
//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();
// 处理公共属性:Sheet名,Sheet合并单元格
parser.setContentHandler(new XSSFSheetXMLHandler(styles,sst, new SheetHandler(), 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();
}
}
}
CSV文件简介:
Comma-Separated Values,中文叫逗号分隔值或者字符分割值,其文件以纯文本的形式存储表格数据。
该文件是一个字符序列,可以由任意数目的记录组成,记录间以某种换行符分割。每条记录由字段组成,字段间的分隔符是其他字符或者字符串。所有的记录都有完全相同的字段序列,相当于一个结构化表的纯文本形式。用文本文件、excel或者类似与文本文件的编辑器都可以打开CSV文件。
<dependency>
<groupId>com.opencsvgroupId>
<artifactId>opencsvartifactId>
<version>4.5version>
dependency>
opencsv常用API:
CSVWriter.DEFAULT_SEPARATOR
用于分割各列。导出与读取CSV文件:
//导出CSV文件
public void downLoadCSV(HttpServletResponse response) {
try {
// 准备输出流
ServletOutputStream outputStream = response.getOutputStream();
// 文件名
String filename="百万数据.csv";
// 设置两个头 一个是文件的打开方式 一个是mime类型
response.setHeader( "Content-Disposition", "attachment;filename=" + new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("text/csv");
// 创建一个用来写入到csv文件中的writer
CSVWriter writer = new CSVWriter(new OutputStreamWriter(outputStream,"utf-8"));
// 先写头信息
writer.writeNext(new String[]{"编号","姓名","手机号","入职日期","现住址"});
// 如果文件数据量非常大的时候,我们可以循环查询写入
int page = 1;
int pageSize=200000;
while (true) { //不停地查询
List<User> userList = this.findPage(page, pageSize);
if (CollectionUtils.isEmpty(userList)) { //如果查询不到就不再查询了
break;
}
// 把查询到的数据转成数组放入到csv文件中
for (User user : userList) {
writer.writeNext(new String[]{user.getId().toString(),user.getUserName(),user.getPhone(),simpleDateFormat.format(user.getHireDate()),user.getAddress()});
}
writer.flush();
page++;
}
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//读取百万级数据的csv文件
public class CsvDemo {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) throws Exception {
CSVReader csvReader = new CSVReader(new FileReader("d:\\百万用户数据的导出.csv"));
String[] titles = csvReader.readNext(); //读取到第一行 是小标题
// "编号","姓名","手机号","入职日期","现住址"
User user = null;
while (true){
user = new User();
String[] content = csvReader.readNext();
if(content==null){
break;
}
user.setId(Long.parseLong(content[0]));
user.setUserName(content[1]);
user.setPhone(content[2]);
user.setHireDate(simpleDateFormat.parse(content[3]));
user.setAddress(content[4]);
System.out.println(user);
}
}
}
POI操作word文档简介:
XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档
一个文档包含多个段落,一个段落包含多个Runs文本,一个Runs包含多个Run,Run是文档的最小单元
一个文档包含多个表格,一个表格包含多行,一行包含多列单元格
导出与读取word文档:
// 向单元格中写入图片
private void setCellImage(XWPFTableCell cell, File imageFile) {
XWPFRun run = cell.getParagraphs().get(0).createRun();
// InputStream pictureData, int pictureType, String filename, int width, int height
try(FileInputStream inputStream = new FileInputStream(imageFile)) {
run.addPicture(inputStream,XWPFDocument.PICTURE_TYPE_JPEG,imageFile.getName(), Units.toEMU(100),Units.toEMU(50));
} catch (Exception e) {
e.printStackTrace();
}
}
// 用于深克隆行
private void copyRow(XWPFTable xwpfTable, XWPFTableRow sourceRow, int rowIndex) {
XWPFTableRow targetRow = xwpfTable.insertNewTableRow(rowIndex);
targetRow.getCtRow().setTrPr(sourceRow.getCtRow().getTrPr());
// 获取源行的单元格
List<XWPFTableCell> cells = sourceRow.getTableCells();
if(CollectionUtils.isEmpty(cells)){
return;
}
XWPFTableCell targetCell = null;
for (XWPFTableCell cell : cells) {
targetCell = targetRow.addNewTableCell();
// 附上单元格的样式
// 单元格的属性
targetCell.getCTTc().setTcPr(cell.getCTTc().getTcPr());
targetCell.getParagraphs().get(0).getCTP().setPPr(cell.getParagraphs().get(0).getCTP().getPPr());
}
}
public void downloadContract(Long id,HttpServletResponse response) throws Exception {
// 1、读取到模板
File rootFile = new File(ResourceUtils.getURL("classpath:").getPath()); //获取项目的根目录
File templateFile = new File(rootFile, "/word_template/contract_template.docx");
XWPFDocument word = new XWPFDocument(new FileInputStream(templateFile));
// 2、查询当前用户User--->map
User user = this.findById(id);
Map<String,String> params = new HashMap<>();
params.put("userName",user.getUserName());
params.put("hireDate",simpleDateFormat.format(user.getHireDate()));
params.put("address",user.getAddress());
// 3、替换数据
// 处理正文开始
List<XWPFParagraph> paragraphs = word.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
for (String key : params.keySet()) {
if(text.contains(key)){
run.setText(text.replaceAll(key,params.get(key)),0);
}
}
}
}
// 处理正文结束
// 处理表格开始 名称 价值 是否需要归还 照片
List<Resource> resourceList = user.getResourceList(); //表格中需要的数据
XWPFTable xwpfTable = word.getTables().get(0);
XWPFTableRow row = xwpfTable.getRow(0);
int rowIndex = 1;
for (Resource resource : resourceList) {
// 添加行
// xwpfTable.addRow(row);
copyRow(xwpfTable,row,rowIndex);
XWPFTableRow row1 = xwpfTable.getRow(rowIndex);
row1.getCell(0).setText(resource.getName());
row1.getCell(1).setText(resource.getPrice().toString());
row1.getCell(2).setText(resource.getNeedReturn()?"需求":"不需要");
File imageFile = new File(rootFile,"/static"+resource.getPhoto());
setCellImage(row1.getCell(3),imageFile);
rowIndex++;
}
// 处理表格开始结束
// 4、导出word
String filename = "员工(" + user.getUserName() + ")合同.docx";
response.setHeader("content-disposition", "attachment;filename=" + new String(filename.getBytes(), "ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
word.write(response.getOutputStream());
}
POI简介:
Apache POI结构:
Excel
格式档案的功能。Excel OOXML
格式档案的功能。Word
格式档案的功能。PowerPoint
格式档案的功能。Visio
格式档案的功能。easyPOI简介:
easyPOI:
<dependency>
<groupId>cn.afterturngroupId>
<artifactId>easypoi-baseartifactId>
<version>4.1.0version>
dependency>
<dependency>
<groupId>cn.afterturngroupId>
<artifactId>easypoi-webartifactId>
<version>4.1.0version>
dependency>
<dependency>
<groupId>cn.afterturngroupId>
<artifactId>easypoi-annotationartifactId>
<version>4.1.0version>
dependency>
或SpringBoot:
<dependency>
<groupId>cn.afterturngroupId>
<artifactId>easypoi-spring-boot-starterartifactId>
<version>4.1.0version>
dependency>
注解方式导出(excel):
--------员工实体类-------
@Data
@Table(name="tb_user")
public class User {
@Id
@KeySql(useGeneratedKeys = true)
@Excel(name = "编号", orderNum = "0", width = 5)
private Long id; //主键
@Excel(name = "员工名", orderNum = "1", width = 15)
private String userName; //员工名
@Excel(name = "手机号", orderNum = "2", width = 15)
private String phone; //手机号
@Excel(name = "省份名", orderNum = "3", width = 15)
private String province; //省份名
@Excel(name = "城市名", orderNum = "4", width = 15)
private String city; //城市名
@Excel(name = "工资", orderNum = "5", width = 10)
private Integer salary; // 工资
@JsonFormat(pattern="yyyy-MM-dd")
@Excel(name = "入职日期", format = "yyyy-MM-dd",orderNum = "6", width = 15)
private Date hireDate; // 入职日期
private String deptId; //部门id
@Excel(name = "出生日期", format = "yyyy-MM-dd",orderNum = "7", width = 15)
private Date birthday; //出生日期
@Excel(name = "照片", orderNum = "10",width = 15,type = 2)
private String photo; //一寸照片
@Excel(name = "现在居住地址", orderNum = "9", width = 30)
private String address; //现在居住地址
private List<Resource> resourceList; //办公用品
}
-----------导出方法------------------
public void downLoadXlsxWithEayPoi(HttpServletRequest request, HttpServletResponse response) throws Exception {
//查询用户数据
List<User> userList = userMapper.selectAll();
//指定导出的格式是高版本的格式
ExportParams exportParams = new ExportParams("员工信息", "数据",ExcelType.XSSF);
//直接使用EasyPOI提供的方法
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, User.class, userList);
String filename="员工信息.xlsx";
//设置文件的打开方式和mime类型
ServletOutputStream outputStream = response.getOutputStream();
response.setHeader( "Content-Disposition", "attachment;filename=" + new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
workbook.write(outputStream);
}
注解方式导入(excel):
--------员工实体类-------
@Data
@Table(name="tb_user")
public class User {
@Id
@KeySql(useGeneratedKeys = true)
@Excel(name = "编号", orderNum = "0", width = 5)
private Long id; //主键
@Excel(name = "员工名", orderNum = "1", width = 15,isImportField="true")
private String userName; //员工名
@Excel(name = "手机号", orderNum = "2", width = 15,isImportField="true")
private String phone; //手机号
@Excel(name = "省份名", orderNum = "3", width = 15,isImportField="true")
private String province; //省份名
@Excel(name = "城市名", orderNum = "4", width = 15,isImportField="true")
private String city; //城市名
@Excel(name = "工资", orderNum = "5", width = 10, type=10, isImportField="true") //type=10表示会导出数字
private Integer salary; // 工资
@JsonFormat(pattern="yyyy-MM-dd")
@Excel(name = "入职日期", format = "yyyy-MM-dd",orderNum = "6", width = 15,isImportField="true")
private Date hireDate; // 入职日期
private String deptId; //部门id
@Excel(name = "出生日期", format = "yyyy-MM-dd",orderNum = "7", width = 15,isImportField="true")
private Date birthday; //出生日期
@Excel(name = "照片", orderNum = "10",width = 15,type = 2,isImportField="true",savePath = "D:\\java_report\\workspace\\user_management\\src\\main\\resources\\static\\user_photos\\")
private String photo; //一寸照片
@Excel(name = "现在居住地址", orderNum = "9", width = 30,isImportField="true")
private String address; //现在居住地址
private List<Resource> resourceList; //办公用品
}
-----------导入方法------------------
public void uploadExcleWithEasyPOI(MultipartFile file) throws Exception {
ImportParams importParams = new ImportParams();
importParams.setTitleRows(1); //有多少行的标题
importParams.setHeadRows(1);//有多少行的头
List<User> userList = ExcelImportUtil.importExcel(file.getInputStream(),User.class,importParams);
System.out.println(userList);
for (User user : userList) {
user.setId(null);
userMapper.insertSelective(user);
}
}
模板方式导出数据(excel):
public void downLoadUserInfoWithEastPOI(Long id, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取模板的路径
File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userInfo3.xlsx");
// 读取模板文件
TemplateExportParams params = new TemplateExportParams(templatePath.getPath(),true);
// 查询用户,转成map
User user = userMapper.selectByPrimaryKey(id);
Map<String, Object> map = EntityUtils.entityToMap(user);
ImageEntity image = new ImageEntity();
// image.setHeight(640); //测试发现 这里设置了长度和宽度在合并后的单元格中没有作用
// image.setWidth(380);
image.setRowspan(4);//向下合并三行
image.setColspan(2);//向右合并两列
image.setUrl(user.getPhoto());
map.put("photo", image);
Workbook workbook = ExcelExportUtil.exportExcel(params, map);
// 导出的文件名称
String filename="用户详细信息数据.xlsx";
// 设置文件的打开方式和mime类型
ServletOutputStream outputStream = response.getOutputStream();
response.setHeader( "Content-Disposition", "attachment;filename=" + new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
workbook.write(outputStream);
}
Excel注解详细(excel):
属性 | 类型 | 类型 | 说明 |
---|---|---|---|
name | String | null | 列名 |
needMerge | boolean | fasle | 纵向合并单元格 |
orderNum | String | “0” | 列的排序,支持name_id |
replace | String[] | {} | 值得替换 导出是{a_id,b_id} 导入反过来 |
savePath | String | “upload” | 导入文件保存路径 |
type | int | 1 | 导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本 |
width | double | 10 | 列宽 |
height | double | 10 | 列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意 |
isStatistics | boolean | fasle | 自动统计数据,在追加一行统计,把所有数据都和输出这个处理会吞没异常,请注意这一点 |
isHyperlink | boolean | false | 超链接,如果是需要实现接口返回对象 |
isImportField | boolean | true | 校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id |
exportFormat | String | “” | 导出的时间格式,以这个是否为空来判断是否需要格式化日期 |
importFormat | String | “” | 导入的时间格式,以这个是否为空来判断是否需要格式化日期 |
format | String | “” | 时间格式,相当于同时设置了exportFormat 和 importFormat |
databaseFormat | String | “yyyyMMddHHmmss” | 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string类型,这个需要设置这个数据库格式,用以转换时间格式输出 |
numFormat | String | “” | 数字格式化,参数是Pattern,使用的对象是DecimalFormat |
imageType | int | 1 | 导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的 |
suffix | String | “” | 文字后缀,如% 90 变成90% |
isWrap | boolean | true | 是否换行 即支持\n |
mergeRely | int[] | {} | 合并单元格依赖关系,比如第二列合并是基于第一列 则{1}就可以了 |
mergeVertical | boolean | fasle | 纵向合并内容相同的单元格 |
导出CSV(csv):
属性 | 类型 | 默认值 | 功能 |
---|---|---|---|
encoding | String | UTF8 | 文件编码 |
spiltMark | String | , | 分隔符 |
textMark | String | “ | 字符串识别,可以去掉,需要前后一致 |
titleRows | int | 0 | 表格头,忽略 |
headRows | int | 1 | 标题 |
exclusions | String[] | 0 | 忽略的字段 |
public void downLoadCSVWithEasyPOI(HttpServletResponse response) throws Exception {
ServletOutputStream outputStream = response.getOutputStream();
// 文件名
String filename="百万数据.csv";
// 设置两个头 一个是文件的打开方式 一个是mime类型
response.setHeader( "Content-Disposition", "attachment;filename=" + new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("application/csv");
// 创建一个用来写入到csv文件中的writer
CsvExportParams params = new CsvExportParams();
// 设置忽略的列
params.setExclusions(new String[]{"照片"}); //这里写表头 中文
List<User> list = userMapper.selectAll();
CsvExportUtil.exportCsv(params, User.class, list, outputStream);
}
从上述的代码中你会发现,如果需要导出几百万数据时不可能全部加载到一个List中的,所以easyPOI的方式导出csv是支持不了太大的数据量的,如果导出几百万条数据还是得选择OpenCSV方式导出。
EasyPOI导出word(word):
三元运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
&NULL& 空格
&INDEX& 表示循环中的序号,自动添加
]] 换行符 多行遍历导出
sum: 统计数据
public void downloadContractWithEasyPOI(Long id,HttpServletResponse response) throws Exception {
File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
File templatePath = new File(rootPath.getAbsolutePath(),"/word_template/contract_template2.docx");
// 先获取导出word需要的数据
User user = this.findById(id);
// 把需要的数据放到map中,方便替换
Map<String,Object> params = new HashMap<String,Object>();
params.put("userName",user.getUserName());
params.put("hireDate",simpleDateFormat.format(user.getHireDate()));
params.put("address",user.getAddress());
// 下面是表格中需要的数据
List<Map> maplist = new ArrayList<>();
Map<String,Object> map = null;
for (Resource resource : user.getResourceList()) {
map = new HashMap<String,Object>();
map.put("name",resource.getName());
map.put("price",resource.getPrice());
map.put("needReturn",resource.getNeedReturn());
ImageEntity image = new ImageEntity();
image.setHeight(180);
image.setWidth(240);
image.setUrl(rootPath.getPath()+"\\static"+resource.getPhoto());
map.put("photo",image);
maplist.add(map);
}
// 把组建好的表格需要的数据放到大map中
params.put("maplist",maplist);
// 根据模板+数据 导出文档
XWPFDocument xwpfDocument = WordExportUtil.exportWord07(templatePath.getPath(), params);
String filename=user.getUserName()+"_合同.docx";
// 设置文件的打开方式和mime类型
ServletOutputStream outputStream = response.getOutputStream();
response.setHeader( "Content-Disposition", "attachment;filename=" + new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
xwpfDocument.write(outputStream);
}
PDF简介:
Word转PDF:
jacob
,速度上还是可以的,Word中的原样式也不会丢失。JACOB一个Java-COM中间件.通过这个组件你可以在Java应用程序中调用COM组件和Win32程序库。
<dependency>
<groupId>com.jacobgroupId>
<artifactId>jacobartifactId>
<version>1.9version>
dependency>
public class JacobDemo {
public static void main(String[] args) {
String source = "D:\\李四_合同.docx";
String target = "D:\\李四_合同.pdf";
System.out.println("Word转PDF开始启动...");
ActiveXComponent app = null;
try {
// 调用window中的程序
app = new ActiveXComponent("Word.Application");
// 调用的时候不显示窗口
app.setProperty("Visible", false);
// 获得所有打开的文档
Dispatch docs = app.getProperty("Documents").toDispatch();
Dispatch doc = Dispatch.call(docs, "Open", source).toDispatch();
System.out.println("转换文档到PDF:" + target);
// 另存为,将文档保存为pdf,其中Word保存为pdf的格式宏的值是17
Dispatch.call(doc, "SaveAs", target, 17);
Dispatch.call(doc, "Close");
} catch (Exception e) {
System.out.println("Word转PDF出错:" + e.getMessage());
} finally {
// 关闭office
if (app != null) {
app.invoke("Quit", 0);
}
}
}
}
Java PDF制作工具:
iText PDF:
iText是著名的开放项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件。 代码编写太复杂!!!Jasper Report
iText导出PDF(了解):
//建立com.lowagie.text.Document对象的实例。
Document document = new Document();
//建立一个书写器(Writer)与document对象关联,通过书写器(Writer)可以将文档写入到磁盘中。
PDFWriter.getInstance(document, new FileOutputStream("test.PDF"));
//打开文档。
document.open();
//向文档中添加内容。
document.add(new Paragraph("Hello World"));
//关闭文档。
document.close();
Table table = new Table(3);
table.setBorderWidth(1);
table.setBorderColor(new Color(0, 0, 255));
table.setPadding(5);
table.setSpacing(5);
Cell cell = new Cell("header");
cell.setHeader(true);
cell.setColspan(3);
table.addCell(cell);
table.endHeaders();
cell = new Cell("example cell with colspan 1 and rowspan 2");
cell.setRowspan(2);
cell.setBorderColor(new Color(255, 0, 0));
table.addCell(cell);
table.addCell("1.1");
table.addCell("2.1");
table.addCell("1.2");
table.addCell("2.2");
table.addCell("cell test1");
cell = new Cell("big cell");
cell.setRowspan(2);
cell.setColspan(2);
table.addCell(cell);
table.addCell("cell test2");
Font font = getPdfChineseFont();
font.setColor(new BaseColor(0xff0000));
font.setSize(16);
font.setStyle("bold");
font.setStyle("italic");
font.setStyle("underline");
public static Font getPdfChineseFont() throws Exception {
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",
BaseFont.NOT_EMBEDDED);
Font fontChinese = new Font(bfChinese, 12, Font.NORMAL);
return fontChinese;
}
pdfCell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
pdfCell.setBackgroundColor(new BaseColor(0xdd7e6b));
pdfCell.setBorderWidthTop(0.1f);
pdfCell.setBorderWidthBottom(0.1f);
pdfCell.setBorderWidthLeft(0.1f);
pdfCell.setBorderWidthRight(0.1f);
pdfCell.setBorderColorBottom(new BaseColor(0x674ea7));
pdfCell.setBorderColorLeft(new BaseColor(0x674ea7));
pdfCell.setBorderColorRight(new BaseColor(0x674ea7));
pdfCell.setBorderColorTop(new BaseColor(0x674ea7));
我们使用一个封装了iText的一个类库:JasperReport
。JasperReport简介:
JasperReport的生命周期:
设计(Design)阶段:
所谓的报表设计就是创建一些模板,模板包含了报表的布局与设计,包括执行计算的复杂公式、可选的从数据源获取数据的查询语句、以及其它的一些信息。模板设计完成之后,我们将模板保存为JRXML文件(JR代表JasperReports),其实就是一个XML文件。执行(Execution)阶段:
使用以JRXML文件编译为可执行的二进制文件(即.Jasper文件)结合数据进行执行,填充报表数据。输出(Export)阶段:
数据填充结束,可以指定输出为多种形式的报表。JasperReport的执行流程:
制作报表模板
模板编译
构造数据
填充模板数据
模板工具Jaspersoft Studio:
环境准备:
<dependency>
<groupId>net.sf.jasperreportsgroupId>
<artifactId>jasperreportsartifactId>
<version>6.5.0version>
dependency>
<dependency>
<groupId>org.olap4jgroupId>
<artifactId>olap4jartifactId>
<version>1.2.0version>
dependency>
<dependency>
<groupId>com.lowagiegroupId>
<artifactId>itextartifactId>
<version>2.1.7version>
dependency>
导出一个最基本的PDF文件:
public class PDFDemo1 {
/**
* 基于parameters以Map的形式填充数据
*/
public static void main(String[] args) throws Exception {
String filePath = "D:\\test01.jasper";
// 文件的输入流
InputStream inputStream = new FileInputStream(filePath);
//2.创建JasperPrint,向jasper文件中填充数据
FileOutputStream os = new FileOutputStream("d:\\demo1.pdf");
try {
Map parameters = new HashMap<>();
//设置参数 参数的key = 模板中使用的parameters参数的name
parameters.put("name","张三");
parameters.put("phone","13800000000");
//3.将JasperPrint已PDF的形式输出
JasperPrint jasperPrint = JasperFillManager.fillReport(inputStream,parameters,new JREmptyDataSource());
//导出
JasperExportManager.exportReportToPdfStream(jasperPrint,os);
} catch (JRException e) {
e.printStackTrace();
}finally {
os.flush();
}
}
}
wkhtmltopdf简介:
需要安装在服务器上
),但是它并不是一个简单的桌面软件,而且它直接cmd批处理的。图表报表简介:
ECharts
、Highcharts、FusionCharts、amCharts等。报表生成引擎服务商简介:
帆软报表:
目前市场占有率好像最高,功能较为齐全,适应大多数行业的功能,价格较贵,基础版价格:80000元/服务器,高级版价格:500000/服务器。润乾报表:
传统报表的代表,功能也比较强大,展示方面略显不足,整体美观度差一些,但价格便宜。iReport +JasperReports:
是一个开源报表,功能较单一,使用略微繁琐,展现美观度较差。唯一优势可以自己改造。RDP报表工具:
是一款基于java web实现的报表工具,是唯一一款通过web页面设计报表的工具,感觉挺新颖的,功能性和报表的展现美观度还不错。商用免费的一款报表工具。思迈特:
通过excel来进行设计报表,熟悉excel的人开发会更快一些,体验比帆软感觉较差(个人感觉),收费标准不明JFreechart(后端生成):
<dependency>
<groupId>org.jfreegroupId>
<artifactId>jfreechartartifactId>
<version>1.5.0version>
dependency>
----------------饼图&3D饼图---------------
public class JfreeChartsDemo1 {
public static void main(String[] args) throws Exception {
//构建饼图的数据集
DefaultPieDataset dataset=new DefaultPieDataset();
dataset.setValue("销售部", 120);
dataset.setValue("人事部", 50);
dataset.setValue("技术部", 180);
StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
//设置标题字体
standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
//设置图例的字体
standardChartTheme.setRegularFont(new Font("华文宋体", Font.BOLD,15));
//设置轴向的字体
standardChartTheme.setLargeFont(new Font("华文宋体",Font.BOLD,15));
//应用主题样式
ChartFactory.setChartTheme(standardChartTheme);
//参数1 title 标题
//参数2 dataset 数据集
//参数3 是否开启图例
//参数4 是否开启工具栏
//参数5 是否开启url跳转
// JFreeChart chart= ChartFactory.createPieChart("各部门人数", dataset, true, false, false);
JFreeChart chart= ChartFactory.createPieChart3D("各部门人数", dataset, true, false, false);
//生成一张图表的图片文件
ChartUtils.saveChartAsPNG(new File("d:\\chart1.png"), chart, 400, 300);
}
}
------------------折线图-----------------------
public class JfreeChartsDemo2 {
public static void main(String[] args) throws Exception {
//构建饼图的数据集
DefaultCategoryDataset dataset=new DefaultCategoryDataset();
dataset.addValue(15,"技术部","2011");
dataset.addValue(11,"技术部","2012");
dataset.addValue(10,"技术部","2013");
dataset.addValue(16,"技术部","2014");
dataset.addValue(10,"销售部","2011");
dataset.addValue(30,"销售部","2012");
dataset.addValue(6,"销售部","2013");
dataset.addValue(16,"销售部","2014");
dataset.addValue(10,"产品部","2011");
dataset.addValue(20,"产品部","2012");
dataset.addValue(30,"产品部","2013");
dataset.addValue(15,"产品部","2014");
StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
//设置标题字体
standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
//设置图例的字体
standardChartTheme.setRegularFont(new Font("华文宋体", Font.PLAIN,15));
//设置轴向的字体
standardChartTheme.setLargeFont(new Font("华文宋体",Font.PLAIN,15));
//应用主题样式
ChartFactory.setChartTheme(standardChartTheme);
//参数1 title 标题
//参数2 x轴的说明
//参数3 Y轴的说明
//参数4 数据集
JFreeChart chart= ChartFactory.createLineChart("入职人数", "年度", "人数", dataset);
//生成一张图表的图片文件
ChartUtils.saveChartAsPNG(new File("d:\\chart2.png"), chart, 400, 300);
}
}
---------------柱状图(条形图)-------------
public class JfreeChartsDemo3 {
public static void main(String[] args) throws Exception {
//构建饼图的数据集
DefaultCategoryDataset dataset=new DefaultCategoryDataset();
dataset.addValue(15,"技术部","2011");
dataset.addValue(11,"技术部","2012");
dataset.addValue(10,"技术部","2013");
dataset.addValue(16,"技术部","2014");
dataset.addValue(10,"销售部","2011");
dataset.addValue(30,"销售部","2012");
dataset.addValue(6,"销售部","2013");
dataset.addValue(16,"销售部","2014");
dataset.addValue(10,"产品部","2011");
dataset.addValue(20,"产品部","2012");
dataset.addValue(30,"产品部","2013");
dataset.addValue(15,"产品部","2014");
StandardChartTheme standardChartTheme=new StandardChartTheme("CN");
//设置标题字体
standardChartTheme.setExtraLargeFont(new Font("华文宋体",Font.BOLD,20));
//设置图例的字体
standardChartTheme.setRegularFont(new Font("华文宋体", Font.PLAIN,15));
//设置轴向的字体
standardChartTheme.setLargeFont(new Font("华文宋体",Font.PLAIN,15));
//应用主题样式
ChartFactory.setChartTheme(standardChartTheme);
//参数1 title 标题
//参数2 x轴的说明
//参数3 Y轴的说明
//参数4 数据集
JFreeChart chart= ChartFactory.createBarChart("入职人数", "年度", "人数", dataset);
//生成一张图表的图片文件
ChartUtils.saveChartAsPNG(new File("d:\\chart3.png"), chart, 400, 300);
}
}
Highcharts(前端生成):
Echarts(前端生成):