freemarker生成pdf,同时pdf插入页脚,以及数据量大时批量处理

最近公司有个需求,就是想根据一个模板生成一个pdf文档,当即我就想到了freemarker这个远古老东西,毕竟freemarker在模板渲染方面还是非常有优势的。

准备依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>3.0.5</version>
        </dependency>
        <!--pdf 支持中文(默认不支持)-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

我这里不想选freemarker版本,直接用spring集成的省事。
配置一下freemarker的配置

import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
@org.springframework.context.annotation.Configuration
public class FreemarkerConfig {

	// 我这里为了省事,不想创建那么多的Configuration,而且创建Configuration太多不好
    @Bean(name = "cfg")
    public Configuration freemarkerConfigurer() throws IOException {
    	// 选择版本,不同版本对不同的模板语法或者模板转换也会有差异,如果你css 样式比较新,建议选高版本准没错
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        // 选择你存放模板的位置
        final ClassPathResource classPathResource = new ClassPathResource("templates");
        cfg.setDirectoryForTemplateLoading(classPathResource.getFile());
        cfg.setDefaultEncoding("UTF-8");
        // 模板异常处理
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        return cfg;
    }
}

然后我们准备下我们的ftl模板【freemarker的模板文件】----pdf.ftl
freemarker框架类似于beetlthymeleafjspVelocity等模板引擎
JSP就不用说了吧,基本上开发Java的基本上都会了解开发过

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
    .logo {
        width: 320px;
        height: 80px;
    }
    .user-info {
        padding: 10px 10px;
        background: RGB(221, 235, 247);
    }

    .label {
        width: 150px;
        padding: 0 20px 0 0;
        text-align: left;
    }

    .time {
        width: 100px;
        margin-right: 10px;
        text-align: center;
    }

    .label, .time {
        display: inline-block;
    }

    .range-time {
        margin: 20px 0;
    }

    .table-data {
        width: 100%;
    }
    table{
        border-collapse: collapse;
    }
    .header > th {
        text-align: left;
        height: 50px;
    }
    .divider-line {
        margin: 20px 0;
        height: 3px;
        background: #000;
    }
    .desc {
        padding: 15px 10px;
    }
    .date {
        width: 100px;
    }
    .fee {
        width: 50px;
    }
    .name {
        width: 140px;
    }
    .name, .fee, .date {
        padding: 0 10px;
    }
    .download-date {
        text-align: right;
    }
    .bottom-footer-tip {
        width: 100%;
        margin-top: 300px;
        font-size: 12px;
        transform: scale(.9);
    }
</style>
<body>

<div class="download-date">Download on 2022/2/2</div>
<div class="range-time">
    <span class="time">${startTime}</span>
    <span>to</span>
    <span class="time">${endTime}</span>
</div>

<table class="table-data">
    <tr class="header">
        <th>Date</th>
        <th>Name</th>
        <th>desc</th>
        <th>fee</th>
    </tr>
    <tr class="divider-line">
        <th></th>
        <th></th>
        <th></th>
        <th></th>
    </tr>
    <#list list as item>
        <tr>
            <td class="date">${item.date}</td>
            <td class="name">${item.name}</td>
            <td class="desc">
                <div>${item.desc}</div>
            </td>
            <td class="fee">${item.fee}</td>
        </tr>
    </#list>
    <tr class="divider-line">
        <th></th>
        <th></th>
        <th></th>
        <th></th>
    </tr>
</table>
</body>
</html>

这里ftl的语法,我就不多做解释了,我这里附上freemarker的官方文档,感兴趣的自己去学习一下。

然后准备下我们的代码处理逻辑

首先是PDF实体数据

import lombok.Data;

import java.util.List;

@Data
public class PDFData {
    private String logo;
    private String name;
    private String address;
    private String startTime;
    private String endTime;
    private List<TableData> list;
}

然后是关联(table)数据


import lombok.Data;

