若依定制pdf生成实战

news2025/5/13 9:05:05

一、介绍

使用 Java Apache POI 将文字渲染到 Word 模板是一种常见的文档自动化技术,广泛应用于批量生成或定制 Word 文档的场景。使用aspose可以将word转成pdf从而达到定制化pdf的目的。

参考文档:java实现Word转Pdf(Windows、Linux通用) - 故城归人 - 博客园

二、word模板准备

(1)pdf逆转

本次实践没有word模板,需从生成的pdf先还原成word。所以使用python将pdf逆转成word docx:

!pip install pdf2docx

from pdf2docx import Converter
pdf_file = '专业技术资格评审申报表_预览.pdf'
docx_file = '申报表模板.docx'
cv = Converter(pdf_file)
#cv.convert(docx_file, start=0, end=2)  # 只转前三页
cv.convert(docx_file)# 转全部
cv.close()

创建word模板,在其中插入占位符,例如 {{name}}、{{workorg}}

(2)模版读取方式

   绝对路径读取:缺点路径变化无法读出

String baseDir = System.getProperty("user.dir");//获取项目根目录
String templatePath = baseDir + "/peer-upms/peer-upms-biz/src/main/resources/file/title_template.docx";
File templateFile = new File(templatePath);

   classpath读取:这样就不再依赖项目根目录的绝对路径,打包之后只要 title_template.docx 在 src/main/resources/file/ 下,就能自动被拷贝并使用。之后你再用 templateFile 打开 POI 进行替换就能正常运行了。

// 1. 从 classpath 加载模板资源(src/main/resources/file/title_template.docx)
ClassPathResource tplRes = new ClassPathResource("file/title_template.docx");
if (!tplRes.exists()) {
    throw new FileNotFoundException("classpath:/file/title_template.docx 不存在");
}


// 2. 将模板复制到一个临时文件(因为 POI 需要 File)
File templateFile = File.createTempFile("title_cover_", ".docx");
try (InputStream in = tplRes.getInputStream();
             FileOutputStream out = new FileOutputStream(templateFile)) {
            in.transferTo(out);
        }

三、Java相关代码

word部分(渲染数据写死)

(1)引入依赖:

   <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.1.0</version>
            <scope>compile</scope>
        </dependency>

