SpringBoot自定义banner,如何定制炫酷的banner提升项目B格?

news2024/11/21 2:34:26

文章目录

  • 写在前面
  • 自定义banner
    • 使用banner.txt文件
    • 使用图片
    • 手写一个banner
  • banner参数
    • 在 application.properties 文件中可以配置banner其他属性
    • banner自身参数
  • 源码分析
  • 在线生成banner

写在前面

Springboot启动的时候默认是有一套自己的banner的:
在这里插入图片描述
我们如何自定义这个banner呢?

自定义banner

使用banner.txt文件

在Spring Boot工程的/src/main/resources目录下创建一个banner.txt文件,然后将ASCII字符画复制进去,就能替换默认的banner了。

banner.txt:

 _  _  _  _
(_)(_)(_)(_)
 (_)      (_)_   _  _  _  _     _  _   _  _      _  _  _
 (_)        (_) (_)(_)(_)(_)_  (_)(_)_(_)(_)  _ (_)(_)(_) _
 (_)        (_)(_) _  _  _ (_)(_)   (_)   (_)(_)         (_)
 (_)       _(_)(_)(_)(_)(_)(_)(_)   (_)   (_)(_)         (_)
 (_)_  _  (_)  (_)_  _  _  _  (_)   (_)   (_)(_) _  _  _ (_)
(_)(_)(_)(_)     (_)(_)(_)(_) (_)   (_)   (_)   (_)(_)(_)

启动后的打印效果:
在这里插入图片描述

使用图片

在Spring Boot工程的/src/main/resources目录下,放置一张图片,起名为banner.xxx(其中xxx为gif、jpg、png格式),在项目启动时会自动解析该图片。

banner.jpg:
在这里插入图片描述
启动后的打印效果:
在这里插入图片描述
注意:图片如果太花了,效果可能并不会很好。

手写一个banner

import org.springframework.boot.Banner;
import org.springframework.boot.ansi.AnsiColor;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.boot.ansi.AnsiStyle;
import org.springframework.core.env.Environment;
import java.io.PrintStream;
/** 自定义banner类
 */
public class MyBanner implements Banner {

    private static final String[] BANNER = new String[]{"", "  .   ____          _            __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )", "  '  |____| .__|_| |_|_| |_\\__, | / / / /", " =========|_|==============|___/=/_/_/_/"};

    public MyBanner() {
    }

    @Override
    public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
        String[] bannerArray = BANNER;
        int bannerLength = bannerArray.length;
        for(int i = 0; i < bannerLength; ++i) {
            String line = bannerArray[i];
            out.println(line);
        }
        out.println(AnsiOutput.toString(new Object[]{AnsiColor.GREEN, " :: Spring Boot :: ", AnsiColor.DEFAULT,  AnsiStyle.FAINT}));
        out.println();
    }
}

// 启动类中加入banner即可
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(DemoApplication.class);
        //添加自定义banner
        springApplication.setBanner(new MyBanner());
        springApplication.run(args);
    }

}

banner参数

在 application.properties 文件中可以配置banner其他属性

# 来确定横幅是必须在控制台(console)上打印、发送到配置的记录器(log)还是根本不生成(off)。
spring.main.banner-mode=off
# 在 application.properties 文件中可以配置banner属性
spring.banner.charset=UTF-8
spring.banner.location=classpath:banner.txt
#在 application.properties 文件中可以配置图片的高度、宽度、颜色深度
spring.banner.image.width=100
spring.banner.image.height=20
spring.banner.image.bitdepth=4
# 是否应该为黑暗终端主题反转图像
spring.banner.image.invert=true
# banner图片的位置
spring.banner.image.location=classpath:banner.jpg
# banner右移字符数
spring.banner.image.margin=2

banner自身参数

参数描述
${application.version}MANIFEST.MF中声明的应用程序的版本号
${application.formatted-version}MANIFEST.MF声明的应用程序的版本号并格式化以供显示(用括号括起来并以v为前缀)。比如(v1.0)。
${spring-boot.version}你正在使用的Spring Boot版本
${Ansi.NAME} (or ${AnsiColor.NAME}, ${AnsiBackground.NAME}, ${AnsiStyle.NAME})其中NAME是ANSI转义码的名称
${application.title}在MANIFEST.MF中声明的应用程序的标题。
${AnsiColor.BRIGHT_RED}设置控制台中输出内容的颜色
${…}其他任意配置信息,比如说${server.port}获取端口

源码分析

1、在SpringApplication的run方法中,一直点进去,可以看到这样一段逻辑:

// org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {
	long startTime = System.nanoTime();
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting(bootstrapContext, this.mainApplicationClass);
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		configureIgnoreBeanInfo(environment);
		// 打印banner
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		context.setApplicationStartup(this.applicationStartup);
		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
		}
		listeners.started(context, timeTakenToStartup);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
		listeners.ready(context, timeTakenToReady);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

其中printBanner就是打印banner的代码。

2、printBanner方法

