SpringBoot总结-配置管理和日志管理

原创作者:田超凡(程序员田宝宝)

版权所有,引用请注明原作者,严禁复制转载

整合配置文件

1.在springboot整合配置文件,分成两大类:

application.properties

application.yml

或者是

Bootstrap.properties

Bootstrap.yml

相对于来说yml文件格式写法更加精简,减少配置文件的冗余性。

2.加载顺序:

bootstrap.yml 先加载 application.yml后加载

bootstrap.yml 用于应用程序上下文的引导阶段。

bootstrap.yml 由父Spring ApplicationContext加载。

  1. 区别:

bootstrap.yml 和 application.yml 都可以用来配置参数。

bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。一旦bootStrap.yml 被加载,则内容不会被覆盖。

application.yml 可以用来定义应用级别, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。

分布式配置中心:

Properties在线转换yml格式网址:https://www.toyaml.com/index.html

7.1使用@value注解:

|---------------------------------------------------|
| @Value("${tcf.name}") privateString name; |

7.2@ConfigurationProperties

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| \<!--导入配置文件处理器,配置文件进行绑定就会有提示--\><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> importorg.springframework.boot.context.properties.ConfigurationProperties; importorg.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "tcf") public classTcfUserEntity { privateString addres; privateString age; privateString name; publicString getAddres() { returnaddres; } publicString getAge() { returnage; } publicString getName() { returnname; } public voidsetAddres(String addres) { this.addres= addres; } public voidsetAge(String age) { this.age= age; } public voidsetName(String name) { this.name= name; } @Override publicString toString() { return"TcfUserEntity{"+ "addres='"+ addres+ '\\''+ ", age='"+ age+ '\\''+ ", name='"+ name+ '\\''+ '}'; } } tcf: addres: www.tcf.com age: 22 name: tcf @Autowired privateTcfUserEntity tcfUserEntity; @RequestMapping("/getNameAndAgeAddres") publicString getNameAndAgeAddres() { returntcfUserEntity.toString(); } |

7.3配置文件占位符

在SpringBoot的配置文件中,我们可以使用SpringBoot提供的的一些随机数

{random.value}、{random.int}、${random.long}

{random.int(10)}、{random.int[1024,65536]}

-${app.name:默认值} 来制定找不到属性时的默认值

7.4多环境配置

|---------------------------------------|
| spring: profiles: active: pre |

|-----------------------------------------------------------------------------|
| application-dev.yml:开发环境 application-test.yml:测试环境 application-prd.yml:生产环境 |

7.5、核心配置

复制代码
server:

  port: 8081

  servlet:

    context-path: /tcf
复制代码
复制代码
Springboot 默认的情况下整合tomcat容器
  • 日志管理

8.1.使用logback记录日志

Springboot 已经默认帮你整合好了logback

日志输出文件在当前项目路径log文件夹下

Maven依赖

|---------------------------------------------------------------------------------------------------------|
| <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> |

Logback配置

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <configuration> \<!--本文主要输出日志为控制台日志,系统日志,sql日志,异常日志--\> \<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, --\> \<!--控制台--\><appendername="console"class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d %p (%file:%line\)- %m%n</pattern> <charset>UTF-8</charset> </encoder> </appender> \<!--系统info级别日志--\> \<!--\<File\>日志目录,没有会自动创建--\> \<!--\<rollingPolicy\>日志策略,每天建立一个日志文件,或者当天日志文件超过64MB时--\> \<!--encoder日志编码及输出格式--\><appendername="fileLog"class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>log/file/fileLog.log</File> <rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/file/fileLog.log.%d.%i</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> \<!-- or whenever the file size reaches 64 MB --\><maxFileSize>64 MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <encoder> <pattern> %d %p (%file:%line\)- %m%n </pattern> <charset>UTF-8</charset> \<!--此处设置字符集--\></encoder> </appender> \<!--sql日志--\><appendername="sqlFile"class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>log/sql/sqlFile.log</File> <rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/sql/sqlFile.log.%d.%i</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> \<!-- or whenever the file size reaches 64 MB --\><maxFileSize>64 MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> \<!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。--\><encoder> \<!--用来设置日志的输入格式--\><pattern> %d %p (%file:%line\)- %m%n </pattern> <charset>UTF-8</charset> \<!--此处设置字符集--\></encoder> </appender> \<!--异常日志--\><appendername="errorFile"class="ch.qos.logback.core.rolling.RollingFileAppender"> <File>log/error/errorFile.log</File> <rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>log/error/errorFile.%d.log.%i</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> \<!-- or whenever the file size reaches 64 MB --\><maxFileSize>64 MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> \<!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。--\><encoder> \<!--用来设置日志的输入格式--\><pattern> %d %p (%file:%line\)- %m%n </pattern> <charset>UTF-8</charset> \<!--此处设置字符集--\></encoder> \<!--日志都在这里 过滤出error使用try {}catch (Exception e){}的话异常无法写入日志,可以在catch里用logger.error()方法手动写入日志--\><filterclass="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> \<!--日志输出级别--\> \<!--All\\DEBUG\\INFO\\WARN\\ERROR\\FATAL\\OFF--\> \<!--打印info级别日志,分别在控制台,fileLog,errorFile输出 异常日志在上面由过滤器过滤出ERROR日志打印--\><rootlevel="INFO"> <appender-refref="fileLog"/> <appender-refref="console"/> <appender-refref="errorFile"/> </root> \<!--打印sql至sqlFile文件日志--\><loggername="com.dolphin.mapper"level="DEBUG"additivity="false"> <appender-refref="console"/> <appender-refref="sqlFile"/> </logger> </configuration> |

