EasyExcel导出小结:动态标题、标题格式、相同值合并
1. 实列相关依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
2.EasyExcel导出常见的两种方式:
1.根据路径保存到磁盘:
2.响应Response,用户直接网页下载:
正常分为三个步骤:
(1)构建一个ExcelWriter
对象。
(2)再次通过write
方法写入数据。
(3)调用EasyExcel的finish
。
根据路径保存示例:
private ExcelWriter excelWriter;
public EasyExcelHelper(String path) {
excelWriter = EasyExcel.write(path).build();
//固定的excel标题:
//Class类的属性必须使用`ExcelProperty`注解修饰。
//EasyExcel.write(path, Class).build()
}
//保存到本地磁盘
excelWriter.finish();
响应Respones示例:
private ExcelWriter excelWriter;
public EasyExcelHelper() {
excelWriter = new ExcelWriterBuilder()
.excelType(ExcelTypeEnum.XLSX)
.needHead(true)
.build();
}
public void export(HttpServletResponse response,String fileName ) {
final String exportName = fileName + ExcelTypeEnum.XLSX.getValue();
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
try {
excelWriter.finish();
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(exportName, StandardCharsets.UTF_8.name()));
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(dataBytes.length));
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new ApiException(ErrorEnum.DOWNLOAD_ERROR);
}
}
3.EaxyExcel动态标题
/**
* @param sheetStartNum 默认为0即可
* @param sheetName sheet名称
* @param headList 动态标题,格式:List<List<String>>
* @param list 数据,格式List<List<Object>>;
*/
public void createSheet(Integer sheetStartNum, String sheetName, List headList, List list) {
WriteSheet sheet= EasyExcel.writerSheet(sheetStartNum, sheetName).build();
WriteTable table = new WriteTable();
table.setTableNo(0);
table.setHead(headList);
excelWriter.write(list, sheet, table);
}
4.EaxyExcel标题格式 策略设置
这里我使用两个策略,分别是defaultStyle、CustomerColumnWidthStyleStrategy
。同时启用两个策略时,如果我们创建的excel文件有标题defaultStyle
将会生效。不存在标题时,直接存入数据时,CustomerColumnWidthStyleStrategy
将会适当调整excel宽度。在上面构建WriteSheet的时候我们可以添加这些策略:
EasyExcel.writerSheet(sheetStartNum, sheetName).
registerWriteHandler(defaultStyle()).
registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
/**
* 设置头部样式
*
* @return
*/
private HorizontalCellStyleStrategy defaultStyle() {
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//头部样式
headWriteCellStyle.setFillForegroundColor(IndexedColors.LIME.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 12);
headWriteFont.setFontName("Arial");
headWriteFont.setBold(Boolean.FALSE);
headWriteFont.setColor(IndexedColors.WHITE.getIndex());
headWriteCellStyle.setWriteFont(headWriteFont);
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headWriteCellStyle.setWrapped(Boolean.FALSE);
headWriteCellStyle.setBorderRight(BorderStyle.NONE);
headWriteCellStyle.setBorderLeft(BorderStyle.NONE);
//内容样式
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
}
/**
* 列宽设置
* memo:当数据不存在标题时,defaultStyle头部样式将失效,该设置将会生效
*/
private class CustomerColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
private static final int MAX_COLUMN_WIDTH = 7000;
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead) {
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), MAX_COLUMN_WIDTH);
}
}
5.EaxyExcel 同值合并策略
上面我们添加了excel标题策略,现在我们再添加一个同值合并策略。笔者当前遇到一个需求,需要根据数据中一个字段的集合拆分成多条数据,拆分出来的数据相同值需要合并,所以添加了下面的策略。策略的添加方式与上面一致。
参数说明:
mergeRowIndex:
合并开始的位置,第一行为0,正常是标题行,一般我们从1开始。
eachRow:
多少行合并一次,假设我们现在根据某个属性将一条数据拆分成3条,如果我们不希望这3条以外的数据发生相同值合并,那么可以设置为3。
mergeColumnIndex:
合并列的下标数据,第一列为0,假设等于[0,1,3],那么就意味着只有这3列会发生合并。
这三个参数配合使用,可以达到这样的效果:从x行开始,每y条数据发生合并,合并z[z1,z2,z3]的列。
/**
* 相同值合并策略
*/
public class ExcelMergeStrategy implements CellWriteHandler {
/**
* 合并起始行
*/
private int mergeRowIndex;
/**
* 多少行合并一次
*/
private int eachRow;
/**
* 合并字段的下标
*/
private int[] mergeColumnIndex;
public ExcelMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
if (mergeRowIndex < 0) {
throw new IllegalArgumentException("mergeRowIndex must be greater than 0");
}
if (eachRow < 0) {
throw new IllegalArgumentException("eachRow must be greater than 0");
}
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.eachRow = eachRow;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
//合并条件:
//1.当前行>合并起始行,默认标题行(0)不参加合并
//2.间隔行(eachRow)的上下两条不参加合并
//2.1间隔行(eachRow)==0时,不设置间隔
if (isMerge(curRowIndex)) {
IntStream.range(0, mergeColumnIndex.length).anyMatch(i -> {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cellData, cell, curRowIndex, curColIndex);
return true;
}
return false;
});
}
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
/**
* 判断是否合并
* 1.当前位置必须大于开始位置:curRowIndex > mergeRowIndex
* 2.根据eachRow 判断数据分割的间隔
* 2.1如果根据eachRow=0,默认不合并
* 2.2如果1如果根据eachRow>0,分割后的第一条数据不会与之前的合并:(curRowIndex-mergeRowIndex)%eachRow==0
*
* @return
*/
private boolean isMerge(Integer curRowIndex) {
if ((curRowIndex > mergeRowIndex) && eachRow > 0) {
if ((curRowIndex - mergeRowIndex) % eachRow == 0) {
return false;
}
return true;
}
return false;
}
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, int curRowIndex, int curColIndex) {
//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
Object curData = cellData.getType() == CellDataTypeEnum.STRING ? cellData.getStringValue() : cellData.getNumberValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
preCell.getNumericCellValue();
// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
if (Objects.equals(curData, preData)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
6.动态标题拓展
使用场景:当我们需要动态设置excel标题时,但存在部分标题是固定的情况时,我们可以创建一个DemoVO对象使用DynamicColumn
修饰这些属性。通过调用conver
方法将DemoVO转换成一个ColumnData
对象的集合。
然后通过commons-beanutils包的BeanUtils.describe()方法将查询的集合数据映射成Map。
List<DemoVO> data = query();
List<ColumnData> columnList = conver(DemoVO.class);
//excel数据
List<List<Object>> excelData = Lists.newArrayList();
for (DemoVO o : data) {
//对象转map
Map<String,String> oMap = BeanUtils.describe(o);
List<Object> baseList = Lists.newArrayList();
for (ColumnData columnData : columnList) {
//按照标题顺序设置值
baseList.add(oMap.get(columnData.getFieldName()));
}
excelData.add(baseList);
}
1.自定义动态excel注解
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicColumn {
String name();//excel标题
int index(); //标题顺序
}
@Data
public class DemoVO {
@DynamicColumn(name = "库存", index = 0)
private String stockState;
@DynamicColumn(name = "编码", index = 1)
private String skuCode;
@DynamicColumn(name = "描述", index = 2)
private String skuDesc;
//动态拆分成多个标题
private List<String> address;
}
2.注解对应对象
@Builder
@Data
public class ColumnData {
/**
* excel 标题
*/
private String columnName;
/**
* 字段 属性
*/
private String fieldName;
/**
* 排序
*/
private int index;
}
3.注解转对象工具类
public static <R> List<ColumnData> conver(final Class<R> clazz) {
List<ColumnData> list = Lists.newArrayList();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
DynamicColumn annotation = field.getAnnotation(DynamicColumn.class);
if (!Objects.isNull(annotation)) {
ColumnData columnData = ColumnData.builder().
columnName(annotation.name()).
index(annotation.index()).
fieldName(field.getName()).
build();
list.add(columnData);
}
}
list.sort(Comparator.comparingInt(ColumnData :: getIndex));
return list;
}
7.实际使用
public void export() throws Exception {
String path = "D:/mytest/mycase.xlsx";
new File(path).createNewFile();
EasyExcelHelper easyExcelHelper = new EasyExcelHelper(path);
List<DemoVO> results=query();
//获取注解定义的标题
List<ColumnData> columnList = DynamicColumnUtil.conver(DemoVO.class);
//设置标题,数据
List<List<String>> titles = Lists.newArrayList();
columnList.stream().forEach(c -> titles.add(Lists.newArrayList(c.getColumnName())));
List<List<Object>> excelData = Lists.newArrayList();
//设置合并策略
int[] mergeColumnIndex = columnList.stream().mapToInt(ColumnData :: getIndex).toArray();
easyExcelHelper.mergeStrategy(1, mergeColumnIndex, 5);
boolean isFirst = true;//第一次需要设置动态标题
for (DemoVO o : data) {
//对象转map
Map<String,String> oMap = BeanUtils.describe(o);
List<Object> baseList = Lists.newArrayList();
for (ColumnData columnData : columnList) {
//按照标题顺序设置值
baseList.add(oMap.get(columnData.getFieldName()));
if (isFirst) {
for (String address : o.getAddress()) {
titles.add(address);
}
isFirst=false;
}
//设置值
for (String address : o.getAddress()) {
List<Object> row = Lists.newArrayList();
row.addAll(baseList);//公共部分
row.add(address));
excelData.add(row);
}
}
easyExcelHelper.createSheet(0, "测试", titles, excelData);
easyExcelHelper.getExcelWriter().finish();
}
EasyExcelHelper实际是以上Eaxyexcel功能的封装,部分代码上面均有展示,下方直接给出,方便大家参考:
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import lombok.Data;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;
/**
* @author penggaofeng
* @date 2021/1/25 13:41
* @description:1.辅助实现动态标题;2.实现行数据合并
* @modified By:
* @version: 1.0
*/
@Data
public class EasyExcelHelper {
private ExcelWriter excelWriter;
private ExcelMergeStrategy excelMergeStrategy;
public EasyExcelHelper(String path) {
excelWriter = EasyExcel.write(path).build();
}
/**
* 动态插入
*
* @param sheetStartNum
* @param sheetName sheet名称
* @param headList 动态标题,格式:List<List<String>>
* @param list 数据
*/
public void createSheet(Integer sheetStartNum, String sheetName, List headList, List list) {
WriteSheet sheet;
if (Objects.isNull(excelMergeStrategy)) {
sheet = EasyExcel.writerSheet(sheetStartNum, sheetName).
registerWriteHandler(defaultStyle()).
registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
} else {
sheet = EasyExcel.writerSheet(sheetStartNum, sheetName).
registerWriteHandler(defaultStyle()).
registerWriteHandler(excelMergeStrategy).
registerWriteHandler(new CustomerColumnWidthStyleStrategy()).build();
}
WriteTable table = new WriteTable();
table.setTableNo(0);
table.setHead(headList);
excelWriter.write(list, sheet, table);
}
/**
* 创建合并策略
*
* @param mergeRowIndex 合并开始行 (从1开始,忽略标题)
* @param mergeColumnIndex 合并列(列下标,从0开始)
* @param eachRow 合并间隔,指定几条数据之间合并
*/
public void mergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
excelMergeStrategy = new ExcelMergeStrategy(mergeRowIndex, mergeColumnIndex, eachRow);
}
/**
* 设置头部样式
*
* @return
*/
private HorizontalCellStyleStrategy defaultStyle() {
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//头部样式
headWriteCellStyle.setFillForegroundColor(IndexedColors.LIME.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 12);
headWriteFont.setFontName("Arial");
headWriteFont.setBold(Boolean.FALSE);
headWriteFont.setColor(IndexedColors.WHITE.getIndex());
headWriteCellStyle.setWriteFont(headWriteFont);
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headWriteCellStyle.setWrapped(Boolean.FALSE);
headWriteCellStyle.setBorderRight(BorderStyle.NONE);
headWriteCellStyle.setBorderLeft(BorderStyle.NONE);
//内容样式
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
}
/**
* 列宽设置
* memo:当数据不存在标题时,defaultStyle头部样式将失效,该设置将会生效
*/
private class CustomerColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
private static final int MAX_COLUMN_WIDTH = 7000;
@Override
protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head,
Integer relativeRowIndex, Boolean isHead) {
writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), MAX_COLUMN_WIDTH);
}
}
/**
* 相同值合并策略
*/
public class ExcelMergeStrategy implements CellWriteHandler {
/**
* 合并起始行
*/
private int mergeRowIndex;
/**
* 多少行合并一次
*/
private int eachRow;
/**
* 合并字段的下标
*/
private int[] mergeColumnIndex;
public ExcelMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex, int eachRow) {
if (mergeRowIndex < 0) {
throw new IllegalArgumentException("mergeRowIndex must be greater than 0");
}
if (eachRow < 0) {
throw new IllegalArgumentException("eachRow must be greater than 0");
}
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.eachRow = eachRow;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
//合并条件:
//1.当前行>合并起始行,默认标题行(0)不参加合并
//2.间隔行(eachRow)的上下两条不参加合并
//2.1间隔行(eachRow)==0时,不设置间隔
if (isMerge(curRowIndex)) {
IntStream.range(0, mergeColumnIndex.length).anyMatch(i -> {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cellData, cell, curRowIndex, curColIndex);
return true;
}
return false;
});
}
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
/**
* 判断是否合并
* 1.当前位置必须大于开始位置:curRowIndex > mergeRowIndex
* 2.根据eachRow 判断数据分割的间隔
* 2.1如果根据eachRow=0,默认不合并
* 2.2如果1如果根据eachRow>0,分割后的第一条数据不会与之前的合并:(curRowIndex-mergeRowIndex)%eachRow==0
*
* @return
*/
private boolean isMerge(Integer curRowIndex) {
if ((curRowIndex > mergeRowIndex) && eachRow > 0) {
if ((curRowIndex - mergeRowIndex) % eachRow == 0) {
return false;
}
return true;
}
return false;
}
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, CellData cellData, Cell cell, int curRowIndex, int curColIndex) {
//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
Object curData = cellData.getType() == CellDataTypeEnum.STRING ? cellData.getStringValue() : cellData.getNumberValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() :
preCell.getNumericCellValue();
// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
if (Objects.equals(curData, preData)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex,
curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
}
EasyExcel导出小结:动态标题、标题格式、相同值合并的更多相关文章
- 如何使用DAX函数解决动态图表标题
您可能知道,Power BI中的图表(以及许多其他可视化)具有可以设置为任何静态文本的标题.您可以通过选择图表,转到“可视化对象”窗格中的“格式”选项卡,然后更改“标题”部分中的属性(如下所示)来完成 ...
- Format a Business Object Caption 设置业务对象标题的格式
In this lesson, you will learn how to format the caption of a detail form that displays a business o ...
- Pytest 系列(28)- 参数化 parametrize + @allure.title() 动态生成标题
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 参数化 @pytest.ma ...
- 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续3篇-导出时动态生成多Sheet EXCEL)
ExcelUtility 类库经过我(梦在旅途)近期不断的优化与新增功能,现已基本趋向稳定,功能上也基本可以满足绝大部份的EXCEL导出需求,该类库已在我们公司大型ERP系统全面使用,效果不错,今天应 ...
- Au cs6怎样才能导入和导出m4a或者就是aac格式的文件呢?
[求解]Au cs6怎样才能导入和导出m4a或者就是aac格式的文件呢? 汉化版;解决发法----首选项------常规------媒体与暂存盘-----动态链接媒体下面的启动DLMS格式 ...
- FineReader Mac如何设置参数让导出为DOCX/RTF/ODT格式
Mac版ABBYY FineReader OCR文字识别软件识别文档之后,可以将已识别的文本保存到文件中,还可以通过电子邮件发送输出格式受FineReader支持的已识别文本,了解了ABBYY Fin ...
- easyExcel导出excel的简单使用
easyExcel导出excel的简单使用 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定 ...
- Excel模板导出之动态导出
说明 目前Magicodes.IE已支持Excel模板导出时使用JObject.Dictionary和ExpandoObject来进行动态导出,具体使用请看本篇教程. 本功能的想法.部分实现初步源于a ...
- 复杂的POI导出Excel表格(多行表头、合并单元格)
poi导出excel有两种方式: 第一种:从无到有的创建整个excel,通过HSSFWorkbook,HSSFSheet HSSFCell, 等对象一步一步的创建出工作簿,sheet,和单元格,并添加 ...
随机推荐
- [leetcode]380. Insert Delete GetRandom O(1)设计数据结构,实现存,删,随机取的时间复杂度为O(1)
题目: Design a data structure that supports all following operations in average O(1) time.1.insert(val ...
- 阿里云ssl证书过期怎么解决 (免费SSL证书) 三步解决
阿里云ssl证书过期怎么解决(免费SSL证书),三步解决 使用免费的SSL证书网站 https://ohttps.com 1.注册帐号 2.申请证书 3.部署到阿里云 4.注意事项 1.注册帐号 到 ...
- Spring—SSJ集成&声明式事务管理
1. 课程介绍 1. SSJ集成;(掌握) 2. 声明式事务管理;(掌握) 什么是三大框架 2.1. ssh Struts/Struts2 Spring Hibernate 2.2. ss ...
- JS中的多层次排序算法
引子 排序在编程中随处可见,从开始学习变成,到项目开发,基本上或多或少会遇到一些排序问题,接下来我要写的是我在实际开发终于到的一个排序问题,一开始卡了我很久,后面随着知识积累,实践变多才解决掉了,不知 ...
- java枚举类学习笔记总结
枚举类的说明: 1.枚举类的理解:类的对象只有有限个,确定的.我们称此类为枚举类 2.当需要定义一组常量时,强烈建议使用枚举类 3.如果枚举类中只一个对象,则可以作为单例模式的实现方式. 如何自定义枚 ...
- java容器-Collection
1.介绍 collection<E>是java中容器的最主要的接口,该接口继承于Iterable<E>,使得java中所有实现Collection<E>的容器 ...
- 总结(2019CSP之后),含题解
从\(\mathcal{CSP}\) 爆炸 到现在,已经有\(3\)个月了.这三个月间,我--这个小蒟蒻又接触了许多听不懂的东西 \(\mathcal{No.}1\) 字符串\(\mathcal{ha ...
- [开源软件] 腾讯云Linux服务器一键安装LAMP/LNMP/LANMP环境 转
本帖最后由 我本戏子 于 2015-8-13 22:00 编辑OneinStack是非常优秀的一键PHP/JAVA安装脚本,提供以下环境:lnmp(Linux + Nginx+ MySQL+ PHP) ...
- Haproxy-1.8.20 编译安装:
1 ) haproxy-1.8.20 : # 1.1 ) 安装Haproxy的依赖关系: yum install gcc gcc-c++ glibc glibc-devel pcre pcre-dev ...
- 为了加快速度,Redis都做了哪些“变态”设计
前言 列表对象是 Redis 中 5 种基础数据类型之一,在 Redis 3.2 版本之前,列表对象底层存储结构有两种:linkedlist(双端列表)和 ziplist(压缩列表),而在 Redis ...