springboot集成thymeleaf实战

news2024/9/17 7:46:06

引言

笔者最近接到一个打印标签的需求,由于之前没有做过类似的功能,所以这也是一次学习探索的机会了,打印的效果图如下:
在这里插入图片描述
这个最终的打印是放在58mm*58mm的小标签纸上,条形码就是下面的35165165qweqweqe序列号生成的,也是图片形式。序列号应该放在条形码的正下方居中位置的,但是由于笔者前端技术有点拉跨,碰到样式啥的就头疼,这也是尽力后的效果了。下面看集成过程吧。

一、引入pom相关依赖包

笔者的环境是JDK17,pom相关版本如下,具体用什么版本不固定,不报错就行。

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.4.1</version>
        </dependency>

        <dependency>
            <groupId>ognl</groupId>
            <artifactId>ognl</artifactId>
            <version>3.4.3</version>
        </dependency>

        <!-- Flying Saucer -->
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.20</version>
        </dependency>

        <!--itext-->
        <dependency>
            <groupId>com.lowagie</groupId>
            <artifactId>itext</artifactId>
            <version>2.1.7</version>
        </dependency>


        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

二、条形码工具类

package com.hulei.thymeleafproject;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.Code128Writer;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author hulei
 * @Date 2024/7/26 14:15
 * @Description: 条形码工具类
 *
 */
public class BarCodeUtils {
    /**
     * 默认图片宽度
     */
    private static final int DEFAULT_PICTURE_WIDTH = 400;

    /**
     * 默认图片高度
     */
    private static final int DEFAULT_PICTURE_HEIGHT = 200;

    /**
     * 默认条形码宽度
     */
    private static final int DEFAULT_BAR_CODE_WIDTH = 300;

    /**
     * 默认条形码高度
     */
    private static final int DEFAULT_BAR_CODE_HEIGHT = 30;

    /**
     * 默认字体大小
     */
    private static final int DEFAULT_FONT_SIZE = 15;

    /**
     * 图片格式
     */
    private static final String FORMAT = "png";

    /**
     * 字符集
     */
    private static final String CHARSET = "utf-8";


    /**
     * 设置 条形码参数
     */
    private static final Map<EncodeHintType, Object> hints = new HashMap<>();

    static {
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
    }

    /**
     * 获取条形码图片
     *
     * @param codeValue 条形码内容
     * @return 条形码图片
     */
    public static BufferedImage getBarCodeImage(String codeValue) {
        return getBarCodeImage(codeValue, DEFAULT_BAR_CODE_WIDTH, DEFAULT_BAR_CODE_HEIGHT);
    }

    /**
     * 获取条形码图片
     *
     * @param codeValue 条形码内容
     * @param width     宽度
     * @param height    高度
     * @return 条形码图片
     */
    public static BufferedImage getBarCodeImage(String codeValue, int width, int height) {
        // CODE_128是最常用的条形码格式
        return getBarCodeImage(codeValue, width, height, BarcodeFormat.CODE_128);
    }

    /**
     * 获取条形码图片
     *
     * @param codeValue     条形码内容
     * @param width         宽度
     * @param height        高度
     * @param barcodeFormat 条形码编码格式
     * @return 条形码图片
     */
    public static BufferedImage getBarCodeImage(String codeValue, int width, int height, BarcodeFormat barcodeFormat) {
        Code128Writer writer = switch (barcodeFormat) {
            case CODE_128 ->
                // 最常见的条形码,但是不支持中文
                    new Code128Writer();
            case PDF_417 ->
                // 支持中文的条形码格式
                    new Code128Writer();
            // 如果使用到其他格式,可以在这里添加
            default -> new Code128Writer();
        };

        // 编码内容, 编码类型, 宽度, 高度, 设置参数
        BitMatrix bitMatrix;
        bitMatrix = writer.encode(codeValue, barcodeFormat, width, height, hints);
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }

    /**
     * 获取条形码
     *
     * @param codeValue 条形码内容
     * @param bottomStr 底部文字
     */
    public static BufferedImage getBarCodeWithWords(String codeValue, String bottomStr) {
        return getBarCodeWithWords(codeValue, bottomStr, "", "", "");
    }

