JFreeChart在linux系统或者docker容器中出现中文变成方框的解决方法
1. 背景
因为需要用java做报表,发现JFreeChart很好用,但项目在容器中部署后发现,JFreeChart生成的图表中文变成一个个方框,查看资料知,这是由于linux系统中缺少字体导致,
很多文章都是建议修改服务器linux,忘里面添加字体,但是实际情况中有的时候你没有权限,或不能对系统文件进行修改,而且我试过也没有成功,所以尝试给出一种在项目中解决的办法,供大家参考。
2. 解决方案介绍
2.1 既然系统没有字体,我们就从项目中自带字体,这里选择黑体(字体下载地址),然后把字体读取到系统的某个目录下,接着根据这个字体文件新建一个Font字体,供JFreeChart调用。(注意:项目打成jar后无法读取项目目录下的字体资源,必须通过getResourceAsStream)
1 private Font getFont(int style, Float size) { 2 Font defFont = new Font("黑体", style, 19); 3 4 try { 5 File file = initFontFile(); 6 if (!file.exists()) { 7 return defFont; 8 } 9 Font nf = Font.createFont(Font.TRUETYPE_FONT, file); 10 nf = nf.deriveFont(style, size); 11 log.info("----------------------------nf.getFontName()" + nf.getName() + 12 "----------------------------"); 13 return nf; 14 } catch (Exception e) { 15 log.info(e.getMessage(), e); 16 } 17 return defFont; 18 } 19 private File initFontFile() throws IOException { 20 String fileName = "simhei.ttf"; 21 String filepath = getUploadResource(fileName); 22 23 log.info(filepath); 24 return new File(filepath); 25 } 26 public String getUploadResource(String fileName) throws IOException { 27 //若文件已存在,则返回的filePath中含有"EXIST",则不需再重写文件 28 String filePath = createFile(fileName); 29 30 //文件不存在,则创建流输入默认数据到新文件 31 if (!filePath.contains("exist")) { 32 File file = new File(filePath); 33 try (OutputStream os = new FileOutputStream(file); InputStream is = getClass().getClassLoader().getResourceAsStream(fileName)) { 34 //返回读取指定资源的输入流 35 log.info(os.toString()); 36 int bytesRead = 0; 37 log.info(String.valueOf(bytesRead)); //Avoid code vulnerability scanning 38 byte[] buffer = new byte[1024]; 39 if (is != null) { 40 while ((bytesRead = is.read(buffer, 0, 1024)) != -1) { 41 os.write(buffer, 0, bytesRead); 42 } 43 } else { 44 log.error("---------------------------InputStream is null" + 45 "-------------------------------------"); 46 } 47 } catch (FileNotFoundException e) { 48 log.info(e.getMessage(), e); 49 } catch (IOException e) { 50 log.info(e.getMessage(), e); 51 } 52 return filePath; 53 } 54 return filePath.substring(5); 55 } 56 57 58 public static String createFile(String filename) { 59 String dirPath = System.getProperty("user.dir") + Constants.M_GUARD_PATROL + "/uploadFiles"; 60 File dir = new File(dirPath); 61 dir.mkdirs(); 62 63 //create file 64 String filePath = dirPath + File.separator + filename; 65 File file = new File(filePath); 66 if (!file.exists()) { 67 try { 68 file.createNewFile(); 69 } catch (IOException e) { 70 log.info(e.getMessage(), e); 71 } 72 return filePath; 73 } 74 return "exist" + filePath; 75 }
2.2 然后设置图表的各种属性的字体,不然就会出现方框。
1 JFreeChart chart = ChartFactory.createBarChart(record.getTitle(), "", 2 "", dataSet); 3 // 周围的背景色 4 chart.setBackgroundPaint(ChartColor.WHITE); 5 6 // 设置标题字体,否则会显示乱码 7 TextTitle title = chart.getTitle(); 8 title.setFont(getFont(Font.PLAIN, 13f)); 9 10 CategoryPlot barPlog = (CategoryPlot) chart.getPlot(); 11 chart.getLegend().setItemFont(getFont(Font.PLAIN, 12f)); 12 //设置图例类别字体 13 CategoryAxis domainAxis = barPlog.getDomainAxis(); //水平底部列表 14 domainAxis.setLabelFont(getFont(Font.PLAIN, 12f)); //水平底部标题 15 domainAxis.setTickLabelFont(getFont(Font.PLAIN, 12f)); //垂直标题 16 17 //设置柱状图样式颜色 18 ChartUtils.setBarRenderer(barPlog, true);
3.【附录】关于获取jar包资源路径的问题
这里使用getResourceAsStream方法
3.1 假如你把字体文件simhei.ttf放在resource目录下,如下图所示
你就可以这样写
1 InputStream is =getClass().getClassLoader().getResourceAsStream("simhei.ttf")
3.2 假如你把字体文件simhei.ttf放在resource/fonts目录下,就要写成
1 InputStream is =getClass().getClassLoader().getResourceAsStream("fonts/simhei.ttf")
详细可以参考这边文章《Java中getResourceAsStream的用法》
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)