1、引入maven依赖:
org.projectlombok
lombok
1.18.8
provided
org.jxls
jxls
2.6.0
org.jxls
jxls-poi
1.2.0
org.apache.commons
commons-jexl
2.1.1
org.jxls
jxls-jexcel
1.0.9
compile
org.apache.commons
commons-lang3
3.8.1
2、生成excel的工具类:
```java
import org.jxls.area.Area;
import org.jxls.command.AbstractCommand;
import org.jxls.command.CellRefGenerator;
import org.jxls.command.Command;
import org.jxls.command.SheetNameGenerator;
import org.jxls.common.CellRef;
import org.jxls.common.Context;
import org.jxls.common.JxlsException;
import org.jxls.common.Size;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.util.Util;
import java.util.Collection;
import java.util.List;
/**
* 扩展jxls each命令
* 增加retainEmpty属性,当items为null或size为0时,也保留当前一行数据的格式
* 循环增加下标变量“var_index”。如var="item",获取下标方法:${item_index}
*/
public class EachCommand extends AbstractCommand {
public enum Direction {RIGHT, DOWN}
private String var;
private String items;
private String select;
private Area area;
private Direction direction = Direction.DOWN;
private CellRefGenerator cellRefGenerator;
private String multisheet;
private String retainEmpty; //当集合大小为0时,是否最少保留一行空行数据
public EachCommand() {
}
/**
* @param var name of the key in the context to contain each collection items during iteration
* @param items name of the collection bean in the context
* @param direction defines processing by rows (DOWN - default) or columns (RIGHT)
*/
public EachCommand(String var, String items, Direction direction) {
this.var = var;
this.items = items;
this.direction = direction == null ? Direction.DOWN : direction;
}
public EachCommand(String var, String items, Area area) {
this(var, items, area, Direction.DOWN);
}
public EachCommand(String var, String items, Area area, Direction direction) {
this(var, items, direction);
if (area != null) {
this.area = area;
addArea(this.area);
}
}
/**
* @param var name of the key in the context to contain each collection items during iteration
* @param items name of the collection bean in the context
* @param area body area for this command
* @param cellRefGenerator generates target cell ref for each collection item during iteration
*/
public EachCommand(String var, String items, Area area, CellRefGenerator cellRefGenerator) {
this(var, items, area, (Direction) null);
this.cellRefGenerator = cellRefGenerator;
}
/**
* Gets iteration directino
*
* @return current direction for iteration
*/
public Direction getDirection() {
return direction;
}
/**
* Sets iteration direction
*
* @param direction
*/
public void setDirection(Direction direction) {
this.direction = direction;
}
public void setDirection(String direction) {
this.direction = Direction.valueOf(direction);
}
/**
* Gets defined cell ref generator
*
* @return current {@link CellRefGenerator} instance or null
*/
public CellRefGenerator getCellRefGenerator() {
return cellRefGenerator;
}
public void setCellRefGenerator(CellRefGenerator cellRefGenerator) {
this.cellRefGenerator = cellRefGenerator;
}
@Override
public String getName() {
return "each";
}
/**
* Gets current variable name for collection item in the context during iteration
*
* @return collection item key name in the context
*/
public String getVar() {
return var;
}
/**
* Sets current variable name for collection item in the context during iteration
*
* @param var
*/
public void setVar(String var) {
this.var = var;
}
/**
* Gets collection bean name
*
* @return collection bean name in the context
*/
public String getItems() {
return items;
}
/**
* Sets collection bean name
*
* @param items collection bean name in the context
*/
public void setItems(String items) {
this.items = items;
}
/**
* Gets current 'select' expression for filtering out collection items
*
* @return current 'select' expression or null if undefined
*/
public String getSelect() {
return select;
}
/**
* Sets current 'select' expression for filtering collection
*
* @param select filtering expression
*/
public void setSelect(String select) {
this.select = select;
}
/**
* @return Context variable name holding a list of Excel sheet names to output the collection to
*/
public String getMultisheet() {
return multisheet;
}
/**
* Sets name of context variable holding a list of Excel sheet names to output the collection to
* @param multisheet
*/
public void setMultisheet(String multisheet) {
this.multisheet = multisheet;
}
@Override
public Command addArea(Area area) {
if (area == null) {
return this;
}
if (super.getAreaList().size() >= 1) {
throw new IllegalArgumentException("You can add only a single area to 'each' command");
}
this.area = area;
return super.addArea(area);
}
@Override
@SuppressWarnings("rawtypes")
public Size applyAt(CellRef cellRef, Context context) {
Collection itemsCollection = Util.transformToCollectionObject(getTransformationConfig().getExpressionEvaluator(), items, context);
int width = 0;
int height = 0;
int index = 0;
CellRefGenerator cellRefGenerator = this.cellRefGenerator;
if (cellRefGenerator == null && multisheet != null) {
List sheetNameList = extractSheetNameList(context);
cellRefGenerator = new SheetNameGenerator(sheetNameList, cellRef);
}
CellRef currentCell = cellRefGenerator != null ? cellRefGenerator.generateCellRef(index, context) : cellRef;
JexlExpressionEvaluator selectEvaluator = null;
if (select != null) {
selectEvaluator = new JexlExpressionEvaluator(select);
}
for (Object obj : itemsCollection) {
context.putVar(var, obj);
context.putVar(var+"_index", index);
if (selectEvaluator != null && !Util.isConditionTrue(selectEvaluator, context)) {
context.removeVar(var);
context.removeVar(var+"_index");
continue;
}
Size size = area.applyAt(currentCell, context);
index++;
if (cellRefGenerator != null) {
width = Math.max(width, size.getWidth());
height = Math.max(height, size.getHeight());
if(index < itemsCollection.size()) {
currentCell = cellRefGenerator.generateCellRef(index, context);
}
} else if (direction == Direction.DOWN) {
currentCell = new CellRef(currentCell.getSheetName(), currentCell.getRow() + size.getHeight(), currentCell.getCol());
width = Math.max(width, size.getWidth());
height += size.getHeight();
} else {
currentCell = new CellRef(currentCell.getSheetName(), currentCell.getRow(), currentCell.getCol() + size.getWidth());
width += size.getWidth();
height = Math.max(height, size.getHeight());
}
context.removeVar(var);
context.removeVar(var+"_index");
}
if("true".equalsIgnoreCase(retainEmpty) && width == 0 && height == 0){
return area.applyAt(currentCell, context);
}
return new Size(width, height);
}
@SuppressWarnings("unchecked")
private List extractSheetNameList(Context context) {
try {
return (List) context.getVar(multisheet);
} catch (Exception e) {
throw new JxlsException("Failed to get sheet names from " + multisheet, e);
}
}
public String getRetainEmpty() {
return retainEmpty;
}
public void setRetainEmpty(String retainEmpty) {
this.retainEmpty = retainEmpty;
}
}
```java
```java
import jxl.write.WriteException;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.jxls.area.Area;
import org.jxls.command.AbstractCommand;
import org.jxls.command.Command;
import org.jxls.common.CellRef;
import org.jxls.common.Context;
import org.jxls.common.Size;
import org.jxls.transform.Transformer;
import org.jxls.transform.jexcel.JexcelTransformer;
import org.jxls.transform.poi.PoiTransformer;
/**
* @Author: David.Huang
* @Date: 2019/12/20 0020 15:04
* 合并单元格命令
*/
@Data
public class MergeCommand extends AbstractCommand {
/**
* 合并的列数
*/
private String cols;
/**
* 合并的行数
*/
private String rows;
private Area area;
/**
* 单元格的样式
*/
private CellStyle cellStyle;
@Override
public String getName() {
return "merge";
}
@Override
public Command addArea(Area area) {
if (super.getAreaList().size() >= 1) {
throw new IllegalArgumentException("You can add only a single area to 'merge' command");
}
this.area = area;
return super.addArea(area);
}
@Override
public Size applyAt(CellRef cellRef, Context context) {
int rows = 1, cols = 1;
if (StringUtils.isNotBlank(this.rows)) {
Object rowsObj = getTransformationConfig().getExpressionEvaluator().evaluate(this.rows, context.toMap());
if (rowsObj != null && NumberUtils.isDigits(rowsObj.toString())) {
rows = NumberUtils.toInt(rowsObj.toString());
}
}
if (StringUtils.isNotBlank(this.cols)) {
Object colsObj = getTransformationConfig().getExpressionEvaluator().evaluate(this.cols, context.toMap());
if (colsObj != null && NumberUtils.isDigits(colsObj.toString())) {
cols = NumberUtils.toInt(colsObj.toString());
}
}
if (rows > 1 || cols > 1) {
Transformer transformer = this.getTransformer();
if (transformer instanceof PoiTransformer) {
return poiMerge(cellRef, context, (PoiTransformer) transformer, rows, cols);
} else if (transformer instanceof JexcelTransformer) {
return jexcelMerge(cellRef, context, (JexcelTransformer) transformer, rows, cols);
}
}
area.applyAt(cellRef, context);
return new Size(1, 1);
}
protected Size poiMerge(CellRef cellRef, Context context, PoiTransformer transformer, int rows, int cols) {
Sheet sheet = transformer.getWorkbook().getSheet(cellRef.getSheetName());
CellRangeAddress region = new CellRangeAddress(
cellRef.getRow(),
cellRef.getRow() + rows - 1,
cellRef.getCol(),
cellRef.getCol() + cols - 1);
sheet.addMergedRegion(region);
area.applyAt(cellRef, context);
if (cellStyle == null) {
setPoiCellStyle(transformer);
}
setRegionStyle(cellStyle, region, sheet);
return new Size(cols, rows);
}
protected Size jexcelMerge(CellRef cellRef, Context context, JexcelTransformer transformer, int rows, int cols) {
try {
transformer.getWritableWorkbook().getSheet(cellRef.getSheetName())
.mergeCells(
cellRef.getRow(),
cellRef.getCol(),
cellRef.getRow() + rows - 1,
cellRef.getCol() + cols - 1);
area.applyAt(cellRef, context);
} catch (WriteException e) {
throw new IllegalArgumentException("合并单元格失败");
}
return new Size(cols, rows);
}
public static void setRegionStyle(CellStyle cs, CellRangeAddress region, Sheet sheet) {
for (int i = region.getFirstRow(); i <= region.getLastRow(); i++) {
Row row = sheet.getRow(i);
if (row == null) {
row = sheet.createRow(i);
}
for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
Cell cell = row.getCell(j);
if (cell == null) {
cell = row.createCell(j);
}
cell.setCellStyle(cs);
}
}
}
/**
* 设置单元格格式
* 根据自己需求修改
* @param transformer
* @return
*/
private void setPoiCellStyle(PoiTransformer transformer) {
cellStyle = transformer.getWorkbook().createCellStyle();
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
}
}
```java
import jxl.write.WriteException;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.jxls.area.Area;
import org.jxls.command.AbstractCommand;
import org.jxls.command.Command;
import org.jxls.common.CellRef;
import org.jxls.common.Context;
import org.jxls.common.Size;
import org.jxls.transform.Transformer;
import org.jxls.transform.jexcel.JexcelTransformer;
import org.jxls.transform.poi.PoiCellData;
import org.jxls.transform.poi.PoiTransformer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: David.Huang
* @Date: 2019/11/18 15:06
*
* 根据范围合并单元格,合并区间不能交叉
* 例如:rang="1:3,5:7"即1到3合并,5到7合并
*/
@Data
public class MergeCommand2 extends AbstractCommand {
/**
* 行合并的范围
*/
private String rowRange;
/**
* 列合并的范围
*/
private String cols;
private Area area;
/**
* 单元格的样式
*/
private CellStyle cellStyle;
@Override
public String getName() {
return "mg";
}
@Override
public Command addArea(Area area) {
if (super.getAreaList().size() >= 1) {
throw new IllegalArgumentException("You can add only a single area to 'merge' command");
}
this.area = area;
return super.addArea(area);
}
@Override
public Size applyAt(CellRef cellRef, Context context) {
String[] rangeArray = rowRange.split(",");
Map map = new HashMap<>();
List startRowList = new ArrayList<>();
for (String r : rangeArray) {
map.put(Integer.valueOf(r.split(":")[0]), Integer.valueOf(r.split(":")[1]));
startRowList.add(Integer.valueOf(r.split(":")[0]));
}
int cols = 1;
if (StringUtils.isNotBlank(this.cols)) {
Object colsObj = getTransformationConfig().getExpressionEvaluator().evaluate(this.cols, context.toMap());
if (colsObj != null && NumberUtils.isDigits(colsObj.toString())) {
cols = NumberUtils.toInt(colsObj.toString());
}
}
Transformer transformer = getTransformer();
if (transformer instanceof PoiTransformer) {
if (cellStyle == null) {
PoiCellData cellData = (PoiCellData) transformer.getCellData(cellRef);
cellStyle = cellData.getCellStyle();
}
if (startRowList.contains(cellRef.getRow())) {
return poiMerge(cellRef, context, (PoiTransformer) transformer, cellRef.getRow(), map.get(cellRef.getRow()), cols);
}
} else if (transformer instanceof JexcelTransformer) {
return jexcelMerge(cellRef, context, (JexcelTransformer) transformer, cellRef.getRow(), map.get(cellRef.getRow()), cols);
}
area.applyAt(cellRef, context);
return new Size(1, 1);
}
protected Size poiMerge(CellRef cellRef, Context context, PoiTransformer transformer, int firstRow, int lastRow, int cols) {
if (cellRef.getRow() == firstRow) {
Sheet sheet = transformer.getWorkbook().getSheet(cellRef.getSheetName());
CellRangeAddress region = new CellRangeAddress(
firstRow - 1,
lastRow - 1,
cellRef.getCol(),
cellRef.getCol() + cols - 1);
sheet.addMergedRegion(region);
area.applyAt(cellRef, context);
MergeCommand.setRegionStyle(cellStyle, region, sheet);
}
return new Size(1, 1);
}
protected Size jexcelMerge(CellRef cellRef, Context context, JexcelTransformer transformer, int firstRow, int lastRow, int cols) {
try {
transformer.getWritableWorkbook().getSheet(cellRef.getSheetName())
.mergeCells(
firstRow - 1,
cellRef.getCol(),
lastRow - 1,
cellRef.getCol() + cols - 1);
area.applyAt(cellRef, context);
} catch (WriteException e) {
throw new IllegalArgumentException("合并单元格失败");
}
return new Size(1, 1);
}
}
import com.hyf.demo.command.MergeCommand;
import com.hyf.demo.command.MergeCommand2;
import org.jxls.builder.xls.XlsCommentAreaBuilder;
import org.jxls.command.EachCommand;
import org.jxls.common.Context;
import org.jxls.expression.JexlExpressionEvaluator;
import org.jxls.transform.Transformer;
import org.jxls.transform.poi.PoiTransformer;
import org.jxls.util.JxlsHelper;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class JxlsUtils {
static {
XlsCommentAreaBuilder.addCommandMapping("each", EachCommand.class);
XlsCommentAreaBuilder.addCommandMapping("merge", MergeCommand.class);
XlsCommentAreaBuilder.addCommandMapping("mg", MergeCommand2.class);
}
public static void exportExcel(InputStream is, OutputStream os, Map<String, Object> model)
throws IOException {
Context context = PoiTransformer.createInitialContext();
if (model != null) {
for (String key : model.keySet()) {
context.putVar(key, model.get(key));
}
}
JxlsHelper jxlsHelper = JxlsHelper.getInstance();
Transformer transformer = jxlsHelper.createTransformer(is, os);
//获得配置
JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator) transformer
.getTransformationConfig().getExpressionEvaluator();
//设置静默模式,不报警告
//evaluator.getJexlEngine().setSilent(true);
//函数强制,自定义功能
Map<String, Object> funcs = new HashMap<String, Object>();
funcs.put("utils", new JxlsUtils()); //添加自定义功能
evaluator.getJexlEngine();//.setFunctions(funcs);
//必须要这个,否者表格函数统计会错乱
jxlsHelper.setUseFastFormulaProcessor(false).processTemplate(context, transformer);
}
public static void exportExcel(File xls, File out, Map<String, Object> model)
throws FileNotFoundException, IOException {
exportExcel(new FileInputStream(xls), new FileOutputStream(out), model);
}
public static void exportExcel(String templatePath, OutputStream os, Map<String, Object> model)
throws Exception {
File template = getTemplate(templatePath);
if (template != null) {
exportExcel(new FileInputStream(template), os, model);
} else {
throw new Exception("Excel 模板未找到。");
}
}
/**
* 获取jxls模版文件
*
* @param path
* @return
*/
public static File getTemplate(String path) {
File template = new File(path);
if (template.exists()) {
return template;
}
return null;
}
}
3、测试
```java
```java
import lombok.Data;
/**
* @Author: David.Huang
* @Date: 2019/12/20 0020 15:05
*/
@Data
public class Student {
private String name;
private String sex;
private String age;
private String grade;
public Student(String name, String sex, String age, String grade) {
this.name = name;
this.sex = sex;
this.age = age;
this.grade = grade;
}
}
```java
```java
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: David.Huang
* @Date: 2019/12/20 0020 16:25
*/
@Data
public class Grade {
private String name;
private List<Student> studentList = new ArrayList<>();
}
```java
import com.hyf.demo.entity.Grade;
import com.hyf.demo.entity.Student;
import com.hyf.demo.until.JxlsUtils;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: David.Huang
* @Date: 2019/12/20 0020 15:04
*/
public class MergeTest1 {
public static void main(String[] args) {
//模拟10条学生信息
Grade grade1 = new Grade();
grade1.setName("1年级");
grade1.getStudentList().add(new Student("小明", "男", "9", "1年级"));
grade1.getStudentList().add(new Student("小天", "男", "9", "1年级"));
grade1.getStudentList().add(new Student("小妮", "女", "10", "1年级"));
grade1.getStudentList().add(new Student("小友", "女", "10", "1年级"));
grade1.getStudentList().add(new Student("小空", "男", "10", "1年级"));
Grade grade2 = new Grade();
grade2.setName("2年级");
grade2.getStudentList().add(new Student("小马", "男", "11", "2年级"));
grade2.getStudentList().add(new Student("小易", "女", "11", "2年级"));
grade2.getStudentList().add(new Student("小启", "女", "11", "2年级"));
grade2.getStudentList().add(new Student("小曲", "女", "12", "2年级"));
grade2.getStudentList().add(new Student("小浪", "男", "12", "2年级"));
List<Grade> gradeList = new ArrayList<>();
gradeList.add(grade1);
gradeList.add(grade2);
Map<String, Object> model = new HashMap<>(10);
model.put("gradeList", gradeList);
String template_path = "D:\\excel_test/student1.xlsx";
String target_path = "D:\\test/student1.xlsx";
try {
JxlsUtils.exportExcel(template_path, new FileOutputStream(target_path), model);
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试代码:
import com.hyf.demo.entity.Student;
import com.hyf.demo.until.JxlsUtils;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: David.Huang
* @Date: 2019/12/20 0020 15:04
*/
public class MergeTest2 {
public static void main(String[] args) {
//模拟10条学生信息
List<Student> list = new ArrayList<>();
list.add(new Student("小明", "男", "9", "四年级"));
list.add(new Student("小天", "男", "9", "四年级"));
list.add(new Student("小妮", "女", "10", "四年级"));
list.add(new Student("小友", "女", "10", "四年级"));
list.add(new Student("小空", "男", "10", "四年级"));
list.add(new Student("小马", "男", "11", "五年级"));
list.add(new Student("小易", "女", "11", "五年级"));
list.add(new Student("小启", "女", "11", "五年级"));
list.add(new Student("小曲", "女", "12", "五年级"));
list.add(new Student("小浪", "男", "12", "五年级"));
Map<String, Object> model = new HashMap<>(10);
model.put("list", list);
String template_path = "D:\\excel_test/student2.xlsx";
String target_path = "D:\\test/student2.xlsx";
try {
JxlsUtils.exportExcel(template_path, new FileOutputStream(target_path), model);
} catch (Exception e) {
e.printStackTrace();
}
}
}
导出效果是一样的:
模板地址:添加链接描述
添加链接描述