    /**
     * 获取条形码
     * @param codeValue   条形码内容
     * @param bottomStr   底部文字
     * @param topLeftStr  左上角文字
     * @param topRightStr 右上角文字
     */
    public static BufferedImage getBarCodeWithWords(String codeValue,
                                                    String bottomStr,
                                                    String bottomStr2,
                                                    String topLeftStr,
                                                    String topRightStr) {
        return getCodeWithWords(getBarCodeImage(codeValue),
                bottomStr,
                bottomStr2,
                topLeftStr,
                topRightStr,
                DEFAULT_PICTURE_WIDTH,
                DEFAULT_PICTURE_HEIGHT,
                0,
                -20,
                0,
                0,
                0,
                0,
                DEFAULT_FONT_SIZE);
    }

    /**
     * 获取条形码
     *
     * @param codeImage       条形码图片
     * @param firstBottomStr  底部文字首行
     * @param secondBottomStr 底部文字次行
     * @param topLeftStr      左上角文字
     * @param topRightStr     右上角文字
     * @param pictureWidth    图片宽度
     * @param pictureHeight   图片高度
     * @param codeOffsetX     条形码宽度
     * @param codeOffsetY     条形码高度
     * @param topLeftOffsetX  左上角文字X轴偏移量
     * @param topLeftOffsetY  左上角文字Y轴偏移量
     * @param topRightOffsetX 右上角文字X轴偏移量
     * @param topRightOffsetY 右上角文字Y轴偏移量
     * @param fontSize        字体大小
     * @return 条形码图片
     */
    public static BufferedImage getCodeWithWords(BufferedImage codeImage,
                                                 String firstBottomStr,
                                                 String secondBottomStr,
                                                 String topLeftStr,
                                                 String topRightStr,
                                                 int pictureWidth,
                                                 int pictureHeight,
                                                 int codeOffsetX,
                                                 int codeOffsetY,
                                                 int topLeftOffsetX,
                                                 int topLeftOffsetY,
                                                 int topRightOffsetX,
                                                 int topRightOffsetY,
                                                 int fontSize) {
        BufferedImage picImage = new BufferedImage(pictureWidth, pictureHeight, BufferedImage.TYPE_INT_RGB);

        Graphics2D g2d = picImage.createGraphics();
        // 抗锯齿
        setGraphics2D(g2d);
        // 设置白色
        setColorWhite(g2d, picImage.getWidth(), picImage.getHeight());

        // 条形码默认居中显示
        int codeStartX = (pictureWidth - codeImage.getWidth()) / 2 + codeOffsetX;
        int codeStartY = (pictureHeight - codeImage.getHeight()) / 2 + codeOffsetY;
        // 画条形码到新的面板
        g2d.drawImage(codeImage, codeStartX, codeStartY, codeImage.getWidth(), codeImage.getHeight(), null);

        // 画文字到新的面板
        g2d.setColor(Color.BLACK);
        // 字体、字型、字号
        g2d.setFont(new Font("微软雅黑", Font.PLAIN, fontSize));
        // 文字与条形码之间的间隔
        int wordAndCodeSpacing1 = 0;

        if (StringUtils.isNotEmpty(firstBottomStr)) {
            // 文字长度
            int strWidth = g2d.getFontMetrics().stringWidth(firstBottomStr);
            // 文字X轴开始坐标,这里是居中
            int strStartX = codeStartX + (codeImage.getWidth() - strWidth) / 2;
            // 文字Y轴开始坐标
            int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing1;
            // 画文字
            g2d.drawString(firstBottomStr, strStartX, strStartY);
        }

        // 文字与条形码之间的间隔
        int wordAndCodeSpacing2 = 30;

        if (StringUtils.isNotEmpty(secondBottomStr)) {
            // 文字长度
            int strWidth = g2d.getFontMetrics().stringWidth(secondBottomStr);
            // 文字X轴开始坐标,这里是居中
            int strStartX = codeStartX + (codeImage.getWidth() - strWidth) / 2;
            // 文字Y轴开始坐标
            int strStartY = codeStartY + codeImage.getHeight() + fontSize + wordAndCodeSpacing2;
            // 画文字
            g2d.drawString(secondBottomStr, strStartX, strStartY);
        }

        if (StringUtils.isNotEmpty(topLeftStr)) {
            // 文字长度
            int strWidth = g2d.getFontMetrics().stringWidth(topLeftStr);
            // 文字X轴开始坐标
            int strStartX = codeStartX + topLeftOffsetX;
            // 文字Y轴开始坐标
            int strStartY = codeStartY + topLeftOffsetY - wordAndCodeSpacing1;
            // 画文字
            g2d.drawString(topLeftStr, strStartX, strStartY);
        }

        if (StringUtils.isNotEmpty(topRightStr)) {
            // 文字长度
            int strWidth = g2d.getFontMetrics().stringWidth(topRightStr);
            // 文字X轴开始坐标,这里是居中
            int strStartX = codeStartX + codeImage.getWidth() - strWidth + topRightOffsetX;
            // 文字Y轴开始坐标
            int strStartY = codeStartY + topRightOffsetY - wordAndCodeSpacing1;
            // 画文字
            g2d.drawString(topRightStr, strStartX, strStartY);
        }

        g2d.dispose();
        picImage.flush();

        return picImage;
    }

