JAVA coopera con la plantilla Freemark para generar un flujo de archivos de retorno de palabras y vue en la recepción recibe la descarga

La idea de la plantilla Freemark para generar palabras es similar a la idea de POI, pero la función de Freemark es más poderosa que POI.

Para PDI, consulte el artículo anterior: https://blog.csdn.net/CarryBest/article/details/94630824

Uno: primero haz una plantilla

   Cree una nueva plantilla de Word y cree el formato requerido en ella. Puede escribir el nombre de la variable directamente, luego guardarlo como xml, abrir xml, Baidu para formatear los datos en formato xml, y luego ver si sus variables están desordenadas, si en mal estado, cámbialo manualmente.

El más básico es este uso, puede juzgar la variable como nula y otros procesos

Si desea repetir una determinada variable, puede usar <#list connmlist como connms>. . . . </ # list> Este tipo de escritura, connmlist es una variable de su backend java, connms. connm significa que su formato de datos de backend java es así: el color correspondiente le ayuda a marcarlo

connmMap.put("connm", wqDataEditsData.getConnm());
connmList.add(connmMap);

resultMap.put (" connmlist ", connmList );

 

Dos: crea un nuevo método público DocumentHandler.java

package com.XX.XXXX.documentHandler;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;

/**
 * 类描述:
 *
 * @author :carry
 * @version: 1.0  CreatedDate in  2019年10月12日
 * <p>
 * 修订历史: 日期			修订者		修订描述
 */
public class DocumentHandler {
    private Configuration configuration = null;

    public DocumentHandler() {
        configuration = new Configuration();
        configuration.setDefaultEncoding("utf-8");
    }

    public void createDoc( Map<String ,Object > result,String fileName,String inPath,String outPath) throws Exception {
        configuration.setDefaultEncoding("utf-8");
        //模板方在项目的resource下的template里面
       // configuration.setClassForTemplateLoading(this.getClass(), "/template");
        //模板放在项目的盘符下
        configuration.setDirectoryForTemplateLoading(new File(inPath));
        System.out.println("文件路径"+outPath);
        Template t = null;
        try {
            t = configuration.getTemplate(fileName,"utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        File outFile = new File(outPath);
        Writer out = null;
        try {
              out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            t.process(result, out);
        } catch (TemplateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @方法描述:
     * path 下载的文件路径  projectname  这里意义不大 直接被vue前台替换了   suffix后缀名  这里意义不大 直接被vue前台替换了
     * @return: javax.servlet.http.HttpServletResponse
     * @Author: carry
     */
    public HttpServletResponse download(String downloadPath, HttpServletResponse response) throws Exception {
        // 以流的形式下载文件。
        InputStream fis = new BufferedInputStream(new FileInputStream(downloadPath));
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();
        response.reset();
        // 设置response的Header  这里意义不大 直接被vue前台替换了 所以可以删掉
        response.addHeader("Content-Disposition", "attachment;filename="
                +"test"+ new String(("" + ".docx").getBytes("gbk"),
                "iso-8859-1"));
        OutputStream toClient = new BufferedOutputStream(
                response.getOutputStream());
        //注意这里很重要 vue的回调里根据ContentType类判断是否是下载的操作,这里不要改
        response.setContentType("application/octet-stream");
        toClient.write(buffer);
        toClient.flush();
        this.close(fis);
        this.close(toClient);
        return response;
    }


    /**
     *  关闭输入流
     * @param is
     */
    private void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *  关闭输出流
     * @param os
     */
    private void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Tres: clase de llamada:

// 数据库里的数据与xml映射起来getLogsData这个方法就省略了,意思很清楚,就是你xml里有叫${name}的,那么java的map里也要响应的放一个键值对的键叫name的。
 Map<String, Object> resultMap = this.getLogsData(params);
 /**
     * @方法描述: 下载导出整编数据
     * @return: void
     * @Author: carry
     */
    @GetMapping("/exportToWordByFmk")
    public void exportToWordByFmk(HttpServletRequest request,
                                  HttpServletResponse response,
                                  @RequestParam(value = "tm", required = true) String tm) {
        try {
            Map<String, String> params = new HashMap<String, String>();
            params.put("tm", tm);

            String path = ResourceUtils.getURL("classpath:").getPath();
            //项目获取盘符
            String root =path.substring(1,3);
            //创建生成的目录
            File outPathFile = new File(root+"\\jddsFile\\docResults");
            if (!outPathFile.exists()) {
                outPathFile.mkdirs();
            }
            //创建读取模板的目录
            File inPathFile = new File(root+"\\jddsFile\\docTemplate");
            if (!inPathFile.exists()) {
                inPathFile.mkdirs();
            }
           //模板名称
            String fileName = "WQDataEditsDataTmpFmk.xml";
            //输出模板名字,java生成的文件名字,前台会被vue替换掉
            String outPath =outPathFile.getAbsolutePath()+"\\WQDataEditsData.docx";
            String inPath =inPathFile.getAbsolutePath();
           // 讲数据库里的数据与xml映射起来
            Map<String, Object> resultMap = this.getLogsData(params);

            DocumentHandler dh = new DocumentHandler();
            dh.createDoc(resultMap, fileName,inPath, outPath);
            dh.download(outPath, response);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

Cuatro: llamada de vue

   downloadFiles(row) {
                let params = {};
               
                this.$api.exportToWordByFmk(params).then(res => {
                    if (res.code == "0") {
                        let data = res.result.data;
                        let blob = new Blob([data], {
                            //type   mimi类型  可以百度详细类型
                            //word文档为msword,application/pdfpdf文档为pdf  application/vnd.ms-excel
                            //image/jpeg jpg
                          //  type: `msword`
                            type: `application/msword`
                        });
                        let objectUrl = URL.createObjectURL(blob);
                        let link = document.createElement("a");
                        let fname = "测试";
                        link.href = objectUrl;
                        link.setAttribute("download", fname);
                        document.body.appendChild(link);
                        link.click();
                    } else {
                        this.$message.error(res.msg);
                    }
                });
            },

Cinco: el método de transmisión de archivos de recepción de vue encapsulada

 // Aquí, si el backend regresa en forma de flujo de archivo, el contenido de retorno personalizado empalmado en el flujo de archivo de respuesta

            let contentType = headers ['tipo de contenido'];

            if (contentType == "application / octet-stream") {

                dejar resultData = datos;

                stdRs = {"code": 0, "msg": "操作 成功", "result": {"data": resultData}}

            }

  //核心请求函数,并做拦截处理。
    // config: {url,method,params,data,timeout,headers,message,loading}
    // resp: {data:{},status:200,statusText:'OK',headers:{},config:{},request:{}}
    request(config) {
        this.onStart(config);
        return this.http.request(config).then((res) => {
            let {data, headers, request, status, statusText} = res;
            let stdRs = null;
            //此处如果后台返回的是文件流的形式,则自定义返回内容拼接上response的文件流
            let contentType=headers['content-type'];
            if(contentType=="application/octet-stream"){
                let resultData=data;
                stdRs={"code":0,"msg":"操作成功","result":{ "data":resultData}}
            }else{
                try {
                    stdRs = JSON.parse(data);
                } catch (e) {
                    stdRs = this.stdRs(status + '', statusText, data);
                }
               
            }

            this.onComplete(config, stdRs);
            return this.resultSuccess(stdRs) ? Promise.resolve(stdRs) : Promise.reject(stdRs);
        }).catch((err) => {
            if (!err.response && !err.request) {
                return Promise.reject(err);
            }
            let {request, response} = err;
            let {status, statusText} = response;
            let stdRs = this.stdRs(status + '', statusText, null);
            this.onComplete(config, stdRs);
            return Promise.reject(stdRs);
        });
    }
 //导出文件
    export(config) {
        if (config.data) {
            config.responseType="blob";
            config.params = {...config.params, ...config.data};
            if(config.data.params != undefined){
                config.params={ ...config.params,...config.data.params}
            }

            delete config.data;
        }
        return this.request(config);
    }

 

Supongo que te gusta

Origin blog.csdn.net/CarryBest/article/details/102586653
Recomendado
Clasificación