// org.springframework.boot.SpringApplication#printBanner
private Banner printBanner(ConfigurableEnvironment environment) {
	// 判断banner的模式
	if (this.bannerMode == Banner.Mode.OFF) {
		return null;
	}
	ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
			: new DefaultResourceLoader(null);
	SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
	if (this.bannerMode == Mode.LOG) {
		return bannerPrinter.print(environment, this.mainApplicationClass, logger);
	}
	return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

3、控制台print方法

// org.springframework.boot.SpringApplicationBannerPrinter#print(org.springframework.core.env.Environment, java.lang.Class<?>, java.io.PrintStream)
	Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
		// 获取Banner
		Banner banner = getBanner(environment);
		// 打印Banner
		banner.printBanner(environment, sourceClass, out);
		return new PrintedBanner(banner, sourceClass);
	}

4、getBanner

// org.springframework.boot.SpringApplicationBannerPrinter#getBanner
private Banner getBanner(Environment environment) {
    SpringApplicationBannerPrinter.Banners banners = new SpringApplicationBannerPrinter.Banners();
    //先获取image类型的banner
    banners.addIfNotNull(this.getImageBanner(environment));
    //在获取text类型的banner
    banners.addIfNotNull(this.getTextBanner(environment));
    if (banners.hasAtLeastOneBanner()) {
        // 如果至少有一个,则返回
        // Banners 也实现了 Banner 接口,运用了组合模式,实际上可同时打印图片和文本 banner。
        return banners;
    } else {
         // 返回自定义的banner(this.fallbackBanner) 或者 springboot默认的banner(DEFAULT_BANNER)
         // 默认的banner类:SpringBootBanner。
         // 自定义的banner:需要我们仿照SpringBootBanner去自定义一个类
         
         //this.fallbackBanner: 表示自定义的banner,此参数可在springboot启动类的main方法中设置,后续会介绍
         
         //   public static void main(String[] args) {
         //        SpringApplication springApplication = new SpringApplication(Application.class);
         //        springApplication.setBanner(new MyBanner());//自定义的banner
         //        springApplication.run(args);
         //   }
        
          return this.fallbackBanner != null ? this.fallbackBanner : DEFAULT_BANNER;
    }
}

banner的获取方式有两种,先获取image类型的banner,然后获取text类型的banner,如果至少有一个,则执行该banner,如果没有,返回自定义的banner,如果自定义也没有,则返回默认

5、获取banner

//获取Text类型的banner
private Banner getTextBanner(Environment environment) {
    //先从spring.banner.location路径中去取,如果没有,默认banner.txt
    String location = environment.getProperty("spring.banner.location", "banner.txt");
    Resource resource = this.resourceLoader.getResource(location);
    try {
        if (resource.exists() && !resource.getURL().toExternalForm().contains("liquibase-core")) {
            return new ResourceBanner(resource);
        }
    } catch (IOException var5) {}
    return null;
}

//获取image类型的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];
            // static final String[] IMAGE_EXTENSION = { "gif", "jpg", "png" };
            Resource resource = this.resourceLoader.getResource("banner." + ext);
            if (resource.exists()) {
                return new ImageBanner(resource);
            }
        }
        return null;
    }
}

在线生成banner

这里提供了几个在线生成banner的网址:

https://www.bootschool.net/ascii
http://www.network-science.de/ascii/
http://patorjk.com/software/taag/
http://www.degraeve.com/img2txt.php

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/10605.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot+Vue项目大学生网络教学平台的设计与实现

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JDK版…

retrofit网络框架源码解析

App应用程序通过Retrofit 请求网络&#xff0c;实际上是使用Retrofit接口层封装请求参数&#xff0c;之后由OkHttp完成后续的请求操作。在服务器返回数据之后&#xff0c;OkHttp将原始的结果交给Retrofit&#xff0c;Retrofit根据用户的需求对结果进行解析。 一、retrofit框架网…

【Android】扩展BaseExpandableListAdpter实现ExpandableAdapter

今天分享如何扩展BaseExpandableListAdpter实现ExpandableAdapter&#xff0c;很简单的一个例子。 效果示例&#xff1a; 核心是重写BaseExpandableListAdpter&#xff0c;其中BaseExpandableListAdpter则分成了两部分&#xff1a;组和子列表&#xff0c;要注意的是&#xff0…

IDEA远程debug教程

IDEA远程debug教程 当你在本地开发的时候&#xff0c;你需要调试服务器上的程序时&#xff0c;远程调试就显得非常有用。 JAVA 支持调试功能&#xff0c;本身提供了一个简单的调试工具JDB&#xff0c;支持设置断点及线程级的调试同时&#xff0c;不同的JVM通过接口的协议联系…

【Netty源码系列(二)】解读EventLoopGroup

【Netty源码系列文章中源码出自4.1.84.Final版本】 文章目录1. EventLoopGroup接口类2. NioEventLoopGroup创建过程2.1 Executor实现机制2.2 EventLoop对象创建&#xff08;newChild()方法&#xff09;本篇文章主要看一下 EventLoopGroup的源码&#xff0c;了解一下它的创建过程…