    /**
     * 设置 Graphics2D 属性  (抗锯齿)
     *
     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
     */
    private static void setGraphics2D(Graphics2D g2d) {
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
        Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
        g2d.setStroke(s);
    }

    /**
     * 设置背景为白色
     *
     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
     */
    private static void setColorWhite(Graphics2D g2d, int width, int height) {
        g2d.setColor(Color.WHITE);
        //填充整个屏幕
        g2d.fillRect(0, 0, width, height);
        //设置笔刷
        g2d.setColor(Color.BLACK);
    }

    /**
     * 将 BufferedImage 转为 base64
     */
    public static String bufferedImage2Base64(BufferedImage image) throws IOException {
        // 输出流
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(image, FORMAT, stream);
        java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
        String imgBase64 = new String(encoder.encode(stream.toByteArray()), CHARSET);
        imgBase64 = "data:image/" + FORMAT + ";base64," + imgBase64;
        return imgBase64;
    }

}

这个工具类中,默认生成的条形码图片格式是png,当然可以自己修改格式。

三、thymeleaf画模板

这个就是打印模板了,thymeleaf和freemarker一样都是模板引擎,freemarker模板语法更简单些。如果需要简单的变量替换和循环,FreeMarker可能是更好的选择。如果需要更丰富的模板功能和动态内容处理,Thymeleaf可能更适合。笔者这里选择的是thymeleaf。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>维修库商品打印标签模板</title>
    <meta charset="UTF-8"></meta>
    <style>        body, html {
        margin: 0;
        padding: 0;
        width: 70mm;
        height: 70mm;
        font-family: 'SimSun', sans-serif; /* 防止生成的PDF中文不显示 */
    }

    h1 {
        text-align: center;
        font-size: 12px;
        line-height: 1.5;
    }

    p {
        font-size: 12px;
        margin: 3px 0;
    }

    .device-code {
        display: flex; /* 使用Flexbox布局 */
        align-items: center; /* 垂直居中对齐 */
    }

    .sn-container {
        display: inline-flex; /* 内联Flexbox容器 */
        align-items: center; /* 垂直居中对齐 */
        margin-left: 2px; /* 与“设备码:”之间的间距 */
    }

    .sn-image {
        width: auto; /* 图片宽度自适应 */
    }

    .sn-text {
        margin-top: 5px; /* 文本与图片之间的间距 */
        text-align: center; /* 文字居中 */
    }

    img {
        vertical-align: middle;
        display: inline-block;
    }
    </style>
</head>
<body>
<div>
    <h1>
        <img th:src="${zlbcImage}" alt="Image" style="height:30px;"></img>智链泊车
    </h1>
    <p th:text="${createTime != null ? '入库日期:'+ createTime : '入库日期:未知'}"></p>
    <p th:text="${materialName != null ? '名&nbsp;&nbsp;&nbsp;&nbsp;称:'+ materialName : '名称:未知'}"></p>
    <p th:text="${supplierName != null ? '客&nbsp;&nbsp;&nbsp;&nbsp;户:'+ supplierName : '客户:未知'}"></p>
    <p class="device-code">&nbsp;&nbsp;码:
        <span class="sn-container">
        <img class="sn-image" th:src="${sequencesNumberImage}" alt="Image"/>
        <div class="sn-text" th:text="${sequencesNumber}">${sequencesNumber}</div>
    </span>
    </p>
