• 工具类实现导出复杂excel、word


    1、加入准备的工具类

    1. package com.ly.cloud.utils.exportUtil;
    2. import java.util.Map;
    3. public interface TemplateRenderer {
    4. Writable render(Map dataSource) throws Throwable;
    5. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import java.util.Map;
    3. public interface ExportedFileNameFactory {
    4. String getName(Map dataSource);
    5. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import java.io.IOException;
    3. import java.io.OutputStream;
    4. public interface Writable {
    5. void write(OutputStream outputStream) throws IOException;
    6. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.io.File;
    5. import java.io.FileOutputStream;
    6. import java.util.Map;
    7. public abstract class AbsExporter implements TemplateRenderer {
    8. private static final Logger LOGGER = LoggerFactory.getLogger(AbsExporter.class);
    9. public void doExport(Map dataSource, File exportedFile) throws Throwable {
    10. try(FileOutputStream fos = new FileOutputStream(exportedFile)) {
    11. Writable writable = this.render(dataSource);
    12. writable.write(fos);
    13. }
    14. }
    15. public abstract String getTargetFileSuffix();
    16. public void afterExport() {}
    17. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import org.slf4j.Logger;
    3. import org.slf4j.LoggerFactory;
    4. import java.io.BufferedOutputStream;
    5. import java.io.File;
    6. import java.io.FileOutputStream;
    7. import java.util.ArrayList;
    8. import java.util.List;
    9. import java.util.Map;
    10. import java.util.UUID;
    11. import java.util.zip.ZipOutputStream;
    12. public class ExportProcess {
    13. private static final Logger LOGGER = LoggerFactory.getLogger(ExportProcess.class);
    14. /**
    15. * 要导出的数据源
    16. */
    17. private List> dataSourceList = new ArrayList<>();
    18. /**
    19. * 是否为多文件导出
    20. */
    21. private boolean multiFile;
    22. /**
    23. * 导出器
    24. */
    25. private AbsExporter exporter;
    26. /**
    27. * 导出文件名
    28. */
    29. private String exportedFilename;
    30. /**
    31. * 导出为多文件时的文件名命名工厂
    32. */
    33. private ExportedFileNameFactory nameFactory;
    34. private ExportProcess(Map dataSource, AbsExporter exporter, String exportedFilename) {
    35. this.dataSourceList.add(dataSource);
    36. this.multiFile = false;
    37. this.exporter = exporter;
    38. this.exportedFilename = exportedFilename;
    39. }
    40. private ExportProcess(List> dataSourceList, AbsExporter exporter, String exportedFilename, ExportedFileNameFactory nameFactory) {
    41. this.dataSourceList.addAll(dataSourceList);
    42. this.multiFile = true;
    43. this.exporter = exporter;
    44. this.exportedFilename = exportedFilename;
    45. this.nameFactory = nameFactory;
    46. }
    47. public static ExportProcess newProcess(Map dataSource, AbsExporter exporter, String exportedFilename) {
    48. return new ExportProcess(dataSource, exporter, exportedFilename);
    49. }
    50. public static ExportProcess newProcess(List> dataSourceList, AbsExporter exporter, String exportedFilename, ExportedFileNameFactory nameFactory) {
    51. return new ExportProcess(dataSourceList, exporter, exportedFilename, nameFactory);
    52. }
    53. public ExportResult export() {
    54. ExportResult exportResult = new ExportResult(this.multiFile ? exportAsZipFile() : exportAsSingleFile());
    55. this.exporter.afterExport();
    56. return exportResult;
    57. }
    58. /**
    59. * 导出为单文件
    60. * @return 导出结果
    61. */
    62. private File exportAsSingleFile() {
    63. Map dataSource = this.dataSourceList.get(0);
    64. // 导出文件所在目录路径
    65. String exportedFileDirPath = FileUtils.filePathJoin(FileUtils.TEMP_FILE_PATH, "exportedFileDir" + UUID.randomUUID().toString());
    66. // 创建导出文件所在目录
    67. File exportedFileDir = FileUtils.createDir(exportedFileDirPath);
    68. String exportedFilePath = FileUtils.filePathJoin(exportedFileDirPath, this.exportedFilename + this.exporter.getTargetFileSuffix());
    69. File exportedFile = new File(exportedFilePath);
    70. try {
    71. this.exporter.doExport(dataSource, exportedFile);
    72. return exportedFile;
    73. } catch (Throwable t) {
    74. LOGGER.error(t.getMessage(), t);
    75. FileUtils.deleteDir(exportedFileDir);
    76. }
    77. return null;
    78. }
    79. /**
    80. * 导出为压缩文件
    81. * @return 导出结果
    82. */
    83. private File exportAsZipFile() {
    84. String tempFileDirPath = FileUtils.filePathJoin(FileUtils.TEMP_FILE_PATH, "tempFile" + UUID.randomUUID().toString());
    85. File tempFileDir = FileUtils.createDir(tempFileDirPath);
    86. // 导出文件所在目录路径
    87. String exportedFileDirPath = FileUtils.filePathJoin(FileUtils.TEMP_FILE_PATH, "exportedFileDir" + UUID.randomUUID().toString());
    88. // 创建导出文件所在目录
    89. File exportedFileDir = FileUtils.createDir(exportedFileDirPath);
    90. File exportedFile = new File(FileUtils.filePathJoin(exportedFileDirPath, this.exportedFilename + ".zip"));
    91. try {
    92. for (Map dataSource : this.dataSourceList) {
    93. this.exporter.doExport(dataSource, new File(FileUtils.filePathJoin(tempFileDirPath, this.nameFactory.getName(dataSource) + this.exporter.getTargetFileSuffix())));
    94. }
    95. try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(exportedFile));
    96. BufferedOutputStream bos = new BufferedOutputStream(out)) {
    97. FileUtils.zipDir(tempFileDirPath, out, bos);
    98. }
    99. return exportedFile;
    100. } catch (Throwable t) {
    101. LOGGER.error(t.getMessage(), t);
    102. FileUtils.deleteDir(exportedFileDir);
    103. } finally {
    104. FileUtils.deleteDir(tempFileDir);
    105. }
    106. return null;
    107. }
    108. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import eu.bitwalker.useragentutils.Browser;
    3. import eu.bitwalker.useragentutils.UserAgent;
    4. import org.apache.commons.lang3.StringUtils;
    5. import org.slf4j.Logger;
    6. import org.slf4j.LoggerFactory;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. import java.io.*;
    10. import java.net.URLEncoder;
    11. public class ExportResult {
    12. private static final Logger LOGGER = LoggerFactory.getLogger(ExportResult.class);
    13. private File exportedFile;
    14. ExportResult(File exportedFile) {
    15. this.exportedFile = exportedFile;
    16. }
    17. public File getExportedFile() {
    18. if (null == this.exportedFile) {
    19. throw new NullPointerException("exportedFile 为 null");
    20. }
    21. return exportedFile;
    22. }
    23. public void download(HttpServletRequest request, HttpServletResponse response) {
    24. File exportedFile = getExportedFile();
    25. // 用于清除首部的空白行
    26. response.reset();
    27. response.setContentType("application/x-download; charset=utf-8");
    28. setFileDownloadHeader(request, response, this.exportedFile.getName());
    29. doDownload(response, exportedFile);
    30. }
    31. private void setFileDownloadHeader(HttpServletRequest request, HttpServletResponse response, String filename) {
    32. //获取浏览器信息
    33. String ua = request.getHeader("USER-AGENT");
    34. //转成UserAgent对象
    35. UserAgent userAgent = UserAgent.parseUserAgentString(ua);
    36. //获取浏览器信息
    37. Browser browser = userAgent.getBrowser();
    38. //浏览器名称
    39. String browserName = browser.getName();
    40. String encodedFilename;
    41. try {
    42. encodedFilename = URLEncoder.encode(filename, "UTF8");
    43. if (StringUtils.contains(browserName, "Internet Explorer")) {
    44. response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");
    45. } else if (StringUtils.contains(browserName, "Chrome") || StringUtils.contains(browserName, "Firefox")) {
    46. response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFilename);
    47. } else {// 其他浏览器
    48. response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");
    49. }
    50. } catch (UnsupportedEncodingException e) {
    51. LOGGER.error(e.getMessage(), e);
    52. }
    53. }
    54. private void doDownload(HttpServletResponse response, File exportedFile) {
    55. OutputStream os = null;
    56. byte[] buffer = new byte[1024];
    57. BufferedInputStream bis = null;
    58. FileInputStream exportedFileInputStream = null;
    59. try {
    60. exportedFileInputStream = new FileInputStream(exportedFile);
    61. response.addHeader("content-length", exportedFileInputStream.available() + "");
    62. os = response.getOutputStream();
    63. bis = new BufferedInputStream(exportedFileInputStream);
    64. int i = bis.read(buffer);
    65. while (i != -1) {
    66. os.write(buffer, 0, i);
    67. i = bis.read(buffer);
    68. }
    69. os.flush();
    70. } catch (IOException e) {
    71. LOGGER.error(e.getMessage(), e);
    72. } finally {
    73. if (exportedFileInputStream != null) {
    74. try {
    75. exportedFileInputStream.close();
    76. } catch (IOException e) {
    77. LOGGER.error(e.getMessage(), e);
    78. }
    79. }
    80. if (bis != null) {
    81. try {
    82. bis.close();
    83. } catch (IOException e) {
    84. LOGGER.error(e.getMessage(), e);
    85. }
    86. }
    87. if (os != null) {
    88. try {
    89. os.close();
    90. } catch (IOException e) {
    91. LOGGER.error(e.getMessage(), e);
    92. }
    93. }
    94. // 下载完成后删除临时文件
    95. if (exportedFile.exists()) {
    96. File exportedFileDir = exportedFile.getParentFile();
    97. FileUtils.deleteDir(exportedFileDir);
    98. }
    99. }
    100. }
    101. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import org.apache.commons.lang3.StringUtils;
    3. import java.io.*;
    4. import java.util.zip.ZipEntry;
    5. import java.util.zip.ZipOutputStream;
    6. public class FileUtils {
    7. static {
    8. // 当文件系统中没有nhtemp文件夹的时候,创建
    9. File sf = new File(FileUtils.filePathJoin(System.getProperty("java.io.tmpdir"), "nhtemp"));
    10. if (!sf.exists()) {
    11. sf.mkdirs();
    12. }
    13. }
    14. /**
    15. * 临时文件夹,在临时文件夹中创建nhtemp,用来保存所有使用本工具类创建的文件,以便于统一清空临时文件夹,并且已经包含了文件分割符号,请注意
    16. */
    17. public static final String TEMP_FILE_PATH = FileUtils.filePathJoin(System.getProperty("java.io.tmpdir"), "nhtemp");
    18. /**
    19. * 向文件写入数据
    20. *
    21. * @param is
    22. * @param file
    23. * @throws IOException
    24. */
    25. public static void writeToFile(InputStream is, File file) throws IOException {
    26. FileOutputStream fs = null;
    27. try {
    28. fs = new FileOutputStream(file);
    29. byte[] buffer = new byte[1024];
    30. int byteread = 0;
    31. while ((byteread = is.read(buffer)) != -1) {
    32. fs.write(buffer, 0, byteread);
    33. }
    34. } catch (IOException e) {
    35. throw e;
    36. } finally {
    37. if (fs != null) {
    38. fs.close();
    39. }
    40. is.close();
    41. }
    42. }
    43. /**
    44. * 删除文件夹(会删除文件夹下所有的文件)
    45. *
    46. * @param dir
    47. * @return
    48. */
    49. public static boolean deleteDir(File dir) {
    50. if (dir.isDirectory()) {
    51. String[] children = dir.list();
    52. //递归删除目录中的子目录下
    53. for (int i = 0; i < children.length; i++) {
    54. boolean success = deleteDir(new File(dir, children[i]));
    55. if (!success) {
    56. return false;
    57. }
    58. }
    59. }
    60. // 目录此时为空,可以删除
    61. return dir.delete();
    62. }
    63. public static File createDir(String dirPath) {
    64. File dir = new File(dirPath);
    65. //如果文件夹不存在
    66. if (!dir.exists()) {
    67. //创建文件夹
    68. dir.mkdir();
    69. }
    70. return dir;
    71. }
    72. public static void zipDir(String directoryName, ZipOutputStream zos, BufferedOutputStream bos) {
    73. File file = new File(directoryName);
    74. if (file.exists()) {
    75. File[] fileList = file.listFiles();
    76. assert fileList != null;
    77. for (File f : fileList) {
    78. // 压缩单个文件到 zos
    79. String zipName = f.getName();
    80. try {
    81. zos.putNextEntry(new ZipEntry(zipName));
    82. int len;
    83. FileInputStream is = new FileInputStream(f);
    84. BufferedInputStream bis = new BufferedInputStream(is);
    85. byte[] bytes = new byte[1024];
    86. while ((len = bis.read(bytes)) != -1) {
    87. bos.write(bytes, 0, len);
    88. }
    89. bos.flush();
    90. zos.flush();
    91. // 结束当前压缩文件的添加
    92. bis.close();
    93. is.close();
    94. } catch (IOException e) {
    95. e.printStackTrace();
    96. }
    97. }
    98. }
    99. }
    100. /**
    101. * 路径拼接工具方法
    102. * @param filePath 文件路径
    103. * @return 拼接结果
    104. */
    105. public static String filePathJoin(String... filePath) {
    106. return StringUtils.join(filePath, File.separator);
    107. }
    108. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import cn.afterturn.easypoi.excel.ExcelXorHtmlUtil;
    3. import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
    4. import org.apache.poi.ss.usermodel.Workbook;
    5. import org.slf4j.Logger;
    6. import org.slf4j.LoggerFactory;
    7. import java.util.Map;
    8. public class VelocityTemplateExporter extends AbsExporter {
    9. private static final Logger LOGGER = LoggerFactory.getLogger(VelocityTemplateExporter.class);
    10. private String templateFilename;
    11. public VelocityTemplateExporter(String templateFilename) {
    12. this.templateFilename = templateFilename;
    13. }
    14. @Override
    15. public String getTargetFileSuffix() {
    16. return ".xlsx";
    17. }
    18. @Override
    19. public Writable render(Map dataSource) {
    20. String html = VelocityUtils.render(this.templateFilename + ".vm", dataSource);
    21. LOGGER.trace("渲染的html为:\n{}", html);
    22. Workbook workbook = ExcelXorHtmlUtil.htmlToExcel(html, ExcelType.XSSF);
    23. if (null == workbook) {
    24. throw new NullPointerException("workbook 为 null");
    25. }
    26. return new WorkbookWrapper(workbook);
    27. }
    28. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import org.apache.velocity.VelocityContext;
    3. import org.apache.velocity.app.Velocity;
    4. import org.apache.velocity.exception.VelocityException;
    5. import java.io.StringWriter;
    6. import java.util.Map;
    7. import java.util.Properties;
    8. public class VelocityUtils {
    9. /**
    10. * 模板文件所在目录
    11. */
    12. private static final String TEMPLATE_FILE_DIR = FileUtils.filePathJoin("file", "velocityTemp");
    13. static {
    14. //初始化参数
    15. Properties properties = new Properties();
    16. //设置 velocity 资源加载方式为 class
    17. properties.setProperty("resource.loader", "class");
    18. //设置 velocity 资源加载方式为 class 时的处理类
    19. properties.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
    20. // 执行初始化
    21. Velocity.init(properties);
    22. }
    23. /**
    24. * 渲染对应模板,并输出渲染结果
    25. * @param templateFileName 模板文件名
    26. * @param velocityContext 上下文对象,即渲染使用的数据源
    27. * @return 渲染结果
    28. */
    29. public static String render(String templateFileName, VelocityContext velocityContext) throws VelocityException {
    30. StringWriter writer = new StringWriter();
    31. Velocity.mergeTemplate(FileUtils.filePathJoin(TEMPLATE_FILE_DIR, templateFileName), "UTF-8", velocityContext, writer);
    32. return writer.toString();
    33. }
    34. /**
    35. * 渲染对应模板,并输出渲染结果
    36. * @param templateFileName 模板文件名
    37. * @param renderDataSource 渲染使用的数据源
    38. * @return 渲染结果
    39. */
    40. public static String render(String templateFileName, Map renderDataSource) throws VelocityException {
    41. VelocityContext velocityContext = new VelocityContext(renderDataSource);
    42. return render(templateFileName, velocityContext);
    43. }
    44. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import org.apache.poi.ss.usermodel.Workbook;
    3. import java.io.IOException;
    4. import java.io.OutputStream;
    5. public class WorkbookWrapper implements Writable {
    6. private Workbook workbook;
    7. public WorkbookWrapper(Workbook workbook) {
    8. this.workbook = workbook;
    9. }
    10. @Override
    11. public void write(OutputStream outputStream) throws IOException {
    12. this.workbook.write(outputStream);
    13. }
    14. }
    1. package com.ly.cloud.utils.exportUtil;
    2. import cn.afterturn.easypoi.excel.ExcelExportUtil;
    3. import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
    4. import org.apache.poi.ss.usermodel.Workbook;
    5. import java.util.Map;
    6. import java.util.function.Function;
    7. public class ExcelTemplateExporter extends AbsExporter {
    8. private TemplateExportParams templateExportParams;
    9. private Function afterRender;
    10. public ExcelTemplateExporter(String templateFilename) {
    11. this(templateFilename, null);
    12. }
    13. public ExcelTemplateExporter(String templateFilename, Function afterRender) {
    14. this.templateExportParams = new TemplateExportParams("file/excelTemp/" + templateFilename + ".xlsx");
    15. this.afterRender = afterRender;
    16. }
    17. @Override
    18. public Writable render(Map dataSource) {
    19. Workbook workbook = ExcelExportUtil.exportExcel(this.templateExportParams, dataSource);
    20. if (null == workbook) {
    21. throw new NullPointerException("workbook 为 null");
    22. }
    23. if (this.afterRender != null) {
    24. workbook = this.afterRender.apply(workbook);
    25. }
    26. return new WorkbookWrapper(workbook);
    27. }
    28. @Override
    29. public String getTargetFileSuffix() {
    30. return ".xlsx";
    31. }
    32. }
    1. package com.lili.exportUtil;
    2. import org.apache.poi.xwpf.usermodel.XWPFDocument;
    3. import java.io.IOException;
    4. import java.io.OutputStream;
    5. public class XWPFDocumentWrapper implements Writable {
    6. private XWPFDocument xwpfDocument;
    7. public XWPFDocumentWrapper(XWPFDocument xwpfDocument) {
    8. this.xwpfDocument = xwpfDocument;
    9. }
    10. @Override
    11. public void write(OutputStream outputStream) throws IOException {
    12. this.xwpfDocument.write(outputStream);
    13. }
    14. }
    1. package com.lili.exportUtil;
    2. import cn.afterturn.easypoi.word.WordExportUtil;
    3. import org.apache.poi.xwpf.usermodel.XWPFDocument;
    4. import java.util.Map;
    5. public class WordTemplateExporter extends AbsExporter {
    6. private String templateFilePath;
    7. public WordTemplateExporter(String templateFilename) {
    8. this.templateFilePath = "file/excelTemp/" + templateFilename + ".docx";
    9. }
    10. @Override
    11. public String getTargetFileSuffix() {
    12. return ".docx";
    13. }
    14. @Override
    15. public Writable render(Map dataSource) throws Exception {
    16. XWPFDocument xwpfDocument = WordExportUtil.exportWord07(templateFilePath, dataSource);
    17. XWPFDocumentWrapper xwpfDocumentWrapper = new XWPFDocumentWrapper(xwpfDocument);
    18. return xwpfDocumentWrapper;
    19. }
    20. }

    2、引入所需依赖

    1. <dependency>
    2. <groupId>cn.afterturngroupId>
    3. <artifactId>easypoi-webartifactId>
    4. <version>3.2.0version>
    5. dependency>
    6. <dependency>
    7. <groupId>eu.bitwalkergroupId>
    8. <artifactId>UserAgentUtilsartifactId>
    9. <version>1.21version>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.velocitygroupId>
    13. <artifactId>velocity-engine-coreartifactId>
    14. <version>2.0version>
    15. dependency>
    16. <dependency>
    17. <groupId>org.jsoupgroupId>
    18. <artifactId>jsoupartifactId>
    19. <version>1.12.1version>
    20. dependency>

    3、导出案例

    3.1、导出以下excel

    方式一:

    操作步骤:

    放的位置要和工具类设置位置一样即可。

    然后编写下载接口即可完成。

    访问接口即可下载成功,如下

    方式二:

    操作步骤:

    新建vm文件。放入合适位置(位置取自工具类,可以自行调整)

    vm文件内容示例:

    1. ## 各个列的样式,主要是加上边框
    2. #set($style = 'style="border: 1; height:50;width:12"')
    3. #set($height = 'style="height:30;font-size:9"')
    4. #set($fontSize = 'style="font-size: 20;"')
    5. ## 方法,如果存在则显示否则显示空
    6. #macro(displayValue $value)
    7. #if($value)
    8. $value
    9. #else
    10. #end
    11. #end
    12. ## sheetName 必须存在
    13. <table sheetName="心理咨询来访者登记表">
    14. <tr>
    15. <th colspan="6" $fontSize>心理咨询来访者登记表th>
    16. tr>
    17. <tr>
    18. <th $height colspan="6">为使咨询更有效率,节约你的时间,希望朋友们在咨询前能详细提供如下资料,
    19. 我们承诺进行严格保密!th>
    20. tr>
    21. <tr>
    22. <th $style>姓名th>
    23. <th $style>#displayValue($xm)th>
    24. <th $style>性别th>
    25. <th $style>#displayValue($xb)th>
    26. <th $style>年龄th>
    27. <th $style>#displayValue($age)th>
    28. tr>
    29. <tr>
    30. <th $style>院系th>
    31. <th $style>#displayValue($yx)th>
    32. <th $style>班级th>
    33. <th $style>#displayValue($bj)th>
    34. <th $style>寝室th>
    35. <th $style>#displayValue($qs)th>
    36. tr>
    37. <tr>
    38. <th $style>联系电话th>
    39. <th $style>#displayValue($lxfs)th>
    40. <th colspan="2" $style>辅导员/班主任th>
    41. <th colspan="2" $style>#displayValue($fdyxm)th>
    42. tr>
    43. <tr>
    44. <th colspan="3" $style>如果您有紧急情况,希望我们与谁联系th>
    45. <th colspan="3" $style>#displayValue($jjlxr)th>
    46. tr>
    47. <tr>
    48. <th $style>
    49. 家庭情况(请简要介绍您的家庭背景和成长经历)
    50. th>
    51. <th $style colspan="5">#displayValue($jtqk)th>
    52. tr>
    53. <tr>
    54. <th $style>
    55. 咨询问题(你困惑或难以摆脱的问题是什么?)
    56. th>
    57. <th $style colspan="5">#displayValue($zxwt)th>
    58. tr>
    59. <tr>
    60. <th $style>
    61. 你期望达到的咨询目的
    62. th>
    63. <th $style colspan="5">#displayValue($zxmd)th>
    64. tr>
    65. <tr>
    66. <th colspan="2" $style>以前是否接受过心理咨询或治疗th>
    67. <th $style>#displayValue($sfkgys)th>
    68. <th colspan="2" $style>是否做过相关的心理测验th>
    69. <th $style>#displayValue($fxlcy)th>
    70. tr>
    71. <tr>
    72. <th colspan="2" $style>若做过,结果是:th>
    73. <th colspan="4" $style>#displayValue($xlcyjg)th>
    74. tr>
    75. <tr>
    76. <th colspan="2" $style>预约咨询时间(至少需提前三天预约)th>
    77. <th colspan="4" $style>#displayValue($yysj) #displayValue($yysd)th>
    78. tr>
    79. table>

    这里无非是自己将页面通过tr,th并且合并单元格的方式画出来。

    使用方法:

    结果如下:

    总结:

    方式一:适合那些单条数据,没有变化的excel,直接制作好excel文件,放入项目里面即可完成

    方式二:vm模板可以定义方法与变量,比较适合动态导出sql,可以根据不同map的结果导出不同样子的excel。

    3.2、导出以下excel

    这种就很常见了,平常简单的导出都是这个样子的。今天就用这个工具类来实现一下

    方式一:还是直接放入项目里面的方式

    编写接口进行下载测试:

    下载结果如下:

    注意:这里开头要加{{fe:maplist  结尾要加}},其余就是t.变量名字。其中maplist跟接口设置数据的key对应即可

    方式二:采用vm的方式

    这个时候就用到foreach循环了,vm文件如下

    然后修改接口的实现类

    结果如下:

    总结:

    两种方式都很不错,可以实现效果,但是前者针对那种一成不变的或者简单的很方便。后者对于那种内部循环的就很见效了,比如下面这个。

    红圈的部分就是需要根据次数来循环的部分,这个时候就非常适合用vm模板的方式了。

    拓展

    这个vm文件可自行扩展。非常灵活。下面是我用过的几个vm实战例子

    1. ## 二级列(等级)标题 list
    2. #set($subColumnTitleList = [])
    3. ## 数据索引 list
    4. #set($dataIndexList = [])
    5. ## 各个列的样式,主要是加上边框
    6. #set($style = 'style="border: 1"')
    7. #set($styleW = 'style="border: 1 solid black; width: 25;"')
    8. #set($fontSize = 'style="border: 1 solid black; font-size: 20;"')
    9. #set($bgck = 'style="border: 1 solid black; background-color: yellow;"')
    10. #set($colspanValue = $lbmc.size() + 1)
    11. ## sheetName 必须存在
    12. <table sheetName="columnsExportTest">
    13. <tr>
    14. <th colspan="$num" $fontSize>$titleth>
    15. tr>
    16. <tr>
    17. <th colspan="$num" $style style="font-weight: bold">单位:XXX技术学院th>
    18. tr>
    19. <tr>
    20. <th rowspan="2" $style>院系th>
    21. <th colspan="$colspanValue" $style>学校总人数th>
    22. #foreach($column in $columns)
    23. #if($column.children)
    24. ## <th colspan="$column.children.size()" $style>$column.titleth>
    25. #foreach($subColumn in $column.children)
    26. <th rowspan="1" colspan="2" $style>$subColumn.titleth>
    27. ## 因为 add 方法有返回值,所以这里需要用 html 的方式注释一下,下面同理
    28. #end
    29. #else
    30. <th rowspan="1" colspan="2" $style>$column.titleth>
    31. #end
    32. #end
    33. <th colspan="2" $style>合计th>
    34. tr>
    35. <tr>
    36. #foreach($mc in $lbmc)
    37. <th $style>$mcth>
    38. #end
    39. <th $style>合计th>
    40. #if($subColumnTitleList)
    41. #set($count = 1)
    42. #foreach($subColumnTitle in $subColumnTitleList)
    43. #if ($count % 2 == 0)
    44. <th $bgck>$subColumnTitleth>
    45. #else
    46. <th $style>$subColumnTitleth>
    47. #end
    48. #set($count = $count + 1)
    49. #end
    50. #end
    51. <th $style>人数th>
    52. <th $bgck>发放金额th>
    53. tr>
    54. #foreach($record in $dataSource)
    55. <tr>
    56. <td $styleW>$record.BMMCtd>
    57. #set($sum = 0)
    58. #foreach($dm in $lbdm)
    59. <td $style>$record.get($dm)td>
    60. #set($currentValue = $record.get($dm)) ## 获取当前值
    61. #set($sum = $sum + $currentValue) ## 累加值到 $sum 变量
    62. #end
    63. <td $style>$sumtd>
    64. #set($count = 1)
    65. #foreach($dataIndex in $dataIndexList)
    66. #if($count % 2 == 0)
    67. <td $bgck>$record.get($dataIndex)td>
    68. #else
    69. <td $style>$record.get($dataIndex)td>
    70. #end
    71. #set($count = $count + 1)
    72. #end
    73. #if($record.BMMC == "合计")
    74. <td colspan="1" $style>$record.HJRCtd>
    75. <td colspan="1" $bgck>$record.HJJEtd>
    76. #else
    77. <td $style>$record.HJRCtd>
    78. <td $bgck>$record.HJJEtd>
    79. #end
    80. tr>
    81. #end
    82. table>
    1. ## 各个列的样式,主要是加上边框
    2. #set($style = 'style="border: 1; height:50;width:18"')
    3. #set($bold = 'style="border: 1; height:50;width:18;font-weight: bold;"')
    4. #set($fontSize = 'style="font-size: 20;"')
    5. #macro(displayValue $value)
    6. #if($value)
    7. $value
    8. #else
    9. #end
    10. #end
    11. ## sheetName 必须存在
    12. <table sheetName="心理咨询个案记录表">
    13. <tr>
    14. <th colspan="6" $fontSize>心理咨询个案记录表th>
    15. tr>
    16. <tr>
    17. <th $style>咨询师th>
    18. <th $style>#displayValue($ZXS)th>
    19. <th $style>咨询次数th>
    20. <th $style>#displayValue($dataSource.size())th>
    21. <th $style>来访日期th>
    22. <th $style>#displayValue($dataSource.get(0).ZXSJ)th>
    23. tr>
    24. <tr>
    25. <th $style>来访者th>
    26. <th $style>#displayValue($LFZ)th>
    27. <th $style>性别th>
    28. <th $style>#displayValue($XB)th>
    29. <th $style>年龄th>
    30. <th $style>#displayValue($AGE)th>
    31. tr>
    32. <tr>
    33. <th $style>系部班级th>
    34. <th $style>#displayValue($XBBJ)th>
    35. <th $style>辅导员/班主任th>
    36. <th $style>#displayValue($FDYXM)th>
    37. <th $style>联系人及联系方式th>
    38. <th $style>#displayValue($JJLXR)th>
    39. tr>
    40. #foreach($record in $dataSource)
    41. <tr>
    42. <th rowspan="11" $bold>#displayValue($record.title)th>
    43. <th $bold colspan="5">表现出的问题th>
    44. tr>
    45. <tr>
    46. <th $style>来访者自述th>
    47. <th colspan="4" $style>#displayValue($record.LFZZS)th>
    48. tr>
    49. <tr>
    50. <th $bold colspan="5">问题原因th>
    51. tr>
    52. <tr>
    53. <th $style>促使因素th>
    54. <th colspan="4" $style>#displayValue($record.CSYS)th>
    55. tr>
    56. <tr>
    57. <th $style>先前因素th>
    58. <th colspan="4" $style>#displayValue($record.XQYS)th>
    59. tr>
    60. <tr>
    61. <th $style>社会因素th>
    62. <th colspan="4" $style>#displayValue($record.SHYS)th>
    63. tr>
    64. <tr>
    65. <th $style>健康状况及治疗史th>
    66. <th colspan="4" $style>#displayValue($record.JKZTJZLS)th>
    67. tr>
    68. <tr>
    69. <th $bold colspan="5">分析、评估与咨询方案th>
    70. tr>
    71. <tr>
    72. <th $style>评估诊断th>
    73. <th colspan="4" $style>#displayValue($record.PGZD)th>
    74. tr>
    75. <tr>
    76. <th $style>咨询目标th>
    77. <th colspan="4" $style>#displayValue($record.ZXMB)th>
    78. tr>
    79. <tr>
    80. <th $style>咨询方法th>
    81. <th colspan="4" $style>#displayValue($record.ZXFF)th>
    82. tr>
    83. #end
    84. table>

    3.3、导出word

    接口:

    结果:

  • 相关阅读:
    Jenkins 添加 Slave Agent 节点时报类文件不匹配错误
    Python3.11教程4:异常处理
    程序员与产品之间应该如何配合,什么时候技术为重,什么时候产品为重?
    SQL中:check与 contriate语句约束的区别
    三 TypeScript变量
    PyTorch入门之【dataset】
    2023.11.13 信息学日志
    极致cms1:1精仿资源哟源码/资源网系统/下载教程娱乐网源码
    【零基础入门MyBatis系列】第十五篇——分页插件与注解式开发
    springboot如何集成swagger,swagger如何为所有API添加token参数,swagger常用注解,简介明了,举例说明
  • 原文地址:https://blog.csdn.net/qijing19991210/article/details/136656476