Spring Boot 提升你的项目形象:定制启动 Banner 教程

SpringBoot - 定制自己的Banner

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

什么是Banner?

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

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

如何更改Banner?

更改Banner有如下几种方式:

  1. banner.txt配置(最常用)
    在application.yml中添加配置
spring:
  banner:
    charset: UTF-8
    location: classpath:banner.txt

在resource下创建banner.txt,内容自定义:


  |\    \ \ \ \ \ \ \      __           ___
  |  \    \ \ \ \ \ \ \   | O~-_    _-~~   ~~-_
  |   >----|-|-|-|-|-|-|--|  __/   /  BELIEVE  )
  |  /    / / / / / / /   |__\   <              )
  |/     / / / / / / /             \_   ME !  _)
                                     ~--___--~     

修改后,重启的app的效果

  1. SpringApplication启动时设置参数
SpringApplication application = new SpringApplication(App.class);
/**
* Banner.Mode.OFF:关闭;
* Banner.Mode.CONSOLE:控制台输出,默认方式;
* Banner.Mode.LOG:日志输出方式;
*/
application.setBannerMode(Banner.Mode.OFF); // here
application.run(args);

SpringApplication还可以设置自定义的Banner的接口类

控制banner的开关或者位置

通过配置文件:

spring:
    main:
    banner-mode: console 
    # console 显示,off 不显示, log 日志

通过方法:

如下方法,通过 SpringApplication的setBannerMode方法来控制。

文字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中,还可以进行一些设置:

# springboot的版本号 
${spring-boot.version}             
 
# springboot的版本号前面加v后上括号 
${spring-boot.formatted-version}

# MANIFEST.MF文件中的版本号 
${application.version}              
 
# MANIFEST.MF文件的版本号前面加v后上括号 
${application.formatted-version}

# MANIFEST.MF文件中的程序名称
${application.title}

# ANSI样色/样式等
${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})

${AnsiColor.BRIGHT_RED}:设置控制台中输出内容的颜色

如下

${AnsiColor.BRIGHT_BLUE}这句话下面的文本输出颜色为:蓝色
${AnsiColor.BRIGHT_GREEN}这句话下面的文本输出颜色为:绿色
${AnsiColor.DEFAULT} 这句话下面的文本输出颜色为:默认颜色

输出效果如下:如下,第一种颜色时蓝色(BLUE),再下面是绿色(GREEN),再下面是默认颜色 (DEFAULT)

简单的测试如下(注意必须打包出Jar, 才会生成resources/META-INF/MANIFEST.MF):

动画Banner的设计

那我能不能设置动态的Banner呢?比如一个图片?

SpringBoot2是支持图片形式的Banner,

spring:
  main:
    banner-mode: console
    show-banner: true
  banner:
    charset: UTF-8
    image:
      margin: 0
      height: 10
      invert: false
      location: classpath:pdai.png

效果如下(需要选择合适的照片,不然效果不好, 所以这种方式很少使用),

注意: 格式不能太大,不然会报错

org.springframework.boot.ImageBanner     : Image banner not printable: class path resource [banner.gif] (class java.lang.ArrayIndexOutOfBoundsException: '4096')

进一步思考

图片Banner是如何起作用的?

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

  1. 获取Banner
  • 优先级是环境变量中的Image优先,格式在IMAGE_EXTENSION中
  • 然后才是banner.txt
  • 没有的话就用SpringBootBanner
  1. 如果是图片
  • 获取图片Banner(属性配置等)
  • 转换成ascii
  • 获取banner
class SpringApplicationBannerPrinter {
    static final String BANNER_LOCATION_PROPERTY = "spring.banner.location";
    static final String BANNER_IMAGE_LOCATION_PROPERTY = "spring.banner.image.location";
    static final String DEFAULT_BANNER_LOCATION = "banner.txt";
    static final String[] IMAGE_EXTENSION = new String[]{"gif", "jpg", "png"};
    private static final Banner DEFAULT_BANNER = new SpringBootBanner(); // 默认的Spring Banner
    private final ResourceLoader resourceLoader;
    private final Banner fallbackBanner;

    // 获取Banner,优先级是环境变量中的Image优先,格式在IMAGE_EXTENSION中,然后才是banner.txt
    private Banner getBanner(Environment environment) {
        SpringApplicationBannerPrinter.Banners banners = new SpringApplicationBannerPrinter.Banners();
        banners.addIfNotNull(this.getImageBanner(environment));
        banners.addIfNotNull(this.getTextBanner(environment));
        if (banners.hasAtLeastOneBanner()) {
            return banners;
        } else {
            return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;
        }
    }

获取图片Banner

private Banner getImageBanner(Environment environment) {
    String location = environment.getProperty("spring.banner.image.location");
    if (StringUtils.hasLength(location)) {
        Resource resource = this.resourceLoader.getResource(location);
        return resource.exists() ? new ImageBanner(resource) : null;
    } else {
        String[] var3 = IMAGE_EXTENSION;
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String ext = var3[var5];
            Resource resource = this.resourceLoader.getResource("banner." + ext);
            if (resource.exists()) {
                return new ImageBanner(resource);
            }
        }

        return null;
    }
}

获取图片的配置等

private void printBanner(Environment environment, PrintStream out) throws IOException {
    int width = (Integer)this.getProperty(environment, "width", Integer.class, 76);
    int height = (Integer)this.getProperty(environment, "height", Integer.class, 0);
    int margin = (Integer)this.getProperty(environment, "margin", Integer.class, 2);
    boolean invert = (Boolean)this.getProperty(environment, "invert", Boolean.class, false); // 图片的属性
    BitDepth bitDepth = this.getBitDepthProperty(environment);
    ImageBanner.PixelMode pixelMode = this.getPixelModeProperty(environment);
    ImageBanner.Frame[] frames = this.readFrames(width, height); // 读取图片的帧

    for(int i = 0; i < frames.length; ++i) {
        if (i > 0) {
            this.resetCursor(frames[i - 1].getImage(), out);
        }

        this.printBanner(frames[i].getImage(), margin, invert, bitDepth, pixelMode, out);
        this.sleep(frames[i].getDelayTime());
    }

}

转换成ascii

private void printBanner(BufferedImage image, int margin, boolean invert, BitDepth bitDepth, ImageBanner.PixelMode pixelMode, PrintStream out) {
    AnsiElement background = invert ? AnsiBackground.BLACK : AnsiBackground.DEFAULT;
    out.print(AnsiOutput.encode(AnsiColor.DEFAULT));
    out.print(AnsiOutput.encode(background));
    out.println();
    out.println();
    AnsiElement lastColor = AnsiColor.DEFAULT;
    AnsiColors colors = new AnsiColors(bitDepth);

    for(int y = 0; y < image.getHeight(); ++y) {
        int x;
        for(x = 0; x < margin; ++x) {
            out.print(" ");
        }

        for(x = 0; x < image.getWidth(); ++x) {
            Color color = new Color(image.getRGB(x, y), false);
            AnsiElement ansiColor = colors.findClosest(color);
            if (ansiColor != lastColor) {
                out.print(AnsiOutput.encode(ansiColor));
                lastColor = ansiColor;
            }

            out.print(this.getAsciiPixel(color, invert, pixelMode)); // // 像素点转换成字符输出
        }

        out.println();
    }

    out.print(AnsiOutput.encode(AnsiColor.DEFAULT));
    out.print(AnsiOutput.encode(AnsiBackground.DEFAULT));
    out.println();
}

  • 39
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值