springboot集成thymeleaf实战

引言

笔者最近接到一个打印标签的需求,由于之前没有做过类似的功能,所以这也是一次学习探索的机会了,打印的效果图如下:
在这里插入图片描述
这个最终的打印是放在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 {@Resourceprivate 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://xiahunao.cn/news/3280352.html

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

相关文章

FPGA知识基础之--按键控制LED灯项目

文章目录 前言一、按键简介按键:通过按下或者释放来控制电路通断的电子元件按键原理图 二、实验要求三、程序设计3.1思路整理3.2 模型搭建3.3 顶层模块3.4 波形分析 四、代码整理4.1RTL代码4.2 仿真只需在Testbench上增加上述一段代码即可将参数实例化,可达到在Testbench上更改…

卷积神经网络的入门基本介绍 | 带你快速上手各种概念【附图解】

文章目录 1、简介2、核心概念3、关键操作4、常见架构5、训练过程6、重要概念图解⭐6.1、卷积神经网络工作⭐6.2、卷积核6.3、全连接与卷积网络的对比6.4、池化层6.5、感受野和卷积堆叠6.6、神经元计算和激活函数 7、卷积网络可以改进的地方8、结论 &#x1f343;作者介绍&#…

vue3集成LuckySheet实现导入本地Excel进行在线编辑

第一步&#xff1a;克隆或者下载下面的代码 git clone https://github.com/dream-num/Luckysheet.git第二步&#xff1a;安装依赖 npm install npm install gulp -g 第三步&#xff1a;运行 npm run dev效果如下图所示 第四步&#xff1a;打包 打包执行成功后&#xff0c;…

TypeError: Components is not a function

Vue中按需引入Element-plus时&#xff0c;报错TypeError: Components is not a function。 1、参考Element-plus官方文档 安装unplugin-vue-components 和 unplugin-auto-import这两款插件 2、然后需要在vue.config.js中配置webPack打包plugin配置 3、重新启动项目会报错 T…

程序员开发指南

在这个快节奏的时代&#xff0c;作为一名程序员&#xff0c;大家都希望能更快地开发出高质量的应用&#xff0c;而不是花费大量时间在基础设施和后台服务的搭建上。今天&#xff0c;我要向大家介绍一款专为懒人开发者准备的一站式开发应用的神器——MemFire Cloud。 一站式开发…

制品库nexus

详见&#xff1a;Sonatype Nexus Repository搭建与使用&#xff08;详细教程3.70.1&#xff09;-CSDN博客 注意事项&#xff1a; 1.java8环境使用nexus-3.69.0-02-java8-unix.tar.gz包 2.java11环境使用nexus-3.70.1-02-java11-unix.tar.gz包 3.注意使用制品库/etc/yum.repos.…

动物大联盟游戏攻略:必备游戏攻略!VMOS云手机升级攻略教程!

在《动物大联盟》中&#xff0c;合理的称号选择、活动参与和组队合作可以极大提升游戏体验和效率。以下是详细的攻略建议&#xff1a; 称号选择 称号不仅能展示玩家的实力和成就&#xff0c;还能提供额外的属性加成。合理选择和更换称号是提升战力的重要途径。 前期称号选择&…

Matlab编程资源库(19)级数与符号方程求解

一、级数符号求和 求无穷级数的和需要 符号表达式求和函数 symsum &#xff0c;其调用 格式为&#xff1a; symsum(s,v,n,m) 其中 s 表示一个级数的通项&#xff0c;是一个符号表达式。 v 是求和变 量&#xff0c; v 省略时使用系统的默认变量。 n 和 m 是求和的开始项 和…

【康复学习--LeetCode每日一题】3111. 覆盖所有点的最少矩形数目

题目&#xff1a; 给你一个二维整数数组 point &#xff0c;其中 points[i] [xi, yi] 表示二维平面内的一个点。同时给你一个整数 w 。你需要用矩形 覆盖所有 点。 每个矩形的左下角在某个点 (x1, 0) 处&#xff0c;且右上角在某个点 (x2, y2) 处&#xff0c;其中 x1 < x…

职业教育计算机网络综合实验实训室建设应用案例

近年来&#xff0c;职业教育在培养技能型人才方面发挥着越来越重要的作用。然而&#xff0c;传统的计算机网络技术教学模式往往重理论、轻实践&#xff0c;导致学生缺乏实际操作能力和职业竞争力。为了改变这一现状&#xff0c;唯众结合职业教育特点&#xff0c;提出了“教、学…

04.FreeRTOS任务创建

04. FreeRTOS任务创建与任务删除 1. FreeRTOS创建和删除任务相关API函数 函数描述xTaskCreate()动态方式创建任务xTaskCreateStatic()静态方式创建任务xTaskCreateRestricted()动态方式创建使用 MPU 限制的任务xTaskCreateRestrictedStatic()静态方式创建使用 MPU 限制的任务…

C# Unity 面向对象补全计划 之 继承(字段与属性)

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列旨在通过补全学习之后&#xff0c;给出任意类图都能实现并做到逻辑上严丝合缝 Q&#xff1a;为什么要单讲继承字段与属性&#xff0c;不讲继承方法了吗&#x…

Centos 7配置问题

在VMWare12上面安装Centos 7 Linux虚拟机&#xff0c;在切换到命令界面时&#xff0c;需要登录用户名和密码&#xff0c;但发现输入用户后有字符显示&#xff0c;但是密码没有。 经过一系列查看后&#xff0c;发现这个是Linux的一种机制&#xff0c;即当你输入密码时不显示&…

为什么阿里开发手册不建议使用Date类?

在日常编码中&#xff0c;基本上99%的项目都会有一个DateUtil工具类&#xff0c;而时间工具类里用的最多的就是java.util.Date。 大家都这么写&#xff0c;这还能有问题&#xff1f;&#xff1f; 当你的“默认常识”出现问题&#xff0c;这个打击&#xff0c;就是毁灭性的。 …

Python学习计划——7.2数据可视化

数据可视化是数据分析的重要组成部分&#xff0c;通过图表和图形将数据直观地展示出来&#xff0c;帮助我们发现数据中的模式和趋势。Python中常用的数据可视化库有matplotlib和seaborn。以下是对这些库的详细讲解及可运行的Python案例。 1. matplotlib 库 matplotlib 是一个…

Git 基础操作手册:轻松掌握常用命令

Git 操作完全手册&#xff1a;轻松掌握常用命令 引言一、暂存&#xff1a;git add ✏️二、提交&#xff1a;git commit &#x1f4dd;三、拉取、拉取合并 &#x1f504;四、推送&#xff1a;git push &#x1f310;五、查看状态&#xff1a;git status &#x1f4ca;六、查看历…

数据库管理-第225期 Oracle DB 23.5新特性一览(20240730)

数据库管理225期 2024-07-30 数据库管理-第225期 Oracle DB 23.5新特性一览&#xff08;20240730&#xff09;1 二进制向量维度格式2 RAC上的复制HNSW向量索引3 JSON集合4 JSON_ID SQL函数5 优化的通过网络对NVMe设备的Oracle的原生访问6 DBCA支持PMEM存储7 DBCA支持标准版高可…

[PM]面试题-工作问题

画一个原型需要多久?写一篇PRD文档需求多久? 时间长短取决于项目规模和业务难度, 规模大难度高,就要花费很长的时间, 规模下难度低时间就短, 一般来说, 1-2周的时间就可以完成原型和RED文档 市场需求文档写什么? 从打到下进行编写, 大的方面以市场为主体,包括市场规模, 发…

AI-PaddleOCR2.8在VS2019编译运行基于C++引擎推理CPU版本

1、下载PaddleOCR-release-2.8开源项目 https://github.com/PaddlePaddle/PaddleOCR https://github.com/PaddlePaddle/PaddleOCR/releases https://gitee.com/paddlepaddle/PaddleOCR?_fromgitee_search 2、下载安装Windows预测库 https://paddleinference.paddlepaddle.o…

轻量级服务器资源监控平台Beszel

什么是 Beszel &#xff1f; Beszel 是一个轻量级平台&#xff0c;借助 Beszel&#xff0c;可以访问 CPU 和内存使用情况的历史数据&#xff0c;以及 Docker 容器指标&#xff08;例如特定于容器的 CPU 和内存统计信息&#xff09;。还能收到针对潜在问题的可自定义警报通知&am…