application

|----------------------------------------------------------------------|
| ###指定读取logback配置文件logging: config: classpath:log/logback.xml |

测试案例

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| @RestController @Slf4j public classMyIndexService { @RequestMapping("/getName") publicString getName(String name, intage) { *log*.info("name:{},age:{}", name, age); returnname; } } |

日志级别

ALL 最低等级的,用于打开所有日志记录。

TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。

DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。

INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。

WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示

ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。

FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。

OFF 最高等级的,用于关闭所有日志记录。

日志目录

8.2.使用log4j记录日志

日志级别

机制:如果一条日志信息的级别大于等于配置文件的级别,就记录。

trace:追踪,就是程序推进一下,可以写个trace输出

debug:调试,一般作为最低级别,trace基本不用。

info:输出重要的信息,使用较多

warn:警告,有些信息不是错误信息,但也要给程序员一些提示。

error:错误信息。用的也很多。

fatal:致命错误。

输出源

CONSOLE(输出到控制台)

FILE(输出到文件)

格式

SimpleLayout:以简单的形式显示

HTMLLayout:以HTML表格显示

PatternLayout:自定义形式显示

8.2.1新建log4j配置文件

文件名称log4j.properties

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| #log4j.rootLogger=CONSOLE,info,error,DEBUGlog4j.rootLogger=DEBUG,error,CONSOLE,infolog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} \[%t\] \[%c\] \[%p\] - %m%nlog4j.logger.info=infolog4j.appender.info=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.info.layout=org.apache.log4j.PatternLayoutlog4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} \[%t\] \[%c\] \[%p\] - %m%nlog4j.appender.info.datePattern='.'yyyy-MM-ddlog4j.appender.info.Threshold= infolog4j.appender.info.append=truelog4j.appender.info.File=E:/code/log/info.loglog4j.logger.error=errorlog4j.appender.error=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.error.layout=org.apache.log4j.PatternLayoutlog4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} \[%t\] \[%c\] \[%p\] - %m%nlog4j.appender.error.datePattern='.'yyyy-MM-ddlog4j.appender.error.Threshold= errorlog4j.appender.error.append=truelog4j.appender.error.File=E:/code/log/error.loglog4j.logger.DEBUG=DEBUGlog4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.DEBUG.layout=org.apache.log4j.PatternLayoutlog4j.appender.DEBUG.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} \[%t\] \[%c\] \[%p\] - %m%nlog4j.appender.DEBUG.datePattern='.'yyyy-MM-ddlog4j.appender.DEBUG.Threshold= DEBUGlog4j.appender.DEBUG.append=truelog4j.appender.DEBUG.File=E:/code/log/dubug.log log4j 代码 private static final Logger logger = LoggerFactory.getLogger(IndexController.class); |

8.2.2.Maven依赖

|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> \<!-- spring boot start --\><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <exclusions> \<!--排除自带的logback依赖--\><exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> \<!-- springboot-log4j --\><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency> |

8.2.3.application

|--------------------------------------------------------------------------------|
| ###指定log4j.properties配置文件路径logging: config: classpath:log4j.properties |

8.3.使用AOP统一处理Web请求日志

基于AOP实现 或者elk

在我们的方法的前后实现拦截 减少打印日志代码的冗余性的问题

8.3.1 POM文件新增依赖

|-----------------------------------------------------------------------------------------------------------------------------------------|
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-++aop++</artifactId> </dependency> |

