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

embedded/2025/3/14 9:39:47/

生成二维码

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

java"> @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层:

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

实现类:

java">@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过滤的依赖,如下图:

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外部文件的命令

java">COPY ./SIMSUN.TTC /usr/share/fonts/SIMSUN.TTC

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

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


http://www.ppmy.cn/embedded/1827.html

相关文章

塔面板php7.37.4版本不支持ZipArchive手工安装扩展方法

centos 7 宝塔面板安装的PHP7.3和7.4默认已经不带zip扩展&#xff0c;要手工安装zip扩展首先需要安装libzip&#xff0c; yum -y install libzip 方法如下&#xff1a; 宝塔面板php7.3版本在SSH命令行界面执行以下语句&#xff1a; cd /www/server/php/73/src/ext/zip/ /ww…

✯✯✯宁波 IATF16949 认证:助力汽车企业迈向卓越✯✯✯

&#x1f308;&#x1f308;&#x1f308;宁波IATF16949认证&#xff1a;&#x1f49d;助力汽车企业迈向卓越&#x1f497; &#x1f575;️‍♂️宁波&#xff0c;这座繁华的&#x1f98a;港口城市&#xff0c;不仅以其&#x1f42f;独特的地理位置和丰富的&#x1f54a;️历史…

华为ensp中Hybrid接口原理和配置命令

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月19日14点03分 Hybrid接口是ENSP虚拟化中的一种重要技术&#xff0c;它既可以连接普通终端的接入链路&#xff0c;又可以连接交换机间的干道链路。Hybrid接口允许多…

ChatGPT在论文写作中的应用:提升表达与逻辑的双重助力

随着人工智能技术的快速发展&#xff0c;其在科研领域的应用也愈发广泛。AI不仅提升了科研创新的效率&#xff0c;还为科研人员带来了前所未有的便利。本文将从ChatGPT深度科研应用、数据分析及机器学习、AI绘图以及高效论文撰写等方面&#xff0c;综述AI如何助力科研创新与效率…

C语言中的控制语句(分支语句 if、switch、三目运算符)

程序执行的三大流程 顺序 : 从上向下&#xff0c; 顺序执行代码分支 : 根据条件判断&#xff0c; 决定执行代码的分支循环 : 让特定代码重复的执行 分支语句 条件语句用来根据不同的条件来执行不同的语句&#xff0c;C语言中常用的条件语句包括if语句和switch语句。 if 语句…

华为OD-C卷-开源项目热榜[100分]Python3-100%

题目描述 某个开源社区希望将最近热度比较高的开源项目出一个榜单,推荐给社区里面的开发者。 对于每个开源项目,开发者可以进行关注(watch)、收藏(star)、fork、提issue、提交合并请求(MR)等。 数据库里面统计了每个开源项目关注、收藏、fork、issue、MR的数量,开源…

Java集合进阶——泛型

1.泛型 介绍&#xff1a; 泛型可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。 应用场景&#xff1a; 如果在定义类、方法、接口的时候&#xff0c;如果类型不确定&#xff0c;就可以使用泛型。 格式&#xff1a; <数据类型> 注意&#xff1a; 泛型只支持引…

【汇编】计算机系统构成

计算机系统构成 计算机系统包括硬件和软件两部分 硬件 典型的计算机结构包括 中央处理器(CPU)、存储器和输入输出(I/O)子系统 三个主要组成部分&#xff0c;用系统总线把它们连接在一起 计算机硬件组成与各部分之间的联系 软件 计算机软件可以分为系统软件和用户软件两大类 …