(2)word下载接口:

 @Operation(summary = "申请人DOCX下载",
            responses = {
                    @ApiResponse(
                            responseCode = "200",
                            content = @Content(
                                    mediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                                    schema = @Schema(type = "string", format = "binary")
                            )
                    )
            }
    )
    @RequestMapping(value = "/download/docx", method = RequestMethod.GET)
    public ResponseEntity<Resource> downloadDocx() {
        Map<String, Object> data = new HashMap<>();
        data.put("name", "XX1");
        data.put("department", "XX111测试");
        data.put("zhuanye", "作物育种");
        data.put("jishuzige", "研究员");
        data.put("nian", "2025");
        data.put("yue", "03");
        data.put("ri", "20");
        data.put("datetime", "2025/03/20 14:11:44");
        data.put("zhuanyejishu", "生命科学研究");
        try {
                File docxFile = wordToPdfService.generateDocx(data);
            File file = new File(docxFile.getName());
            if (!file.exists()) {
                return ResponseEntity.notFound().build();
            }
            Resource resource = new FileSystemResource(file);

            if (!resource.exists() || !resource.isReadable()) {
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
            }

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"));

            String fileName = "专业技术资格申报表_" + data.get("name") + "_预览.docx";
//            headers.setContentDisposition(ContentDisposition.builder("attachment").filename(fileName).build());
            //解决中文乱码问题
            ContentDisposition contentDisposition = ContentDisposition.builder("attachment")
                    .filename(fileName, StandardCharsets.UTF_8)
                    .build();
            headers.setContentDisposition(contentDisposition);
            headers.setContentLength(file.length());
            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
@Service
public class WordToPdfService {

    /**
     *
     * 根据word模板生成word文档
     *
     */
    public File generateDocx(Map<String, Object> data) throws Exception {
        String baseDir = System.getProperty("user.dir");
        String templatePath = baseDir + "/peer-upms/peer-upms-biz/src/main/resources/file/title_template.docx";
        File templateFile = new File(templatePath);
        if (!templateFile.exists()) {
            throw new Exception("Template file does not exist at: " + templatePath);
        }
        try (FileInputStream fis = new FileInputStream(templateFile)) {
            if (fis.available() <= 0) {
                throw new Exception("Template file is empty.");
            }
        }
        XWPFDocument document = WordExportUtil.exportWord07(templatePath, data);
        try (FileOutputStream fos = new FileOutputStream("output.docx")) {
            document.write(fos);
        }
        File docxFile = new File("output.docx");
        return docxFile;
    }
......

pdf部分(渲染数据从mysql中拉取)

(1) 引入jar包:

mvn install:install-file   -Dfile=peer-upms/peer-upms-biz/libs/aspose-words-15.8.0-jdk16.jar   -DgroupId=com.aspose   -DartifactId=aspose-words   -Dversion=15.8.0-jdk16   -Dpackaging=jar

(2)下载pdf接口(先转word再生成对应的pdf)


@Inner(value = false)
@RestController
@RequiredArgsConstructor
public class TitlePdfDownloadController {
    @Autowired
    private ApplyDataPdfPreviewService applyDataPdfPreviewService;
    @GetMapping(value = "/downloadPdf")
    @Inner(value = false)
    public ResponseEntity<Resource> downloadWord() {
        try {
            Map<String, Object> data = new HashMap<>();
            data = applyDataPdfPreviewService.getDataByApplyId(applyId);

            // 1. Generate DOCX file
            File docxFile = wordToPdfService.generateDocx(data);

            // 2. Convert DOCX to PDF
            File pdfFile = wordToPdfService.convertDocxToPdf(docxFile);

            // 3. Read PDF file bytes
            byte[] pdfBytes = Files.readAllBytes(pdfFile.toPath());

            // 4. Set file name and response headers with PDF MIME type
            String fileName = "专业技术资格申报表_" + data.get("name") + "_" + "预览.pdf";
            Resource resource = new ByteArrayResource(pdfBytes);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_PDF);
            headers.setContentDispositionFormData("attachment", fileName);
            headers.setContentLength(pdfBytes.length);
            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

(3)将动态从mysql获取数据写成一个service:


@Service
public class ApplyDataPdfPreviewService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private FindCitiidMapper findCitiidMapper;

    /**
     * 根据 applyId 拉取申报表、学历和奖惩信息,
     * 并组装到一个 Map 中返回。
     */
    public Map<String,Object> getDataByApplyId(long applyId) {
        Map<String,Object> data = new HashMap<>();
        // 0)拉取 title_apply_applypers 中的mobile字段
        String citiid = findCitiidMapper.findCitiidByApplyId(applyId);
        String sqlMobile = "select mobile from title_apply_applypers where citiid=?";
        Map<String,Object> mobile = jdbcTemplate.queryForMap(sqlMobile, citiid);
        data.put("mobile", mobile.get("mobile"));

        // 1) 拉取 title_applytable 中的所有字段
        String sqlMain = """
            SELECT
              exctypecd,
              techqualtype_cd,
              citiid,
              name,
              workorg,
              gend_cd,
              birthday,
              job_dt,
              presdivtechjob,
              discactisitu,
              presdivtechpost,
              presdivtechpostbgn_tm,
              apply_id,
              apply_serie_nm,
              applydiv_nm,
              prestechqual_nm,
              fillin_tm,
              perm_nm,
              permget_tm,
              permcertnum,
              divtype,
              prestechqualget_tm,
              prestechqualapprorg_nm,
              presdivtechjobbyear,
              applytechqualdetail_cd,
              innovationteam
            FROM title_applytable
            WHERE apply_id = ?
            """;
        Map<String,Object> main = jdbcTemplate.queryForMap(sqlMain, applyId);
        // 基本字段放入 map
        String exctypecd = main.get("exctypecd").toString();
        switch (exctypecd) {
            case "1":
                data.put("c1",                 "√");
                data.put("c2",                 " ");
                data.put("c3",                 " ");
                data.put("c4",                 " ");
                break;
            case "2":
                data.put("c1",                 " ");
                data.put("c2",                 "√");
                data.put("c3",                 " ");
                data.put("c4",                 " ");
                break;
            case "5":
                data.put("c1",                 " ");
                data.put("c2",                 " ");
                data.put("c3",                 "√");
                data.put("c4",                 " ");
                break;
            case "6":
                data.put("c1",                 " ");
                data.put("c2",                 " ");
                data.put("c3",                 " ");
                data.put("c4",                 "√");
                break;
            default:
                data.put("c1",                 " ");
                data.put("c2",                 " ");
                data.put("c3",                 " ");
                data.put("c4",                 " ");
                break;
        }

        String techqualtype_cd = main.get("techqualtype_cd").toString();
        String techType ="";
        switch (techqualtype_cd) {
            case "1":
                techType = "应用基础研究与技术开发人员";
                break;
            case "2":
                techType = "试验发展与转化应用人员";
                break;
            case "3":
                techType = "农业政策与科技管理研究人员";
                break;
            default:
                techType = "";
                break;
        }
        data.put("techType",                techType);
        ......
        
        // 2) 拉取学历信息列表
        String sqlEdu = """
            SELECT
              school_nm,
              edu_nm,
              edutype_cd,
              edu_cd,
              digree_cd,
              gradsitu_cd,
              edubegin_tm,
              grad_tm
            FROM title_edurec
            WHERE apply_id = ?
            ORDER BY edubegin_tm
            """;
        List<Map<String,Object>> edus = jdbcTemplate.queryForList(sqlEdu, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String,Object> e = i < edus.size() ? edus.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("school_nm" + idx,    e.get("school_nm") != null ? e.get("school_nm") : " ");
            data.put("edu_nm" + idx,       e.get("edu_nm") != null ? e.get("edu_nm") : " ");
            data.put("edutype_cd" + idx,   e.get("edutype_cd") != null ? e.get("edutype_cd") : " ");
            data.put("edu_cd" + idx,       e.get("edu_cd") != null ? e.get("edu_cd") : " ");
            data.put("digree_cd" + idx,    e.get("digree_cd") != null ? e.get("digree_cd") : " ");
            data.put("gradsitu_cd" + idx,  e.get("gradsitu_cd") != null ? e.get("gradsitu_cd") : " ");
            data.put("edubegin_tm" + idx,  e.get("edubegin_tm") != null ? e.get("edubegin_tm") : " ");
            data.put("grad_tm" + idx,      e.get("grad_tm") != null ? e.get("grad_tm") : " ");
        }

        // 3) 拉取奖惩信息列表
        String sqlBonus = """
            SELECT
              bonus_nm,
              bonus_tm,
              bonusorg
            FROM title_bonus
            WHERE apply_id = ?
            ORDER BY bonus_tm DESC
            """;
        List<Map<String,Object>> bonuses = jdbcTemplate.queryForList(sqlBonus, applyId);
        for (int i = 0; i < 3; i++) {
            Map<String,Object> b = i < bonuses.size()  ? bonuses.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("bonus_nm" + idx, b.size() != 0 ? b.get("bonus_nm") : " ");
            data.put("bonus_tm" + idx, b.size() != 0  ? b.get("bonus_tm") : " ");
            data.put("bonusorg" + idx, b.size() != 0 ? b.get("bonusorg") : " ");
        }
        data.put("nian", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy")));
        data.put("yue", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("MM")));
        data.put("ri", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("dd")));
        data.put("print_time", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        // 4) 继续教育情况
        String sqlContEdu = """
        SELECT begin_tm, end_tm, content, chargorg, studyaddr
        FROM title_applycontedusitu
        WHERE apply_id = ?
        ORDER BY begin_tm
        """;
        List<Map<String,Object>> contEdus = jdbcTemplate.queryForList(sqlContEdu, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String,Object> ce = i < contEdus.size() ? contEdus.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("cont_b" + idx, ce.size() != 0 ? ce.get("begin_tm") : " ");
            data.put("cont_e" + idx, ce.size() != 0 ? ce.get("end_tm") : " ");
            data.put("content" + idx, ce.size() != 0 ? ce.get("content") : " ");
            data.put("contedu_char" + idx, ce.size() != 0 ? ce.get("chargorg") : " ");
            data.put("caddr" + idx, ce.size() != 0 ? ce.get("studyaddr") : " ");
        }

        // 5) 专业考试成绩情况
        String sqlExam = """
        SELECT exam_tm, org, project, score, qualifycode
        FROM title_professionalexaminfo
        WHERE apply_id = ?
        ORDER BY exam_tm
        """;
        List<Map<String,Object>> exams = jdbcTemplate.queryForList(sqlExam, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String,Object> ex = i < exams.size() ? exams.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("exam_tm" + idx, ex.size() != 0 ? ex.get("exam_tm") : " ");
            data.put("exam_org" + idx, ex.size() != 0 ? ex.get("org") : " ");
            data.put("exam_project" + idx, ex.size() != 0 ? ex.get("project") : " ");
            data.put("escore" + idx, ex.size() != 0 ? ex.get("score") : " ");
            data.put("exam_qualifycode" + idx, ex.size() != 0 ? ex.get("qualifycode") : " ");
        }

        // 6) 工作经历
        String sqlWork = """
        SELECT begin_tm, end_tm, workposi, workcont, post
        FROM title_workresu
        WHERE apply_id = ?
        ORDER BY begin_tm
        """;
        List<Map<String,Object>> works = jdbcTemplate.queryForList(sqlWork, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String, Object> w = i < works.size() ? works.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("workresu_begin" + idx, w.size() != 0 ? w.get("begin_tm") : " ");
            data.put("workresu_end" + idx, w.size() != 0 ? w.get("end_tm") : " ");
            data.put("workresu_workposi" + idx, w.size() != 0 ? w.get("workposi") : " ");
            data.put("workresu_workcont" + idx, w.size() != 0 ? w.get("workcont") : " ");
            data.put("workresu_post" + idx, w.size() != 0 ? w.get("post") : " ");
        }

        // 7) 著作、论文及报告登记
        String sqlArticle = """
        SELECT artititle, publorg, charorg, volumes, publish_time, persduty
        FROM title_applyarticle
        WHERE apply_id = ?
        ORDER BY publish_time
        """;
        List<Map<String,Object>> articles = jdbcTemplate.queryForList(sqlArticle, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String, Object> w = i < articles.size() ? articles.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("article_artititle" + idx, !w.isEmpty() ? w.get("artititle") : " ");
            data.put("article_publorg" + idx, !w.isEmpty() ? w.get("publorg") : " ");
            data.put("article_charorg" + idx, !w.isEmpty() ? w.get("charorg") : " ");
            data.put("article_volumes" + idx, !w.isEmpty() ? w.get("volumes") : " ");
            data.put("article_publish_time" + idx, !w.isEmpty() ? w.get("publish_time") : " ");
            data.put("article_persduty" + idx, !w.isEmpty() ? w.get("persduty") : " ");
        }

        // 8) 任现职以来考核情况
        String sqlAssess = """
        SELECT year, divtechpost, asserslt, asseorg, remark
        FROM title_applyassesitu
        WHERE apply_id = ?
        ORDER BY year
        """;
        List<Map<String,Object>> assesses = jdbcTemplate.queryForList(sqlAssess, applyId);
        for (int i = 0; i < 4; i++) {
            Map<String, Object> as = i < assesses.size() ? assesses.get(i) : new HashMap<>();
            int idx = i + 1;
            data.put("assess_year"        + idx, !as.isEmpty() ? as.get("year") : " ");
            data.put("assess_divtechpost" + idx, !as.isEmpty() ? as.get("divtechpost") : " ");
            data.put("assess_asserslt"    + idx, !as.isEmpty() ? as.get("asserslt") : " ");
            data.put("assess_asseorg"     + idx, !as.isEmpty() ? as.get("asseorg") : " ");
            data.put("assess_remark"      + idx, !as.isEmpty() ? as.get("remark") : " ");
        }

        // 9) 工作总结(单值)
        String sqlSumm = """
        SELECT presjobsumm
        FROM title_applytable
        WHERE apply_id = ?
        """;
        String summary = jdbcTemplate.queryForObject(sqlSumm, String.class, applyId);
        data.put("presjobsumm", summary);

        return data;
    }

(4)使用aspose将word转pdf

 /**
     * 商业版pdf许可 license,从 classpath 下读取 license.xml
     */
    public static boolean getLicense() {
        boolean result = false;
        InputStream is = null;
        try {
            Resource resource = new ClassPathResource("license.xml");
            is = resource.getInputStream();
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
    /**
     * 将传入的 DOCX 文件转换成带完整样式的 PDF 并返回该 File。
     *
     * @param docxFile  Word 模板(已填充占位符)的 File
     * @return           生成的 PDF 临时文件
     * @throws Exception 转换失败时抛出
     */
    public File convertDocxToPdf(File docxFile, long applyId) throws Exception {
        getLicense(); // 验证License 若不验证则转化出的pdf文档会有水印产生
        // 1. 构造输出 PDF 的临时文件
        String uuid = IdUtil.simpleUUID();
        String fileName = uuid+".pdf";
        Path targetPath = Paths.get(fileLocalPath, "PreviewPdf", fileName);
        File pdfFile = new File(targetPath.toString());
        pdfFile.getParentFile().mkdirs();
        TitleApplyApplydataappe applyDataAppe = new TitleApplyApplydataappe();
        applyDataAppe.setApplyId(applyId);
        applyDataAppe.setAppefile(fileName);
        applyDataAppe.setFilesize(pdfFile.length());
        applyDataAppe.setAppefiledispnm("专业技术资格申报表预览_"+applyId+".pdf");
        applyDataAppe.setOpTm(LocalDateTime.now());
        applyDataAppe.setDir("PreviewPdf");
        titleApplyApplydataappeService.save(applyDataAppe);
        // 使用商业破解版 Aspose.Words 完成转换
        try (FileOutputStream os = new FileOutputStream(pdfFile)) {
            // Document 可以直接接收 File 或 String 路径
            Document doc = new Document(docxFile.getAbsolutePath());
            doc.save(os, SaveFormat.PDF);
        }

        return pdfFile;
    }
 

四、部署

单体后端jar包部署

docker run -d --name peer-boot   -v $PWD/peer-boot.jar:/app/peer-boot.jar -v /usr/share/fonts:/usr/share/fonts   --net host   eclipse-temurin:17-jdk   java -Dfile.encoding=utf-8 -jar /app/peer-boot.jar

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c++STL-vector的模拟实现

cSTL-vector的模拟实现 vector的模拟实现基本信息构造函数析构函数返回容量&#xff08;capacity&#xff09;返回元素个数&#xff08;size&#xff09;扩容&#xff08;reserve和resize&#xff09;访问&#xff08;[]&#xff09;迭代器&#xff08;**iterator**&#xff09…

在 Elasticsearch 中连接两个索引

作者&#xff1a;来自 Elastic Kofi Bartlett 解释如何使用 terms query 和 enrich processor 来连接 Elasticsearch 中的两个索引。 更多有关连接两个索引的查询&#xff0c;请参阅文章 “Elastic&#xff1a;开发者上手指南” 中的 “丰富数据及 lookup” 章节。 Elasticsea…

使用 Watt toolkit 加速 git clone

一、前言 Watt toolkit 工具是我经常用于加速 GitHub 网页和 Steam 游戏商店访问的工具&#xff0c;最近想加速 git clone&#xff0c;发现可以使用 Watt toolkit 工具的代理实现。 二、查看端口 我这里以 Ubuntu 为例&#xff0c;首先是需要将加速模式设置为 System&#xff1…

应急响应靶机——WhereIS?

用户名及密码&#xff1a;zgsf/zgsf 下载资源还有个解题.exe: 1、攻击者的两个ip地址 2、flag1和flag2 3、后门程序进程名称 4、攻击者的提权方式(输入程序名称即可) 之前的命令&#xff1a; 1、攻击者的两个ip地址 先获得root权限&#xff0c;查看一下历史命令记录&#x…

Docke容器下JAVA系统时间与Linux服务器时间不一致问题解决办法

本篇文章主要讲解&#xff0c;通过docker部署jar包运行环境后出现java系统内时间与服务器、个人电脑真实时间不一致的问题原因及解决办法。 作者&#xff1a;任聪聪 日期&#xff1a;2025年5月12日 问题现象&#xff1a; 说明&#xff1a;与实际时间不符&#xff0c;同时与服务…

【MCP】其他MCP服务((GitHub)

【MCP】其他MCP服务&#xff08;&#xff08;GitHub&#xff09; 1、其他MCP服务&#xff08;GitHub&#xff09; MCP广场&#xff1a;https://www.modelscope.cn/mcp 1、其他MCP服务&#xff08;GitHub&#xff09; 打开MCP广场 找到github服务 访问github生成令牌 先…

内存 -- Linux内核内存分配机制

内存可以怎么用&#xff1f; kmalloc&#xff1a;内核最常用&#xff0c;用于频繁使用的小内存申请 alloc_pages&#xff1a;以页框为单位申请&#xff0c;物理内存连续 vmalloc&#xff1a;虚拟地址连续的内存块&#xff0c;物理地址不连线 dma_alloc_coherent&#xff1a;常…

关于读写锁的一些理解

同一线程的两种情况&#xff1a; 读读&#xff1a; public static void main(String[] args) throws InterruptedException {ReentrantReadWriteLock lock new ReentrantReadWriteLock();Lock readLock lock.readLock();Lock writeLock lock.writeLock();readLock.lock();S…

C++修炼:模板进阶

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》 欢迎点赞&#xff0c;关注&am…

android-ndk开发(10): use of undeclared identifier ‘pthread_getname_np‘

1. 报错描述 使用 pthread 获取线程名字&#xff0c; 用到 pthread_getname_np 函数。 交叉编译到 Android NDK 时链接报错 test_pthread.cpp:19:5: error: use of undeclared identifier pthread_getname_np19 | pthread_getname_np(thread_id, thread_name, sizeof(thr…

UI自动化测试框架:PO 模式+数据驱动

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1. PO 设计模式简介 什么是 PO 模式&#xff1f; PO&#xff08;PageObject&#xff09;设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成…

Java笔记4

第一章 static关键字 2.1 概述 以前我们定义过如下类&#xff1a; public class Student {// 成员变量public String name;public char sex; // 男 女public int age;// 无参数构造方法public Student() {}// 有参数构造方法public Student(String a) {} }我们已经知道面向…

2025年渗透测试面试题总结-渗透测试红队面试八(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 渗透测试红队面试八 二百一十一、常见中间件解析漏洞利用方式 二百一十二、MySQL用户密码存储与加密 …

MiniMind:3块钱成本 + 2小时!训练自己的0.02B的大模型。minimind源码解读、MOE架构

大家好&#xff0c;我是此林。 目录 1. 前言 2. minimind模型源码解读 1. MiniMind Config部分 1.1. 基础参数 1.2. MOE配置 2. MiniMind Model 部分 2.1. MiniMindForCausalLM: 用于语言建模任务 2.2. 主干模型 MiniMindModel 2.3. MiniMindBlock: 模型的基本构建块…

如何进行前端性能测试?--性能标准

如何进行前端性能测试&#xff1f;–性能标准 前端性能测试指标&#xff1a; 首次加载阶段 场景&#xff1a;用户首次访问网页&#xff0c;在页面还未完全呈现各种内容和功能时的体验。重要指标及原因 首次内容绘制&#xff08;FCP - First Contentful Paint&#xff09;​…

通信网络编程——JAVA

1.计算机网络 IP 定义与作用 &#xff1a;IP 地址是在网络中用于标识设备的数字标签&#xff0c;它允许网络中的设备之间相互定位和通信。每一个设备在特定网络环境下都有一个唯一的 IP 地址&#xff0c;以此来确定其在网络中的位置。 分类 &#xff1a;常见的 IP 地址分为 I…

Off-Policy策略演员评论家算法SAC详解:python从零实现

引言 软演员评论家&#xff08;SAC&#xff09;是一种最先进的Off-Policy策略演员评论家算法&#xff0c;专为连续动作空间设计。它在 DDPG、TD3 的基础上进行了显著改进&#xff0c;并引入了最大熵强化学习的原则。其目标是学习一种策略&#xff0c;不仅最大化预期累积奖励&a…

热门CPS联盟小程序聚合平台与CPA推广系统开发搭建:助力流量变现与用户增长

一、行业趋势&#xff1a;CPS与CPA模式成流量变现核心 在移动互联网流量红利见顶的背景下&#xff0c;CPS&#xff08;按销售付费&#xff09;和CPA&#xff08;按行为付费&#xff09;模式因其精准的投放效果和可控的成本&#xff0c;成为企业拉新与用户增长的核心工具。 CPS…

Linux系统管理与编程15:vscode与Linux连接进行shell开发

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 【1】打开vscode 【2】点击左下角连接图标 【3】输入远程连接 选择合适的操作系统 输入密码&#xff0c;就进入Linux环境的shell编程了。 在vscode下面粘贴拷贝更方便。比如 然后在v…

RabbitMQ概念详解

什么是消息队列&#xff1f; 消息队列是一种在应用程序之间传递消息的技术。它提供了一种异步通信模式&#xff0c;允许应用程序在不同的时间处理消 息。消息队列通常用于解耦应用程序&#xff0c;以便它们可以独立地扩展和修改。在消息队列中&#xff0c;消息发送者将消息发送…