@Data
public class TableData {
    private String date;
    private String desc;
    private String name;
    private String fee;
}

然后我们处理我们处理逻辑的代码

import com.alibaba.fastjson.JSONObject;
import com.example.web.pojo.TableData;
import com.example.web.pojo.PDFData;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.resolver.font.DefaultFontProvider;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.TextAlignment;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Component
public class FreemarkerExecution {
	
	// 准备下字体文件
    private static String FONT = "./src/main/resources/templates/AlibabaPuHuiTi-3-65-Medium.ttf";
    // 后续转pdf时的配置
    private static ConverterProperties converterProperties = new ConverterProperties();
    private static String base64LogoData = null;
    {
        FontProvider dfp = new DefaultFontProvider();
        //添加字体库
        dfp.addFont(FONT);
        //设置解析属性
        converterProperties.setFontProvider(dfp);
        converterProperties.setCharset("utf-8");
        try {
        	// 有一个logo处理,因为一般服务器渲染的话一般建议将部分图片处理成base64然后放进来,或者大家看看其他的方式
            base64LogoData = imgToBase64(new FileInputStream("./src/main/resources/templates/logo.png"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Resource(name = "cfg")
    private Configuration configuration;

	// 普通处理逻辑
    public void converterHTML() {
    	// 这个会将处理后的html语法输出至 命令行窗口,可以手动创建一个html文件,然后把结果复制进去直接打开查看
        try (Writer out = new OutputStreamWriter(System.out)) {
        	// 获取数据
            final PDFData pdfData = getData();
            Template temp = configuration.getTemplate("pdf.ftl");
            // 直接写出文件
            temp.process(pdfData, out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }
    }

    private void writeToPDF(Template template, Map<String, Object> dataModel) {
        try {
            final File file = new File("D:/pdf/test.html");
            template.process(dataModel, new OutputStreamWriter(new FileOutputStream(file)));
            final File pdfFile = new File("D:/pdf/test.pdf");
            HtmlConverter.convertToPdf(file, pdfFile, converterProperties);
            PdfReader reader = new PdfReader(new File("D:/pdf/test.pdf"));
            PdfWriter writer = new PdfWriter(new FileOutputStream("D:/pdf/test_1.pdf"));
            PdfDocument pdfDocument = new PdfDocument(reader, writer);
            // 页大小
            final PageSize pageSize = pdfDocument.getDefaultPageSize();
            // 页数
            final int numberOfPages = pdfDocument.getNumberOfPages();
            for (int i = 1; i <= numberOfPages; i++) {
                PdfPage page = pdfDocument.getPage(i);
                final PdfDocument pdfDoc = page.getDocument();
                final Document document = new Document(pdfDoc);
                final Paragraph paragraph = new Paragraph("Page" + i)
                        .setFont(PdfFontFactory.createFont(FONT))
                        .setFontColor(new DeviceRgb(0, 0, 0))
                        .setFixedPosition(i, 0, 10, pageSize.getWidth())
                        .setFontSize(10)
                        .setTextAlignment(TextAlignment.CENTER);
                document.add(paragraph);
            }
            pdfDocument.close();
            reader.close();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private PDFData getData() throws FileNotFoundException {
        PDFData data = new PDFData();
        data.setName("重生之我是蔡徐坤");
        data.setAddress("蔡徐坤蔡徐坤喜欢唱跳rap篮球");
        data.setStartTime("01-Feb-22");
        data.setEndTime("28-Feb-22");
        data.setLogo("data:image/png;base64," + base64LogoData);
        final LocalDateTime nowTime = LocalDateTime.now();
        final List<TableData> arr = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            final TableData tableData = new TableData();
            tableData .setDesc(i % 2 == 0 ? "交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大" : "交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大交会毫不我交会毫不我哒哒哒哒哒哒多多多多多多多交会毫不我电话电话大");
            tableData .setName("蔡徐坤" + i);
            tableData .setFee(1000 + i + "");
            tableData .setDate(nowTime.plusDays(-i).format(DateTimeFormatter.ofPattern("YYYY/MM/dd")));
            arr.add(tableData);
        }
        data.setList(arr);
        return data;
    }

    private String imgToBase64(InputStream inputStream) {
        byte[] data = null;
        try {
            data = new byte[inputStream.available()];
            inputStream.read(data);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(data);
    }
}

这里会又有一个问题出现,就是我们一般处理PDF的时候,数据不可能一次性处理到内存中,因为我们服务器内存等问题,假如我们有100w数据,肯定不能一次性查出来,由此我们就需要批量处理,这里我们可以将模板拆分开,重复的数据放一个模板文件,然后后续进行模板的组装。

首先,我将一个ftl模板文件拆成了三个 👉 header.ftl,content.ftl,footer.ftl,然后再由一个主的核心ftl模板来组装这几个模板。
思路:准备上述模板文件,然后渲染模板后继续解析成ftl模板文件,然后读取选然后的ftl模板文件,然后转成html,最后通过html文件处理成pdf文件。

这里content.ftl是批量的数据,因为不能一次读取大量数据,所以这里content.ftl要单独处理一下。

Main.ftl
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
    .logo {
        width: 320px;
        height: 80px;
    }

    .user-info {
        padding: 10px 10px;
        background: RGB(221, 235, 247);
    }

    .label {
        width: 150px;
        padding: 0 20px 0 0;
        text-align: left;
    }

    .time {
        width: 100px;
        margin-right: 10px;
        text-align: center;
    }

    .label, .time {
        display: inline-block;
    }

    .range-time {
        margin: 20px 0;
    }

    .table-data {
        width: 100%;
    }

    table {
        border-collapse: collapse;
    }

    .header > th {
        text-align: left;
        height: 50px;
    }

    .divider-line {
        margin: 20px 0;
        height: 3px;
        background: #000;
    }

    .desc {
        padding: 15px 10px;
    }

    .date {
        width: 100px;
    }

    .name {
        width: 50px;
    }

    .fee{
        width: 140px;
    }

    .fee, .name , .date {
        padding: 0 10px;
    }

    .download-date {
        text-align: right;
    }

    .bottom-footer-tip {
        width: 100%;
        margin-top: 300px;
        font-size: 12px;
        transform: scale(.9);
    }
</style>
<body>


${headerPath}
<table class="table-data">
    <tr class="header">
        <th>Date</th>
        <th>Desc</th>
        <th>Name</th>
        <th>Fee</th>
    </tr>
    <tr class="divider-line">
        <th></th>
        <th></th>
        <th></th>
        <th></th>
    </tr>
    <#list contentPathList as content>
        ${content}
    </#list>
    <tr class="divider-line">
        <th></th>
        <th></th>
        <th></th>
        <th></th>
    </tr>
</table>
${footerPath}

<#--<#include "header.ftl">-->
<#--<#include "content.ftl">-->
<#--<#include "footer.ftl">-->

</body>
</html>
header.ftl
<img src="${logo}" class="logo">
<div class="download-date">Download on 2022/2/2</div>
<div class="user-info">
    <div>
        <div class="label">User:</div>
        <span>${name}</span>
    </div>
    <div>
        <div class="label">Address:</div>
        <span>${address}</span>
    </div>
</div>

<div class="range-time">
    <span class="time">${startTime}</span>
    <span>to</span>
    <span class="time">${endTime}</span>
</div>
content.ftl

    <#list list as item>
        <tr>
            <td class="date">${item.date}</td>
            <td class="desc">
                <div>${item.desc}</div>
            </td>
            <td class="fee">${item.fee}</td>
            <td class="name">${item.name}</td>
        </tr>
    </#list>

footer.ftl

    <#list list as item>
        <tr>
            <td class="date">${item.date}</td>
            <td class="desc">
                <div>${item.desc}</div>
            </td>
            <td class="fee">${item.fee}</td>
            <td class="name">${item.name}</td>
        </tr>
    </#list>

核心处理逻辑
    void allTemplatesWriteToPDF() {
        // 所有子模板
        final List<String> ftlNameList = new ArrayList<>();
        try {
        	// 读取对应的模板文件
            final Template template = getTemplate("content.ftl");
            final Template headerTemplate = getTemplate("header.ftl");
            final Template footerTemplate = getTemplate("footer.ftl");
            final PDFData data = getData();
            // 先处理头部和尾部
            headerTemplate.process(data, new FileWriter("D:/pdf/content/header.ftl"));
            footerTemplate.process(data, new FileWriter("D:/pdf/content/footer.ftl"));
            // mock 模拟数据库查询10次
            for (int i = 0; i < 10; i++) {
                // 组装10条数据,算上10次循环一共100条数据
                final PDFData pdfData = getData();
                String fileName = "D:/pdf/content/content" + i + ".ftl";
                final FileWriter writer = new FileWriter(fileName);
                // 存储最后框架模板的数据,这里是存储了freemarker include 语法连接所有的需要组装的数据模板名称
                ftlNameList.add("<#include \"" + fileName.substring(fileName.lastIndexOf("/") + 1, fileName.lastIndexOf(".")) + ".ftl \"/>");
                // 生成对应的模板文档
                template.process(pdfData, writer);
                writer.flush();
                writer.close();
            }
            // 获取所有子模板
            final Configuration cdf = new Configuration(Configuration.VERSION_2_3_22);
            cdf.setDirectoryForTemplateLoading(new File("D:/pdf/content"));
            cdf.setDefaultEncoding("UTF-8");
            cdf.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            final Template mainTemplate = getTemplate("main.ftl");
            final HashMap<Object, Object> map = new HashMap<>();
            map.put("headerPath", "<#include \"" + "header.ftl\"/>");
            map.put("contentPathList", ftlNameList);
            map.put("footerPath", "<#include \"" + "footer.ftl\"/>");
            mainTemplate.process(map, new FileWriter("D:/pdf/content/main.ftl"));
            final Template cdfTemplate = cdf.getTemplate("main.ftl");
            cdfTemplate.process(null, new FileWriter("D:/pdf/content/main.html"));
            final File pdfFile = new File("D:/pdf/test_new.pdf");
            HtmlConverter.convertToPdf(new File("D:/pdf/content/main.html"), pdfFile, converterProperties);
            PdfReader reader = new PdfReader(pdfFile);
            PdfWriter writer = new PdfWriter(new FileOutputStream("D:/pdf/test_new_1.pdf"));
            PdfDocument pdfDocument = new PdfDocument(reader, writer);
            // 页大小
            final PageSize pageSize = pdfDocument.getDefaultPageSize();
            // 页数
            final int numberOfPages = pdfDocument.getNumberOfPages();
            // 这里是处理页脚数据
            for (int i = 1; i <= numberOfPages; i++) {
                PdfPage page = pdfDocument.getPage(i);
                final PdfDocument pdfDoc = page.getDocument();
                final Document document = new Document(pdfDoc);
                final Paragraph paragraph = new Paragraph("Page" + i)
                        .setFont(PdfFontFactory.createFont(FONT))
                        .setFontColor(new DeviceRgb(0, 0, 0))
                        .setFixedPosition(i, 0, 10, pageSize.getWidth())
                        .setFontSize(10)
                        .setTextAlignment(TextAlignment.CENTER);
                document.add(paragraph);
            }
            pdfDocument.close();
            reader.close();
            writer.close();
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
    }

    private Template getTemplate(String name) throws IOException {
        return configuration.getTemplate(name);
    }

在这里插入图片描述

在这里插入图片描述

OK,大概就这样,剩下的大家自己去玩吧, 解散!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/770139.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大华设备接入GB28181/GAT1400视频汇聚管理平台EasyCVR安防监控系统的具体操作步骤

智慧城市/视频汇聚/安防监控平台EasyCVR兼容性强&#xff0c;支持多协议接入&#xff0c;包括国标GB/T 28181协议、GA/T 1400协议、部标JT808协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大华SDK、华为SDK、宇视SDK、乐橙SDK、萤石云SDK等&#xff0c;并能对外分发RTMP、…

vue H5页面video 视频流自动播放, 解决ios不能自动播放问题

视频组件 <videostyle"width: 100%; height: 100%;object-fit: fill"class"player"refplayer_big_boxcontrolspreloadautoplay //自动播放muted //是否静音playsinline"true"x5-playsinline""webkit-playsinline"tru…

Vanchip新一代WiFi产品全新亮相

1‧ 研讨会介绍 随着 Wi-Fi7 时代的到来&#xff0c;高频信号衰减较高&#xff0c;因此需要外挂 FEM 电路以提高发射信号的增益&#xff0c;从而保障远距离通信的效果和范围。WiFi-FEM 逐渐成为智慧手机、路由器等终端产品中的标配芯片。Vanchip 针对客户的迫切需求&#x…

AI+若依框架(低代码开发)

一、若依介绍 1.版本介绍 若依为满足多样化的开发需求&#xff0c;提供了多个版本 RuoYi-Vue&#xff08;SpringBootVue的单体项目&#xff09; RuoYi-Cloud&#xff08;SpringCloudVue的微服务版本项目&#xff09; RuoYi-App&#xff08;UniappVue移动版本&#xff09; Ru…

Linux_管道通信

目录 一、匿名管道 1、介绍进程间通信 2、理解管道 3、管道通信 4、用户角度看匿名管道 5、内核角度看匿名管道 6、代码实现匿名管道 6.1 创建子进程 6.2 实现通信 7、匿名管道阻塞情况 8、匿名管道的读写原子性 二、命名管道 1、命名管道 1.1 命名管道通信 …

14-4 深入探究小型语言模型 (SLM)

大型语言模型 (LLM) 已经流行了一段时间。最近&#xff0c;小型语言模型 (SLM) 增强了我们处理和使用各种自然语言和编程语言的能力。但是&#xff0c;一些用户查询需要比在通用语言上训练的模型所能提供的更高的准确性和领域知识。此外&#xff0c;还需要定制小型语言模型&…

IDEA:插件和配置推荐(2024版)

文章目录 一、插件1.1 主题1.2 代码缩略图1.3 Maven插件2.4 彩虹括号2.5 翻译插件2.6 图标插件2.7 MyBatis插件2.8 阿里巴巴开发规范 二、全局配置2.1 主题2.2 字符编码2.3 注释颜色2.4 自动导包2.5 鼠标控制界面大小 三、新项目设置3.1 Maven3.2 SDK 四、恢复初始化 一、插件 …

flutter开发实战-Charles抓包设置,dio网络代理

flutter开发实战-Charles抓包设置 在开发过程中抓包&#xff0c;可以看到请求参数等数据&#xff0c;方便分析问题。flutter上使用Charles抓包设置。dio需要设置网络代理。 一、dio设置网络代理 在调试模式下需要抓包调试&#xff0c;所以需要使用代理&#xff0c;并且仅用H…

操作系统缓存与缓冲

缓存与缓冲 缓冲区是一块临时存储数据的区域&#xff0c;这些数据后面会被传输到其他设备上。缓冲区更像消息队列&#xff0c;用以弥补高速设备和低速设备通信时的速度差&#xff0c;平衡读写速度。例如&#xff1a;IO中内核缓冲区Ring Buffer。 缓存&#xff1a;存在于速度相…

鸿蒙应用开发之Badge容器

在开发应用的时候,经常需要一些提示,特别当用户打开应用时,有一些事情需要提醒一下用户,但是不能自动打开这个窗口提示,这样会让用户比较烦。所以设计一些提示显示来告诉用户,这里有新东西了,赶紧来点击一下查看。 比如像下面例子显示的界面: 在这里显示红点的地方,就…

区块链加载解析方法

一.区块链加载解析 对于数据的下载主要包括三种方式&#xff1a; 1.实现比特币网络协议&#xff0c;通过该协议和其他比特币全节点建立联系&#xff0c;然后同步区块数据。 2.通过比特币节点提供的API服务下载区块链数据。 3.通过blickchain.com提供的rest服务下载区块数据…

Python可实现各种算法库之algorithms使用详解

概要 在软件开发和计算机科学领域,算法是解决问题的核心工具。Python 作为一种广泛使用的编程语言,提供了多种内置和第三方库来实现各种算法。algorithms 库是一个集合了多种常用算法和数据结构的 Python 库,旨在帮助开发者快速实现和应用这些算法。本文将详细介绍 algorit…

【 2024!深入了解 大语言模型(LLM)微调方法(总结)】

引言 众所周知&#xff0c;大语言模型(LLM)正在飞速发展&#xff0c;各行业都有了自己的大模型。其中&#xff0c;大模型微调技术在此过程中起到了非常关键的作用&#xff0c;它提升了模型的生成效率和适应性&#xff0c;使其能够在多样化的应用场景中发挥更大的价值。 那么&…

C++ Linux调试(无IDE)

跨平台IDE编译调试C很方便&#xff0c;如QTCreate 、VSCode、Eclipse等&#xff0c;但是如果只能使用Shell控制台呢&#xff0c;gdb调试的优势就很明显了&#xff0c;在没有IDE的情况下&#xff0c;这个方式最有效。因为上手不是很难&#xff0c;特此整理 参考链接 目录 1、G…

MAC下打印机启用用户代码(RICOH理光打印机)

之前一直用Windows操作公司打印机&#xff0c;最近研究了下用MAC&#xff08;macos 13.6.7&#xff09;也能成功打印。公司为了防止恶意打印&#xff0c;因此对打印机设置了用户代码&#xff0c;输入正确的用户代码才能打印&#xff0c;因此配置会复杂一些。 1.安装适配的打印机…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

【APK】Unity出android包,报错 Gradle build failed.See the Console for details

参考大佬的博客&#xff1a;报错&#xff1a;Gradle build failed.See the Console for details.&#xff08;已解决&#xff09;_starting a gradle daemon, 1 incompatible daemon co-CSDN博客 本地出Android包&#xff0c;Build失败 解决办法&#xff1a; 1.下载一个低版本…

如何在多个服务器上安装WordPress分布式部署

许多网络主机现在保证其服务的正常运行时间为 99.9%&#xff0c;但这仍然每年最多有 8.7 小时的停机时间。 许多公司不能够承担这种风险。例如。在超级碗比赛中失败的体育新闻网站可能会失去忠实的追随者。 我们通过设置维护高可用性 WordPress分布式部署配置来帮助 WordPres…

SF-HCI-SAP问题收集17:值映射布尔型EC数据

Complacency is the enemy of study 学习的敌人是自己的满足。 SAP SuccessFactors Employee Central 到 SAP ERP 的员工主数据复制 successfactor employee center主数据同步&#xff0c;一直以来排错比较难&#xff0c;难的地方是这个提示消息比较隐晦&#xff0c;而且同步的…

C#的多线程UI窗体控件显示方案 - 开源研究系列文章

上次编写了《LUAgent服务器端工具》这个应用&#xff0c;然后里面需要新启动一个线程去对文件进行上传到FTP服务器&#xff0c;但是新线程里无法对应用主线程UI的内容进行更改&#xff0c;所以就需要在线程里设置主UI线程里控件信息的方法&#xff0c;于是就有了此博文。此文记…