Freemarker 模板导出(带图片)

本文介绍如何使用Freemarker模板引擎,结合Spring MVC实现廉政档案模板的导出,包括数据查询、Base64解密图片并插入Word文档。关键步骤包括配置Freemarker、处理变量替换和图片编码,以及响应头设置实现下载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

1. 依赖

        <!--FreeMarker-->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.28</version>
        </dependency>

2. 模板

  • 需要放图片的位置,直接把图片粘贴进去调整好大小。

    <pkg:part pkg:name="/word/media/image1.jpeg" pkg:contentType="image/jpeg">
       <pkg:binaryData>${image}</pkg:binaryData>
    </pkg:part>
    
  • doc或docx文件另存为xml,然后将xml文件保存到项目模板位置。

  • pkg:binaryData原本的Base64编码</pkg:binaryData>,替换为${变量名}

在这里插入图片描述

3. 具体实现

  • 将需要填充的数据查询,填充模板,本地生成,返回流给前端,浏览器自动下载。
   @GetMapping("/exportPersonalInformation")
    @ApiOperation("廉政档案模板导出")
    @LogAnnotation("廉政档案模板导出")
    public Result exportPersonalInformation(HttpServletResponse response, String oid) {
        try {
            Map<String,Object> map = personalInformationService.exportPersonalInformation(oid);
            //创建文件名称 +String.valueOf(System.currentTimeMillis())
            String fileName = "D:\\" + File.separator + "干部任免审批表.doc";
            String templateFileName = this.getClass().getResource("/").getPath() + "templates" + File.separator;

            //1、创建Configuration对象,传参freemarker的版本号
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_22);
            configuration.setClassicCompatible(true);   //解决空值问题,必不可少
            configuration.setDefaultEncoding("UTF-8");
            //2、设置模板文件所在的路径
            // configuration.setClassForTemplateLoading(this.getClass(), "E:\\workspace\\Java\\company\\cg-server-project\\enterprise-vertical\\vertical-system\\src\\main\\resources\\templates\\leader.ftl");//File.separator
            //3、设置模板文件所用的字符集,一般设置为utf-8
            configuration.setDefaultEncoding("utf-8");
            // 设置存放路径
            configuration.setDirectoryForTemplateLoading(new File(templateFileName));//File.separator

            //4、根据获取到的名称加载一个模板,获取一个模板对象'
            Template template = configuration.getTemplate("personalInfomation.xml", "utf-8");


            //6、创建一个Writer对象,指定生成的文件名
            File outFile = new File(fileName);
            //若是路径不存在则创建
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            Writer out = null;
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(outFile);
                OutputStreamWriter oWriter = new OutputStreamWriter(fos, "UTF-8");
                //这个地方对流的编码不可或缺,使用main()单独调用时,应该可以,但是如果是web请求导出时导出后word文档就会打不开,并且包XML文件错误。主要是编码格式不正确,无法解析。
                //out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));
                out = new BufferedWriter(oWriter);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            try {
                template.process(map, out);
                out.close();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            response.setContentType("application/force-download");// 设置强制下载不打开
            response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("干部任免审批表.doc", "UTF-8"));// 设置文件名
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(outFile);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
               outFile.delete();
            }

            return null;
        } catch (Exception e) {
            log.error("廉政档案模板导出失败", e);
            return Result.error().message("廉政档案模板导出失败");
        }
    }
  • 获得图片的base64码(我的有解密,正常用下面的就行。

        //获得图片的base64码
        public static String getImageBase(String src) throws Exception {
            if (src == null || src == "") {
                return "";
            }
            File file = new File(src);
            if (!file.exists()) {
                return "";
            }
            InputStream in = null;
            byte[] data = null;
            try {
                in = new FileInputStream(file);
                data = new byte[in.available()];
                in.read(data);
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(data);
        }
    
  • 遍历表格我用的 stringBuffer 拼接的数据,仅供参考。

        @Override
        public Map<String, Object> exportPersonalInformation(String oid) throws IOException {
            HashMap<String, Object> map = new HashMap<>();
            LzdaPersonalInformation personalInformation = personalInformationMapper.selectById(oid);
            if (personalInformation != null) {
                SimpleDateFormat ymdFormat = new SimpleDateFormat("yyyy年MM月dd日");
                // 姓名
                map.put("personName", personalInformation.getPersonName());
                // 性别
                map.put("sexName", personalInformation.getSexName());
                // 出生年月
                if (personalInformation.getBirthday() != null) {
                    map.put("birthday", ymdFormat.format(personalInformation.getBirthday()));
                } else {
                    map.put("birthday", "");
                }
                // 民族
                map.put("nationName", personalInformation.getNationName());
                // 籍贯
                map.put("censusRegisterProvinceName", personalInformation.getCensusRegisterProvinceName());
                // 出生地
                map.put("birthplace", personalInformation.getBirthplace());
                // 入党时间
                if (personalInformation.getPartyTime() != null) {
                    map.put("partyTime", ymdFormat.format(personalInformation.getPartyTime()));
                } else {
                    map.put("partyTime", "");
                }
                if (personalInformation.getWorkTime() != null) {
                    // 参加工作时间
                    map.put("workTime", ymdFormat.format(personalInformation.getWorkTime()));
                } else {
                    map.put("workTime", "");
                }
    
                // 健康状况
                map.put("healthConditionNameOne", personalInformation.getHealthConditionNameOne());
                // 专业技术职务
                map.put("professionalTechnical", personalInformation.getProfessionalTechnical());
                // 熟悉专业有何专长
                map.put("specialSkill", personalInformation.getSpecialSkill());
                // 学历 全日制
                map.put("allEducationBackgroundFirstName", personalInformation.getAllEducationBackgroundFirstName());
                map.put("allEducationBackgroundSecondName", personalInformation.getAllEducationBackgroundSecondName());
                // 学历 在职教育
                map.put("inEducationBackgroundFirstName", personalInformation.getInEducationBackgroundFirstName());
                map.put("inEducationBackgroundSecondName", personalInformation.getInEducationBackgroundSecondName());
                // 全日制 毕业院校系及专业
                map.put("allEducationGraduateInstitutions", personalInformation.getAllEducationGraduateInstitutions());
                // 在职教育 毕业院校系及专业
                map.put("inEducationGraduateInstitutions", personalInformation.getInEducationGraduateInstitutions());
                // 现任职务
                map.put("presentOccupation", personalInformation.getPresentOccupation());
                // 拟任职务
                map.put("designatedPosition", personalInformation.getDesignatedPosition());
                // 拟免职务
                map.put("toFreeOccupation", personalInformation.getToFreeOccupation());
                // 简历
                map.put("resume", personalInformation.getResume());
                // 奖惩情况
                map.put("rewardsPunishment", personalInformation.getRewardsPunishment());
                // 年度考核结果
                map.put("annualAssessment", personalInformation.getAnnualAssessment());
                // 任免理由
                map.put("appointReason", personalInformation.getAppointReason());
                // 家庭成员及重要社会关系
                List<LzdaFamilyRelationInfo> familyRelationInfos = familyRelationInfoMapper.selectList(Wrappers.<LzdaFamilyRelationInfo>lambdaQuery().eq(LzdaFamilyRelationInfo::getBusinessId, oid).orderByAsc(LzdaFamilyRelationInfo::getSerialNumber));
                if (CollectionUtils.isNotEmpty(familyRelationInfos)) {
                    StringBuffer family = new StringBuffer();
                    List<LzdaFamilyRelationInfo> familyList = new ArrayList<>();
                    familyList.addAll(familyRelationInfos);
                    // 不到6行添加空数据
                    if (familyRelationInfos.size() < 6) {
                        for (int i = 0; i < 7 - familyRelationInfos.size(); i++) {
                            LzdaFamilyRelationInfo lzdaFamilyRelationInfo = new LzdaFamilyRelationInfo();
                            // 称谓
                            lzdaFamilyRelationInfo.setFamilyRelationAppellation("");
                            // 姓名
                            lzdaFamilyRelationInfo.setFamilyName("");
                            // 年龄
                            lzdaFamilyRelationInfo.setAge("");
                            // 政治面貌
                            lzdaFamilyRelationInfo.setFamilyPartyName("");
                            // 工作单位及职务
                            lzdaFamilyRelationInfo.setFamilyWorkUnit("");
                            familyList.add(lzdaFamilyRelationInfo);
                        }
                    }
                    for (LzdaFamilyRelationInfo lzdaFamilyRelationInfo : familyList) {
                        family.append("<w:tr>\n" +
                                "                            <w:tblPrEx>\n" +
                                "                                <w:tblBorders>\n" +
                                "                                    <w:top w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" +
                                "                                    <w:left w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" +
                                "                                    <w:bottom w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" +
                                "                                    <w:right w:val=\"single\" w:color=\"auto\" w:sz=\"12\" w:space=\"0\"/>\n" +
                                "                                    <w:insideH w:val=\"single\" w:color=\"auto\" w:sz=\"8\" w:space=\"0\"/>\n" +
                                "                                    <w:insideV w:val=\"single\" w:color=\"auto\" w:sz=\"8\" w:space=\"0\"/>\n" +
                                "                                </w:tblBorders>\n" +
                                "                                <w:tblCellMar>\n" +
                                "                                    <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "                                    <w:left w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "                                    <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "                                    <w:right w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "                                </w:tblCellMar>\n" +
                                "                            </w:tblPrEx>\n" +
                                "                            <w:trPr>\n" +
                                "                                <w:cantSplit/>\n" +
                                "                                <w:trHeight w:val=\"697\" w:hRule=\"exact\"/>\n" +
                                "                            </w:trPr>\n" +
                                "                            <w:tc>\n" +
                                "                                <w:tcPr>\n" +
                                "                                    <w:tcW w:w=\"742\" w:type=\"dxa\"/>\n" +
                                "                                    <w:vMerge w:val=\"continue\"/>\n" +
                                "                                    <w:noWrap w:val=\"0\"/>\n" +
                                "                                    <w:textDirection w:val=\"tbRlV\"/>\n" +
                                "                                    <w:vAlign w:val=\"center\"/>\n" +
                                "                                </w:tcPr>\n" +
                                "                                <w:p>\n" +
                                "                                    <w:pPr>\n" +
                                "                                        <w:spacing w:line=\"0\" w:lineRule=\"atLeast\"/>\n" +
                                "                                        <w:ind w:left=\"113\" w:right=\"113\"/>\n" +
                                "                                        <w:jc w:val=\"center\"/>\n" +
                                "                                        <w:rPr>\n" +
                                "                                            <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                                            <w:sz w:val=\"24\"/>\n" +
                                "                                        </w:rPr>\n" +
                                "                                    </w:pPr>\n" +
                                "                                </w:p>\n" +
                                "                            </w:tc>\n" +
                                "<w:tc>\n" +
                                "    <w:tcPr>\n" +
                                "        <w:tcW w:w=\"1092\" w:type=\"dxa\"/>\n" +
                                "        <w:noWrap w:val=\"0\"/>\n" +
                                "        <w:tcMar>\n" +
                                "            <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:left w:w=\"60\" w:type=\"dxa\"/>\n" +
                                "            <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:right w:w=\"40\" w:type=\"dxa\"/>\n" +
                                "        </w:tcMar>\n" +
                                "        <w:vAlign w:val=\"center\"/>\n" +
                                "    </w:tcPr>\n" +
                                "    <w:p>\n" +
                                "        <w:pPr>\n" +
                                "            <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" +
                                "            <w:jc w:val=\"center\"/>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "        </w:pPr>\n" +
                                "        <w:r>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "            <w:t>" + lzdaFamilyRelationInfo.getFamilyRelationAppellation() + "</w:t>\n" +
                                "        </w:r>\n" +
                                "    </w:p>\n" +
                                "</w:tc>\n" +
                                "<w:tc>\n" +
                                "    <w:tcPr>\n" +
                                "        <w:tcW w:w=\"1274\" w:type=\"dxa\"/>\n" +
                                "        <w:noWrap w:val=\"0\"/>\n" +
                                "        <w:tcMar>\n" +
                                "            <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:left w:w=\"60\" w:type=\"dxa\"/>\n" +
                                "            <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:right w:w=\"40\" w:type=\"dxa\"/>\n" +
                                "        </w:tcMar>\n" +
                                "        <w:vAlign w:val=\"center\"/>\n" +
                                "    </w:tcPr>\n" +
                                "    <w:p>\n" +
                                "        <w:pPr>\n" +
                                "            <w:kinsoku w:val=\"0\"/>\n" +
                                "            <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" +
                                "            <w:jc w:val=\"center\"/>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "        </w:pPr>\n" +
                                "        <w:r>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "            <w:t>" + lzdaFamilyRelationInfo.getFamilyName() + "</w:t>\n" +
                                "        </w:r>\n" +
                                "    </w:p>\n" +
                                "</w:tc>\n" +
                                "<w:tc>\n" +
                                "    <w:tcPr>\n" +
                                "        <w:tcW w:w=\"574\" w:type=\"dxa\"/>\n" +
                                "        <w:noWrap w:val=\"0\"/>\n" +
                                "        <w:tcMar>\n" +
                                "            <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:left w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:right w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "        </w:tcMar>\n" +
                                "        <w:vAlign w:val=\"center\"/>\n" +
                                "    </w:tcPr>\n" +
                                "    <w:p>\n" +
                                "        <w:pPr>\n" +
                                "            <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" +
                                "            <w:jc w:val=\"center\"/>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "        </w:pPr>\n" +
                                "        <w:r>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "            <w:t>" + lzdaFamilyRelationInfo.getAge() + "</w:t>\n" +
                                "        </w:r>\n" +
                                "    </w:p>\n" +
                                "</w:tc>\n" +
                                "<w:tc>\n" +
                                "    <w:tcPr>\n" +
                                "        <w:tcW w:w=\"1008\" w:type=\"dxa\"/>\n" +
                                "        <w:noWrap w:val=\"0\"/>\n" +
                                "        <w:tcMar>\n" +
                                "            <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:left w:w=\"60\" w:type=\"dxa\"/>\n" +
                                "            <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:right w:w=\"40\" w:type=\"dxa\"/>\n" +
                                "        </w:tcMar>\n" +
                                "        <w:vAlign w:val=\"center\"/>\n" +
                                "    </w:tcPr>\n" +
                                "    <w:p>\n" +
                                "        <w:pPr>\n" +
                                "            <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" +
                                "            <w:jc w:val=\"center\"/>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "        </w:pPr>\n" +
                                "        <w:r>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "            <w:t>" + lzdaFamilyRelationInfo.getFamilyPartyName() + "</w:t>\n" +
                                "        </w:r>\n" +
                                "    </w:p>\n" +
                                "</w:tc>\n" +
                                "<w:tc>\n" +
                                "    <w:tcPr>\n" +
                                "        <w:tcW w:w=\"4731\" w:type=\"dxa\"/>\n" +
                                "        <w:gridSpan w:val=\"3\"/>\n" +
                                "        <w:noWrap w:val=\"0\"/>\n" +
                                "        <w:tcMar>\n" +
                                "            <w:top w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:left w:w=\"60\" w:type=\"dxa\"/>\n" +
                                "            <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n" +
                                "            <w:right w:w=\"40\" w:type=\"dxa\"/>\n" +
                                "        </w:tcMar>\n" +
                                "        <w:vAlign w:val=\"center\"/>\n" +
                                "    </w:tcPr>\n" +
                                "    <w:p>\n" +
                                "        <w:pPr>\n" +
                                "            <w:spacing w:line=\"320\" w:lineRule=\"exact\"/>\n" +
                                "            <w:jc w:val=\"left\"/>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\" w:eastAsia=\"宋体\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "        </w:pPr>\n" +
                                "        <w:r>\n" +
                                "            <w:rPr>\n" +
                                "                <w:rFonts w:hint=\"eastAsia\"/>\n" +
                                "                <w:szCs w:val=\"28\"/>\n" +
                                "                <w:lang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/>\n" +
                                "            </w:rPr>\n" +
                                "            <w:t>" + lzdaFamilyRelationInfo.getFamilyWorkUnit() + "</w:t>\n" +
                                "        </w:r>\n" +
                                "    </w:p>\n" +
                                "</w:tc>" +
                                "</w:tr>");
                    }
                    map.put("family", family);
                }
                // 呈报单位
                map.put("regionName", SessionUtils.getRegionName());
                map.put("date", ymdFormat.format(new Date()));
                // 填表人
                map.put("preparer", SessionUtils.getUserName());
                // 图片
                MultiMediaInfo multiMediaInfo = multiMediaInfoMapper.selectOne(Wrappers.<MultiMediaInfo>lambdaQuery().eq(MultiMediaInfo::getBusinessOid, oid));
                // 解密图片文件,并生成64编码
                if (multiMediaInfo != null) {
                    byte[] decrypt = MultiMediaUtils.decrypt(multiMediaConfig.getProfile(), multiMediaInfo.getFilePath(), multiMediaConfig.getSecretKey());
                    BASE64Encoder encoder = new BASE64Encoder();
                    if (decrypt != null) {
                        map.put("image", encoder.encode(decrypt));
                    } else {
                        map.put("image", "");
                    }
                }
            }
            return map;
        }
    
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值