ToB企服应用市场:ToB评测及商务社交产业平台

标题: SpringBoot开发 - 如何定制自己的Banner?还能用图片? [打印本页]

作者: 盛世宏图    时间: 2022-8-24 23:00
标题: SpringBoot开发 - 如何定制自己的Banner?还能用图片?
SpringBoot开发 - 如何定制自己的Banner?还能用图片?

我们在启动Spring Boot程序时,有SpringBoot的Banner信息,那么如何自定义成自己项目的信息呢? @pdai

什么是Banner

我们在启动Spring Boot程序时,有如下Banner信息:

那么如何自定义成自己项目的名称呢?
如何更改Banner

更改Banner有如下几种方式:

在application.yml中添加配置
  1. spring:
  2.   banner:
  3.     charset: UTF-8
  4.     location: classpath:banner.txt
复制代码
在resource下创建banner.txt,内容自定义:
  1. ----welcome----
  2. https://pdai.tech
  3. ---------------
复制代码
修改后,重启的app的效果

  1. SpringApplication application = new SpringApplication(App.class);
  2. /**
  3. * Banner.Mode.OFF:关闭;
  4. * Banner.Mode.CONSOLE:控制台输出,默认方式;
  5. * Banner.Mode.LOG:日志输出方式;
  6. */
  7. application.setBannerMode(Banner.Mode.OFF); // here
  8. application.run(args);
复制代码
SpringApplication还可以设置自定义的Banner的接口类

文字Banner的设计

如何设计上面的文字呢?
一些设计Banner的网站

可以通过这个网站进行设计:patorjk Banner
比如:

我们修改banner.txt, 运行的效果如下

IDEA中Banner的插件

IDEA中也有插件,不过没有预览功能

其它工具

http://www.network-science.de/ascii/
http://www.degraeve.com/img2txt.php
http://www.bootschool.net/ascii
Banner中其它配置信息

除了文件信息,还有哪些信息可以配置呢?比如Spring默认还带有SpringBoot当前的版本号信息。
在banner.txt中,还可以进行一些设置:
  1. # springboot的版本号
  2. ${spring-boot.version}            
  3. # springboot的版本号前面加v后上括号
  4. ${spring-boot.formatted-version}
  5. # MANIFEST.MF文件中的版本号
  6. ${application.version}              
  7. # MANIFEST.MF文件的版本号前面加v后上括号
  8. ${application.formatted-version}
  9. # MANIFEST.MF文件中的程序名称
  10. ${application.title}
  11. # ANSI样色/样式等
  12. ${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})
复制代码
简单的测试如下(注意必须打包出Jar, 才会生成resources/META-INF/MANIFEST.MF):

动画Banner的设计

那我能不能设置动态的Banner呢?比如一个图片?
SpringBoot2是支持图片形式的Banner,
  1. spring:
  2.   main:
  3.     banner-mode: console
  4.     show-banner: true
  5.   banner:
  6.     charset: UTF-8
  7.     image:
  8.       margin: 0
  9.       height: 10
  10.       invert: false
  11.       location: classpath:pdai.png
复制代码
效果如下(需要选择合适的照片,不然效果不好, 所以这种方式很少使用),

注意: 格式不能太大,不然会报错
  1. org.springframework.boot.ImageBanner     : Image banner not printable: class path resource [banner.gif] (class java.lang.ArrayIndexOutOfBoundsException: '4096')
复制代码
进一步思考

图片Banner是如何起作用的?

发现 Springboot 可以把图片转换成 ASCII 图案,那么它是怎么做的呢?以此为例,我们看下Spring 的Banner是如何生成的呢?

