关于“使用java中的二维矩阵方法生成二维码“ 以及 “Java加载外部字体文件时出错的原因“

生成二维码

铁铁们,这两日写了一个导出二维码的接口,要求有一个是在二维码下方生成字体,现在奉上生成二维码的代码:
controller层

 @Operation(summary = "导出机构二维码",description = "导出机构二维码")@GetMapping("/orgCode")public void getOr(@RequestParam("url") String url,@RequestParam("orgIds") List<Long> orgIds,@RequestParam("channels") List<String> channels, HttpServletResponse response) throws IOException{//返回二维码生成的数据byte[] data = orgCodeService.downLoadOrg(url, orgIds, channels);response.reset();//指定返回的文件为附件形式,指定文件名为"二维码zip"response.setHeader(org.springframework.http.HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode("二维码.zip","UTF-8"));//设置返回数据的长度response.addHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(data.length));//设置相应类型为二进制流response.setContentType("application/octet-stream; charset=UTF-8");//将二维码数据写入响应的输出流中,完成文件下载操作IoUtil.write(response.getOutputStream(), Boolean.TRUE, data);}

service层:

    byte[] downLoadOrg(String url,List<Long> orgIdList,List<String> channels) throws IOException;

实现类:

@Slf4j
@Service
public class QRGCodeServiceImpl implements QRGCodeService {// 设置二维码的默认宽度和高度private final static int width = 756;private final static int height = 850;// 设置二维码缩放比例和文件类型private final static int SCALE = 2;private final static String fileType = "png";// 设置字体大小、圆角半径和文字位置private final static int fontSize = 50;private final static int roundingRadius = 250;private final static int pixel = 50;private final static int FONT_SIZE_BIG = 23 * SCALE;@Resourceprivate OrgOrganizationService orgOrganizationService;/*** @author dongruipeng* @date 2024/4/10* @description 根据URL,机构ID列表和渠道列表生成二维码后压缩并返回给前端* @param*/@Overridepublic byte[] downLoadOrg(String url, List<Long> orgIdList, List<String> channels) throws IOException {//参数校验Objects.requireNonNull(url, "url can not be null");Objects.requireNonNull(orgIdList, "orgIdList can not be null");Objects.requireNonNull(channels, "channels cannot be null");url = URLDecoder.decode(url, StandardCharsets.UTF_8);log.info("url参数:{}", url);ByteArrayOutputStream stream = new ByteArrayOutputStream();try (ZipOutputStream zos = new ZipOutputStream(stream)) {for (Long orgId : orgIdList) {// 获取机构名称String orgName = getOrgName(orgId);for (String channel : channels) {String qrContent = url + "?orgId=" + orgId + "&channel=" + channel;Color color = getColorByChannel(channel);byte[] qrCodeBytes = generateQRCode(qrContent, channel.equals(OrgChannelConstant.ONSITE_QR_CODE), orgName, color);String fileName = orgName + "_" + OrgCodeConstant.getByCode(Integer.parseInt(channel)) + ".png";ZipEntry entry = new ZipEntry(fileName);zos.putNextEntry(entry);zos.write(qrCodeBytes);zos.closeEntry();}}}return stream.toByteArray();}// 获取机构名称private String getOrgName(Long orgId) {OrganizationVo organizationVo = orgOrganizationService.selectByOrgId(orgId);Assert.notNull(organizationVo, "该机构信息不存在");return organizationVo.getName();}// 生成二维码图片private byte[] generateQRCode(String qrContent, boolean isSharpCorner, String orgName, Color color) {try {//设置二维码参数QRCodeWriter qrCodeWriter = new QRCodeWriter();BitMatrix bitMatrix = qrCodeWriter.encode(qrContent, BarcodeFormat.QR_CODE, width, height);//创建BufferedImage对象,并设置背景颜色BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D graphics = bufferedImage.createGraphics();graphics.setColor(Color.WHITE);graphics.fillRect(0, 0, width, height);graphics.setColor(color);//将BitMatrix - 二维矩阵 对象转换为BufferedImage对象for (int i = 0; i < width; i++) {for (int j = 0; j < height; j++) {if (bitMatrix.get(i, j)) {graphics.fillRect(i, j, 1, 1);}}}Font font;File yuanti = new File("/usr/share/fonts/SIMSUN.TTC");try {if (yuanti.exists()) {font = Font.createFont(Font.TRUETYPE_FONT, new File("/usr/share/fonts/SIMSUN.TTC"));font = font.deriveFont(Font.BOLD, FONT_SIZE_BIG);log.info("加载宋体字体文件成功");} else {font = new Font("宋体", Font.BOLD, FONT_SIZE_BIG);}} catch (IOException | FontFormatException e) {log.error("加载字体文件时出错: {}", e.getMessage());font = new Font("宋体", Font.BOLD, FONT_SIZE_BIG); //加载失败时使用默认字体}graphics.setFont(font);FontMetrics fontMetrics = graphics.getFontMetrics(font);int orgNameWidth = fontMetrics.stringWidth(orgName);//计算居中的X坐标int orgNameX = (width - orgNameWidth) / 2;//调整像素,文本接近底部int orgNameY = height - pixel;//机构名称居中graphics.drawString(orgName, orgNameX, orgNameY);//设置二维码边框白色圆角if (!isSharpCorner) {//圆角半径BufferedImage roundedImage = makeRoundedCorner(bufferedImage, roundingRadius);bufferedImage = roundedImage;}// 保存二维码图片到字节数组try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {ImageIO.write(bufferedImage, fileType, outputStream);return outputStream.toByteArray();} catch (IOException e) {log.error("保存二维码图片时出错: {}", e.getMessage());throw new RuntimeException("保存二维码图片时出错", e);}} catch (WriterException e) {log.error("生成二维码时出错: {}", e.getMessage());throw new RuntimeException("生成二维码时出错", e);}}//创建圆角图片private static BufferedImage makeRoundedCorner(BufferedImage image, int cornerRadius) {//获取图像宽高int width = image.getWidth();int height = image.getHeight();//创建新的透明背景的 BufferedImage 对象,存储有圆角的图像BufferedImage roundedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);//创建 Graphics2D 对象绘制图像Graphics2D g2 = roundedImage.createGraphics();//设置图片合成模式为 Src,用于在创建新的图形之前清除现有的g2.setComposite(AlphaComposite.Src);//设置抗锯齿,确保图形边缘平滑g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//设置图片颜色为白色,用于设置圆角矩形作为图像的背景g2.setColor(Color.WHITE);//绘制圆角矩形,作为图像的背景,cornerRadius参数确定圆角的大小g2.fill(new RoundRectangle2D.Float(0, 0, width, height, cornerRadius, cornerRadius));//设置合成模式为 SrcAtop,在现有图形上绘制新内容g2.setComposite(AlphaComposite.SrcAtop);//在背景图像上绘制原来的图像,使该图带圆角g2.drawImage(image, 0, 0, null);//释放资源g2.dispose();return roundedImage;}// 根据渠道设置颜色private Color getColorByChannel(String channel) {switch (channel) {case "1":return Color.BLACK;case "2":return new Color(37, 82, 151); //#255297default:return Color.BLACK;}}
}

上述代码中,可谓是耗费了我十足的精力,在自己本地测试时,因为我们的系统文件,也就是"C:\Windows Fonts文件夹"下面存放的字体文件十分之多,如下图:
在这里插入图片描述

所以如果自己本地使用postman测试的话,上述代码中二维码生成的下方文字无论如何也不会乱码,但是一旦发送至我们的服务器上,如果虚拟服务器上的"/usr/share/fonts/"文件夹下面没有字体文件的话,前端一调接口,就会产生乱码问题,那么如何解决呢?

1.首先查看自己引入的字体文件是否已经破坏,最好的测试方法就是:自己在postman上测试,如果生成的字体是系统默认的,那就是坏的,如果生成的字体是我们想要的字体,例如代码所示,使用该方法排除是否字体文件已经破坏
在这里插入图片描述
2.如果在确保字体文件没有被破坏的情况下还是无法加载成功,那么这个时候我们就需要在pom文件当中添加防止打包jar包时能够不被java过滤的依赖,如下图:

<plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><!-- 过滤后缀不需要转码的文件后缀名.crt--><nonFilteredFileExtensions><nonFilteredFileExtension>ttf</nonFilteredFileExtension><nonFilteredFileExtension>xlsx</nonFilteredFileExtension><nonFilteredFileExtension>xls</nonFilteredFileExtension><nonFilteredFileExtension>zip</nonFilteredFileExtension><nonFilteredFileExtension>cer</nonFilteredFileExtension><nonFilteredFileExtension>pfx</nonFilteredFileExtension><nonFilteredFileExtension>py</nonFilteredFileExtension></nonFilteredFileExtensions></configuration></plugin>
</plugins>

在这里插入图片描述
3.在确保文件没有被破坏和已经加载了依赖的情况下还是无法加载成功的话,这个时候我们就需要查看服务器上的文件夹下是否存在我们需要的字体文件,首先,在DockerFile文件中添加一行Copy外部文件的命令

COPY ./SIMSUN.TTC /usr/share/fonts/SIMSUN.TTC

我存放的目录是这样的:
在这里插入图片描述

一定要确保我们的服务器上文件夹下有我们要的字体文件才可以,如果你们遇到了这种情况,一定要排查!

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

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

相关文章

Java-Doc

Java-Doc javdoc命令是用来生成自己的API文档的 参数信息&#xff1a;author作者名version版本号since知名需要最早使用的jdk版本param参数名return返回值情况throws异常抛出情况 1.参数信息的使用&#xff1a; 未完待续... ...

HashMap部分底层源码解析

哈希表的物理结构 HashMap底层都是哈希表&#xff08;也称散列表&#xff09;&#xff0c;线程不安全&#xff0c;其中维护了一个长度为2的幂次方的Entry类型的数组table&#xff0c;数组的每一个索引位置被称为一个桶(bucket)&#xff0c;你添加的映射关系(key,value)最终都被…

腾讯云向量数据库-RAG介绍

1.说明 RAG结合LLM(通用大预言模型)构件基于私有文档、专业领域知识、实时信息的charbot。 2.RAG的主要步骤 知识切片成chunk向量化chunk入库query检索知识chunk构件prompts调用llm生成回答 3.优势 快速构件demo快速理解rag社区支持 4.痛点 投入大效果差调优难 5.RAG应…

一、flask入门和视图

run启动参数 模板渲染 后端给前端页面传参 前端页面设置css from flask import Flask, render_template,jsonify# 创建flask对象 app = Flask(__name__)# 视图函数 + 路由route @app.route("/") def hello_world():# 响应,返回给前端的数据return "hello worl…

多 线 程

1&#xff0e;什么是多线程? 有了多线程&#xff0c;我们就可以让程序同时做多件事情 2.多线程的作用? 提高效率 3&#xff0e;多线程的应用场景? 只要你想让多个事情同时运行就需要用到多线程 比如:软件中的耗时操作、所有的聊天软件、所有的服务器 1.进程和线程【理解】 …

Day36|贪心算法part05:435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 有了上题射气球的因子&#xff0c;这题也就有思路了&#xff0c;反正无脑排序就行了&#xff1a; 首先将所有区间按照end的大小从小到大排序&#xff1b;选取最早end为起始x_end遍历所有区间&#xff0c;如果该区间的start比end大&#xff08;可重叠&#xf…

活动预告|如何构建云原生现代化数据栈?北京首场 Meetup 来啦!

数字化时代带来了海量的数据涌现&#xff0c;传统的数据架构已然无法满足现代企业的需求&#xff0c;现代化数据栈应运而生。基于云原生的现代化数据栈具备了多云兼容的特性&#xff0c;在不同的云环境下能够保持高性能运作&#xff0c;使企业得以无缝地处理和分析海量的数据集…

利用SARscape对日本填海造陆和天然气开采进行地表形变监测

日本千叶市&#xff0c;是日本南部重要的工业港市。位于西部的浦安市是一个典型的"填海造田"城市&#xff0c;东南部的东金区有一片天然气开采区域&#xff0c;本文利用SARscape&#xff0c;用干涉叠加的方法&#xff0c;即PS和SBAS&#xff0c;对这两个区域进行地表…

倒计时4天!百度Create AI开发者大会“大模型与深度学习技术”论坛亮点抢鲜看!

作为人工智能的核心基础技术&#xff0c;深度学习具有很强的通用性&#xff0c;大模型技术在深度学习的基础上&#xff0c;通过构建更加庞大神经网络模型和应用transformer等更加领先的算法&#xff0c;使模型的处理能力产生质的飞跃。飞桨&#xff08;PaddlePaddle&#xff09…

MySQL分区表(14/16)

分区表 基本概述 分区表是数据库中一种用于优化大型表数据管理和查询性能的技术。它将一个表的数据根据特定的规则或条件分割成多个部分&#xff0c;每个部分称为一个分区。每个分区可以独立于其他分区进行存储、管理和查询&#xff0c;这样可以提高数据处理的效率&#xff0…

VS Code中“@“符号如何自动补全导入路径

一、下载 Path Intellisense 插件 二、打开设置&#xff0c;在扩展中选择该插件&#xff0c;点击setting.json 三、添加配置&#xff1a; "":"${workspaceRoot}/src" 如图&#xff1a; 四、在项目src目录中新建jsconfig.json文件 &#xff08;一定要是src目…

动态规划(背包问题)

一:动态规划概述: 动态规划实际上是一种将原本的 大 方面的问题转化为许许多多的 小方面 的一种应用, 在一定程度上避免数据的重复, 并且能够将数据以自己希望的方式进行存储, 用来解决多阶段的数学问题, 从而提高算法的效率 在算法当中, 动态规划主要包括有: 递推, 线性DP 记忆…

【Java核心技术】第3章 Java的基本程序设计结构

1 数据类型 Java一共有8种数据类型&#xff1a; 4种整型 类型存储需求int4字节short2字节long8字节byte1字节 2种浮点型 类型存储需求float4字节double8字节 1种字符型 1种布尔型 2 变量声明 2.1 局部类型推断 如果可以从变量的初始值推断变量类型&#xff0c;只需要使用…

【数组】5螺旋矩阵

这里写自定义目录标题 一、题目二、解题精髓-循环不变量三、代码 一、题目 给定⼀个正整数 n&#xff0c;⽣成⼀个包含 1 到 n^2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的正⽅形矩阵。 示例: 输⼊: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ] 二、解题精髓…

JVM参数列表

-client :设置JVM使用client模式,特点启动较快(神机不明显(I5/8G/SSD)) -server :设置JVM使用server模式。64位JDK默认启动该模式 -agentlib:libname[options] :用于加载本地的lib -agentlib:hprof :用于获取JVM的运行情况 -agentpath:pathnamep[options] :加载制定路径的本…

Day:007(1) | Python爬虫:高效数据抓取的编程技术(scrapy框架使用)

Scrapy的介绍 Scrapy 是一个用于抓取网站和提取结构化数据的应用程序框架&#xff0c;可用于各种有用的应用程序&#xff0c;如数据挖掘、信息处理或历史存档。 尽管 Scrapy 最初是为网络抓取而设计的&#xff0c;但它也可用于使用API提取数据或用作通用网络爬虫。 Scrapy的优势…

【Nacos】Nacos最新版的安装、配置过程记录和踩坑分享

Nacos是什么&#xff1f;有什么功能&#xff1f;大家可以自行联网&#xff08;推荐 https://cn.bing.com/&#xff09;搜索&#xff0c;这里就不做介绍了。 简单的看了下官网&#xff0c;安装最新版的Nacos&#xff08;v2.3.2&#xff09;需要使用到JDK&#xff08;1.8.0&…

应急响应-战前反制主机HIDSElkeid蜜罐系统HFish

知识点 战前-反制-平台部署其他更多项目&#xff1a; https://github.com/birdhan/SecurityProduct HIDS&#xff1a;主机入侵检测系统&#xff0c;通常会有一个服务器承担服务端角色&#xff0c;其他主机就是客户端角色&#xff0c;客户端加入到服务端的检测范围里&#xff…

滑动窗口用法

文章目录 1. 长度最小的子数组&#xff08;模板&#xff09;2. 无重复字符的最长字串3. 最小覆盖字串4. 加油站5. 替换字串得到平衡字符串 1. 长度最小的子数组&#xff08;模板&#xff09; 题目分析 直接用步骤分析示例1&#xff0c;[]表示窗口&#xff0c;min_length表示满…

软件测试级别和对应要求

软件测试级别指的是将软件测试活动按照不同的开发阶段和测试目的进行分类&#xff0c;形成不同层次的测试过程。 分级依据&#xff0c;根据V模型 单元测试&#xff1a;这是软件生命周期中的第一个测试级别&#xff0c;主要针对软件的最小单元模块进行&#xff0c;例如类、函数…