一、Spring Boot 入门
1、Spring Boot 简介
因而 Spring Boot 应用本质上就是一个基于 Spring 框架的应用,它是 Spring 对“约定优先于配置”理念的最佳实践产物,它能够帮助开发者更快速高效地构建基于 Spring 生态圈的应用。自动配置、起步依赖、Actuator
优点:独立运行,简化配置,自动装配
与 Spring 的区别:
2、微服务
微服务:架构风格(服务微化)一个应用应该是一组小型服务;可以通过 HTTP 的方式进行互通;
单体应用:ALL IN ONE
微服务:每一个功能元素最终都是一个可独立替换和独立升级的软件单元;
详细参照微服务文档
4、Spring Boot HelloWorld
一个功能:浏览器发送 hello 请求,服务器接受请求并处理,响应 Hello World 字符串;
1、创建一个 maven 工程;(jar)
2、导入 spring boot 相关的依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
3、编写一个主程序;启动 Spring Boot 应用
/**
* @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用
*/
@SpringBootApplication
public class HelloWorldMainApplication {
public static void main(String[] args) {
// Spring应用启动起来
SpringApplication.run(HelloWorldMainApplication.class,args);
}
}
4、编写相关的 Controller、Service
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "Hello World!";
}
}
5、运行主程序测试
6、简化部署
<!-- 这个插件,可以将应用打包成一个可执行的jar包;-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
将这个应用打成 jar 包,直接使用 java -jar 的命令进行执行;
主程序类
如何在 SpringBoot 启动时运行一定的代码?
你可以实现接口 ApplicationRunner或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个 run 方法。
如果启动的时候有多个 ApplicationRunner 和 CommandLineRunner,想控制它们的启动顺序,可以实现 org.springframework.core.Ordered接口或者使用 org.springframework.core.annotation.Order注解。
import org.springframework.boot.*
import org.springframework.stereotype.*
@Component
public class MyBean implements CommandLineRunner
{
public void run(String... args){
// Do something...
}
}
二、starter 启动器
自动配置
在 Spring 程序 main 方法中,run 方法刷新容器,扫描@SpringBootApplication注解, @SpringBootApplication 注解为组合注解,其中 @EnableAutoConfiguration 会自动去 maven 中读取每个 starter 中的 MRTA-INF 目录下的 spring.factories 文件,该文件里配置了很多自动配置类,自动配置类会根据条件注解,将所有需要被创建的 bean 加载到 Spring 容器里
如果我们要禁用特定的自动配置,我们可以使用 @EnableAutoConfiguration 注解的 exclude 属性来指示它。
@Conditional 派生注解(Spring 注解版原生的@Conditional 作用)
作用:必须是@Conditional 指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
@Conditional 扩展注解 | 作用(判断是否满足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的 java 版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定 Bean; |
@ConditionalOnMissingBean | 容器中不存在指定 Bean; |
@ConditionalOnExpression | 满足 SpEL 表达式指定 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的 Bean,或者这个 Bean 是首选 Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是 web 环境 |
@ConditionalOnNotWebApplication | 当前不是 web 环境 |
@ConditionalOnJndi | JNDI 存在指定项 |
自动配置类必须在一定的条件下才能生效;我们怎么知道哪些自动配置类生效;
我们可以通过启用 debug=true 属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
启动器
启动器是一套方便的依赖没描述符,它可以放在自己的程序中。你可以一站式的获取你所需要的 Spring 和相关技术,而不需要依赖描述符的通过示例代码搜索和复制黏贴的负载。
常见启动器:
spring-boot-starter-web-services - SOAP Web Services
spring-boot-starter-web - Web 和 RESTful 应用程序
spring-boot-starter-test - 单元测试和集成测试
spring-boot-starter-jdbc - 传统的 JDBC
spring-boot-starter-hateoas - 为服务添加 HATEOAS 功能
spring-boot-starter-security - 使用 SpringSecurity 进行身份验证和授权
spring-boot-starter-data-jpa - 带有 Hibeernate 的 Spring Data JPA
spring-boot-starter-data-rest - 使用 Spring Data REST 公布简单的 REST 服务
自定义启动器
1:新建项目
并建立两个 module,一个为启动器 module,一个为自动配置 module
启动器 Module
作用:只用来做依赖导入
启动器命名规范:
springboot 官方的启动器: spring-boot-starter-XXX 如:spring-boot-starter-jdbc
我们自定义的启动器:XXX-spring-boot-starter 如:sglhello-spring-boot-starter
自动配置 Module
作用:具体实现启动器的业务逻辑
命名规范:
XXX-spring-boot-starter-autoconfigurer
XXX 最好跟启动器的 XXX 保持一致!
2:配置启动器依赖
在启动器 Module 的 pom.xml 文件中添加添加对自动配置模块项目的依赖
3:配置自动配置模块的依赖
这里我们把 dependencies 里面只留一个最基础的 springboot 对 starter 的支持就行了插件的引用,web 的依赖都去掉
4:编写自动配置业务逻辑
当其他 SpringBoot 项目引用启动器,因为启动器依赖于自动配置模块,然后也会扫描自动配置模块的类路径下的/META-INF 目录下的 spring.factories HelloServiceAutoConfiguration 配置类就会被拿到,然后里面的 helloService() 方法返回的 HelloService 对象就会被创建并且被@Bean 注解注册到 ioc 容器里面,这样 springboot 项目 里面就可以 通过@Autowired 注解使用 HelloService 对象了。
在 Config 目录下创建如下三个文件:
HelloProperties.java
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "xqc.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
HelloService.java
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHellXqc(String name){
return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix();
}
}
HelloServiceAutoConfiguration.java
@Configuration//申明这是一个配置类
@ConditionalOnWebApplication//引用启动器的项目是web应用此自动配置模块才生效
@EnableConfigurationProperties(HelloProperties.class)//加载配置对象到容器
public class HelloServiceAutoConfiguration {
@Autowired<br /> HelloProperties helloProperties;<br /> //方法返回结果对象加载到容器<br /> @Bean<br /> public HelloService helloService(){<br /> //新建业务逻辑处理对象,并返回加载到容器中,<br /> // 这样引用启动器的项目就可以 @Autowired HelloService 对象直接使用了<br /> HelloService service = new HelloService();<br /> service.setHelloProperties(helloProperties);<br /> return service;<br /> }<br />}
5:创建扫描配置文件
因为 springboot 在启动的过程中会去扫描项目和所有项目依赖引用的 jar 包 类路径下的 META-IN 目录下的 spring.factories 配置读取所有的拦截器,过滤器,自动配置 XXXAutoConfiguration 等等。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.sgl.mystarter.sglhello.config.HelloServiceAutoConfiguration
二:常用注解
@SpringBootApplication
标在主类上,SpringBoot 就应该运行这个类的 main 方法来启动 SpringBoot 应用;主要组合包含了以下 3 个注解:
(1)@Configuration 注解,实现配置文件的功能;
(2)@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置的功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class});
它也组合了两个注解:
@AutoConfigurationPackage:自动配置包
@Import(AutoConfigurationPackages.Registrar.class):导入一个类到 IOC 容器中,类路径为 meta-inf 的 spring.factories 配置进行导入。
(3)@ComponentScan:Spring 组件扫描。
就配置文件自动装配,装配到依赖的类里面,再以动态代理的方式注入到 Spring 容器里
@RequestMapping 和 @ GetMapping 的区别?
RequestMapping 具有类属性的,可以进行 GET、POST、PUT 或者其他的注释中具有的请求方法。
GetMapping 是 Get 请求方法中的一个特例,它只是 RequestMapping 的一个延伸,目的是为了提高清晰度。
@Component
把普通的 pojo 实例化到 spring 绒球中,相当于配置文件中的,泛指各种组件,就是说类不属于@Controller,@Service 等的时候
@Bean
作用在方法上边,将方法的返回值纳入 spring 管理,告诉 Spring 这个方法将会返回一个对象,这个对象要注册为 Spring 应用上下文中的 bean。
如果想将第三方的类变成组件,你又没有没有源代码,也就没办法使用@Component进行自动配置,这种时候使用@Bean就比较合适了。不过同样的也可以通过 xml 方式来定义。
另外@Bean 注解的方法返回值是对象,可以在方法中为对象设置属性。
@Configuration
标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean 注解标记的方法的实例纳入到 srping 容器中,并且实例名就是方法名。
@Value
@Repository
@ComponentScan
组件扫描。相当于,如果扫描到有@Component @Controller @Service 等这些注解的类,则把
这些类注册为 bean。
@Qualifier
当有多个同一类型的 Bean 时,可以用@Qualifier(“name”)来指定。与@Autowired 配合使用,@Autowired @Qualifie(“userService”) 两个结合起来可以根据名字和类型注入
@Autowired
原理:
当 Spring 容器启动时,注解解析器会被注册到容器中,扫描代码,如果带有@Autowired 注解,则将依赖注入信息封装到 InjectionMetadata 中,创建 Bean 时,会调用各种 BeanPostProcessor 对 bean 初始化,注解解析器 AutowiredAnnotationBeanPostProcessor 负责将相关的依赖注入进来;
@Resource
和@Autowired 注解都是用来实现依赖注入的。只是@AutoWried 按 by type 自动注入,而@Resource 默认按 byName 自动注入。
@Resource 有两个重要属性,分别是 name 和 type
spring 将 name 属性解析为 bean 的名字,而 type 属性则被解析为 bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,如果使用 type 属性则使用 byType 的自动注入策略。如果都没有指定,则通过反射机制使用 byName 自动注入策略。
@Controller
默认是单例的,主要是为了性能,单例不用每次都创建;还有就是不需要多例,只要 controller 中不定义属性,那么单例够用了,如果定义了就会出现竞争访问,则通过注解@Scope(“prototype”)将其设置为多例模式
二、配置文件
1、配置文件
核心配置文件是 application 和 bootstrap 配置文件
application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。
bootstrap 配置文件有以下几个应用场景:
- 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;
- 一些固定的不能被覆盖的属性;
- 一些加密/解密的场景
SpringBoot 使用一个全局的配置文件,配置文件名是固定的;
application.properties
application.yml
配置文件的作用:修改 SpringBoot 自动配置的默认值;SpringBoot 在底层都给我们自动配置好
标记语言:
以前的配置文件;大多都使用的是 xxxx.xml文件;
YAML:以数据为中心,比 json、xml 等更适合做配置文件;
YAML:配置例子
server:
port: 8081
XML:
2、YAML 语法:
1、基本语法
k:(空格)v:表示一对键值对(空格必须有);
以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一个层级的
server:
port: 8081
path: /hello
属性和值也是大小写敏感;
2、值的写法
字面量:普通的值(数字,字符串,布尔)
k: v:字面直接来写;
字符串默认不用加上单引号或者双引号;
“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
name: “zhangsan \n lisi”:输出;zhangsan 换行 lisi
‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi
对象、Map(属性和值)(键值对):
k: v:在下一行来写对象的属性和值的关系;注意缩进
对象还是 k: v 的方式
friends:
lastName: zhangsan
age: 20
行内写法:
friends: { lastName: zhangsan, age: 18 }
数组(List、Set):
用- 值表示数组中的一个元素
pets:
- cat
- dog
- pig
行内写法
pets: [cat, dog, pig]
3、读取配置
配置文件
yml 形式:
person:
lastName: hello
age: 18
boss: false
birth: 2017/12/12
maps: { k1: v1, k2: 12 }
lists:
- lisi
- zhaoliu
dog:
name: 小狗
age: 12
application.properties 形式
info.address=USA
info.company=Spring
info.degree=high
我们可以导入配置文件处理器,以后编写配置就有提示了
properties 配置文件在 idea 中默认 utf-8 可能会乱码,调整
idea配置乱码
@Value
@Component
public class InfoConfig{
@Value(“${info.address}”)
private String address;
}
@ConfigurationProperties
@Component
@ConfigurationProperties(prefix = “info”)
public class InfoConfig{
private String address;
private String company;
private String degree;
}
@Value 获取值和@ConfigurationProperties 获取值比较
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303 数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
配置文件 yml 还是 properties 他们都能获取到值;
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果说,我们专门编写了一个 javaBean 来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
读取指定文件:
@PropertySource+@Value
资源目录下建立 config/db-config.properties:
@Component
@PropertySource(value = { “config/db-config.properties” })
public class DBConfig {
@Value(“${db.username}”)
private String username;
@Value(“${db.password}”)
private String password;
}
@PropertySource+@ConfigurationProperties
@Component
@ConfigurationProperties(prefix = “db”)
@PropertySource(value = { “config/db-config.properties” })
public class DBConfig {
private String username;
private String password;
@PropertySource:加载指定的配置文件;
@ImportResource:导入 Spring 的配置文件,让配置文件里面的内容生效;
Spring Boot 里面没有 Spring 的配置文件,我们自己编写的配置文件,也不能自动识别;
想让 Spring 的配置文件生效,加载进来;@ImportResource标注在一个配置类上
@ImportResource(locations = {“classpath:beans.xml”})
导入Spring的配置文件让其生效
编写 Spring 的配置文件
<?xml version=”1.0” encoding=”UTF-8”?>
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd”>
<bean id="helloService" class="com.xqc.springboot.service.HelloService"></bean><br /></beans><br />SpringBoot 推荐给容器中添加组件的方式;推荐使用全注解的方式<br />1、配置类**@Configuration**------>Spring 配置文件<br />2、使用**@Bean**给容器中添加组件<br />/**<br /> * @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件<br /> *<br /> * 在配置文件中用<bean><bean/>标签添加组件<br /> *<br /> */<br />@Configuration<br />public class MyAppConfig {
//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名<br /> @Bean<br /> public HelloService helloService02(){<br /> System.out.println("配置类@Bean给容器中添加组件了...");<br /> return new HelloService();<br /> }<br />}
4、配置文件占位符
1、随机数
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
2、占位符获取之前配置的值,如果没有可以是用:指定默认值
person.last-name=张三${random.uuid}
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog
person.dog.age=15
5、Profile
1、多 Profile 文件
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml
默认使用 application.properties 的配置;
2、yml 支持多文档块方式
server:
port: 8081
spring:
profiles:
active: prod
—-
server:
port: 8083
spring:
profiles: dev
—-
server:
port: 8084
spring:
profiles: prod #指定属于哪个环境
3、激活指定 profile
1、在配置文件中指定 spring.profiles.active=dev
2、命令行:
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar —spring.profiles.active=dev;
可以直接在测试的时候,配置传入命令行参数
3、虚拟机参数;
-Dspring.profiles.active=dev
6、配置文件加载位置
springboot 启动会扫描以下位置的 application.properties 或者 application.yml 文件作为 Spring boot 的默认配置文件
–file:./config/
–file:./
–classpath:/config/
–classpath:/
优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot 会从这四个位置全部加载主配置文件;互补配置;
==我们还可以通过 spring.config.location 来改变默认的配置文件位置==
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar —spring.config.location=G:/application.properties
7、配置加载顺序
SpringBoot 也可以从以下位置加载配置;
优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
1:命令行参数
所有的配置都可以在命令行上进行指定
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar —server.port=8087 —server.context-path=/abc
多个配置用空格分开; —配置项=值
2:来自 java:comp/env 的 JNDI 属性
3:Java 系统属性(System.getProperties())
4:操作系统环境变量
5:RandomValuePropertySource 配置的 random.属性值
由 jar 包外向 jar 包内进行寻找;优先加载带 profile
6:jar 包外部的 application-{profile}.properties 或 application.yml(带 spring.profile)配置文件
7:jar 包内部的 application-{profile}.properties 或 application.yml(带 spring.profile)配置文件
再来加载不带 profile
8.jar 包外部的 application.properties 或 application.yml(不带 spring.profile)配置文件
*9.jar 包内部的 application.properties 或 application.yml(不带 spring.profile)配置文件
10:@Configuration 注解类上的@PropertySource
11:通过 SpringApplication.setDefaultProperties 指定的默认属性
三、日志
SpringBoot 使用 Slf4j 做日志抽象和 Logback 作为默认日志框架实现
1、日志
日志体系
左边选一个门面(抽象层)、右边来选一个实现;
日志门面
日志门面定义了一组日志的接口规范,它并不提供底层具体的实现逻辑。Apache Commons Logging 和 Slf4j 就属于这一类。
日志实现
日志实现则是日志具体的实现,包括日志级别控制、日志打印格式、日志输出形式(输出到数据库、输出到文件、输出到控制台等)。Log4j、Log4j2、Logback 以及 Java Util Logging 则属于这一类。
SpringBoot:底层是 Spring 框架,Spring 框架默认是用 JCL;‘
==SpringBoot 选用 SLF4j 和 logback;==
2、SLF4j 使用
1、如何在系统中使用 SLF4j https://www.slf4j.org
以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;
给系统里面导入 slf4j 的 jar 和 logback 的实现 jar
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger(HelloWorld.class);
logger.info(“Hello World”);
}
}
图示;
每一个日志的实现框架都有自己的配置文件。使用 slf4j 以后,配置文件还是做成日志实现框架自己本身的配置文件;
2、遗留问题
a(slf4j+logback): Spring(commons-logging)、Hibernate(jboss-logging)、MyBatis、xxxx
统一日志记录,即使是别的框架和我一起统一使用 slf4j 进行输出?
如何让系统中所有的日志都统一到 slf4j;
==1、将系统中其他日志框架先排除出去;==
==2、用中间包来替换原有的日志框架;==
==3、我们导入 slf4j 其他的实现==
3、SpringBoot 日志关系
<dependency><br /> <groupId>org.springframework.boot</groupId><br /> <artifactId>spring-boot-starter</artifactId><br /> </dependency><br />SpringBoot 使用它来做日志功能;<br /> <dependency><br /> <groupId>org.springframework.boot</groupId><br /> <artifactId>spring-boot-starter-logging</artifactId><br /> </dependency><br />底层依赖关系<br />![](https://cdn.nlark.com/yuque/0/2021/png/21566525/1620484618371-15b8fa40-ac98-40a9-bc1e-fbabf7b27c7a.png#align=left&display=inline&height=339&margin=%5Bobject%20Object%5D&originHeight=339&originWidth=871&status=done&style=none&width=871)
总结:
1)、SpringBoot 底层也是使用 slf4j+logback 的方式进行日志记录
2)、SpringBoot 也把其他的日志都替换成了 slf4j;
3)、中间替换包?
@SuppressWarnings(“rawtypes”)
public abstract class LogFactory {
static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J = "http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
static LogFactory logFactory = new SLF4JLogFactory();<br />![](https://cdn.nlark.com/yuque/0/2021/png/21566525/1620484618913-abe2664e-c97d-4eb4-95a7-dbd17f21e7da.png#align=left&display=inline&height=210&margin=%5Bobject%20Object%5D&originHeight=210&originWidth=409&status=done&style=none&width=409)
4)、如果我们要引入其他框架?一定要把这个框架的默认日志依赖移除掉?
Spring 框架用的是 commons-logging;
==SpringBoot 能自动适配所有的日志,而且底层使用 slf4j+logback 的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉即可;==
4、日志使用;
1、默认配置
SpringBoot 默认帮我们配置好了日志;
//记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
//System.out.println();
//日志的级别;<br /> //由低到高 trace<debug<info<warn<error<br /> //可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效<br /> logger.trace("这是trace日志...");<br /> logger.debug("这是debug日志...");<br /> //SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别<br /> logger.info("这是info日志...");<br /> logger.warn("这是warn日志...");<br /> logger.error("这是error日志...");
}<br /> 日志输出格式:<br /> %d表示日期时间,<br /> %thread表示线程名,<br /> %-5level:级别从左显示5个字符宽度<br /> %logger{50} 表示logger名字最长50个字符,否则按照句点分割。<br /> %msg:日志消息,<br /> %n是换行符<br /> --><br /> %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n<br />SpringBoot 修改日志的默认配置<br />logging.level.com.xqc=trace
logging.path=
# 不指定路径在当前项目下生成springboot.log日志
# 可以指定完整的路径;
#logging.file=G:/springboot.log
在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用 spring.log 作为默认文件
logging.path=/spring/log
在控制台输出的日志的格式
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n
logging.file | logging.path | Example | Description |
---|---|---|---|
(none) | (none) | 只在控制台输出 | |
指定文件名 | (none) | my.log | 输出日志到 my.log 文件 |
(none) | 指定目录 | /var/log | 输出到指定目录的 spring.log 文件中 |
2、指定配置
给类路径下放上每个日志框架自己的配置文件即可;SpringBoot 就不使用他默认配置的了
Logging System | Customization |
---|---|
Logback | logback-spring.xml, logback-spring.groovy, logback.xml or logback.groovy |
Log4j2 | log4j2-spring.xml or log4j2.xml |
JDK (Java Util Logging) | logging.properties |
logback.xml:直接就被日志框架识别了;
logback-spring.xml:日志框架就不直接加载日志的配置项,由 SpringBoot 解析日志配置,可以使用 SpringBoot 的高级 Profile 功能
可以指定某段配置只在某个环境下生效
如:
如果使用 logback.xml 作为日志配置文件,还要使用 profile 功能,会有以下错误
no applicable action for [springProfile]
5、切换日志框架
可以按照 slf4j 的日志适配图,进行相关的切换;
slf4j+log4j 的方式;
切换为 log4j2
Thymeleaf 是新一代 Java 模板引擎,Thymeleaf 支持 HTML 原型。它既可以让前端工程师在浏览器中直接打开查看样式,也可以让后端工程师结合真实数据查看显示效果,同时,SpringBoot 提供了 Thymeleaf 自动化配置解决方案,因此在 SpringBoot 中使用 Thymeleaf 非常方便。 ## 使用 ### 1、引入 thymeleaf
2.1.6
切换thymeleaf版本
导入 thymeleaf 的名称空间
使用 thymeleaf 语法;
<!DOCTYPE html>
成功!
## 语法 ### 简单表达式 变量表达式:${……}
消息表达式:#{……}
选择表达式:{……} 链接表达式:@{……}
分段表达式:th:insert 或者 th:replace ~{…}
片段表达式是 Thymeleaf 的特色之一,细粒度可以达到标签级别,这是 JSP 无法做到的。片段表达式拥有三种语法: - ~{ viewName }:表示引入完整页面 - ~{ viewName ::selector}:表示在指定页面寻找片段,其中 selector 可为片段名、jquery 选择器等 - ~{ ::selector}:表示在当前页寻找 ### 字面量 这些是一些可以直接写在表达式中的字符,主要有如下几种: - 文本字面量:’one text’, ‘Another one!’,… - 数字字面量:0, 34, 3.0, 12.3,… - 布尔字面量:true, false - Null 字面量:null - 字面量标记:one, sometext, main,… ### 文本运算 文本可以使用 + 进行拼接。
如果字符串中包含变量,也可以使用另一种简单的方式,叫做字面量置换,用 | 代替 ‘…’ + ‘…’,如下:
比较与相等
表达式里的值可以使用 >, <, >= 和 <= 符号比较。== 和 != 运算符用于检查相等(或者不相等)。注意 XML规定 < 和 > 标签不能用于属性值,所以应当把它们转义为 < 和 >。
如果不想转义,也可以使用别名:gt (>);lt (<);ge (>=);le (<=);not (!)。还有 eq (==), neq/ne (!=)。
<div th:with=”age=(9999/99+99-1)”>
### 内置对象 基本内置对象: - #ctx:上下文对象。 - #vars: 上下文变量。 - #locale:上下文区域设置。 - #request:(仅在 Web 上下文中)HttpServletRequest 对象。 - #response:(仅在 Web 上下文中)HttpServletResponse 对象。 - #session:(仅在 Web 上下文中)HttpSession 对象。 - #servletContext:(仅在 Web 上下文中)ServletContext 对象。 ### 遍历 数组/集合/Map/Enumeration/Iterator 等的遍历也算是一个非常常见的需求,Thymeleaf 中通过 th:each 来实现遍历,像下面这样:
当然,Thymeleaf 不仅仅能在 Spring Boot 中使用,也可以使用在其他地方,只不过 Spring Boot 针对 Thymeleaf 提供了一整套的自动化配置方案,这一套配置类的属性在 org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties 中 # 五:Web 开发 ## 2、静态资源 在源文件夹下,创建一个名为 static 的文件夹。然后,你可以把你的静态的内容放在这里面。
@ConfigurationProperties(prefix = “spring.resources”, ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware {
//可以设置和静态资源有关的参数,缓存时间等
WebMvcAuotConfiguration:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug(“Default resource handling disabled”);
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern(“/webjars/“)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(“/webjars/“)
.addResourceLocations(
“classpath:/META-INF/resources/webjars/“)
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
//静态资源文件夹映射
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
} //配置欢迎页映射
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
} //配置喜欢的图标
@Configuration
@ConditionalOnProperty(value = “spring.mvc.favicon.enabled”, matchIfMissing = true)
public static class FaviconConfiguration { private final ResourceProperties resourceProperties; public FaviconConfiguration(ResourceProperties resourceProperties) {
this.resourceProperties = resourceProperties;
} @Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHESTPRECEDENCE + 1);
//所有 /favicon.ico
mapping.setUrlMap(Collections.singletonMap(“/favicon.ico”,
faviconRequestHandler()));
return mapping;
} @Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler
.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
} }
==1)、所有 /webjars/ ,都去 classpath:/META-INF/resources/webjars/ 找资源;==
webjars:以 jar 包的方式引入静态资源;
http://www.webjars.org/
localhost:8080/webjars/jquery/3.3.1/jquery.js
在访问的时候只需要写webjars下面资源的名称即可
==2)、”/“ 访问当前项目的任何资源,都去(静态资源的文件夹)找映射==
“classpath:/META-INF/resources/“,
“classpath:/resources/“,
“classpath:/static/“,
“classpath:/public/“
“/“:当前项目的根路径
localhost:8080/abc === 去静态资源文件夹里面找 abc
==3)、欢迎页; 静态资源文件夹下的所有 index.html 页面;被”/“映射;==
localhost:8080/ 找 index 页面
==4)、所有的 /favicon.ico 都是在静态资源文件下找;== ## 3:MVC 结构框架 SpringBoot 提供了 SpringMVC 的自动配置。
(1)自动配置了 ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))我们可以自己给容器添加一个视图解析器,会自动组合进来。
(2)自动注册了 Converter(转换器,类型转换), GenericConverter(格式化器), Formatter beans.
==自己添加的格式化器转换器,我们只需要放在容器中即可==
(3)自动配置了HttpMessageConverters
SpringMVC 用来转换 Http 请求和响应的;User 转换成 Json;HttpMessageConverters 是从容器中确定;获取所有的 HttpMessageConverter;
==自己给容器中添加 HttpMessageConverter,只需要将自己的组件注册容器中(@Bean,@Component)== #### 如何修改 SpringBoot 的默认配置 模式:
1)、SpringBoot 在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
2)、在 SpringBoot 中会有非常多的 xxxConfigurer 帮助我们进行扩展配置
3)、在 SpringBoot 中会有很多的 xxxCustomizer 帮助我们进行定制配置 #### 扩展 SpringMVC ==编写一个配置类(@Configuration),是 WebMvcConfigurerAdapter 类型;不能标注@EnableWebMvc==;
既保留了所有的自动配置,也能用我们扩展的配置;
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /xqc 请求来到 success
registry.addViewController(“/xqc”).setViewName(“success”);
}
}
原理:
1)、WebMvcAutoConfiguration 是 SpringMVC 的自动配置类
2)、在做其他自动配置时会导入;
@Import(EnableWebMvcConfiguration.class)
3)、容器中所有的 WebMvcConfigurer 都会一起起作用;
4)、我们的配置类也会被调用; #### 全面接管 SpringMVC SpringBoot 对 SpringMVC 的自动配置不需要了,所有都是我们自己配置;所有的 SpringMVC 的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc 即可; ## 6、RestfulCRUD ### 1)、默认访问首页 //使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
//@EnableWebMvc 不要接管SpringMVC
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /xqc 请求来到 success
registry.addViewController(“/xqc”).setViewName(“success”);
} //所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(“/“).setViewName(“login”);
registry.addViewController(“/index.html”).setViewName(“login”);
}
};
return adapter;
}
} ### 2)、国际化 1)、编写国际化配置文件;
2)、使用 ResourceBundleMessageSource 管理国际化资源文件
3)、在页面使用 fmt:message 取出国际化内容
步骤:
1)、编写国际化配置文件,抽取页面需要显示的国际化消息
2)、SpringBoot 自动配置好了管理国际化资源文件的组件;
@ConfigurationProperties(prefix = “spring.messages”)
public class MessageSourceAutoConfiguration { /
Comma-separated list of basenames (essentially a fully-qualified classpath
location), each following the ResourceBundle convention with relaxed support for
slash based locations. If it doesn’t contain a package qualifier (such as
“org.mypackage”), it will be resolved from the classpath root.
*/
private String basename = “messages”;
//我们的配置文件可以直接放在类路径下叫messages.properties; @Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(this.basename)) {
//设置国际化资源文件的基础名(去掉语言国家代码的)
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename)));
}
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name());
}
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource;
}
3)、去页面获取国际化的值;
<!DOCTYPE html>
name=”viewport”
content=”width=device-width, initial-scale=1, shrink-to-fit=no”
/>
href=”asserts/css/bootstrap.min.css”
th:href=”@{/webjars/bootstrap/4.0.0/css/bootstrap.css}”
rel=”stylesheet”
/>
href=”asserts/css/signin.css”
th:href=”@{/asserts/css/signin.css}”
rel=”stylesheet”
/>
可以在连接上携带区域信息
/
public class MyLocaleResolver implements LocaleResolver { @Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter(“l”);
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(l)){
String[] split = l.split(““);
locale = new Locale(split[0],split[1]);
}
return locale;
} @Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { }
} @Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
} ### 3)、登陆 开发期间模板引擎页面修改以后,要实时生效
1)、禁用模板引擎的缓存
# 禁用缓存
spring.thymeleaf.cache=false
2)、页面修改完成以后 ctrl+f9:重新编译;
登陆错误消息的显示
### 4)、拦截器进行登陆检查 拦截器
/
登陆检查,
/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute(“loginUser”);
if(user == null){
//未登陆,返回登陆页面
request.setAttribute(“msg”,”没有权限请先登陆”);
request.getRequestDispatcher(“/index.html”).forward(request,response);
return false;
}else{
//已登陆,放行请求
return true;
} } @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
}
注册拦截器
//所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController(“/“).setViewName(“login”);
registry.addViewController(“/index.html”).setViewName(“login”);
registry.addViewController(“/main.html”).setViewName(“dashboard”);
} //注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//静态资源; .css , .js
//SpringBoot已经做好了静态资源映射
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns(“/“)
.excludePathPatterns(“/index.html”,”/“,”/user/login”);
}
};
return adapter;
} ### 5)、CRUD-员工列表 实验要求:
1)、RestfulCRUD:CRUD 满足 Rest 风格;
URI: /资源名称/资源标识 HTTP 请求方式区分对资源 CRUD 操作 | | 普通 CRUD(uri 来区分操作) | RestfulCRUD | | —- | —- | —- | | 查询 | getEmp | emp—-GET | | 添加 | addEmp?xxx | emp—-POST | | 修改 | updateEmp?id=xxx&xxx=xx | emp/{id}—-PUT | | 删除 | deleteEmp?id=1 | emp/{id}—-DELETE | 2)、实验的请求架构; | 实验功能 | 请求 URI | 请求方式 | | —- | —- | —- | | 查询所有员工 | emps | GET | | 查询某个员工(来到修改页面) | emp/1 | GET | | 来到添加页面 | emp | GET | | 添加员工 | emp | POST | | 来到修改页面(查出员工进行信息回显) | emp/1 | GET | | 修改员工 | emp | PUT | | 删除员工 | emp/1 | DELETE | 3)、员工列表: #### thymeleaf 公共页面元素抽取 1、抽取公共片段
~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名 3、默认效果:
insert的公共片段在div标签中 如果使用th:insert等属性进行引入,可以不用写~{}:
行内写法可以加上:[[~{}]];[(~{})];
三种引入公共片段的 th 属性:
th:insert:将公共片段整个插入到声明引入的元素中
th:replace:将声明引入的元素替换为公共片段
th:include:将被引入的片段的内容包含进这个标签中
引入方式
效果
引入片段的时候传入参数:
### 6)、CRUD-员工添加 添加页面
提交的数据格式不对:生日:日期;
2017-12-12;2017/12/12;2017.12.12;
日期的格式化;SpringMVC 将页面提交的值需要转换为指定的类型;
2017-12-12—-Date; 类型转换,格式化;
默认日期是按照/的方式; ### 7)、CRUD-员工修改 修改添加二合一表单