• jframe生成柱状图片+图片垂直合并+钉钉机器人推送


    需求:

            后端根据数据自动生成2个图片,然后把两张图片合并成一张图片,再发到钉钉群里,涉及到定时生成和推送,当时我们测试同事说他们写定时脚本放到服务器上,然后让我提供生成图片的方法和钉钉机器人的逻辑

    天下文字一大抄,集各位大佬精华,最后成果如下

     

     

    依赖

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <parent>
    6. <groupId>org.springframework.boot</groupId>
    7. <artifactId>spring-boot-starter-parent</artifactId>
    8. <version>2.6.6</version>
    9. <relativePath/> <!-- lookup parent from repository -->
    10. </parent>
    11. <groupId>com.example</groupId>
    12. <artifactId>demo</artifactId>
    13. <version>0.0.1-SNAPSHOT</version>
    14. <name>imagedemo</name>
    15. <description>Demo project for Spring Boot</description>
    16. <properties>
    17. <java.version>8</java.version>
    18. </properties>
    19. <dependencies>
    20. <dependency>
    21. <groupId>org.springframework.boot</groupId>
    22. <artifactId>spring-boot-starter</artifactId>
    23. </dependency>
    24. <dependency>
    25. <groupId>org.springframework.boot</groupId>
    26. <artifactId>spring-boot-starter-test</artifactId>
    27. <scope>test</scope>
    28. </dependency>
    29. <!--柱状图制作引入-->
    30. <dependency>
    31. <groupId>org.jfree</groupId>
    32. <artifactId>jfreechart</artifactId>
    33. <version>1.0.19</version>
    34. </dependency>
    35. <!--oss引入-->
    36. <dependency>
    37. <groupId>com.aliyun.oss</groupId>
    38. <artifactId>aliyun-sdk-oss</artifactId>
    39. <version>3.15.1</version>
    40. </dependency>
    41. <dependency>
    42. <groupId>org.projectlombok</groupId>
    43. <artifactId>lombok</artifactId>
    44. <version>1.18.22</version>
    45. </dependency>
    46. <!--钉钉机器人引入-->
    47. <dependency>
    48. <groupId>com.aliyun</groupId>
    49. <artifactId>alibaba-dingtalk-service-sdk</artifactId>
    50. <version>2.0.0</version>
    51. </dependency>
    52. <!--常用工具类-->
    53. <dependency>
    54. <groupId>cn.hutool</groupId>
    55. <artifactId>hutool-all</artifactId>
    56. <version>5.8.20</version>
    57. </dependency>
    58. </dependencies>
    59. <build>
    60. <plugins>
    61. <plugin>
    62. <groupId>org.springframework.boot</groupId>
    63. <artifactId>spring-boot-maven-plugin</artifactId>
    64. </plugin>
    65. </plugins>
    66. </build>
    67. </project>

    配置  

     

    1. server:
    2. port: 9111
    3. #oss配置
    4. aliyun:
    5. oss:
    6. enable: true
    7. name: alioss
    8. accessKey: xxx
    9. secretKey: xxx
    10. bucketName: xxx
    11. endpoint: xxx
    12. pathPrefix: xxx #生成图片所在的文件夹
    13. #钉钉机器人
    14. sys:
    15. pe:
    16. dingtalk:
    17. robotMsgUrl: xxxurl
    18. secret: xxx

    配置类 

    1. package com.example.demo.config;
    2. import lombok.Data;
    3. import org.springframework.boot.context.properties.ConfigurationProperties;
    4. import org.springframework.stereotype.Component;
    5. @Data
    6. @Component
    7. @ConfigurationProperties(prefix = "sys.pe.dingtalk")
    8. public class DingTalkConfig {
    9. private String robotMsgUrl; //系统预警机器人推送群地址
    10. private String secret; //系统预警机器人推送群地址
    11. }

     

    1. package com.example.demo.config;
    2. import lombok.Data;
    3. import org.springframework.boot.context.properties.ConfigurationProperties;
    4. import org.springframework.stereotype.Component;
    5. @Data
    6. @Component
    7. @ConfigurationProperties(prefix = "aliyun.oss")
    8. public class OssConfig {
    9. private String endpoint;
    10. private String accessKey;
    11. private String secretKey;
    12. private String bucketName; //桶名称
    13. private String pathPrefix; //生成文件路径前缀
    14. }

    module【除serie外,另外一个根据自己需求自行确定是否要用】 

     

    1. package com.example.demo.model;
    2. import java.io.Serializable;
    3. import java.util.Vector;
    4. /**
    5. * @author zsl0
    6. * created on 2023/7/6 17:51
    7. */
    8. public class Serie implements Serializable {
    9. private static final long serialVersionUID = 1L;
    10. private String name;// 名字
    11. private Vector data;// 数据值
    12. public Serie() {
    13. }
    14. /**
    15. *
    16. * @param name
    17. * 名称(线条名称)
    18. * @param data
    19. * 数据(线条上的所有数据值)
    20. */
    21. public Serie(String name, Vector data) {
    22. this.name = name;
    23. this.data = data;
    24. }
    25. /**
    26. *
    27. * @param name
    28. * 名称(线条名称)
    29. * @param array
    30. * 数据(线条上的所有数据值)
    31. */
    32. public Serie(String name, Object[] array) {
    33. this.name = name;
    34. if (array != null) {
    35. data = new Vector(array.length);
    36. for (int i = 0; i < array.length; i++) {
    37. data.add(array[i]);
    38. }
    39. }
    40. }
    41. public String getName() {
    42. return name;
    43. }
    44. public void setName(String name) {
    45. this.name = name;
    46. }
    47. public Vector getData() {
    48. return data;
    49. }
    50. public void setData(Vector data) {
    51. this.data = data;
    52. }
    53. }
      1. package com.example.demo.model;
      2. import lombok.AllArgsConstructor;
      3. import lombok.Builder;
      4. import lombok.Data;
      5. import lombok.NoArgsConstructor;
      6. @Data
      7. @AllArgsConstructor
      8. @NoArgsConstructor
      9. @Builder
      10. public class SystemApiCount {
      11. private String systemName;
      12. private Integer count;
      13. }

       生成图片util

      1. package com.example.demo.utils;
      2. import com.example.demo.model.Serie;
      3. import lombok.extern.slf4j.Slf4j;
      4. import org.jfree.chart.ChartFactory;
      5. import org.jfree.chart.StandardChartTheme;
      6. import org.jfree.chart.axis.CategoryAxis;
      7. import org.jfree.chart.axis.NumberAxis;
      8. import org.jfree.chart.axis.ValueAxis;
      9. import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
      10. import org.jfree.chart.plot.CategoryPlot;
      11. import org.jfree.chart.plot.DefaultDrawingSupplier;
      12. import org.jfree.chart.plot.PieLabelLinkStyle;
      13. import org.jfree.chart.renderer.category.BarRenderer;
      14. import org.jfree.chart.renderer.category.StandardBarPainter;
      15. import org.jfree.chart.renderer.xy.StandardXYBarPainter;
      16. import org.jfree.data.category.DefaultCategoryDataset;
      17. import org.jfree.ui.RectangleInsets;
      18. import java.awt.*;
      19. import java.util.Vector;
      20. /**
      21. * Jfreechart工具类
      22. *

      23. * 解决中午乱码问题
      24. * 用来创建类别图表数据集、创建饼图数据集、时间序列图数据集
      25. * 用来对柱状图、折线图、饼图、堆积柱状图、时间序列图的样式进行渲染
      26. * 设置X-Y坐标轴样式
      27. *

      28. *
      29. * @author chenchangwen
      30. * @since:2014-2-18
      31. */
      32. @Slf4j
      33. public class ChartUtil {
      34. private static String NO_DATA_MSG = "数据加载失败";
      35. private static Font FONT = new Font("宋体", Font.PLAIN, 12);
      36. // public static Color[] CHART_COLORS = {
      37. // new Color(22, 102, 149), new Color(92, 92, 97), new Color(144, 237, 125), new Color(255, 188, 117),
      38. // new Color(60, 142, 116), new Color(255, 117, 153), new Color(253, 236, 109), new Color(128, 133, 232),
      39. // new Color(43, 66, 147), new Color(255, 204, 102)};// 颜色
      40. public static Color[] CHART_COLORS = {
      41. new Color(12, 250, 194, 195), new Color(16, 161, 246), new Color(22, 102, 149)};// 颜色
      42. static {
      43. setChartTheme();
      44. }
      45. public ChartUtil() {
      46. }
      47. /**
      48. * 中文主题样式 解决乱码
      49. */
      50. private static void setChartTheme() {
      51. // 设置中文主题样式 解决乱码
      52. StandardChartTheme chartTheme = new StandardChartTheme("CN");
      53. // 设置标题字体
      54. chartTheme.setExtraLargeFont(FONT);
      55. // 设置图例的字体
      56. chartTheme.setRegularFont(FONT);
      57. // 设置轴向的字体
      58. chartTheme.setLargeFont(FONT);
      59. chartTheme.setSmallFont(FONT);
      60. chartTheme.setTitlePaint(new Color(51, 51, 51));
      61. chartTheme.setSubtitlePaint(new Color(85, 85, 85));
      62. chartTheme.setLegendBackgroundPaint(Color.WHITE);// 设置标注
      63. chartTheme.setLegendItemPaint(Color.BLACK);//
      64. chartTheme.setChartBackgroundPaint(Color.WHITE);
      65. // 绘制颜色绘制颜色.轮廓供应商
      66. // paintSequence,outlinePaintSequence,strokeSequence,outlineStrokeSequence,shapeSequence
      67. Paint[] OUTLINE_PAINT_SEQUENCE = new Paint[]{Color.WHITE};
      68. // 绘制器颜色源
      69. DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(CHART_COLORS, CHART_COLORS, OUTLINE_PAINT_SEQUENCE,
      70. DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
      71. DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
      72. chartTheme.setDrawingSupplier(drawingSupplier);
      73. chartTheme.setPlotBackgroundPaint(Color.WHITE);// 绘制区域
      74. chartTheme.setPlotOutlinePaint(Color.WHITE);// 绘制区域外边框
      75. chartTheme.setLabelLinkPaint(new Color(8, 55, 114));// 链接标签颜色
      76. chartTheme.setLabelLinkStyle(PieLabelLinkStyle.CUBIC_CURVE);
      77. chartTheme.setAxisOffset(new RectangleInsets(5, 12, 5, 12));
      78. chartTheme.setDomainGridlinePaint(new Color(192, 208, 224));// X坐标轴垂直网格颜色
      79. chartTheme.setRangeGridlinePaint(new Color(192, 192, 192));// Y坐标轴水平网格颜色
      80. chartTheme.setBaselinePaint(Color.WHITE);
      81. chartTheme.setCrosshairPaint(Color.BLUE);// 不确定含义
      82. chartTheme.setAxisLabelPaint(new Color(51, 51, 51));// 坐标轴标题文字颜色
      83. chartTheme.setTickLabelPaint(new Color(67, 67, 72));// 刻度数字
      84. chartTheme.setBarPainter(new StandardBarPainter());// 设置柱状图渲染
      85. chartTheme.setXYBarPainter(new StandardXYBarPainter());// XYBar 渲染
      86. chartTheme.setItemLabelPaint(Color.black);
      87. chartTheme.setThermometerPaint(Color.white);// 温度计
      88. ChartFactory.setChartTheme(chartTheme);
      89. }
      90. /**
      91. * 创建类别数据集合
      92. */
      93. public static DefaultCategoryDataset createDefaultCategoryDataset(Vector series, String[] categories) {
      94. DefaultCategoryDataset dataset = new DefaultCategoryDataset();
      95. for (Serie serie : series) {
      96. String name = serie.getName();
      97. Vector data = serie.getData();
      98. if (data != null && categories != null && data.size() == categories.length) {
      99. for (int index = 0; index < data.size(); index++) {
      100. String value = data.get(index) == null ? "" : data.get(index).toString();
      101. if (isPercent(value)) {
      102. value = value.substring(0, value.length() - 1);
      103. }
      104. if (isNumber(value)) {
      105. dataset.setValue(Double.parseDouble(value), name, categories[index]);
      106. }
      107. }
      108. }
      109. }
      110. return dataset;
      111. }
      112. /**
      113. * 设置柱状图渲染
      114. *
      115. * @param plot 绘图
      116. * @param isShowDataLabels
      117. */
      118. public static void setBarRenderer(CategoryPlot plot, boolean isShowDataLabels) {
      119. plot.setNoDataMessage(NO_DATA_MSG);
      120. plot.setInsets(new RectangleInsets(10, 20, 5, 20));
      121. // 设置柱状图样式
      122. BarRenderer renderer = (BarRenderer) plot.getRenderer();
      123. renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
      124. //设置每个柱子之间的距离【柱子之间的距离和柱子的最大宽度以及你生成的图片的宽度,这三个参数应该挺有关系会影响展示】
      125. renderer.setItemMargin(-3);
      126. renderer.setMaximumBarWidth(0.015);// 设置柱子最大宽度
      127. for (int i = 0; i < CHART_COLORS.length; i++) {
      128. // 设置柱子颜色
      129. renderer.setSeriesPaint(i, CHART_COLORS[i]);
      130. }
      131. renderer.setShadowVisible(false); // 去除阴影效果
      132. // 设置轴样式jf
      133. CategoryAxis domainAxis = plot.getDomainAxis();
      134. domainAxis.setTickLabelFont(new Font("宋体", Font.PLAIN, 14)); // 设置X轴上提示文字样式
      135. domainAxis.setLabelFont(new Font("宋体", Font.PLAIN, 15)); // 设置X轴下的标签文字
      136. domainAxis.setTickLabelInsets(new RectangleInsets(10, 20, 5, 20));
      137. // domainAxis.setTickMarksVisible(false); // 坐标轴标尺不显示
      138. // domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); //X轴刻度倾斜45度
      139. NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
      140. rangeAxis.setTickLabelFont(new Font("宋体", Font.PLAIN, 14)); // 设置Y轴的提示文字样式
      141. rangeAxis.setLabelFont(new Font("宋体", Font.PLAIN, 15));
      142. rangeAxis.setTickLabelsVisible(false); //y轴数值不显示
      143. plot.setRangeGridlinesVisible(false); //数据轴网格不显示
      144. // rangeAxis.setLowerMargin(0.35); // 设置最低的一个 Item 与图片底端的距离
      145. // rangeAxis.setUpperMargin(0.45); // 设置最高的一个 Item 与图片顶端的距离
      146. // rangeAxis.setUpperBound(8000.0); // 设置Y轴的最大值
      147. if (isShowDataLabels) {
      148. renderer.setBaseItemLabelsVisible(true);
      149. }
      150. setXAixs(plot);
      151. setYAixs(plot);
      152. }
      153. /**
      154. * 设置类别图表(CategoryPlot) X坐标轴线条颜色和样式
      155. *
      156. * @param plot 绘图
      157. */
      158. private static void setXAixs(CategoryPlot plot) {
      159. Color lineColor = new Color(31, 121, 170);
      160. plot.getDomainAxis().setAxisLinePaint(lineColor);// X坐标轴颜色
      161. plot.getDomainAxis().setTickMarkPaint(lineColor);// X坐标轴标记|竖线颜色
      162. }
      163. /**
      164. * 设置类别图表(CategoryPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
      165. *
      166. * @param plot 绘图
      167. */
      168. private static void setYAixs(CategoryPlot plot) {
      169. Color lineColor = new Color(192, 208, 224);
      170. ValueAxis axis = plot.getRangeAxis();
      171. axis.setAxisLinePaint(lineColor);// Y坐标轴颜色
      172. axis.setTickMarkPaint(lineColor);// Y坐标轴标记|竖线颜色
      173. // 隐藏Y刻度
      174. axis.setAxisLineVisible(false);
      175. axis.setTickMarksVisible(false);
      176. // Y轴网格线条
      177. plot.setRangeGridlinePaint(new Color(192, 192, 192));
      178. plot.setRangeGridlineStroke(new BasicStroke(1));
      179. plot.getRangeAxis().setUpperMargin(0.1);// 设置顶部Y坐标轴间距,防止数据无法显示
      180. plot.getRangeAxis().setLowerMargin(0.1);// 设置底部Y坐标轴间距
      181. }
      182. /**
      183. * 是不是一个%形式的百分比
      184. *
      185. * @param str
      186. * @return
      187. */
      188. private static boolean isPercent(String str) {
      189. return str != null ? str.endsWith("%") && isNumber(str.substring(0, str.length() - 1)) : false;
      190. }
      191. /**
      192. * 是不是一个数字
      193. *
      194. * @param str
      195. * @return
      196. */
      197. private static boolean isNumber(String str) {
      198. return str != null ? str.matches("^[-+]?(([0-9]+)((([.]{0})([0-9]*))|(([.]{1})([0-9]+))))$") : false;
      199. }
      200. }
      201. 阿里云oss上传util 

        1. package com.example.demo.utils;
        2. import cn.hutool.core.date.DatePattern;
        3. import cn.hutool.core.date.DateUtil;
        4. import com.aliyun.oss.OSS;
        5. import com.aliyun.oss.OSSClientBuilder;
        6. import com.example.demo.config.OssConfig;
        7. import lombok.extern.slf4j.Slf4j;
        8. import org.springframework.context.annotation.Configuration;
        9. import java.io.FileInputStream;
        10. import java.io.IOException;
        11. import java.io.InputStream;
        12. import java.net.URL;
        13. import java.util.Date;
        14. import java.util.UUID;
        15. @Slf4j
        16. @Configuration
        17. public class OssUploadUtil {
        18. public static String uploadImage(String filPath, OssConfig ossConfig) throws IOException {
        19. OSS ossClient = null;
        20. InputStream inputStream = null;
        21. try {
        22. // 创建OSSClient实例。
        23. ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKey(), ossConfig.getSecretKey());
        24. //生成任意文件名称
        25. UUID uuid = UUID.randomUUID();
        26. String imagePath = ossConfig.getPathPrefix() + "/" + DateUtil.format(new Date(System.currentTimeMillis()), DatePattern.NORM_DATE_PATTERN) + "/" + uuid + ".png";
        27. // 数据流
        28. inputStream = new FileInputStream(filPath);
        29. // 填写Bucket名称和Object完整路径。Object完整路径中不能包含Bucket名称。
        30. ossClient.putObject(ossConfig.getBucketName(), imagePath, inputStream);
        31. String key = imagePath;
        32. System.out.println("imagePath = " + imagePath);
        33. //因为申请公司内的阿里云oss桶的时候,oss生成的图片所在的文件夹权限继承于桶,那么生成这个链接之后就不能被公网访问,当时公司要求文件夹权限或图片权限不能改成公共读,所以就采用了生成的url链接拼接有效期的形式
        34. Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 365); //设置从此刻开始一年有效
        35. URL url = ossClient.generatePresignedUrl(ossConfig.getBucketName(), key, expiration);
        36. return url.toString();
        37. } catch (Exception e) {
        38. log.error("sso upload error", e);
        39. } finally {
        40. // 关闭OSSClient和数据流【一定要关闭,否则会失败】
        41. if (ossClient != null) ossClient.shutdown();
        42. if (inputStream != null) inputStream.close();
        43. }
        44. return "";
        45. }
        46. }

        钉钉机器人uitl 

        1. package com.example.demo.utils;
        2. import com.dingtalk.api.DefaultDingTalkClient;
        3. import com.dingtalk.api.DingTalkClient;
        4. import com.dingtalk.api.request.OapiRobotSendRequest;
        5. import com.dingtalk.api.response.OapiRobotSendResponse;
        6. import com.example.demo.config.DingTalkConfig;
        7. import com.taobao.api.ApiException;
        8. import lombok.extern.slf4j.Slf4j;
        9. import org.apache.commons.codec.binary.Base64;
        10. import javax.crypto.Mac;
        11. import javax.crypto.spec.SecretKeySpec;
        12. import java.net.URLEncoder;
        13. @Slf4j
        14. public class DingTalkUtil {
        15. /**
        16. * 图片语法
        17. *
        18. * @param phone
        19. */
        20. public static void sendRobotMessage(String phone, String imageUrl, DingTalkConfig dingTalkConfig) throws Exception {
        21. try {
        22. Long timestamp = System.currentTimeMillis();
        23. String sign = getSign(dingTalkConfig.getSecret(), timestamp);
        24. DingTalkClient client = new DefaultDingTalkClient(dingTalkConfig.getRobotMsgUrl() + "&sign=" + sign + "×tamp=" + timestamp);
        25. OapiRobotSendRequest request = new OapiRobotSendRequest();
        26. request.setMsgtype("markdown");
        27. OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
        28. markdown.setTitle("测试图片");
        29. // markdown.setText(" @" + phone + " \n " +
        30. // "![这是一张图片](" + imageUrl + ")");
        31. markdown.setText("![这是一张图片](" + imageUrl + ")");
        32. request.setMarkdown(markdown);
        33. //@全体,如果要@单独几个人再去看钉钉机器人推送相关文档
        34. OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
        35. // at.setAtUserIds(Arrays.asList(userId));
        36. // isAtAll类型如果不为Boolean,请升级至最新SDK
        37. at.setIsAtAll(Boolean.TRUE);
        38. request.setAt(at);
        39. OapiRobotSendResponse response = client.execute(request);
        40. System.out.println(response.getBody());
        41. } catch (ApiException e) {
        42. e.printStackTrace();
        43. }
        44. }
        45. //钉钉机器人推送设置加签方式推送
        46. public static String getSign(String secret, Long timestamp) throws Exception {
        47. String stringToSign = timestamp + "\n" + secret;
        48. Mac mac = Mac.getInstance("HmacSHA256");
        49. mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
        50. byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
        51. String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        52. return sign;
        53. }
        54. }

         图片合并util

        1. package com.example.demo.utils;
        2. import javax.imageio.ImageIO;
        3. import java.awt.*;
        4. import java.awt.image.BufferedImage;
        5. import java.io.File;
        6. import java.io.IOException;
        7. public class ImageConnectUtil {
        8. //图片垂直合并
        9. public static void connectImageWidthVertical(String topImagePath, String bottomImagePath, String targetImagePath) throws IOException {
        10. BufferedImage topBufImage = ImageIO.read(new File(topImagePath));
        11. BufferedImage bottomBufImage = ImageIO.read(new File(bottomImagePath));
        12. int connImageWidth = Math.max(topBufImage.getWidth(), bottomBufImage.getHeight()); //目标图片宽度
        13. int connImageHeight = topBufImage.getHeight() + bottomBufImage.getHeight() + 40; //目标图片高度=第一个图片高度+第二个图片高度+两个图片之间间距
        14. BufferedImage connImage = new BufferedImage(connImageWidth, connImageHeight, BufferedImage.TYPE_INT_RGB);
        15. Graphics connGraphics = connImage.getGraphics();
        16. connGraphics.fillRect(0, 0, connImageWidth, connImageHeight); //设置目标图片底部为白色
        17. connGraphics.setColor(Color.white);
        18. //第一张图左上角坐标为(0, 0)
        19. connGraphics.drawImage(topBufImage, 0, 0, null);
        20. connGraphics.drawImage(bottomBufImage, 0, topBufImage.getHeight() + 40, null); //第二张图片在第一章图片40px高的位置下边
        21. String targetFileName = targetImagePath.split("\\.")[1];
        22. ImageIO.write(connImage, targetFileName, new File(targetImagePath));
        23. }
        24. }

         测试类

        1. package com.example.demo;
        2. import cn.hutool.core.date.DatePattern;
        3. import cn.hutool.core.date.DateUtil;
        4. import com.example.demo.config.DingTalkConfig;
        5. import com.example.demo.config.OssConfig;
        6. import com.example.demo.model.Serie;
        7. import com.example.demo.model.SystemApiCount;
        8. import com.example.demo.utils.ChartUtil;
        9. import com.example.demo.utils.DingTalkUtil;
        10. import com.example.demo.utils.ImageConnectUtil;
        11. import com.example.demo.utils.OssUploadUtil;
        12. import org.jfree.chart.ChartFactory;
        13. import org.jfree.chart.ChartUtilities;
        14. import org.jfree.chart.JFreeChart;
        15. import org.jfree.chart.block.BlockBorder;
        16. import org.jfree.chart.plot.CategoryPlot;
        17. import org.jfree.chart.plot.PlotOrientation;
        18. import org.jfree.chart.title.TextTitle;
        19. import org.jfree.data.category.DefaultCategoryDataset;
        20. import org.jfree.ui.RectangleEdge;
        21. import org.jfree.ui.RectangleInsets;
        22. import org.junit.jupiter.api.Test;
        23. import org.springframework.beans.factory.annotation.Autowired;
        24. import org.springframework.boot.test.context.SpringBootTest;
        25. import java.awt.*;
        26. import java.io.File;
        27. import java.io.FileOutputStream;
        28. import java.io.IOException;
        29. import java.util.List;
        30. import java.util.*;
        31. import java.util.stream.Collectors;
        32. @SpringBootTest
        33. public class TestImageJF {
        34. @Autowired
        35. private DingTalkConfig dingTalkConfig;
        36. @Autowired
        37. private OssConfig ossConfig;
        38. @Test
        39. public void testCreateImage() throws Exception {
        40. String fileName1 = UUID.randomUUID().toString();
        41. //创建image文件夹
        42. String dirPath = createFolder("image") + File.separator + fileName1 + ".png";
        43. System.out.println("dirPath = " + dirPath);
        44. //获取创建的图片地址1
        45. createImage(dirPath);
        46. //获取创建的图片地址2
        47. String dirPath2 = createFolder("image") + File.separator + fileName1 + ".png";
        48. createImage(dirPath2);
        49. //合并图片1和图片2
        50. String dirPath3 = createFolder("image") + File.separator + fileName1 + ".png";
        51. ImageConnectUtil.connectImageWidthVertical(dirPath, dirPath2, dirPath3);
        52. //sso上传图片,获得公网下的图片url
        53. String uploadUrl = OssUploadUtil.uploadImage(dirPath3, ossConfig);
        54. System.out.println("uploadUrl = " + uploadUrl);
        55. //钉钉上传图片
        56. //钉钉机器人发送图片消息
        57. String phone = "19890909090";
        58. DingTalkUtil.sendRobotMessage(phone, uploadUrl, dingTalkConfig);
        59. //删除在项目中生成的图片
        60. deleteFile(dirPath);
        61. deleteFile(dirPath2);
        62. deleteFile(dirPath3);
        63. }
        64. //生成image文件夹
        65. public String createFolder(String folderName) {
        66. String path = System.getProperty("user.dir");
        67. //create folder
        68. String dirPath = path + File.separator + folderName;
        69. File dir = new File(dirPath);
        70. dir.mkdirs();
        71. return dirPath;
        72. }
        73. //删除图片
        74. private void deleteFile(String filePath) {
        75. File file = new File(filePath);
        76. if (file.isFile() && file.exists()) {
        77. boolean delete = file.delete();
        78. System.out.println("delete = " + delete);
        79. }
        80. }
        81. public void createImage(String fileLocation) throws IOException {
        82. FileOutputStream fileOutputStream = null;
        83. try {
        84. //获取所有系统的接口数量
        85. List systemApiCounts = new ArrayList<>();
        86. int count = 900;
        87. String prefix = "xx中心";
        88. for (int i = 0; i < 16; i++) {
        89. systemApiCounts.add(SystemApiCount.builder().systemName(prefix + i).count(count).build());
        90. count -= 50;
        91. }
        92. //获取所有系统的执行用例数
        93. List systemUseCaseExecCounts = new ArrayList<>();
        94. int useCaseCount = 900;
        95. for (int i = 0; i < 16; i++) {
        96. systemUseCaseExecCounts.add(SystemApiCount.builder().systemName(prefix + i).count(useCaseCount).build());
        97. useCaseCount -= 50;
        98. }
        99. //获取所有系统的失败用例数
        100. List failUseCaseExecCounts = new ArrayList<>();
        101. int failedUseCaseCount = 900;
        102. for (int i = 0; i < 16; i++) {
        103. failUseCaseExecCounts.add(SystemApiCount.builder().systemName(prefix + i).count(failedUseCaseCount).build());
        104. failedUseCaseCount -= 50;
        105. }
        106. // // 创建数据系列
        107. List systemName = systemApiCounts.stream().map(SystemApiCount::getSystemName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        108. //数据分别根据中心排序
        109. List apiCounts = systemApiCounts.stream()
        110. .sorted(Comparator.comparing(item -> systemName.indexOf(item.getSystemName()))).map(SystemApiCount::getCount).collect(Collectors.toList());
        111. List useCaseExecCounts = systemUseCaseExecCounts.stream()
        112. .sorted(Comparator.comparing(item -> systemName.indexOf(item.getSystemName()))).map(SystemApiCount::getCount).collect(Collectors.toList());
        113. List failUseCaseExecCountList = failUseCaseExecCounts.stream()
        114. .sorted(Comparator.comparing(item -> systemName.indexOf(item.getSystemName()))).map(SystemApiCount::getCount).collect(Collectors.toList());
        115. Serie serie1 = new Serie("调用接口数", new Vector<>(apiCounts));
        116. Serie serie2 = new Serie("超时接口数", new Vector<>(useCaseExecCounts));
        117. Serie serie3 = new Serie("失败接口数", new Vector<>(failUseCaseExecCountList));
        118. // 创建数据集
        119. DefaultCategoryDataset dataset = ChartUtil.createDefaultCategoryDataset(new Vector<>(Arrays.asList(serie1, serie2, serie3)),
        120. systemName.toArray(new String[systemName.size()]));
        121. // 创建柱状图
        122. String title = DateUtil.format(new Date(System.currentTimeMillis()), DatePattern.CHINESE_DATE_PATTERN) + "系统接入接口监控情况";
        123. JFreeChart chart = ChartFactory.createBarChart(
        124. title, // 图表标题
        125. "", // X轴标题
        126. "", // Y轴标题
        127. dataset, // 数据集
        128. PlotOrientation.VERTICAL,// 图表方向
        129. // PlotOrientation.HORIZONTAL,// 图表方向
        130. true, // 是否显示图例
        131. true, // 是否生成工具提示
        132. false // 是否生成URL链接
        133. );
        134. chart.setTitle(new TextTitle(title, new Font("宋体", Font.BOLD, 20)));
        135. chart.getTitle().setMargin(18, 0, 0, 0);
        136. chart.getTitle().setPaint(Color.GREEN);
        137. chart.getLegend().setFrame(new BlockBorder(Color.WHITE));
        138. chart.getLegend().setPosition(RectangleEdge.TOP);//设置图例在顶部
        139. chart.getLegend().setItemFont(new Font("宋体", Font.PLAIN, 14)); //设置图例大小
        140. chart.getLegend().setItemLabelPadding(new RectangleInsets(2, 2, 2, 2)); //设置图例位置
        141. chart.getLegend().setMargin(18, 0, 0, 0); //这样就只是距离右边有距离 margin 18
        142. chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        143. chart.setBorderVisible(true); //设置图片边框显示
        144. chart.setBorderPaint(Color.BLACK); //图片边框颜色
        145. // StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
        146. // //创建主题样式
        147. // //设置标题字体
        148. // standardChartTheme.setExtraLargeFont(new Font("隶书", Font.BOLD, 20));
        149. // //设置图例的字体
        150. // standardChartTheme.setRegularFont(new Font("宋书", Font.PLAIN, 15));
        151. // //设置轴向的字体
        152. // standardChartTheme.setLargeFont(new Font("宋书", Font.PLAIN, 15));
        153. // //应用主题样式
        154. // ChartFactory.setChartTheme(standardChartTheme);
        155. // 对柱状图进行样式渲染
        156. CategoryPlot plot = chart.getCategoryPlot();
        157. ChartUtil.setBarRenderer(plot, true);
        158. fileOutputStream = new FileOutputStream(fileLocation);
        159. //如果后续有其他中心接入,数据增多的情况下可把宽高设置大点
        160. ChartUtilities.writeChartAsJPEG(fileOutputStream, 1.0f, chart,
        161. 1850, 650, null);// 输出图表
        162. } catch (Exception e) {
        163. e.printStackTrace();
        164. } finally {
        165. if (fileOutputStream != null) {
        166. fileOutputStream.close();
        167. }
        168. }
        169. }
        170. }

         

      202. 相关阅读:
        药物临床试验数据递交PMDA的规定
        MYSQL海量数据存储与优化
        (三) CPU 性能测试 (CPU负载高对应的不同情况)
        学会@ConfigurationProperties月薪过三千
        java 比较运算符
        JavaWeb前端框架VUE和Element组件详解
        maven项目正在idea的创建和配置
        【算法】数组中出现次数超过一半的数字
        CentOS7安装Oracle数据库的全流程
        ShopXO商城系统文件上传0Day代审历程
      203. 原文地址:https://blog.csdn.net/qq_43318174/article/details/132763029