SpringBoot学习记录(二)
一. SpringBoot日志框架
SpringBoot:底层是Spring框架,Spring框架默认是用JCL(commons-logging);
SpringBoot选用SLF4j和logback;
1.SLF4j使用
(1) 如何在系统中使用SLF4j
以后开发的时候,日志记录方法的调用,不应该直接调用日志的实现类,而是调用日志抽象层里面的方法;给系统里面导入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) 遗留问题
SpringBoot (slf4j+logback);Spring (commons-logging); Hibernate (jboss-logging); Mybatis
统一日志记录,即使是别的框架如何与SpringBoot一起使用slf4j进行输出?
1. 将系统中其他日志框架先排除出去;
2. 用中间包替换原有的日志框架;
3. 导入slf4j其他的实现
(3) SpringBoot日志关系
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter</artifactId> </dependency>
SpringBoot使用它来做日志功能;
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring‐boot‐starter‐logging</artifactId> </dependency>
底层依赖关系
总结:
(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();
(4) 如果我们要引入其他框架一定要把这个框架的默认日志依赖移除掉
例如;Spring框架用的是commons-logging;那么如果要使用Spring就需要吧这个依赖移除
<dependency> <groupId>org.springframework</groupId> <artifactId>spring‐core</artifactId> <exclusions> <exclusion> <groupId>commons‐logging</groupId> <artifactId>commons‐logging</artifactId> </exclusion> </exclusions> </dependency>
SpringBoot能自动适配所有的日志,而且底层使用slf4j+logback的方式记录日志,引入其他框架的时候,只需要把这个框架的依赖的日志框架排除掉即可
2. SpringBoot的日志配置
SpringBoot默认帮我们配置了日志;
@RunWith(SpringRunner.class) @SpringBootTest public class SpringBootLoggingApplicationTests { @Test public void contextLoads() { // System.out.println(); Logger logger = LoggerFactory.getLogger(getClass()); //日志的级别:由低到高 trace < debug < info < warn < error //可以调整输出的日志级别;日志就只会在这个级别以及之后的高级别生效 logger.trace("这是trace日志。。。"); logger.debug("这是debug日志。。。"); //SpringBoot默认级别是从info开始,即root级别; 可以通过配置文件进行调节 logger.info("这是info日志。。。"); logger.warn("这是warn日志。。。"); logger.error("这是error日志。。。"); } }
日志输出格式: %d表示日期时间, %thread表示线程名, %‐5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 %d{yyyy‐MM‐dd HH:mm:ss.SSS} [%thread] %‐5level %logger{50} ‐ %msg%n
SpringBoot修改日志的默认配置
logging.level.com.javaweb=trace #在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用spring.log作为默认文件 logging.path=/spring/log #不指定路径在当前项目下生成springboot.log,也可以指定完胜的路径 #logging.file=springboot.log #logging.file=D:/springboot.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
1. 使用SpringBoot:
(1) 创建SpringBoot应用,选中我们需要的模块
(2) SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来
(3) 自己编写业务代码
自动配置原理:
这个场景SpringBoot帮我们配置了什么?能不能修改?能修改那些配置?能不能扩展?
xxxxAutoConfiguration:帮我们给容器中自动配置组件;
xxxxProperties:配置类来封装配置文件的内容;
2. SpringBoot对静态济源的映射规则
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties { public void addResourceHandlers(ResourceHandlerRegistry registry) { if(!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); if(!registry.hasMappingForPattern("/webjars/**")) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if(!registry.hasMappingForPattern(staticPathPattern)) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } }
(1) 所有/webjars/**,都去classpath:/META-INF/resource/webjars/ 找资源
以jar包的方式引入静态资源
localhost:8080/webjars/jquery/3.3.1/jquery.js
<!-- 引入jquery-webjars 在访问的时候只需要写webjars下面资源的名称即可--> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1</version> </dependency>
(2) /** 访问当前项目的任何资源 (静态资源文件夹)
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
localhost:8080/abc ===>自动去静态资源文件夹寻找abc资源
(3) 欢迎页;静态资源文件夹下的所有index.html页面;被"/**"映射;
(4) 所有的**/facivon.ico都是在静态资源文件下找
3. 模板引擎
JSP,Veloctiy,Freemarker,Thymeleaf;
SpringBoot推荐使用Thymeleaf:
语法更简单,功能更强大;
1. 引入thymeleaf
<!-- 引入模板引擎 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
2. 使用thymeleaf
@ConfigurationProperties( prefix = "spring.thymeleaf" ) public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; //只要我们把html页面放在classpath:/templates/,thymeleaf就能自动渲染 private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML";
只需要在页面中导入thymeleaf的空间,就可以使用thymeleaf的语法
<html lang="en" xmlns:th="http://www.thymeleaf.org">
3. thymeleaf语法规则
(1) th:text:改变当前元素里面的文本内容;
th:任意html属性;来替换原生属性:
<div th:text="${hello}" th:id="${hello}" th:class="${hello}"></div>
(2) 表达式
Simple expressions:(表达式语法) Variable Expressions: ${...}:获取变量值;OGNL; 1)、获取对象的属性、调用方法 2)、使用内置的基本对象: #ctx : the context object. #vars: the context variables. #vars: the context variables. #locale : the context locale. #request : (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object. ${session.foo} 3)、内置的一些工具对象: #execInfo : information about the template being processed. #messages : methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax. #uris : methods for escaping parts of URLs/URIs #conversions : methods for executing the configured conversion service (if any). #dates : methods for java.util.Date objects: formatting, component extraction, etc. #calendars : analogous to #dates , but for java.util.Calendar objects. #numbers : methods for formatting numeric objects. #strings : methods for String objects: contains, startsWith, prepending/appending, etc. #objects : methods for objects in general. #bools : methods for boolean evaluation. #arrays : methods for arrays. #lists : methods for lists. #sets : methods for sets. #maps : methods for maps. #aggregates : methods for creating aggregates on arrays or collections. #ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration). Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样; 补充:配合 th:object="${session.user}: <div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div> Message Expressions: #{...}:获取国际化内容 Link URL Expressions: @{...}:定义URL; @{/order/process(execId=${execId},execType='FAST')} Fragment Expressions: ~{...}:片段引用表达式 <div th:insert="~{commons :: main}">...</div> Literals(字面量) Text literals: 'one text' , 'Another one!' ,… Number literals: 0 , 34 , 3.0 , 12.3 ,… Boolean literals: true , false Null literal: null Literal tokens: one , sometext , main ,… Text operations:(文本操作) String concatenation: + Literal substitutions: |The name is ${name}| Arithmetic operations:(数学运算) Binary operators: + , ‐ , * , / , % Minus sign (unary operator): ‐ Boolean operations:(布尔运算) Binary operators: and , or Boolean negation (unary operator): ! , not Comparisons and equality:(比较运算) Comparators: > , < , >= , <= ( gt , lt , ge , le ) Equality operators: == , != ( eq , ne ) Conditional operators:条件运算(三元运算符) If‐then: (if) ? (then) If‐then‐else: (if) ? (then) : (else) Default: (value) ?: (defaultvalue) Special tokens: No‐Operation: _
例如:
我在业务层java编写:
/** * @program: spring-boot-web * @description: * @author: Yukai Fan * @create: 2018-10-20 09:46 **/ @Controller public class HelloController { //查处一些数据,在页面展示 @RequestMapping("success") public String success(Map<String, Object> map) { map.put("hello","<h1>你好</h1>"); map.put("users", Arrays.asList("zhangsan","lisi","wangwu")); //classpath:/templates/success.html return "success"; } }
根据thymeleaf可以默认从classpath:/templates/下寻找success.html
所以使用tyhmeleaf语法在success.html上:
<body> <h1>成功</h1> <!-- th:text 设置文本内容 --> <div th:text="${hello}"></div> <div th:utext="${hello}"></div> <hr/> <!-- th:each每次遍历都会生成当前标签 3个h4标签--> <h4 th:text="${user}" th:each="user:${users}"></h4> <hr/> <h4> <span th:each="user:${users}"> [[${user}]] </span> </h4> </body>
得到的效果为:
其中审查元素可知,有三个h4标签,3个span标签