二、react的组件-state-props-setState

目标 理解组件和组件的创建、以及能够根据实际场景去划分合理的组件。理解并且能够灵活的应用组件中的state、props。可以使用组件去实现各种前端交互。 知识点 组件的定义&#xff1a;组件能够表示一块视图的结构表现以及逻辑交互&#xff0c;并且可以重复利用。如何创建组件…

【ROS】机械人开发四--ROS常用概念与Launch文件

机械人开发四--ROS常用概念与Launch文件一、ROS常用概念1.1 ROS 的结构1.2 ROS 话题通信1.3 海龟仿真器 仿真 例程二、Launch文件2.1 功能2.2 文件语法2.3 参数服务器2.4 节点分组与重命名标签一、ROS常用概念 1.1 ROS 的结构 ROS 中有一些很重要的基础概念&#xff1a;节点&…

四、ref与DOM-findDomNode-unmountComponentAtNode

目标 理解react的框架使用中&#xff0c;真实dom存在的意义。 使用真实dom和使用虚拟dom的场景。 灵活掌握并能够合理使用操作真实dom的方法。 知识点 react中提供了ref这个属性来获取原生的dom节点&#xff0c;使用方式&#xff1a;在虚拟dom中添加ref属性&#xff0c;即可…

笔试强训(三十七)

目录一、选择题二、编程题2.1 mkdir2.1.1 题目2.1.2 题解2.2 数据库连接池2.2.1 题目2.2.2 题解一、选择题 &#xff08;1&#xff09;下面关于源端口地址和目的端口地址的描述中&#xff0c;正确的是&#xff08;A&#xff09; A.在TCP/UDP传输段中&#xff0c;源端口地址和目…

从内部失衡到外部失衡-中国视角下的宏观经济

从内部失衡到外部失衡 – 潘登同学的宏观经济学笔记 文章目录从内部失衡到外部失衡 -- 潘登同学的宏观经济学笔记国际金融复习全球失衡与储蓄过剩利用拉姆齐模型进行分析数值模拟外部失衡与国际收支危机国际支付工具的作用资产价格泡沫国际收支危机亚洲金融危机中国在亚洲金融危…

智能家居项目开发准备工作

智能家居代码机构——简单工厂模式&#xff1a; 什么是设计模式&#xff1f;百度百科解释&#xff1a; 软件设计模式&#xff08;Design pattern&#xff09;&#xff0c;又称设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设…

好心情精神心理平台:精神疾病怎样才算「治好」?医生和患者眼中的标准不一样!

精神疾病恢复到什么程度才算「治好」了&#xff1f; 很多患者朋友认为&#xff0c;症状消失就代表病好了&#xff0c;就可以停药了。 不是我吓唬你&#xff0c;如果你见症状好转就停药&#xff0c;那病情出现反复是必然结果。 实现疾病症状的消除&#xff0c;这只是达到了「临…

[附源码]java毕业设计驾校管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]java毕业设计基于的疫苗预约系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

详解VSCode中C++工程配置

安装MinGW-w64及环境变量配置 下载MinGW-w64 可以通过官网直接进行下载在线安装包&#xff0c;然后在本地进行安装即可&#xff08;但是基本都会由于网络超时等各种原因终止&#xff09;。 因此这里建议直接下载 MinGW-w64 库解压&#xff0c;然后在系统中指定环境变量即可。…

低资源场景下的命名实体识别

Overview 低资源下的命名实体识别主要分为两个方面&#xff0c;一种是in-domain下的N-way-K-shot类型的少样本&#xff0c;一种是cross-domain下现在资源丰富的sourc-domain上进行微调&#xff0c;之后再迁移到低资源的target-domain进一步微调。 基于prompt的方法在少样本分…

C语言学习-数组(4)

目录 思维导图&#xff1a; 1. 一维数组的创建和初始化 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存…

C# async / await 的使用方法

目录 一、简介 二、异步等待返回结果 三、异步方法的返回类型 四、await foreach 五、Task.Delay 结束 一、简介 await 运算符暂停对其所属的 async 方法的求值&#xff0c;直到其操作数表示的异步操作完成。 异步操作完成后&#xff0c;await 运算符将返回操作的结果&a…

【Xilinx】Zynq\MPSoc\Versal不同速度等级下的ARM主频

【Xilinx】Zynq\MPSoc\Versal不同速度等级下的ARM主频一、Zynq&#xff08;A9&#xff09;二、MPSoC(A53R5)三、Versal(A72R5F)最近有很多人在选型的时候&#xff0c;问到ARM主频的问题&#xff0c;不知道去哪里找这个参数。 授人以鱼不如授人以渔&#xff0c;基本的通用方法是…

【面试题】 TypeScript 前端面试题 由浅到深

给大家推荐一个实用面试题库 1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 基本类型介绍 1.Boolean&#xff0c;Number&#xff0c;String 声明:类型 类型对应变量 let flag:boolean true let …