需求:
1、根据固定的Excel模板,填充对应的数据生成报表等。
2、不用poi等可以直接操作excel文件表格的类库。
3、增加字段不要频繁去修改代码。
原理:
excel文件其本质都是一个固定格式的文件的组合,我们可以通过zip等工具进行解压并查看里面的文件内容。通过替换对应的文本,再压缩后,即可转为我们最终的excel文件。
示例:
话不多说,先上图:
1.jpg
最终Excel如下图
2.png
本示例是以根据固定的简历模板(简历模板.xlsx
)来生成Excel文件(lastExcel.xlsx
)。
我本地的测试目录为:
C:/Code/Study/excel-demo/doc/
测试中简历模板文件为:
/简历模板.xlsx
临时文件生成目录为:
C:/Code/Study/excel-demo/temp/
其他常量见文件:ExcelConstants.java
主要文件:
1、文本替换工具类 TemplateUtils.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 描述:
*
* @outhor Calebit
* @create 2020-09-24 14:10
*/
public class TemplateUtils {
private static final Logger logger = LoggerFactory.getLogger(TemplateUtils.class);
/**
* 根据键值对填充字符串
* 输出:
* @param content
* @param map
* @return
*/
public static String renderString(String content, Map<String, String> map){
if(StringUtils.isEmpty(content)){
throw new RuntimeException("模板内容为空");
}
Set<Map.Entry<String, String>> sets = map.entrySet();
for(Map.Entry<String, String> entry : sets) {
String regex = "\\$\\{" + entry.getKey() + "\\}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll(entry.getValue());
}
return content;
}
}
2、测试类:TestExcelTemplate.java
import com.constant.ExcelConstants;
import com.utils.FileUtils;
import com.utils.TemplateUtils;
import com.utils.ZipUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* 描述:
*Liuliux
* @outhor Calebit
* @create 2020-09-24 14:34
*/
public class TestExcelTemplate {
public static void main(String[] args) throws Exception {
TestExcelTemplate testExcelTemplate = new TestExcelTemplate();
long nowMillis = System.currentTimeMillis();
//1.组织数据
Map<String, String> data = assembleDataFromDb();
//2、模板文件 ———> zip
String zipFile = copyTemplate(ExcelConstants.TEMPLATE_EXCEL_PATH, ExcelConstants.TEMP_PATH + nowMillis + ".zip");
//3、解压 zip
String descDir = ExcelConstants.TEMP_PATH + nowMillis;
unzipFile(zipFile, descDir);
String templateDataPath = descDir + ExcelConstants.ZIP_DATA_FILE_PATH;
//4、读取并且替换数据
String templateString = FileUtils.readFile(templateDataPath);
//5、替换文件内容
String lastData = TemplateUtils.renderString(templateString, data);
FileUtils.fileLinesWrite(templateDataPath, lastData, false);
String lastZip = ExcelConstants.TEMP_PATH + ExcelConstants.LAST_ZIP_FILE_NAME;
//6、再次压缩文件
ZipUtil.zip(descDir, lastZip);
//7、生成新的excel
String lastExcelPath = ExcelConstants.TEMP_PATH + ExcelConstants.LAST_EXCEL_FILE_NAME;
File lastExcel = new File(lastExcelPath);
if (!lastExcel.exists()) {
lastExcel.createNewFile();
}
FileUtils.copy(new File(lastZip), lastExcel);
//8、TODO 删除临时目录数据
}
/**
* 解压zip文件
*
* @param zipFile
*/
private static void unzipFile(String zipFile, String descDirStr) throws Exception {
File file = new File(descDirStr);
if (!file.exists()) {
file.mkdirs();
}
ZipUtil.unZip(zipFile, descDirStr);
}
/**
* copy文件
*
* @param templateExcelPath
* @param dest
* @return
*/
private static String copyTemplate(String templateExcelPath, String dest) {
try {
File templateFile = new File(templateExcelPath);
File destFile = new File(dest);
if (!destFile.exists()) {
destFile.createNewFile();
}
FileUtils.copy(templateFile, destFile);
return dest;
} catch (Exception exception) {
exception.printStackTrace();
}
return null;
}
public static Map<String, String> assembleDataFromDb() {
Map<String, String> dataMap = new HashMap<>(20);
dataMap.put("userName", "西施");
dataMap.put("sex", "女");
dataMap.put("birthDay", "1700-01-08");
dataMap.put("height", "190CM");
dataMap.put("weight", "47KG");
dataMap.put("nation", "藏族");
dataMap.put("subject", "美女大学");
dataMap.put("telPhone", "18899992222");
dataMap.put("eduExperience1", "美女大学一班");
dataMap.put("eduExperience2", "美女大学二班");
dataMap.put("workExperience1", "美女公司1");
dataMap.put("workExperience2", "美女公司2");
return dataMap;
}
}
3、常量类:ExcelConstants.java
/**
* 描述:
*
* @outhor Calebit
* @create 2020-09-24 14:28
*/
public class ExcelConstants {
/**
* 模板文件所在路径
*/
public static final String TEMPLATE_EXCEL_PATH = "C:/Code/Study/excel-demo/doc/简历模板.xlsx";
/**
* 解压临时目录
*/
public static final String TEMP_PATH = "C:/Code/Study/excel-demo/temp/";
/**
* Excel文件解压后 sharedStrings.xml 所在路径
*/
public static final String ZIP_DATA_FILE_PATH = "/xl/sharedStrings.xml";
/**
* 最终zip文件名
*/
public static final String LAST_ZIP_FILE_NAME = "lastExcel.zip";
/**
* 最终 EXCEL 文件名
*/
public static final String LAST_EXCEL_FILE_NAME = "lastExcel.xlsx";
}
4、工具类FileUtils.java
import java.io.*;
import java.nio.channels.FileChannel;
import java.util.*;
/**
* 描述:
*
* @outhor Calebit
* @create 2020-09-24 14:10
*/
public class FileUtils {
/**
* 拷贝文件
* @param source
* @param dest
* @throws IOException
*/
private static void copyFileUsingFileChannels(File source, File dest) throws IOException {
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
inputChannel = new FileInputStream(source).getChannel();
outputChannel = new FileOutputStream(dest).getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
} finally {
inputChannel.close();
outputChannel.close();
}
}
/**
* 复制文件
*
* @param src
* @param dst
* @throws Exception
*/
public static void copy(File src, File dst) throws Exception {
int BUFFER_SIZE = 4096;
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
out = new BufferedOutputStream(new FileOutputStream(dst), BUFFER_SIZE);
byte[] buffer = new byte[BUFFER_SIZE];
int len = 0;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
} catch (Exception e) {
throw e;
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
}
/**
* 获取windows/linux的项目根目录
*
* @return
*/
public static String getConTextPath() {
String fileUrl = Thread.currentThread().getContextClassLoader().getResource("").getPath();
if ("usr".equals(fileUrl.substring(1, 4))) {
fileUrl = (fileUrl.substring(0, fileUrl.length() - 16));//linux
} else {
fileUrl = (fileUrl.substring(1, fileUrl.length() - 16));//windows
}
return fileUrl;
}
/**
* 字符串转数组
*
* @param str 字符串
* @param splitStr 分隔符
* @return
*/
public static String[] StringToArray(String str, String splitStr) {
String[] arrayStr = null;
if (!"".equals(str) && str != null) {
if (str.indexOf(splitStr) != -1) {
arrayStr = str.split(splitStr);
} else {
arrayStr = new String[1];
arrayStr[0] = str;
}
}
return arrayStr;
}
/**
* 读取文件
*
* @param Path
* @return
*/
public static String readFile(String Path) {
BufferedReader reader = null;
String laststr = "";
try {
FileInputStream fileInputStream = new FileInputStream(Path);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
reader = new BufferedReader(inputStreamReader);
String tempString = null;
while ((tempString = reader.readLine()) != null) {
laststr += tempString;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return laststr;
}
/**
* 获取文件夹下所有文件的名称 + 模糊查询(当不需要模糊查询时,queryStr传空或null即可)
* 1.当路径不存在时,map返回retType值为1
* 2.当路径为文件路径时,map返回retType值为2,文件名fileName值为文件名
* 3.当路径下有文件夹时,map返回retType值为3,文件名列表fileNameList,文件夹名列表folderNameList
*
* @param folderPath 路径
* @param queryStr 模糊查询字符串
* @return
*/
public static HashMap<String, Object> getFilesName(String folderPath, String queryStr) {
HashMap<String, Object> map = new HashMap<>();
List<String> fileNameList = new ArrayList<>();//文件名列表
List<String> folderNameList = new ArrayList<>();//文件夹名列表
File f = new File(folderPath);
if (!f.exists()) { //路径不存在
map.put("retType", "1");
} else {
boolean flag = f.isDirectory();
if (flag == false) { //路径为文件
map.put("retType", "2");
map.put("fileName", f.getName());
} else { //路径为文件夹
map.put("retType", "3");
File fa[] = f.listFiles();
queryStr = queryStr == null ? "" : queryStr;//若queryStr传入为null,则替换为空(indexOf匹配值不能为null)
for (int i = 0; i < fa.length; i++) {
File fs = fa[i];
if (fs.getName().indexOf(queryStr) != -1) {
if (fs.isDirectory()) {
folderNameList.add(fs.getName());
} else {
fileNameList.add(fs.getName());
}
}
}
map.put("fileNameList", fileNameList);
map.put("folderNameList", folderNameList);
}
}
return map;
}
/**
* 以行为单位读取文件,读取到最后一行
*
* @param filePath
* @return
*/
public static List<String> readFileContent(String filePath) {
BufferedReader reader = null;
List<String> listContent = new ArrayList<>();
try {
reader = new BufferedReader(new FileReader(filePath));
String tempString = null;
int line = 1;
// 一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
listContent.add(tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return listContent;
}
/**
* 读取指定行数据 ,注意:0为开始行
*
* @param filePath
* @param lineNumber
* @return
*/
public static String readLineContent(String filePath, int lineNumber) {
BufferedReader reader = null;
String lineContent = "";
try {
reader = new BufferedReader(new FileReader(filePath));
int line = 0;
while (line <= lineNumber) {
lineContent = reader.readLine();
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
return lineContent;
}
/**
* 读取从beginLine到endLine数据(包含beginLine和endLine),注意:0为开始行
*
* @param filePath
* @param beginLineNumber 开始行
* @param endLineNumber 结束行
* @return
*/
public static List<String> readLinesContent(String filePath, int beginLineNumber, int endLineNumber) {
List<String> listContent = new ArrayList<>();
try {
int count = 0;
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String content = reader.readLine();
while (content != null) {
if (count >= beginLineNumber && count <= endLineNumber) {
listContent.add(content);
}
content = reader.readLine();
count++;
}
} catch (Exception e) {
}
return listContent;
}
/**
* 读取若干文件中所有数据
*
* @param listFilePath
* @return
*/
public static List<String> readFileContent_list(List<String> listFilePath) {
List<String> listContent = new ArrayList<>();
for (String filePath : listFilePath) {
File file = new File(filePath);
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String tempString = null;
int line = 1;
// 一次读入一行,直到读入null为文件结束
while ((tempString = reader.readLine()) != null) {
listContent.add(tempString);
line++;
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e1) {
}
}
}
}
return listContent;
}
/**
* 文件数据写入(如果文件夹和文件不存在,则先创建,再写入)
*
* @param filePath
* @param content
* @param flag true:如果文件存在且存在内容,则内容换行追加;false:如果文件存在且存在内容,则内容替换
*/
public static String fileLinesWrite(String filePath, String content, boolean flag) {
String filedo = "write";
FileWriter fw = null;
try {
File file = new File(filePath);
//如果文件夹不存在,则创建文件夹
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {//如果文件不存在,则创建文件,写入第一行内容
file.createNewFile();
fw = new FileWriter(file);
filedo = "create";
} else {//如果文件存在,则追加或替换内容
fw = new FileWriter(file, flag);
}
} catch (IOException e) {
e.printStackTrace();
}
PrintWriter pw = new PrintWriter(fw);
pw.println(content);
pw.flush();
try {
fw.flush();
pw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
return filedo;
}
/**
* 写文件
*
* @param ins
* @param out
*/
public static void writeIntoOut(InputStream ins, OutputStream out) {
byte[] bb = new byte[10 * 1024];
try {
int cnt = ins.read(bb);
while (cnt > 0) {
out.write(bb, 0, cnt);
cnt = ins.read(bb);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.flush();
ins.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 判断list中元素是否完全相同(完全相同返回true,否则返回false)
*
* @param list
* @return
*/
private static boolean hasSame(List<? extends Object> list) {
if (null == list)
return false;
return 1 == new HashSet<Object>(list).size();
}
/**
* 判断list中是否有重复元素(无重复返回true,否则返回false)
*
* @param list
* @return
*/
private static boolean hasSame2(List<? extends Object> list) {
if (null == list)
return false;
return list.size() == new HashSet<Object>(list).size();
}
/**
* 递归删除文件或者目录
*
* @param file_path
*/
public static void deleteEveryThing(String file_path) {
try {
File file = new File(file_path);
if (!file.exists()) {
return;
}
if (file.isFile()) {
file.delete();
} else {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
String root = files[i].getAbsolutePath();//得到子文件或文件夹的绝对路径
deleteEveryThing(root);
}
file.delete();
}
} catch (Exception e) {
System.out.println("删除文件失败");
}
}
/**
* 创建目录
*
* @param dir_path
*/
public static void mkDir(String dir_path) {
File myFolderPath = new File(dir_path);
try {
if (!myFolderPath.exists()) {
myFolderPath.mkdir();
}
} catch (Exception e) {
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}
/**
* 判断指定的文件是否存在。
*
* @param fileName
* @return
*/
public static boolean isFileExist(String fileName) {
return new File(fileName).isFile();
}
/* 得到文件后缀名
*
* @param fileName
* @return
*/
public static String getFileExt(String fileName) {
int point = fileName.lastIndexOf('.');
int length = fileName.length();
if (point == -1 || point == length - 1) {
return "";
} else {
return fileName.substring(point + 1, length);
}
}
/**
* 删除文件夹及其下面的子文件夹
*
* @param dir
* @throws IOException
*/
public static void deleteDir(File dir) throws IOException {
if (dir.isFile())
throw new IOException("IOException -> BadInputException: not a directory.");
File[] files = dir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isFile()) {
file.delete();
} else {
deleteDir(file);
}
}
}
dir.delete();
}
}
5、工具类ZipUtil.java
package com.utils;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Arrays;
import java.util.Enumeration;
/**
* 描述:
*
* @outhor Calebit
* @create 2020-09-24 14:18
*/
public class ZipUtil {
private static final Logger logger = LoggerFactory.getLogger(ZipUtil.class);
/**
* 使用GBK编码可以避免压缩中文文件名乱码
*/
private static final String CHINESE_CHARSET = "GBK";
/**
* 文件读取缓冲区大小
*/
private static final int CACHE_SIZE = 1024;
private ZipUtil() {
}
/**
* <p>
* 压缩文件
* </p>
*
* @param sourceFolder 需压缩文件 或者 文件夹 路径
* @param zipFilePath 压缩文件输出路径
* @throws Exception
*/
public static void zip(String sourceFolder, String zipFilePath) throws Exception {
logger.debug("开始压缩 [" + sourceFolder + "] 到 [" + zipFilePath + "]");
OutputStream out = new FileOutputStream(zipFilePath);
BufferedOutputStream bos = new BufferedOutputStream(out);
org.apache.tools.zip.ZipOutputStream zos = new org.apache.tools.zip.ZipOutputStream(bos);
// 解决中文文件名乱码
zos.setEncoding(CHINESE_CHARSET);
File file = new File(sourceFolder);
String basePath = null;
if (file.isDirectory()) {
basePath = file.getPath();
} else {
basePath = file.getParent();
}
zipFile(file, basePath, zos);
zos.closeEntry();
zos.close();
bos.close();
out.close();
logger.debug("压缩 [" + sourceFolder + "] 完成!");
}
/**
* <p>
* 压缩文件
* </p>
*
* @param sourceFolders 一组 压缩文件夹 或 文件
* @param zipFilePath 压缩文件输出路径
* @throws Exception
*/
public static void zip(String[] sourceFolders, String zipFilePath) throws Exception {
OutputStream out = new FileOutputStream(zipFilePath);
BufferedOutputStream bos = new BufferedOutputStream(out);
org.apache.tools.zip.ZipOutputStream zos = new org.apache.tools.zip.ZipOutputStream(bos);
// 解决中文文件名乱码
zos.setEncoding(CHINESE_CHARSET);
for (int i = 0; i < sourceFolders.length; i++) {
logger.debug("开始压缩 [" + sourceFolders[i] + "] 到 [" + zipFilePath + "]");
File file = new File(sourceFolders[i]);
String basePath = null;
basePath = file.getParent();
zipFile(file, basePath, zos);
}
zos.closeEntry();
zos.close();
bos.close();
out.close();
logger.debug("压缩 " + Arrays.deepToString(sourceFolders) + " 完成!");
}
/**
* <p>
* 递归压缩文件
* </p>
*
* @param parentFile
* @param basePath
* @param zos
* @throws Exception
*/
public static void zipFile(File parentFile, String basePath, ZipOutputStream zos) throws Exception {
File[] files = new File[0];
if (parentFile.isDirectory()) {
files = parentFile.listFiles();
} else {
files = new File[1];
files[0] = parentFile;
}
String pathName;
InputStream is;
BufferedInputStream bis;
byte[] cache = new byte[CACHE_SIZE];
for (File file : files) {
if (file.isDirectory()) {
logger.debug("目录:" + file.getPath());
basePath = basePath.replace('\\', '/');
if (basePath.substring(basePath.length() - 1).equals("/")) {
pathName = file.getPath().substring(basePath.length()) + "/";
} else {
pathName = file.getPath().substring(basePath.length() + 1) + "/";
}
zos.putNextEntry(new org.apache.tools.zip.ZipEntry(pathName));
zipFile(file, basePath, zos);
} else {
pathName = file.getPath().substring(basePath.length());
pathName = pathName.replace('\\', '/');
if (pathName.substring(0, 1).equals("/")) {
pathName = pathName.substring(1);
}
logger.debug("压缩:" + pathName);
is = new FileInputStream(file);
bis = new BufferedInputStream(is);
zos.putNextEntry(new org.apache.tools.zip.ZipEntry(pathName));
int nRead = 0;
while ((nRead = bis.read(cache, 0, CACHE_SIZE)) != -1) {
zos.write(cache, 0, nRead);
}
bis.close();
is.close();
}
}
}
/**
* 解压zip文件
*
* @param zipFileName 待解压的zip文件路径,例如:c:\\111.zip
* @param outputDirectory 解压目标文件夹,例如:c:\\111\
*/
public static void unZip(String zipFileName, String outputDirectory)
throws Exception {
logger.debug("开始解压 [" + zipFileName + "] 到 [" + outputDirectory + "]");
org.apache.tools.zip.ZipFile zipFile = new org.apache.tools.zip.ZipFile(zipFileName);
try {
Enumeration<?> e = zipFile.getEntries();
org.apache.tools.zip.ZipEntry zipEntry = null;
createDirectory(outputDirectory, "");
while (e.hasMoreElements()) {
zipEntry = (org.apache.tools.zip.ZipEntry) e.nextElement();
logger.debug("解压:" + zipEntry.getName());
if (zipEntry.isDirectory()) {
String name = zipEntry.getName();
name = name.substring(0, name.length() - 1);
File f = new File(outputDirectory + File.separator + name);
f.mkdir();
logger.debug("创建目录:" + outputDirectory + File.separator + name);
} else {
String fileName = zipEntry.getName();
fileName = fileName.replace('\\', '/');
if (fileName.indexOf("/") != -1) {
createDirectory(outputDirectory, fileName.substring(0,
fileName.lastIndexOf("/")));
fileName = fileName.substring(
fileName.lastIndexOf("/") + 1,
fileName.length());
}
File f = new File(outputDirectory + File.separator
+ zipEntry.getName());
f.createNewFile();
InputStream in = zipFile.getInputStream(zipEntry);
FileOutputStream out = new FileOutputStream(f);
byte[] by = new byte[1024];
int c;
while ((c = in.read(by)) != -1) {
out.write(by, 0, c);
}
in.close();
out.close();
}
}
logger.debug("解压 [" + zipFileName + "] 完成!");
} catch (Exception ex) {
System.out.println(ex.getMessage());
} finally {
zipFile.close();
}
}
/**
* 创建目录
*
* @param directory
* @param subDirectory
*/
private static void createDirectory(String directory, String subDirectory) {
String dir[];
File fl = new File(directory);
try {
if (subDirectory == "" && fl.exists() != true) {
fl.mkdir();
} else if (subDirectory != "") {
dir = subDirectory.replace('\\', '/').split("/");
for (int i = 0; i < dir.length; i++) {
File subFile = new File(directory + File.separator + dir[i]);
if (subFile.exists() == false)
subFile.mkdir();
directory += File.separator + dir[i];
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
/**
* 无需解压直接读取Zip文件和文件内容
*
* @param file 文件
* @throws Exception
*/
public static void readZipFile(String file) throws Exception {
java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(file);
InputStream in = new BufferedInputStream(new FileInputStream(file));
java.util.zip.ZipInputStream zin = new java.util.zip.ZipInputStream(in);
java.util.zip.ZipEntry ze;
while ((ze = zin.getNextEntry()) != null) {
if (ze.isDirectory()) {
} else {
logger.info("file - " + ze.getName() + " : "
+ ze.getSize() + " bytes");
long size = ze.getSize();
if (size > 0) {
BufferedReader br = new BufferedReader(
new InputStreamReader(zipFile.getInputStream(ze)));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}
System.out.println();
}
}
zin.closeEntry();
}
}
后记
1、本测试只为简单的测试,不提供编码规范(所有的工具类有些为网络摘抄,如有侵权,请联系我删除,其他代码均一口气成型。顺便说一句,需要代码规范的同学,请安装Idea并下载阿里巴巴规约插件,对提升代码质量有很大的帮助,参考地址:https://blog.csdn.net/weixin_39220472/article/details/80077803
)
2、通过以上步骤,我们可以不通过更改代码的情况,只修改模板和原始数据(main方法中的dataMap 中的key
)便可以修改Excel文件。
3、excel中的文件,有些为模板样式文件,理论上也可以更改该文件达到更改模板最终的样式。请读者自行研究。
4、需要源码的同学请自行移步到:https://github.com/liuxianzhong/excel-demo
网友评论