获取banner
  1. class SpringApplicationBannerPrinter {
  2.     static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
  3.     static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
  4.     static final String DEFAULT_BANNER_LOCATION = "banner.txt";
  5.     static final String[] IMAGE_EXTENSION = new String[]{"gif", "jpg", "png"};
  6.     private static final Banner DEFAULT_BANNER = new SpringBootBanner(); // 默认的Spring Banner
  7.     private final ResourceLoader resourceLoader;
  8.     private final Banner fallbackBanner;
  9.     // 获取Banner,优先级是环境变量中的Image优先,格式在IMAGE_EXTENSION中,然后才是banner.txt
  10.     private Banner getBanner(Environment environment) {
  11.         SpringApplicationBannerPrinter.Banners banners = new SpringApplicationBannerPrinter.Banners();
  12.         banners.addIfNotNull(this.getImageBanner(environment));
  13.         banners.addIfNotNull(this.getTextBanner(environment));
  14.         if (banners.hasAtLeastOneBanner()) {
  15.             return banners;
  16.         } else {
  17.             return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;
  18.         }
  19.     }
复制代码
获取图片Banner
  1. private Banner getImageBanner(Environment environment) {
  2.     String location = environment.getProperty("spring.banner.image.location");
  3.     if (StringUtils.hasLength(location)) {
  4.         Resource resource = this.resourceLoader.getResource(location);
  5.         return resource.exists() ? new ImageBanner(resource) : null;
  6.     } else {
  7.         String[] var3 = IMAGE_EXTENSION;
  8.         int var4 = var3.length;
  9.         for(int var5 = 0; var5 < var4; ++var5) {
  10.             String ext = var3[var5];
  11.             Resource resource = this.resourceLoader.getResource("banner." + ext);
  12.             if (resource.exists()) {
  13.                 return new ImageBanner(resource);
  14.             }
  15.         }
  16.         return null;
  17.     }
  18. }
复制代码
获取图片的配置等
  1. private void printBanner(Environment environment, PrintStream out) throws IOException {
  2.     int width = (Integer)this.getProperty(environment, "width", Integer.class, 76);
  3.     int height = (Integer)this.getProperty(environment, "height", Integer.class, 0);
  4.     int margin = (Integer)this.getProperty(environment, "margin", Integer.class, 2);
  5.     boolean invert = (Boolean)this.getProperty(environment, "invert", Boolean.class, false); // 图片的属性
  6.     BitDepth bitDepth = this.getBitDepthProperty(environment);
  7.     ImageBanner.PixelMode pixelMode = this.getPixelModeProperty(environment);
  8.     ImageBanner.Frame[] frames = this.readFrames(width, height); // 读取图片的帧
  9.     for(int i = 0; i < frames.length; ++i) {
  10.         if (i > 0) {
  11.             this.resetCursor(frames[i - 1].getImage(), out);
  12.         }
  13.         this.printBanner(frames[i].getImage(), margin, invert, bitDepth, pixelMode, out);
  14.         this.sleep(frames[i].getDelayTime());
  15.     }
  16. }
复制代码
转换成ascii
  1. private void printBanner(BufferedImage image, int margin, boolean invert, BitDepth bitDepth, ImageBanner.PixelMode pixelMode, PrintStream out) {
  2.     AnsiElement background = invert ? AnsiBackground.BLACK : AnsiBackground.DEFAULT;
  3.     out.print(AnsiOutput.encode(AnsiColor.DEFAULT));
  4.     out.print(AnsiOutput.encode(background));
  5.     out.println();
  6.     out.println();
  7.     AnsiElement lastColor = AnsiColor.DEFAULT;
  8.     AnsiColors colors = new AnsiColors(bitDepth);
  9.     for(int y = 0; y < image.getHeight(); ++y) {
  10.         int x;
  11.         for(x = 0; x < margin; ++x) {
  12.             out.print(" ");
  13.         }
  14.         for(x = 0; x < image.getWidth(); ++x) {
  15.             Color color = new Color(image.getRGB(x, y), false);
  16.             AnsiElement ansiColor = colors.findClosest(color);
  17.             if (ansiColor != lastColor) {
  18.                 out.print(AnsiOutput.encode(ansiColor));
  19.                 lastColor = ansiColor;
  20.             }
  21.             out.print(this.getAsciiPixel(color, invert, pixelMode)); // // 像素点转换成字符输出
  22.         }
  23.         out.println();
  24.     }
  25.     out.print(AnsiOutput.encode(AnsiColor.DEFAULT));
  26.     out.print(AnsiOutput.encode(AnsiBackground.DEFAULT));
  27.     out.println();
  28. }
复制代码
示例源码

https://github.com/realpdai/tech-pdai-spring-demos
更多内容

告别碎片化学习,无套路一站式体系化学习后端开发: Java 全栈知识体系(https://pdai.tech)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4