</div>
</body>
</html>

这个模板里面的变量赋值时比较简单的,主要是有两个图片的变量zlbcImagesequencesNumberImage,一个是智慧停车前面的原型小图标,一个就是条形码是,在赋值时是需要把图片读成BufferedImage,再把BufferedImage使用base64编码一下。

另外一个重要的点是:font-family: ‘SimSun’, sans-serif;
这个属性必须加上,否则后面把html转成PDF时,中文会不显示。

四、字体准备simsun.ttc

这个字体是因为,我要把html转成一个PDF,中间转换需要一些字体,并且支持中文,网上搜索了下,选择了simsun.ttc这个字体,同时我在html上也指定了这个字体。网上下载这个字体资源库后,放在如下位置,以便程序中加载使用。
在这里插入图片描述

五、测试代码

package com.hulei.thymeleafproject;

import com.lowagie.text.pdf.BaseFont;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;

/**
 * @author hulei
 * @date 2024/7/27 9:26
 */

@RestController
public class TestController {

    @Resource
    private TemplateEngine templateEngineBySelf;

    @PostMapping("/printSNLabel")
    public void test(@RequestBody List<PrintSNLabelReqDTO> list) {
        list.forEach(loop -> {
            Map<String, Object> map = new HashMap<>();
            map.put("createTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            map.put("materialName", loop.getMaterialName());
            map.put("supplierName", loop.getSupplierName());
            //设备码图片二进制字节流
            BufferedImage sequencesNumberImage = BarCodeUtils.getBarCodeImage(loop.getSequencesNumber(), 100, 50);
            this.storeImage(sequencesNumberImage, "E:/111.png");
            try {
                String base64Image = BarCodeUtils.bufferedImage2Base64(sequencesNumberImage);
                System.out.println("base64Image: " + base64Image);
                map.put("sequencesNumberImage", base64Image);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            map.put("sequencesNumber", loop.getSequencesNumber());
            try {
                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
                String symbolImagePath = "images/zlbcImage.png";
                InputStream inputStream = classLoader.getResourceAsStream(symbolImagePath);
                assert inputStream != null;
                BufferedImage zlbcImageBufferedImage = ImageIO.read(inputStream);
                this.storeImage(zlbcImageBufferedImage, "E:/222.png");
                String zlbcImage = BarCodeUtils.bufferedImage2Base64(zlbcImageBufferedImage);
                System.out.println("zlbcImage: " + zlbcImage);
                map.put("zlbcImage", zlbcImage);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try {
                generateSNPicture(map);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
    }


    private void generateSNPicture(Map<String,Object> map) throws IOException {
        // 填充模板数据
        Context context = new Context();
        context.setVariable("createTime", map.get("createTime"));
        context.setVariable("materialName", map.get("materialName"));
        context.setVariable("supplierName", map.get("supplierName"));
        context.setVariable("sequencesNumberImage", map.get("sequencesNumberImage"));
        context.setVariable("sequencesNumber", map.get("sequencesNumber"));
        context.setVariable("zlbcImage", map.get("zlbcImage"));
        String htmlContent = templateEngineBySelf.process("printTemplate", context);
        System.out.println(htmlContent);
        htmlToPdf(htmlContent);

    }

    private void htmlToPdf(String htmlContent){
        try {
            //创建PDf文件
            ITextRenderer renderer = new ITextRenderer();
            //获取使用的字体数据(由于对中文字体显示可能会不支持,所以需要主动添加字体数据设置。)
            ITextFontResolver fontResolver = renderer.getFontResolver();
            fontResolver.addFont("templates/fonts/simsun.ttc",BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

            //设置文件名称
            String sDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String sTime = new SimpleDateFormat("HHmmssSSS").format(new Date());

            // 生成临时文件
            Path tempPdfPath = Files.createTempFile("temp_pdf_"+sDate+sTime, ".pdf");
            String pdfFilePath = tempPdfPath.toAbsolutePath().toString();

            // 将html生成文档
            renderer.setDocumentFromString(htmlContent);
            renderer.layout();
            OutputStream os = new FileOutputStream(pdfFilePath);
            // 将文档写入到输出流中
            renderer.createPDF(os);
            // 关闭流
            os.close();

            //把临时生成的文件转移到E盘,这里可以根据个人需求选在把临时文件上传到文件服务器
            System.out.println("pdfFilePath: "+pdfFilePath);
            File tempPdfFile = tempPdfPath.toFile();
            System.out.println("tempPdfFileName: "+tempPdfFile.getName());
            // 复制文件到E盘
            try {
                Path targetPath = Paths.get("E:", tempPdfFile.getName()); // 目标路径
                Files.copy(tempPdfPath, targetPath);
                System.out.println("文件已复制到 E 盘");
            } catch (Exception e) {
                System.err.println("复制文件时发生错误: " + e.getMessage());
            }
            //删除临时生成的本地PDF文件
            Files.delete(tempPdfPath);
        } catch (Exception e) {
            System.out.println("生成pdf文件失败");
            throw new RuntimeException(e);
        }

    }

    private void storeImage(BufferedImage image, String filePath){
        try {
            // 指定输出文件路径和格式
            File outputFile = new File(filePath);

            // 使用 ImageIO.write 方法将图片写入磁盘
            boolean isWritten = ImageIO.write(image, "png", outputFile);

            if (isWritten) {
                System.out.println("图片已成功保存到磁盘.");
            } else {
                System.out.println("图片保存失败.");
            }
        } catch (IOException e) {
            System.err.println("保存图片时发生错误: " + e.getMessage());
        }
    }

}

这里为了展示代码,没有分层了,全都放在了controller层。主要分为三块:加载html模板,变量赋值,html转pdf

转成pdf后的效果如下:

在这里插入图片描述

Apifox测试工具,测试数据如下,注意json是数组形式,因为后端controller接收的是List
在这里插入图片描述

整个代码我已上传到gitee:gitee仓库地址

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

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

相关文章

民大食堂用餐小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;档口号管理&#xff0c;商家餐品管理&#xff0c;餐品种类管理&#xff0c;购物车管理&#xff0c;订单信息管理 微信端账号功能包括&#xff1a;系统首页&a…

pytorch-迁移学习

目录 1. 宝可梦数据集训练的问题2. 迁移学习3. 迁移学习实现4. 完整代码 1. 宝可梦数据集训练的问题 宝可梦数据总共有1000多张&#xff0c;对于resnet18网络来说数据量是不够的&#xff0c;训练时很容易出现过拟合&#xff0c;那么如何解决这个问题呢&#xff1f; 宝可梦数据…

常见的几种数据标注类型

数据标注是机器学习和人工智能项目中一个至关重要的步骤&#xff0c;它帮助算法理解输入数据中的关键特征。根据不同的应用场景和技术需求&#xff0c;数据标注可以分为多种类型。 以下是一些常见的数据标注类型&#xff1a; 图像标注&#xff1a; 边界框&#xff1a;在物体周…

手撕数据结构---栈和队列的概念以及实现

栈的概念&#xff1a; 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作的⼀端称为栈顶&#xff0c;另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈…

Doris-计算特性

1 全新优化器 1.1 如何开启1.2 统计信息 1.2.1 使用ANALYZE语句手动收集1.2.1 自动收集1.2.3 作业管理1.3 会话变量及配置项调优参数2 Join相关 2.1 支持的Join算子2.2 支持的shuffle方式 2.2.1 Broadcast Join2.2.2 Shuffle Join2.2.3 Bucket Shuffle Join 2.2.3.1 原理2.2.3.…

【CTFWP】ctfshow-web40

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 题目介绍&#xff1a;题目分析&#xff1a;payload&#xff1a;payload解释&#xff1a;payload2&#xff1a;payload2解释&#xff1a;flag 题目介绍&#xff1a; …

python-分享篇-用Python分析文本数据的词频

上次批量提取了上市公司主要业务信息&#xff0c;要分析这些文本数据&#xff0c;就需要做文本词频分析。由于中文不同于英文&#xff0c;词是由一个一个汉字组成的&#xff0c;而英文的词与词之间本身就有空格&#xff0c;所以中文的分词需要单独的库才能够实现&#xff0c;常…

2024年必备技能:小红书笔记评论自动采集,零基础也能学会的方法

摘要&#xff1a; 面对信息爆炸的2024年&#xff0c;小红书作为热门社交平台&#xff0c;其笔记评论成为市场洞察的金矿。本文将手把手教你&#xff0c;即便编程零基础&#xff0c;也能轻松学会利用Python自动化采集小红书笔记评论&#xff0c;解锁营销新策略&#xff0c;提升…

pmp学习交流组队~

首先&#xff0c;来看看什么是PMP PMP指的是项目管理专业人士资格认证。它是由美国项目管理协会&#xff08;Project Management Institute(PMI)发起的&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。 pmp备考攻略本人推荐的参考资料比较多&#xff0…

MySQL 9 安装第1辑-版本选择和安装包获取

一、MySQL 9 版本选择 在准备安装MySQL时&#xff0c;选择合适的版本和分发格式至关重要。首先&#xff0c;需要决定是安装长期支持&#xff08;LTS&#xff09;系列版本还是创新系列版本。长期支持版本&#xff08;如MySQL 8.x LTS&#xff09;专注于稳定性、性能优化和安全性…

RocketMQ知识总结(基本原理)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 基本原理 总体架构图 零拷贝 零拷贝技术是一个思想&#xff0c;指…

蓝屏事件一些想法

影响全球的蓝屏事件 2024年7月19日发生了大量windows操作系统电脑蓝屏的事情&#xff0c;造成了全球级别的影响。其中国外的影响最大&#xff0c;甚至像医院、银行、航班等与人民生活密切相关的行业都受到了本次影响。导致全球数千架次航班被取消&#xff0c;数万架次航班延误…

Java | Leetcode Java题解之第303题区域和检索-数组不可变

题目&#xff1a; 题解&#xff1a; class NumArray {int[] sums;public NumArray(int[] nums) {int n nums.length;sums new int[n 1];for (int i 0; i < n; i) {sums[i 1] sums[i] nums[i];}}public int sumRange(int i, int j) {return sums[j 1] - sums[i];} }…

【Web开发手礼】探索Web开发的秘密(十三)-Vue(3)好友列表、登录

前言 主要介绍了好友列表、登录界面所涉及的vue知识点&#xff01;&#xff01;&#xff01; 好友列表 从云端API读取数据信息 地址 https://app165.acapp.acwing.com.cn/myspace/userlist/方法&#xff1a;GET是否验证jwt&#xff1a;否输入参数&#xff1a;无返回结果&…

C++自定义接口类设计器

关键代码 #include "mainwindow.h" #include "ui_mainwindow.h" #include <QStringListModel>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);// C基础数据类型列表QStringList typ…

求.netcore 按模板导出pdf免费插件,来谈谈。

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

图书管理系统设计

设计一个图书管理系统时&#xff0c;我们需要考虑系统的基本功能、用户需求、技术选型以及数据的安全性和完整性。下面是一个基本的图书管理系统的设计概览&#xff1a; 1. 系统目标 管理图书信息&#xff1a;添加、删除、修改图书信息。借阅管理&#xff1a;处理借书、还书流…

低代码应用版本管理能力探讨

低代码平台为开发者提供易用的可视化、定制化开发能力&#xff0c;无需编写原生代码或者只有少量代码编写就能实现需求&#xff0c;从而带来开发门槛的降低&#xff0c;开发效率的提升。低代码作为提升应用研发生产力的关键型技术&#xff0c;成为企业数字化转型的助推器。 低代…

StarRock3.3 安装部署(存算分离、存算一体保姆式教程)

服务器前置要求&#xff1a; 1、内存>32GB 2、JDK 8 is not supported, please use JDK 11 or 17 1、安装 wget https://releases.starrocks.io/starrocks/StarRocks-3.3.0.tar.gz tar zxvf StarRocks-3.3.0.tar.gz 2、FE服务启动 2.1 配置FE节点(默认配置&#xff0c;…

C#知识|文件与目录操作:文本读写操作

哈喽,你好啊,我是雷工! 今天学习文件与目录的操作,以下为文本读写操作的学习笔记。 01 文件操作说明 1.1、数据的存取方式 数据库:适合存取大量且关系复杂并有序的数据; 文件:适合存取大量但数据关系简单的数据,像系统的日志文件; 1.2、文件存取的优点 ①:读取操…