6.3.2 AOP切面相关配置

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| @Aspect @Component public class WebLogAspect { private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class ); @Pointcut("execution(public * com.tcf.controller.*.*(..))") public void webLog() { } @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 接收到请求,记录请求内容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 记录下请求内容 logger .info("URL : " + request.getRequestURL().toString()); logger .info("HTTP_METHOD : " + request.getMethod()); logger .info("IP : " + request.getRemoteAddr()); Enumeration<String> enu = request.getParameterNames(); while (enu.hasMoreElements()) { String name = (String) enu.nextElement(); logger .info("name:{},value:{}", name, request.getParameter(name)); } } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable { // 处理完请求,返回内容 logger .info("RESPONSE : " + ret); } } |

  • 其他内容

9.1、使用@Scheduled创建定时任务

在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置

@Component

public class ScheduledTasks {

private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

@Scheduled(fixedRate = 5000)

++public++ ++void++ ++reportCurrentTime++ ++() {++

++System.out.println(++ ++"++ ++现在时间:++ ++"++ +++ dateFormat.format(++ ++new++ ++Date()));++

++}++

}

@Scheduled(cron = "0/2 * * * * *") 写法:

quartz/Cron/Crontab表达式在线生成工具-BeJSON.com

Xxl-job

9.2、使用@Async实现异步调用

启动加上@EnableAsync ,需要执行异步方法上加入 @Async

异步应用场景

@Async实际就是多线程封装的

异步线程执行方法有可能会非常消耗cpu的资源,所以大的项目建议使用

Mq异步实现。

整合线程池

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.core.task.TaskExecutor; importorg.springframework.scheduling.annotation.EnableAsync; importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; importjava.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync public classThreadPoolConfig { /\*\* \*每秒需要多少个线程处理? \* tasks/(1/taskcost) \*/private intcorePoolSize= 3; /\*\* \*线程池维护线程的最大数量\* (max(tasks)- queueCapacity)/(1/taskcost) \*/private intmaxPoolSize= 3; /\*\* \*缓存队列\* (coreSizePool/taskcost)\*responsetime \*/private intqueueCapacity= 10; /\*\* \*允许的空闲时间\*默认为60 \*/private intkeepAlive= 100; @Bean publicTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = newThreadPoolTaskExecutor(); //设置核心线程数executor.setCorePoolSize(corePoolSize); //设置最大线程数executor.setMaxPoolSize(maxPoolSize); //设置队列容量executor.setQueueCapacity(queueCapacity); //设置允许的空闲时间(秒)//executor.setKeepAliveSeconds(keepAlive); //设置默认线程名称executor.setThreadNamePrefix("thread-"); //设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy()); //等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true); returnexecutor; } } importlombok.extern.slf4j.Slf4j; importorg.springframework.scheduling.annotation.Async; importorg.springframework.stereotype.Component; @Slf4j @Component public classMemberServiceAsync { @Async("taskExecutor") publicString smsAsync() { *log*.info("\>02\<"); try{ *log*.info("\>正在发送短信..\<"); Thread.sleep(3000); } catch(Exception e) { } *log*.info("\>03\<"); return"短信发送完成!"; } } |

异步注解配置类

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.core.task.TaskExecutor; importorg.springframework.scheduling.annotation.EnableAsync; importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; importjava.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync public classThreadPoolConfig { /\*\* \*每秒需要多少个线程处理? \* tasks/(1/taskcost) \*/private intcorePoolSize= 3; /\*\* \*线程池维护线程的最大数量\* (max(tasks)- queueCapacity)/(1/taskcost) \*/private intmaxPoolSize= 3; /\*\* \*缓存队列\* (coreSizePool/taskcost)\*responsetime \*/private intqueueCapacity= 10; /\*\* \*允许的空闲时间\*默认为60 \*/private intkeepAlive= 100; @Bean publicTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = newThreadPoolTaskExecutor(); //设置核心线程数executor.setCorePoolSize(corePoolSize); //设置最大线程数executor.setMaxPoolSize(maxPoolSize); //设置队列容量executor.setQueueCapacity(queueCapacity); //设置允许的空闲时间(秒)//executor.setKeepAliveSeconds(keepAlive); //设置默认线程名称executor.setThreadNamePrefix("thread-"); //设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy()); //等待所有任务结束后再关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true); returnexecutor; } } |

注意失效问题

注意:如果异步注解写当前自己类,有可能aop会失效,无法拦截注解,最终导致异步注解失效,需要经过代理类调用接口;

所以需要将异步的代码单独抽取成一个类调用接口。

9.3全局捕获异常

@ExceptionHandler 表示拦截异常

  • @ControllerAdvice 是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类
  • @ControllerAdvice 可以指定扫描范围
  • @ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换
    • 返回 String,表示跳到某个 view
    • 返回 modelAndView
    • 返回 model + @ResponseBody

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| @ControllerAdvice public classTcfExceptionHandler { /\*\* \*拦截运行异常出现的错误\~\~\~ \* \* **@return**\*/@ExceptionHandler(RuntimeException.class) @ResponseBody publicMap<Object, Object> exceptionHandler() { Map<Object, Object> map = newHashMap<>(); map.put("error", "500"); map.put("msg", "系统出现错误\~"); returnmap; } } |

9.4发布打包

使用mvn package 打包

使用java --jar 包名

如果报错没有主清单,在pom文件中新增

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <mainClass>com.tcf.App</mainClass> <excludes> <exclude> <groupId>junit</groupId> <artifactId>junit</artifactId> </exclude> <exclude> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> |

本文部分素材转载自蚂蚁课堂

相关推荐
WaaTong16 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484416 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries18 分钟前
Java字节码增强库ByteBuddy
java·后端
佳佳_32 分钟前
Spring Boot 应用启动时打印配置类信息
spring boot·后端
小灰灰__38 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭42 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果1 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林1 小时前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el
许野平2 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono