需要pdf文件下载:(回复获取)
一、Spring Boot入门
1、Spring Boot简介
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
2、微服务
微服务:架构风格(服务微化)
一个应用应该是一组小型服务,可以通过HTTP的方式进行互通
单体应用:ALL IN ONE
微服务:每个功能元素最终都是一个可以独立替换和升级的软件单元
3、环境准备
环境约束
- jdk1.8
- maven 3.x :maven3.3以上
- IDEA2017
- SpringBoot 1.5.9RELEASE
1、MAVEN设置
♾️ xml 代码:<!-- 配置JDK版本 -->
<profile>
<id>jdk18</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
<!-- 当 nexus-aliyun 下不了的包,或许这个镜像能下,
才开放它,这个实在太慢,而且要把它放在首位,即 nexus-aliyun 之前,做过测试。
所以它的用途只有那么一瞬间,就是或许它能下载,可以通过 url 去查找确定一下
-->
<!-- <mirror>
<id>spring-libs-milestone</id>
<mirrorOf>central</mirrorOf>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone</url>
</mirror> -->
<!-- nexus-aliyun 首选,放第一位,有不能下载的包,再去做其他镜像的选择 -->
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
<!-- 备选镜像,也是可以通过 url 去查找确定一下,
该镜像是否含有你想要的包,它比 spring-libs-milestone 快 -->
<mirror>
<id>central-repository</id>
<mirrorOf>*</mirrorOf>
typor<name>Central Repository</name>
<url>http://central.maven.org/maven2/</url>
</mirror>
2、IDEA设置
配置IDEA的Maven,指定Setting的Maven目录和MAVEN的setting.xml文件
快捷键:
Ctrl+D 复制一行
Ctrl+Y 删除一行
Ctrl+P 参数提示
Ctrl+Alt+V 自动补齐方法
Ctrl+N 查找类方法
Alt+Ins 构造器、getter/setter toString
Ctrl+O 重载方法提示
Alt+Enter 提示导入类etc
Shift+F6 :文件重命名
4、Spring Boot的Hello World
1、创建一个Maven工程
2、导入Spring Boot的相关依赖
♾️ xml 代码:<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3、编写个主程序
♾️ java 代码:@SpringBootApplication
public class SpringBoot01HelloQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloQuickApplication.class, args);
}
}
4、编写相应的Controller和Service
♾️ java 代码:@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello(){
return "hello world";
}
}
5、运行主程序测试
访问 localhost:8080/hello
6、简化部署
在pom.xml文件中,导入build插件
♾️ xml 代码:<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
5、HelloWorld深度理解
1.POM.xml文件
1、父项目
♾️ xml 代码:<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
这个父项目spring-boot-starter-parent又依赖一个父项目
♾️ xml 代码:<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
下面有个属性,定义了对应的版本号
♾️ xml 代码:<properties>
<activemq.version>5.15.3</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
<appengine-sdk.version>1.9.63</appengine-sdk.version>
<artemis.version>2.4.0</artemis.version>
<aspectj.version>1.8.13</aspectj.version>
<assertj.version>3.9.1</assertj.version>
<atomikos.version>4.0.6</atomikos.version>
<bitronix.version>2.1.4</bitronix.version>
<build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>
。。。。。。。
Spring Boot的版本仲裁中心 会自动导入对应的版本,不需要我们自己导入依赖,没有dependencies里面管理的依赖自己声明
2、启动器
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web:帮我们导入web模块正常运行所依赖的组件
spring boot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目里引入这些starter相关场景的所有依赖都会被导入进来,要用什么功能就导入什么场景的启动器。
2、主程序入口
♾️ java 代码:@SpringBootApplication
public class SpringBoot01HelloQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot01HelloQuickApplication.class, args);
}
}
@SpringBootApplication: 说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动应用
进入SpringBootApplication注解
♾️ java 代码:@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
@SpringBootConfiguration:SpringBoot的配置类: 标准在某个类上,表示这是一个SpringBoot的配置类
@Configuration:配置类上,来标注这个注解;
配置类 ---- 配置文件,也是容器中的一个组件(@Component)
@EnableAutoConfiguration:开启自动配置功能
以前需要自动配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动
配置功能;这样自动配置才能生效。
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自动配置包
@Import({Registrar.class}):底层注解,给容器导入组件;
将主配置类(@SpringBootApplication标注的类)的所在包及下面所有的子包里面的所有组件扫描到Spring容器;
@Import({AutoConfigurationImportSelector.class}):
给容器导入组件?
AutoConfigurationImportSelector:导入组件选择器
将所有需要导入的组件以及全类名的方式返回;这些组件将以字符串数组 String[] 添加到容器中;
会给容器非常多的自动配置类,(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置
好这些组件。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations =
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),
this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META‐INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),
this.getBeanClassLoader());
Spring Boot在启动的时候从类路径下的META-INF/spring.factorys中获取的EnableAutoConfiguration指定的值;
将这些值作为自动配置类导入到容器中,自动配置就生效了。
J2EE的整体解决方案
org\springframework\boot\spring-boot-autoconfigure\2.0.1.RELEASE\spring-boot-autoconfigure-2.0.1.RELEASE.jar
6、使用Spring Initializer创建一个快速向导
1.IDE支持使用Spring Initializer
自己选择需要的组件:例如web
默认生成的SpringBoot项目
- 主程序已经生成好了,我们只需要完成我们的逻辑
resources文件夹目录结构
- static:保存所有的静态文件;js css images
templates:保存所有的模板页面;(Spring Boot默认jar包使用嵌入式的Tomcat,默认不支持JSP);可
以使用模板引擎(freemarker.thymeleaf);
- application.properties:Spring Boot的默认配置,例如 server.port=9000
二、配置文件
1、配置文件
Spring Boot使用全局配置文件,配置文件名是固定的;
- application.properties
- application.yml
配置文件作用:修改Spring Boot在底层封装好的默认值;
YAML(YAML AIN'T Markup Language)
是一个标记语言
又不是一个标记语言
标记语言:
以前的配置文件;大多数使用的是 xxx.xml文件;
以数据为中心,比json、xml等更适合做配置文件
YAML:配置例子
♾️ yaml 代码:server:
port: 9000
XML:
♾️ xml 代码:<server>
<port>9000</port>
</server>
2、YAML语法
1、基本语法
k:(空格)v:表示一堆键值对(空格必须有);
以空格的缩进来控制层级关系;只要是左对齐的一列数据,都是同一层级的
♾️ yaml 代码:server:
port: 9000
path: /hello
属性和值也是大小写敏感
2、值的写法
字面量:普通的值(数字,字符串,布尔)
k: v:字面直接来写;
字符串默认不用加上单引号或者双引号
"":双引号 不会转义字符串里的特殊字符;特殊字符会作为本身想要表示的意思
name:"zhangsan\n lisi"
输出:zhangsan换行 lisi
'':单引号 会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name:'zhangsan\n lisi'
输出:zhangsan\n lisi
对象、Map(属性和值)键值对
k :v :在下一行来写对象的属性和值的关系;注意空格控制缩进
对象还是k:v的方式
♾️ yaml 代码:frends:
lastName: zhangsan
age: 20
行内写法
♾️ yaml 代码:friends: {lastName: zhangsan,age: 18}
数组(List、Set):
用-表示数组中的一个元素
pets:
‐ cat
‐ dog
‐ pig
行内写法
♾️ yaml 代码:pets: [cat,dog,pig]
组合变量
多个组合到一起
3、配置文件值注入
1、@ConfigurationProperties
1、application.yml 配置文件
♾️ yaml 代码:person:
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
- lisi
- zhaoliu
dog:
name: wangwang
age: 2
last-name: wanghuahua
application.properties
配置文件(二选一)
idea配置文件utf-8
properties 默认GBK
person.age=12
person.boss=false
person.last-name=张三
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=wanghuahu
person.dog.age=15
所以中文输出乱码,改进settings-->file encoding -->[property-->utf-8 ,勾选转成ascii]
javaBean
♾️ java 代码:/**
* 将配置文件的配置每个属性的值,映射到组件中
* @ConfigurationProperties:告诉SpringBoot将文本的所有属性和配置文件中的相关配置进行绑定;
* prefix = "person" 配置文件爱你的那个属性进行一一映射
* *
只有这个组件是容器中的组件,才能提供到容器中
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
导入配置文件处理器,以后编写配置就有提示了
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐configuration‐processor</artifactId>
<optional>true</optional>
</dependency>
2、@Value注解
更改javaBean中的注解
♾️ java 代码:@Component
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}从环境变量/#{spEL}"></property>
* </bean>
*/
@Value("${person.last-name}")
private String lastName;
@Value("#{11*2}")
private Integer age;
@Value("true")
private Boolean boss;
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件属性 | 单个指定 |
松散绑定(语法) | 支持 | 不支持 |
spEL | 不支持 | 支持 |
JSR303校验 | 支持 | 不支持 |
复杂类型 | 支持 | 不支持 |
松散语法:javaBean中last-name(或者lastName) -->application.properties中的last-name;
spEL语法:#{11*2}
JSR303:@Value会直接忽略,校验规则
JSR303校验:
♾️ java 代码:@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
@Email
private String lastName;
复杂类型栗子:
♾️ java 代码:@Component
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}从环境变量/#{spEL}"></property>
* </bean>
*/
private String lastName;
private Integer age;
private Boolean boss;
// @Value("${person.maps}")
private Map<String,Object> maps;
以上会报错,不支持复杂类型
使用场景分析
如果说,我们只是在某个业务逻辑中获取一下配置文件的某一项值,使用@Value;
如果专门编写了一个javaBean和配置文件进行映射,我们直接使用@ConfigurationProperties
举栗子:
1、编写新的Controller文件
♾️ java 代码:@RestController
public class HelloController {
@Value("${person.last-name}")
private String name;
@RequestMapping("/hello")
public String sayHello(){
return "Hello"+ name;
}
}
2、配置文件
♾️ properties 代码:person.age=12
person.boss=false
person.last-name=李四
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=wanghuahu
person.dog.age=15
3、测试运行
访问 localhost:9000/hello
结果为Hello 李四
3、其他注解
@PropertySource
作用:加载指定的properties配置文件
1、新建一个person.properties文件
♾️ properties 代码:person.age=12
person.boss=false
person.last-name=李四
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=wanghuahu
person.dog.age=15
2、在javaBean中加入@PropertySource注解
♾️ java 代码:@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
@ImportResource
作用:导入Spring配置文件,并且让这个配置文件生效
1、新建一个Spring的配置文件,bean.xml
♾️ xml 代码:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="HelloService" class="com.wdjr.springboot.service.HelloService"></bean>
</beans>
2、编写测试类,检查容器是否加载Spring配置文件写的bean
♾️ java 代码:@Autowired
ApplicationContext ioc;
@Test
public void testHelloService(){
boolean b = ioc.containsBean("HelloService");
System.out.println(b);
}
import org.springframework.context.ApplicationContext;
3、运行检测
结果为false,没有加载配置的内容
4、使用@ImportResource注解
将@ImportResource标注在主配置类上
♾️ java 代码:@ImportResource(locations={"classpath:beans.xml"})
@SpringBootApplication
public class SpringBoot02ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot02ConfigApplication.class, args);
}
}
5、再次运行检测
结果为true
缺点:每次指定xml文件太麻烦
SpringBoot推荐给容器添加组件的方式:
1、配置类=====Spring的xml配置文件(old)
2、全注解方式@Configuration+@Bean(new)
/**
* @Configuration:指明当前类是一个配置类;就是来代替之前的Spring配置文件
*
* 在配置文件中用<bean></bean>标签添加组件
*/
@Configuration
public class MyAppConfig {
//将方法的返回值添加到容器中;容器这个组件id就是方法名
@Bean
public HelloService helloService01(){
System.out.println("配置类给容器添加了HelloService组件");
return new HelloService();
}
}
♾️ java 代码:@Autowired
ApplicationContext ioc;
@Test
public void testHelloService(){
boolean b = ioc.containsBean("helloService01");
System.out.println(b);
}
容器这个组件id就是方法名
4、配置文件占位符
1、随机数
♾️ properties 代码:${random.value} 、${random.int}、${random.long}
${random.int(10)}、${random.int[100,200]}
2、获取配置值
♾️ properties 代码:person.age=${random.int}
person.boss=false
person.last-name=张三${random.uuid}
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=${person.last-name}'s wanghuahu
person.dog.age=15
存在以下两种情况
没有声明person.last-name
会报错,新声明的需要加默认值
person.age=${random.int}
person.boss=false
person.last-name=张三${random.uuid}
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=${person.hello:hello}'s wanghuahu
person.dog.age=15
结果:输出hello's wanghuahua
5、Profile
1、多Profile文件
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml
- application.properties
- application-dev.properties
- application-prod.properties
默认使用application.properties
application.properties配置文件指定
♾️ properties 代码:spring.profiles.active=dev
2、YAML文档块
♾️ yaml 代码:server:
port: 8081
spring:
profiles:
active: dev
---
server:
port: 9000
spring:
profiles: dev
---
server:
port: 80
spring:
profiles: prod
3、激活指定profile
1、在配置文件中激活
2、命令行:
--spring.profiles.active=dev
优先级大于配置文件
打包 成jar后
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
虚拟机参数
-Dspring.profiles.active=dev
6、加载配置文件位置
SpringBoot启动扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
- file:./config/
- file./
- classpath:/config/
- classpath:/
优先级从高到低顺序,高优先级会覆盖低优先级的相同配置;互补配置
也可以通过spring.config.location来改变默认配置
♾️ text 代码:server.servlet.context-path=/boot03
注:spring boot1x 是server.context.path=/boot02
还可以通过spring.config.location来改变配置文件的位置
项目打包好了以后,可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认的配置文件会共同起作用,互补配置
java -jar spring-boot-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=E:/work/application.properties
运维比较有用,从外部加载,不用修改别的文件
7.引入外部配置
SpringBoot也可以从以下位置加载配置;优先级从高到低;高优先级覆盖低优先级,可以互补
命令行参数
java -jar spring-boot-config-02-0.0.1-SNAPSHOT.jar --server.port=9005 --server.context-path=/abc
中间一个空格
- 来自java:comp/env的JNDI属性
- java系统属性(System.getProperties())
- 操作系统环境变量
- RandomValuePropertySource配置的random.*属性值
优先加载profile, 由jar包外到jar包内
- jar包外部的application-{profile}.properties或application.yml(带Spring.profile)配置文件
- jar包内部的application-{profile}.properties或application.yml(带Spring.profile)配置文件
- jar包外部的application.properties或application.yml(带Spring.profile)配置文件
- jar包内部的application.properties或application.yml(不带spring.profile)配置文件
- @Configuration注解类的@PropertySource
- 通过SpringApplication.setDefaultProperties指定的默认属性
8、自动配置
配置文件到底怎么写?
自动配置原理很关键
1、自动配置原理
1)、SpringBoot启动的时候加载主配置类,开启自动配置功能,@EnableAutoConfiguration
2)、@EnableAutoConfiguration 作用:
- 利用AutoConfigurationImportSelector给容器中导入一些组件?
- 可以查看selectImports()方法的内容
- 获取候选的配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
- 扫描类路径下的
SpringFactoriesLoader.loadFactoryNames()
扫描所有jar包类路径下的 MATA-INF/spring.factories
把扫描到的这些文件的内容包装成properties对象
从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加到容器中
将类路径下 MATE-INF/spring.factories里面配置的所有的EnableAutoConfiguration的值加入到了容器中;
3)、每一个自动配置类进行自动配置功能;
4)、以HttpEncodingAutoConfiguration 为例
♾️ java 代码:@Configuration //表示是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties({HttpEncodingProperties.class})//启动指定类的Configurationproperties功能;将配置文件中的值和HttpEncodingProperties绑定起来了;并把HttpEncodingProperties加入ioc容器中
@ConditionalOnWebApplication//根据不同的条件,进行判断,如果满足条件,整个配置类里面的配置就会失效,判断是否为web应用;
(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类,解决乱码的过滤器
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//判断配置文件是否存在某个配置 spring.http.encoding,matchIfMissing = true如果不存在也是成立,即使不配置也生效
public class HttpEncodingAutoConfiguration {
//给容器添加组件,这个组件的值需要从properties属性中获取
private final HttpEncodingProperties properties;
//只有一个有参数构造器情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpEncodingProperties.Type.RESPONSE));
return filter;
}
5)、所有在配置文件中能配置的属性都是在xxxProperties类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类
♾️ java 代码:@ConfigurationProperties(prefix = "spring.http.encoding")//从配置文件中的值进行绑定和bean属性进行绑定
public class HttpEncodingProperties {
根据当前不同条件判断,决定这个配置类是否生效?
一旦这个配置类生效;这个配置类会给容器添加各种组件;这些组件的属性是从对应的properties中获取的,这些类里面的每个属性又是和配置文件绑定的
2、所有的自动配置组件
每一个xxxAutoConfiguration这样的类都是容器中的一个组件,都加入到容器中;
作用:用他们做自动配置
♾️ properties 代码:# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
3、精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、我们看我们需要的功能有没有SpringBoot默认写好的默认配置类;
3)、如果有在看这个自动配置类中配置了哪些组件;(只要我们要用的组件有,我们需要再来配置)
4)、给容器中自动配置添加组件的时候,会从properties类中获取属性。我们就可以在配置文件中指定这些属性的值
xxxAutoConfiguration:自动配置类;
给容器中添加组件
xxxProperties:封装配置文件中的属性;
跟之前的Person类一样,配置文件中值加入bean中
4、细节
1、@Conditional派生注解
利用Spring注解版原生的@Conditional作用
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
@Conditional派生注解 | 作用(判断是否满足当前指定条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 满足spEL表达式 |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissClass | 系统中没有指定的类 |
@ConditionalOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定的资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
@ConditionalOnNotWebApplication | 当前不是web环境 |
@ConditionalOnJndi | JNDI存在指定项 |
2、自动配置报告
自动配置类必须在一定条件下生效
我们可以通过启用debug=true属性,配置文件,打印自动配合报告,这样就可以知道自动配置类生效
♾️ properties 代码:debug=true
自动配置报告
♾️ java 代码:============================
CONDITIONS EVALUATION REPORT
============================
Positive matches:(启动的,匹配成功的)
-----------------
CodecsAutoConfiguration matched:
- @ConditionalOnClass found required class 'org.springframework.http.codec.CodecConfigurer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
......
Negative matches:(没有启动的,没有匹配成功的)
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
.....
三、日志
Spring Boot2对日志有更改
1、日志框架
小张:开发一个大型系统;
1、System.out.println("");将关键数据打印在控制台;去掉?卸载文件中
2、框架记录系统的一些运行信息;日志框架zhanglog.jar
3、高大上功能,异步模式?自动归档?xxx?zhanglog-good.jar?
4、将以前的框架卸下来?换上新的框架,重新修改之前的相关API;zhanglog-perfect.jar;
5、JDBC--数据库驱动;
写了一个统一的接口层;日志门面(日志的一个抽象层);logging-abstract.jar;
给项目中导入具体的日志实现就行;我们之前的日志框架都是实现的抽象层;
市面上的日志框架
日志抽象层 | 日志实现 |
---|---|
Log4j | |
左边的抽象,右边的实现
SLF4J -- Logback
Spring Boot:底层是Spring框架,Spring默认框架是JCL;
SpringBoot选用SLF4J和logback
2、SLF4J使用
1、如何在系统中使用SLF4j
以后开发的时候,日志记录方法的调用,不应该来直接调用日志的实现类,而是调用日志抽象层里面的方法;
应该给系统里面导入slf4j的jar包和logback的实现jar
♾️ java 代码: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
统一日志框架,即使是别的框架和我一起统一使用slf4j进行输出;
核心:
1、将系统中其他日志框架排除出去;
2、用中间包来替换原有的日志框架/
3、导入slf4j的其他实现
3、SpingBoot日志框架解析
打开IDEA ,打开pom文件的依赖图形化显示
SpringBoot的基础框架
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
SpringBoot的日志功能
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<version>2.0.1.RELEASE</version>
<scope>compile</scope>
</dependency>
总结:
- SpringBoot底层也是使用SLF4J+log4jback
- SpringBoot也把其他日志替换成了slf4j
起着commons.loggings的名字其实new的SLF4J替换中间包
SpringBoot2中改成了bridge
- 如果要引入其他框架?一定要把这个框架的日志依赖移除掉,而且底层
4、日志的使用
1、默认配置
trace-debug-info-warn-error
可以调整需要的日志级别进行输出,不用注释语句。
♾️ java 代码://记录器
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
//日志的级别
//从低到高
//可以调整输出的日志级别;日志就只会在这个级别以后的高级别生效
logger.trace("这是trace日志");
logger.debug("这是debug信息");
//SpringBoot默认给的是info级别,如果没指定就是默认的root级别
logger.info("这是info日志");
logger.warn("这是warn信息");
logger.error("这是Error信息");
}
调整指定包的日志级别在配置文件中进行配置
♾️ properties 代码:logging.level.com.wdjr=trace
日志输出格式
♾️ properties 代码:#控制台输出的日志格式
#%d:日期
#%thread:线程号
#%-5level:靠左 级别
#%logger{50}:全类名50字符限制,否则按照句号分割
#%msg:消息+换行
#%n:换行
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
SpringBoot修改日志的默认配置
♾️ properties 代码:logging.level.com.wdjr=trace
#不指定path就是当前目录下生成springboot.log
#logging.file=springboot.log
#当前磁盘下根路径创建spring文件中log文件夹,使用spring.log作为默认
logging.path=/spring/log
#控制台输出的日志格式 日期 + 线程号 + 靠左 级别 +全类名50字符限制+消息+换行
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
#指定文件中日志输出的格式
logging.pattern.file=xxx
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加载
♾️ xml 代码:<springProfile name="dev">
<!-- 可以指定某段配置只在某个环境下生效 -->
</springProfile>
<springProfile name!="dev">
<!-- 可以指定某段配置只在某个环境下生效 -->
</springProfile>
如何调试开发环境,输入命令行参数
--spring.profiles.active=dev
如果不带后面的xx-spring.xml就会报错
3、切换日志框架
可以根据slf4j的日志适配图,进行相关切换;
1、log4j
slf4j+log4j的方式;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
不推荐使用仅作为演示
2、log4j2
切换为log4j2
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
四、web开发
1、简介
使用SpringBoot;
1)、创建SpringBoot应用,选中我们需要的模块;
2)、SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来
3)、自己编写业务代码
自动配置原理?
这个场景的SpringBoot帮我们配置了什么?能不能修改?能修改那些配置?能不能扩展?xxx
♾️ java 代码:xxxAutoConfiguration:帮我们给容器中自动配置组件
xxxProperties:配置类来封装配置文件的内容
2、静态资源文件映射规则
♾️ java 代码:@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware, InitializingBean {
//可以设置和静态资源相关的参数,缓存时间等
♾️ java 代码:@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));
}
}
1、webjar
1)、所有的/webjars/**,都去classpath:/META-INF/resources/webjars/找资源;
webjars:以jar包的方式引入静态资源
localhost:8080/webjars/jquery/3.3.1/jquery.js
2、本地资源
♾️ text 代码:private String staticPathPattern = "/**";
访问任何资源
2、会在这几文件夹下去找静态路径(静态资源文件夹)
♾️ text 代码:"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
"/";当前项目的根路径
localhost:8080/abc ==>去静态资源文件夹中找abc
3、index页面欢迎页,静态资源文件夹下所有的index.html页面;被“/**”映射;
localhost:8080/ -->index页面
♾️ JAVA 代码:@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(
ResourceProperties resourceProperties) {
return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
}
4、喜欢的图标,即网站title的图标favicon
♾️ java 代码:@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.HIGHEST_PRECEDENCE + 1);
//把任何favicon的图标都在静态文件夹下找
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
faviconRequestHandler()));
return mapping;
}
@Bean
public ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
requestHandler
.setLocations(this.resourceProperties.getFaviconLocations());
return requestHandler;
}
}
可以在配置文件配置静态资源文件夹
♾️ properties 代码:spring.resources.static-locations=classpath:xxxx
3、模板引擎
将html和数据 结合到一起 输出组装处理好的新文件
SpringBoot推荐Thymeleaf;语法简单,功能强大
1、引入thymeleaf 3
♾️ xml 代码:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
默认导入thymeleaf2,版本太低 所以使用thymeleaf3.
♾️ xml 代码:<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--thymeleaf 3的导入-->
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<!--布局功能支持 同时支持thymeleaf3主程序 layout2.0以上版本 -->
<!--布局功能支持 同时支持thymeleaf2主程序 layout1.0以上版本 -->
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
</properties>
2、Thymeleaf使用和语法
♾️ java 代码:@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
//只要把HTML文件方法类路径下的template文件夹下,就会自动导入
只要把HTML页面放到classpath:/templates/,thymeleaf就能自动渲染;
使用:
1、导入thymeleaf的名称空间
♾️ html 代码:<html xmlns:th="http://www.thymeleaf.org">
2、使用thymeleaf语法;
♾️ html 代码:<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>success</title>
</head>
<body>
<h1>success</h1>
<!--th:text 将div里面的文本内容设置为-->
<div th:text="${Lion}">
前端数据
</div>
</body>
</html>
3、语法规则
1)、th:text="${hello}"可以使用任意标签 替换原生的任何属性
在SpringBoot的环境下
♾️ html 代码:<div id="testid" class="testcalss" th:id="${Lion}" th:class="${Lion}" th:text="${Lion}">
前端数据
</div>
直接访问HTML页面
2)、内联写法注意需要在body上加上 th:inline="text"敲黑板
不然不起作用
♾️ html 代码:<body class="text-center" th:inline="text"></body>
th标签的访问优先级
Order Feature Attributes
3、语法规则
功能 | 标签 | 功能和jsp对比 | |
---|---|---|---|
1 | Fragment inclusion | th:insert th:replace | include(片段包含) |
2 | Fragment iteration | th:each | c:forEach(遍历) |
3 | Conditional evaluation | th:if th:unless th:switch th:case | c:if(条件判断) |
4 | Local variable definition | th:object th:with | c:set(声明变量) |
5 | General attribute modification | th:attr th:attrprepend th:attrappend | 属性修改支持前面和后面追加内容 |
6 | Specific attribute modification | th:value th:href th:src ... | 修改任意属性值 |
7 | Text (tag body modification) | th:text th:utext | 修改标签体内容utext:不转义字符大标题 |
8 | Fragment specification | th:fragment | 声明片段 |
9 | Fragment removal | th:remove |
Simple expressions:(表达式语法)
Variable Expressions: ${...}
1、获取对象属性、调用方法
2、使用内置基本对象:
#ctx : the context object.
#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.
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使用,object=${object} 以后获取就可以使用*{a} 相当于${object.a}
<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链接
#<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>
Fragment Expressions: ~{...}//片段文档
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: _
inline写法
♾️ html 代码:[[]] -->th:text
[()] -->th:utext
4、SpringMVC自动配置
1、SpringMVC的自动导入
自动配置好了mvc:
以下是SpringBoot对SpringMVC的默认
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans.- 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染(转发?重定向?))
ContentNegotiatingViewResolver
组合所有视图解析器- 如何定制:我们可以自己给容器中添加一个视图解析器;自动将其整合进来
- Support for serving static resources, including support for WebJars (see below).静态资源
- Static
index.html
support. - Custom
Favicon
support (see below). 自动注册 了
Converter
,GenericConverter
,Formatter
beans.Converter
:类型转换 文本转为字面量
♾️ java 代码:Formatter
:格式化器 转换后格式转换@Bean @ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")//在文件配置入职格式化的规则 public Formatter<Date> dateFormatter() { return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件 }
自己添加的格式化转换器,只需要放在容器中即可
Support for
HttpMessageConverters
(see below).HttpMessageConverters
:转换HTTP转换和响应:User - jsonHttpMessageConverters
:是从容器中确定;获取所有的HttpMessageConverters
,将自己的组件注册在容器中@BeanIf you need to add or customize converters you can use Spring Boot’s
♾️ java 代码:HttpMessageConverters
class:import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.context.annotation.*; import org.springframework.http.converter.*; @Configuration public class MyConfiguration { @Bean public HttpMessageConverters customConverters() { HttpMessageConverter<?> additional = ... HttpMessageConverter<?> another = ... return new HttpMessageConverters(additional, another); } }
Automatic registration of
MessageCodesResolver
(see below).- 定义错误代码生成规则
Automatic use of a
ConfigurableWebBindingInitializer
bean (see below).- ♾️ java 代码:
@Override protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() { try { return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class); } catch (NoSuchBeanDefinitionException ex) { return super.getConfigurableWebBindingInitializer(); } }
在beanFactory:中可以自己创建一个,初始化webDataBinder
请求数据 ==》javaBean
If you want to keep Spring Boot MVC features, and you just want to add additional MVC configuration (interceptors, formatters, view controllers etc.) you can add your own
@Configuration
class of typeWebMvcConfigurerAdapter
, but without@EnableWebMvc
. If you wish to provide custom instances ofRequestMappingHandlerMapping
,RequestMappingHandlerAdapter
orExceptionHandlerExceptionResolver
you can declare aWebMvcRegistrationsAdapter
instance providing such components.If you want to take complete control of Spring MVC, you can add your own
@Configuration
annotated with@EnableWebMvc
.思想:修改默认配置
2、扩展SpringMVC
编写一个配置类,类型是WebMvcConfigurerAdapter(继承),使用WebMvcConfigurerAdapter可以扩展,不能标注@EnableWebMvc;既保留了配置,也能拓展我们自己的应用
♾️ java 代码:@Configuration public class MyMvcConfig extends WebMvcConfigurerAdapter { @Override public void addViewControllers(ViewControllerRegistry registry) { // super.addViewControllers(registry); //浏览器发送wdjr请求,也来到success页面 registry.addViewController("/wdjr").setViewName("success"); } }
原理:
1)、WebMvcAutoConfiguration是SpringMVC的自动配置
2)、在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
♾️ java 代码:@Configuration public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); //从容器中获取所有webMVCconfigurer @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); @Override protected void addViewControllers(ViewControllerRegistry registry) { this.configurers.addViewControllers(registry); } //一个参考实现,将所有的webMVCconfigurer相关配置一起调用(包括自己的配置类) @Override // public void addViewControllers(ViewControllerRegistry registry) { // for (WebMvcConfigurer delegate : this.delegates) { //delegate.addViewControllers(registry); //} } } }
- ♾️ java 代码:
3)、自己的配置被调用
效果:SpringMVC的自动配置和我们的扩展配置都会起作用
### 3、全面接管mvc
不需要SpringBoot对SpringMVC的自动配置。
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
♾️ text 代码: //浏览器发送wdjr请求,也来到success页面
registry.addViewController("/wdjr").setViewName("success");
}
}
♾️ text 代码:
例如静态资源访问,不推荐全面接管
原理:
为什么@EnableWebMvc注解,SpringBoot对SpringMVC的控制就失效了
1)、核心配置
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2)、DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
3)、WebMvcAutoConfiguration
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//容器没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
♾️ text 代码:
4)、@EnableWebMvc将WebMvcConfigurationSupport导入进来了;
5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能
## 5、修改SpringMVC默认配置
模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
2)、在SpringBoot中会有 xxxConfigurer帮助我们扩展配置。
## 6、RestfulCRUD
### 1、默认访问首页
在config/MyConfig.java中编写配置类
//所有的webMvcConfigurerAdapter组件会一起起作用
@Bean //註冊到容器去
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/login.html").setViewName("login");
}
};
return adapter;
}
♾️ text 代码:
静态资源引用
♾️ text 代码:
### 2、国际化
1、编写国际化配置文件
2、使用ResourceBundleMessageSource管理国际化资源文件
3、在页面中使用fmt:message,取出国际化内容
#### 1、浏览器切换国际化
步骤
1、编写国际化配置文件,抽取页面需要的显示的国际化消息
![16.national](https://www.xnijika.com/pic/images/16.national.jpg)
2、SpringBoot自动配置好了国际化配置的资源文件
@ConfigurationProperties(prefix = "spring.messages")
public class MessageSourceAutoConfiguration {
//我们的配置文件可以直接放在类路径下叫messages.properties
private String basename = "messages";
@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;
}
♾️ text 代码:
3、对IDEA的编码进行设置
![17.encoding](https://www.xnijika.com/pic/images/17.encoding.jpg)
4、login进行标签插入
<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<link rel="icon" href="https://getbootstrap.com/favicon.ico" />
<title>登录页面</title>
<!-- Bootstrap core CSS -->
<link href="#" th:href="@{/css/bootstrap.min.css}" rel="stylesheet" />
<!-- Custom styles for this template -->
<link href="./login_files/signin.css" th:href="@{/css/signin.css}" rel="stylesheet" />
♾️ text 代码:<form class="form-signin">
<img class="mb-4" src="./login_files/bootstrap-solid.svg" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72" />
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text" name="username" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus=""/>
<label for="inputPassword" class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" th:placeholder="#{login.password}" required="" />
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" /> [[#{login.remember}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
</form>
♾️ text 代码:
效果根据浏览器语言的信息切换国际化
原理:
国际化locale(区域信息对象);LocaleResolver(获取区域对象);
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
♾️ text 代码:
默认的就是根据请求头带来的区域信息获取local国际化信息(截图就是这么犀利)
![18.accept-language](https://www.xnijika.com/pic/images/18.accept-language.jpg)
#### 2、点击链接切换国际化
自己编写localResolver,加到容器中
1、更改HTML代码
© 2017-2018
♾️ text 代码:
2、新建一个MyLocaleResolver.class
public class MyLocaleResolver implements LocaleResolver {
♾️ text 代码://解析区域信息
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("lg");
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) {
}
}
♾️ text 代码:
3、将MyLocaleResolver加入到容器中
@Bean
public LocaleResolver localeResolver(){
return new MyLocalResolver();
}
♾️ text 代码:
4、启动演示
### 3、登录拦截器
#### 1、登录
开发技巧
1、清除模板缓存
2、Ctrl+F9刷新
1、新建一个LoginController
@Controller
public class LoginController {
@PostMapping(value ="/user/login")
public String login(@RequestParam("username")String username,
@RequestParam("password")String password,
Map<String,Object> map){
if(!StringUtils.isEmpty(username) && "123456".equals(password)){
//登录成功
return "list";
}else{
map.put("msg", "用户名密码错误");
return "login";
}
}
}
♾️ text 代码:
2、登录错误消息显示
♾️ text 代码:
3、表单重复提交
表单重复提交事件 --》重定向来到成功页面--》模板引擎解析
if(!StringUtils.isEmpty(username) && "123456".equals(password)){
♾️ text 代码://登录成功,防止重复提交
return "redirect:/main.html";
}else{
♾️ text 代码:map.put("msg", "用户名密码错误");
return "login";
}
♾️ text 代码:
模板引擎解析
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("Dashboard");
}
♾️ text 代码:
### 4、拦截器
作用:实现权限控制,每个页面请求前中后,都会进入到拦截器进行处理(登录权限)
1、在component下新建一个LoginHandlerInterceptor拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
♾️ text 代码://目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user!=null){
//已经登录
return true;
}
//未经过验证
request.setAttribute("msg", "没权限请先登录");
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
}
@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 {
}
}
♾️ text 代码:
2、在MyMvcConfig配置中重写拦截器方法,加入到容器中
//所有的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) {
//静态资源 css js img 已经做好了静态资源映射
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").
excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
}
♾️ text 代码:
3、在LoginHandler中添加登录成功写入session
@Controller
public class LoginController {
@PostMapping(value ="/user/login")
public String login(@RequestParam("username")String username,
@RequestParam("password")String password,
Map<String,Object> map,
HttpSession session){
if(!StringUtils.isEmpty(username) && "123456".equals(password)){
//登录成功,防止重复提交
session.setAttribute("loginUser", username);
return "redirect:/main.html";
}else{
map.put("msg", "用户名密码错误");
return "login";
}
}
}
♾️ text 代码:
### 5、CRUD-员工列表
实验要求:
1)、RestfulCRUD:CRUD满足Rest风格
URI:/资源名称/资源标识+HTTP操作
| | 普通CRUD | 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/{id} | GET |
| 添加页面 | emp | GET |
| 添加员工 | emp | POST |
| 修改页面(回显) | emp/{id} | GET |
| 修改员工 | emp/{id} | PUT |
| 删除员工 | emp/{id} | DELETE |
3、员工列表
#### 1、公共页面抽取
使用方法
1、抽取公共片段
2、引入公共片段
~{templatename::selector} 模板名::选择器 footer::#footid
~{templatename::fragmentname} 模板名::片段名称 footer::copy
行内写法可以加~{xx::xx} 标签体可以 xx::xx
**三种引用方式**
**th:insert** :加个外层标签 +1
**th:replace** :完全替换 1
**th:include**:就替换里面的内容 -1
公共页面
♾️ text 代码:...
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
♾️ text 代码:
结果
...♾️ text 代码:
<!-- th:insert -->
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<!--th:replace-->
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--th:include-->
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
♾️ text 代码:
用此种方法将公共页面引入
#### 2、列表高亮
引入片段的时候传入参数,新建一个commons文件夹存储公共页面bar.html
模板引入变量名
dashboard
<a class="nav-link active"
th:class="${activeUri}=='main.html'?'nav-link active':'nav-link'"
href="https://getbootstrap.com/docs/4.1/examples/dashboard/#" th:href="@{/main.html}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
Dashboard <span class="sr-only">(current)</span>
♾️ text 代码:
员工管理
<a class="nav-link"
th:class="${activeUri}=='emps'?'nav-link active':'nav-link'"
href="https://getbootstrap.com/docs/4.1/examples/dashboard/#" th:href="@{/emps}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
员工管理
</a>
♾️ text 代码:
引入模板的时候传入参数
dashboard.html引入
♾️ text 代码:
list.html引入
♾️ text 代码:
### 6、列表数据显示(查)
#### 1、传入员工对象
EmployeeController类,传入员工对象
@Controller
public class EmployeeController {
@Autowired
EmployeeDao employeeDao;
/**
* 查询所有员工返回列表页面
*/
@GetMapping(value = "/emps")
public String list(Model model){
Collection<Employee> employees = employeeDao.getAll();
model.addAttribute("emps",employees);
return "emp/list";
}
}
♾️ text 代码:
#### 2、 遍历对象
list.html中 使用模板的 `th:each`方法
table class="table table-striped table-sm">
♾️ text 代码:<thead>
<tr>
<th>#</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>department</th>
<th>birth</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.id}">1</td>
<td th:text="${emp.lastName}">1</td>
<td th:text="${emp.email}">1</td>
<td th:text="${emp.gender}">1</td>
<td th:text="${emp.department.departmentName}">1</td>
<td th:text="${#dates.format(emp.birth,'yyyy-MM-dd HH:mm:ss')}">1</td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>
♾️ text 代码:
#### 3、效果显示
![19.table list](https://www.xnijika.com/pic/images/19.table list.jpg)
### 7、员工添加(增)
功能:点击添加按钮,出现新增页面
#### 1、新增页面
♾️ text 代码:
#### 2、页面跳转
在EmployeeController中添加addEmpPage方法
/**
- 添加员工
*/
@GetMapping(value = "/emp")
public String toAddPage(Model model){
//来到添加页面,查出所有部门显示
Collection<Department> depts = departmentDao.getDepartments();
model.addAttribute("depts",depts);
return "emp/add";
}
♾️ text 代码:
关键点:在添加部门页面要遍历部门信息,所以在方法中出入部门信息
#### 3、添加功能完成
新建一个PostMapping
> ThymeleafViewResolver 查看redirect和forward,原生的sendredirect方法;
1、新建一个postMapping的方法用来接受页面的添加POST请求
/**
- 员工添加
*/
@PostMapping(value = "/emp")
public String addEmp(Employee employee){
employeeDao.save(employee);
//来到员工列表页面、redirect:重定向到一个地址,forward转发到一个地址
return "redirect:/emps";
}
♾️ text 代码:
2、修改添加页面,添加name属性
♾️ text 代码:
1、部门对象问题?
♾️ text 代码:
2、日期格式化?
属性中添加 date-formate 默认是 /
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")
public Formatter
return new DateFormatter(this.mvcProperties.getDateFormat());
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
resolver.setMessageCodeFormatter(
this.mvcProperties.getMessageCodesResolverFormat());
return resolver;
}
return null;
}
spring.mvc.date-format=yyyy-MM-dd
♾️ text 代码:
### 8、员工编辑(改)
思路使用add页面,并且数据回显,然后区分添加,PUT请求
#### 1、修改按钮
在list.html的`编辑`按钮加上链接
<a href="#" th:href="@{/emp/}+${emp.id}" class="btn btn-sm btn-primary">编辑</a>
<button class="btn btn-sm btn-danger">删除</button>
#### 2、编写跳转页面
跳转到员工编辑页面的Controller
/**
- 员工编辑页面
*/
@GetMapping(value = "/emp/{id}")
public String toEditPage(@PathVariable("id") Integer id ,Model model){
Employee emp = employeeDao.getEmpById(id);
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("emp",emp);
model.addAttribute("depts",departments);
return "emp/add";
}
♾️ text 代码:
#### 3、对页面修改
对add页面进行修改
1)、添加回显
2)、添加判断是否emp!=null(区分add or edit)
3)、添加put请求 --两个input的hidden标签
♾️ text 代码:
### 9、员工删除(删)
#### 1、新建Contoller
/**
- 员工删除
*/
@DeleteMapping(value = "/emp/{id}")
public String deleteEmp(@PathVariable("id") Integer id){
employeeDao.deleteEmpById(id);
return "redirect:/emps";
}
♾️ text 代码:
#### 2、修改删除标签
♾️ text 代码:删除
♾️ text 代码:
#### 3、写Form表单
form表单卸载外面,input 中 name="_method" value="delete" 模拟delete请求
♾️ text 代码: </tbody>
</table>
</div>
</main>
<form id="deleteEmpForm" method="post">
<input type="hidden" name="_method" value="delete">
</form>