pring Boot是Pivotal團隊在Spring的基礎(chǔ)上提供的一套全新的開源框架,其目的是為了簡化Spring應(yīng)用的搭建和開發(fā)過程。Spring Boot去除了大量的XML配置文件,簡化了復(fù)雜的依賴管理。
官網(wǎng)地址:spring.io/projects/sp…
Spring Boot是簡化Spring應(yīng)用開發(fā)的一個框架、整個Spring技術(shù)棧的一個大整合(Spring全家桶時代)、J2EE開發(fā)的一站式解決方案(Spring Cloud是分布式整體解決方案)。 優(yōu)點: – 快速創(chuàng)建獨立運行的Spring項目以及與主流框架集成 – 使用嵌入式的Servlet容器,應(yīng)用無需打成WAR包 – starters自動依賴與版本控制 – 大量的自動配置,簡化開發(fā),也可修改默認值 – 無需配置XML,無代碼生成,開箱即用 – 準生產(chǎn)環(huán)境的運行時應(yīng)用監(jiān)控 – 與云計算的天然集成
– 單體應(yīng)用:ALL IN ONE(所有內(nèi)容都在一個應(yīng)用里面) – 微服務(wù):每一個功能元素最終都是一個可獨立替換和獨立升級的軟件單元 微服務(wù)是一種架構(gòu)風(fēng)格(服務(wù)微化),一個應(yīng)用應(yīng)該是一組小型服務(wù),可以通過HTTP的方式進行互通
工程創(chuàng)建及案例可以參考文章進行操作:在IDEA中創(chuàng)建SpringBoot項目
父項目是Spring Boot的版本仲裁中心(他來真正管理Spring Boot應(yīng)用里面的所有依賴版本),以后我們導(dǎo)入依賴默認是不需要寫版本(沒有在dependencies里面管理的依賴自然需要聲明版本號)
xml 代碼解讀復(fù)制代碼<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
啟動器 spring-boot-starter(spring-boot場景啟動器),spring-boot-starter-web 幫我們導(dǎo)入了web模塊正常運行所依賴的組件。
xml 代碼解讀復(fù)制代碼<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>
Spring Boot將所有的功能場景都抽取出來,做成一個個的starters(啟動器),只需要在項目里面引入這些starter相關(guān)場景的所有依賴都會導(dǎo)入進來。要用什么功能就導(dǎo)入什么場景的啟動器。
// 自動生成的
@SpringBootApplication
public class SpringBootDemo0Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo0Application.class, args);
}
}
@SpringBootApplication: Spring Boot應(yīng)用標(biāo)注在某個類上說明這個類是SpringBoot的主配置類,SpringBoot 就應(yīng)該運行這個類的main方法來啟動SpringBoot應(yīng)用。
SpringBoot使用一個全局的配置文件,配置文件名固定:application.properties 或者 application.yml。配置文件放在 src/main/resources目錄 或者 類路徑/config 下。作用是修改SpringBoot自動配置的默認值。
YAML(YAML Ain't Markup Language),.yml為結(jié)尾,以數(shù)據(jù)為中心,比json、xml等更適合做配置文件。
YAML配置例子
server:
port: 8081
等價于XML配置:
<server>
<port>8081</port>
</server>
【語法】 key: value(注意冒號后面有個空格) 以空格的縮進來控制層級關(guān)系,只要是左對齊的一列數(shù)據(jù),都是同一個層級
【值寫法】
(1)字面量:普通的值(數(shù)字,字符串,布爾)
(2)對象、Map
friends:
lastName: zhangsan
age: 20
或者:
friends: {lastName:zhangsan,age:18}
(3)數(shù)組(List、Set)
pets:
‐ cat
‐ dog
‐ pig
pets: [cat,dog,pig]
1)導(dǎo)入配置文件處理器
<!‐‐導(dǎo)入配置文件處理器,配置文件進行綁定就會有提示‐‐>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
2)javaBean對象 @ConfigurationProperties(prefix = "person") 會將配置文件和類進行綁定:
/**
* 將配置文件中配置的每一個屬性的值,映射到這個組件中
* @ConfigurationProperties:告訴SpringBoot將本類中的所有屬性和配置文件中相關(guān)的配置進行綁定;
* prefix = "person":配置文件中哪個下面的所有屬性進行一一映射
* 只有這個組件是容器中的組件,才能容器提供的@ConfigurationProperties功能;
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
....
}
3)配置文件 application.yml
person:
lastName: haha
age: 18
boss: false
birth: 2022/01/01
maps: {k1: v1,k2: v2}
lists:
- lisi
- wangwu
dog:
name: 芒果
age: 1
或者配置文件application.properties
properties 代碼解讀復(fù)制代碼#解決亂碼問題
spring.message.encoding=UTF-8
#person
person.last-name=haha
person.age=20
person.birth=2022/01/02
person.boss=true
person.maps.k1=v1
person.maps.k2=v2
person.lists=a,b,c
person.dog.name=丸子
person.dog.age=5
亂碼問題還需要配置:
4)單元測試,先將內(nèi)容注入(@Autowired)然后使用
@ConfigurationProperties 與 @Value 的區(qū)別:
@Component
// @ConfigurationProperties(prefix = "person")
public class Person {
@Value("${person.last-name}")
private String lastName;
@Value("#{2*4}")
private Integer age;
@Value("true")
private Boolean boss;
@Value("${person.birth}")
private Date birth;
...
松散綁定: – person.firstName:使用標(biāo)準方式 – person.first-name:大寫用- – person.first_name:大寫用_ – PERSON_FIRST_NAME:推薦系統(tǒng)屬性使用這種寫法 JSR303數(shù)據(jù)校驗:
使用規(guī)則:
@Value("${febase.api.host}")
private String febaseHost;
@PropertySource:加載指定的配置文件
@PropertySource("classpath:person.properties")
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastName;
private Integer age;
private Boolean boss;
...
}
@ImportResource:導(dǎo)入Spring的配置文件,讓配置文件里面的內(nèi)容生效--標(biāo)注在一個配置類上 如下我們自己編寫的配置文件:
xml 代碼解讀復(fù)制代碼<?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.stydyspring.spring_boot_demo0.service.HelloService"></bean>
</beans>
我們可以標(biāo)注在主配置類上:
@SpringBootApplication
// 導(dǎo)入Spring的配置文件讓其生效
@ImportResource(locations = {"classpath:beans.xml"})
public class SpringBootDemo0Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemo0Application.class, args);
}
}
測試:
@SpringBootTest
class SpringBootDemo0ApplicationTests {
@Autowired
ApplicationContext ioc;
@Test
public void testHelloService(){
boolean containsBean = ioc.containsBean("helloService");
System.out.println(containsBean);
// 上一步?jīng)]加@ImportResource之前返回false
// 添加@ImportResource之后返回true
}
}
SpringBoot推薦給容器中添加組件的方式,推薦使用全注解的方式 @Configuration
/**
* @Configuration:指明當(dāng)前類是一個配置類,就是來替代之前的Spring配置文件
*
* 在配置文件中用<bean><bean/>標(biāo)簽添加組件。在配置類中使用@Bean注解
*/
@Configuration
public class MyAppConfig {
// 將方法的返回值添加到容器中;容器中這個組件默認的id就是方法名
@Bean
public HelloService helloService(){
System.out.println("配置類@Bean給容器中添加組件了");
return new HelloService();
}
}
隨機數(shù)
${random.value}、${random.int}、${random.long}、${random.uuid}
${random.int(10)}、${random.int[1024,65536]}
占位符獲取之前配置的值,如果沒有可以是用:指定默認值
properties 代碼解讀復(fù)制代碼#person
person.last-name=haha${random.uuid}
person.age=${random.int}
person.birth=2222/02/02
person.boss=false
person.maps.k1=v11111
person.maps.k2=v22222
person.lists=a,b,c,d,e,f
person.dog.name=${person.hello:hello}_dog
person.dog.age=1
Profile是Spring對不同環(huán)境提供不同配置功能的支持,可以通過激活、指定參數(shù)等方式快速切換環(huán)境。 多profile文件形式格式如:application-{profile}.properties/yml,如 application-dev.properties、application-prod.properties
默認使用application.properties的配置
激活方式:
yml支持多文檔塊方式:
properties 代碼解讀復(fù)制代碼server:
port: 8081
spring:
profiles:
active: prod
‐‐‐
server:
port: 8083
spring:
profiles: dev
‐‐‐
server:
port: 8084
spring:
profiles: prod #指定屬于哪個環(huán)境
spring boot 啟動會掃描以下位置的application.properties或者application.yml文件作為Spring boot的默認配置文件
以上是按照優(yōu)先級從高到低的順序,所有位置的文件都會被加載,高優(yōu)先級配置內(nèi)容會覆蓋低優(yōu)先級配置內(nèi)容。 可以通過配置spring.config.location來改變默認配置。項目打包好以后,可以使用命令行參數(shù)的形式,啟動項目的時候來指定配置文件的新位置;指定配置文件和默認加載的這些配置文件共同起作用形成互補配置: java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
Spring Boot支持多種外部配置方式,優(yōu)先級從高到低。高優(yōu)先級的配置覆蓋低優(yōu)先級的配置,所有的配置會形成互補配置:
由jar包外向jar包內(nèi)進行尋找。優(yōu)先加載帶profile:
再來加載不帶profile:
配置文件可以配置的屬性:docs.spring.io/spring-boot…
自動配置原理: 1)Spring Boot啟動時加載主配置類(帶有@SpringBootApplication),其里面開啟了自動配置功能@EnableAutoConfiguration 2)@EnableAutoConfiguration利用@Import(AutoConfigurationImportSelector.class)給容器導(dǎo)入一些組件。導(dǎo)入的組件是通過List configurations = getCandidateConfigurations(annotationMetadata, attributes);獲取到的。里面通過SpringFactoriesLoader.loadFactoryNames 掃描所有jar包類路徑下"META-INF/spring.factories",把掃描到的這些文件的內(nèi)容包裝成properties對象,從properties中獲取到EnableAutoConfiguration.class類(類名)對應(yīng)的值,然后把他們添加在容器中。其實就是將類路徑下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中。每一個這樣的 xxxAutoConfiguration 類都是容器中的一個組件,都加入到容器中;用他們來做自動配置; 3)每一個自動配置類進行自動配置功能 4)以HttpEncodingAutoConfiguration配置類進行分析:
// 表示這是一個配置類,以前編寫的配置文件一樣,也可以給容器中添加組件
@AutoConfiguration
// 啟動指定類的ConfigurationProperties功能,將配置文件中對應(yīng)的值和xxxProperties綁定起來,???把xxxProperties加入到ioc容器中
@EnableConfigurationProperties(ServerProperties.class)
// Spring底層@Conditional注解(Spring注解版),根據(jù)不同的條件,如果滿足指定的條件,整個配置類里面的配置就會生效;
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
// 判斷當(dāng)前項目有沒有這個類CharacterEncodingFilter-SpringMVC中進行亂碼解決的過濾器
@ConditionalOnClass(CharacterEncodingFilter.class)
// 判斷配置文件中是否存在某個配置 spring.servlet.encoding.enabled;如果不存在,判斷也是成立的
// 即使我們配置文件中不配置spring.servlet.encoding.enabled=true,也是默認生效的;
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
// 他已經(jīng)和SpringBoot的配置文件映射了
private final Encoding properties;
// 只有一個有參構(gòu)造器的情況下,參數(shù)的值就會從容器中拿
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
@Bean // 給容器中添加一個組件,這個組件的某些值需要從properties中獲取
@ConditionalOnMissingBean // 判斷容器沒有這個組件,就給配置一個
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}
...
}
根據(jù)當(dāng)前不同的條件判斷,決定這個配置類是否生效 一但這個配置類生效,這個配置類就會給容器中添加各種組件,這些組件的屬性是從對應(yīng)的properties類中獲取的,這些類里面的每一個屬性又是和配置文件綁定的 5)、所有在配置文件中能配置的屬性都是在xxxxProperties類中封裝著,配置文件能配置什么就可以參照某個功能對應(yīng)的這個屬性類
使用精髓: 1)、SpringBoot啟動會加載大量的自動配置類 ; 2)、我們看我們需要的功能有沒有SpringBoot默認寫好的自動配置類; 3)、我們再來看這個自動配置類中到底配置了哪些組件(只要我們要用的組件有,我們就不需要再來配置了) 4)、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。我們就可以在配置文件中指定這些屬性的值; xxxxAutoConfigurartion:自動配置類; 給容器中添加組件 xxxxProperties:封裝配置文件中相關(guān)屬性
作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置配里面的所有內(nèi)容才生效 也就是說,自動配置類必須在一定的條件下才能生效
@Conditional擴展注解 | 作用(判斷是否滿足當(dāng)前指定條件) |
@ConditionalOnJava | 系統(tǒng)的java版本是否符合要求 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean |
@ConditionalOnExpression | 滿足SpEL表達式指定 |
@ConditionalOnClass | 系統(tǒng)中有指定的類 |
@ConditionalOnMissingClass | 系統(tǒng)中沒有指定的類 |
@ConditionalOnSingleCandidate | 容器中只有一個指定的Bean,或者這個Bean是首選Bean |
@ConditionalOnProperty | 系統(tǒng)中指定的屬性是否有指定的值 |
@ConditionalOnResource | 類路徑下是否存在指定資源文件 |
@ConditionalOnWebApplication | 當(dāng)前是web環(huán)境 |
@ConditionalOnNotWebApplication | 當(dāng)前不是web環(huán)境 |
@ConditionalOnJndi | JNDI存在指定項 |
想要查看生效的自動配置類,可以在配置文件中配置debug=true,positive為啟動的,negative沒啟用的
市場上存在非常多的日志框架:JUL(java.util.logging),JCL(Apache Commons Logging),Log4j,Log4j2,Logback、SLF4j、jboss-logging等。 Spring Boot在框架內(nèi)容部使用JCL,spring-boot-starter-logging采用了 slf4j+logback的形式,Spring Boot也能自動適配(jul、log4j2、logback) 并簡化配置 SpringBoot底層是Spring框架,Spring框架默認是用JCL。SpringBoot選用SLF4j(日志抽象層)和logback(日志實現(xiàn))
開發(fā)時日志記錄方法的調(diào)用,不應(yīng)該來直接調(diào)用日志的實現(xiàn)類,而是調(diào)用日志抽象層里面的方法:
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");
}
}
每一個日志的實現(xiàn)框架都有自己的配置文件。使用slf4j以后,配置文件還是做成日志實現(xiàn)框架自己本身的配置文件。 如何讓系統(tǒng)中所有的日志都統(tǒng)一到slf4j:
添加依賴:
xml 代碼解讀復(fù)制代碼<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
SpringBoot能自動適配所有的日志,而且底層使用slf4j+logback的方式記錄日志,引入其他框架的時候,只需要把這個框架依賴的日志框架排除掉即可
xml 代碼解讀復(fù)制代碼<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring‐core</artifactId>
<exclusions>
<exclusion>
<groupId>commons‐logging</groupId>
<artifactId>commons‐logging</artifactId>
</exclusion>
</exclusions>
</dependency>
日志級別由低到高:trace<debug<info<warn<error SpringBoot默認給我們使用的是info級別的(日志就只會在這個級別及以后的高級別生效),沒有指定級別的就用SpringBoot默認規(guī)定的級別。 日志輸出格式:
public class Hello {
// 記錄器
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/world")
public String hello() {
logger.trace("trace日志");
logger.debug("debug日志");
// 默認
logger.info("info日志");
logger.warn("warn日志");
logger.error("error日志");
return "Hello World~";
}
}
默認是info,所以只會輸出:
2023-05-23 11:44:27.419 INFO 98527 --- [nio-8080-exec-2] c.s.spring_boot_demo3.controller.Hello : info日志
2023-05-23 11:44:27.419 WARN 98527 --- [nio-8080-exec-2] c.s.spring_boot_demo3.controller.Hello : warn日志
2023-05-23 11:44:27.419 ERROR 98527 --- [nio-8080-exec-2] c.s.spring_boot_demo3.controller.Hello : error日志
修改默認級別:
logging.level.com.study=trace
2023-05-23 11:50:00.774 TRACE 98971 --- [nio-8080-exec-1] c.s.spring_boot_demo3.controller.Hello : trace日志
2023-05-23 11:50:00.774 DEBUG 98971 --- [nio-8080-exec-1] c.s.spring_boot_demo3.controller.Hello : debug日志
2023-05-23 11:50:00.774 INFO 98971 --- [nio-8080-exec-1] c.s.spring_boot_demo3.controller.Hello : info日志
2023-05-23 11:50:00.774 WARN 98971 --- [nio-8080-exec-1] c.s.spring_boot_demo3.controller.Hello : warn日志
2023-05-23 11:50:00.774 ERROR 98971 --- [nio-8080-exec-1] c.s.spring_boot_demo3.controller.Hello : error日志
日志配置:
logging.file.name(建議) | logging.file.path | 例子 | 備注 |
空 | 空 | 只在控制臺輸出 | |
指定文件名 | 空 | my.log | 輸出日志到my.log文件 |
空 | 指定目錄 | /var/log | 輸出到指定目錄的 spring.log 文件中 |
xml 代碼解讀復(fù)制代碼# 日志
# logging.file.name=my.log
# 配置日志路徑,默認在此目錄下生成一個名為:spring.log的日志文件
logging.file.path=/test/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
給類路徑下放上每個日志框架自己的配置文件即可,SpringBoot就不使用他默認配置的了
日志系統(tǒng) | 自定義配置文件 |
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功能(激活對應(yīng)環(huán)境下生效)
xml 代碼解讀復(fù)制代碼<springProfilename="staging">
<!‐‐ configuration to be enabled when the "staging" profile is active ‐‐>
可以指定某段配置只在某個環(huán)境下生效
</springProfile>
xml 代碼解讀復(fù)制代碼<appendername="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ‐‐‐‐> [%thread] ‐‐‐> %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy‐MM‐dd HH:mm:ss.SSS} ==== [%thread] ==== %‐5level
%logger{50} ‐ %msg%n</pattern>
</springProfile>
</layout>
</appender>
1)所有 /webjars/** ,都去 classpath:/META-INF/resources/webjars/ 找資源
webjars:是以jar包的方式引入靜態(tài)資源(網(wǎng)址:www.webjars.org/)
引入后訪問:http://localhost:8080/webjars/jquery/3.3.1/src/jquery.js,就可以找到資源:
2) /** 訪問當(dāng)前項目的任何資源,都去「靜態(tài)資源的文件夾」找映射
如,localhost:8080/abc,會去靜態(tài)資源文件夾里面找abc
3)首頁映射,靜態(tài)資源文件夾下的所有index.html頁面,被"/**"映射 localhost:8080/ ,會找index頁面
4)所有的 **/favicon.ico 都是在靜態(tài)資源文件下找
默認規(guī)則:只要我們把HTML頁面放在classpath:/templates/,thymeleaf就能自動渲染
// 源碼
@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";
第一步)添加依賴
xml 代碼解讀復(fù)制代碼 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
第二步)屬性配置
xml 代碼解讀復(fù)制代碼# 將緩存關(guān)閉
spring.thymeleaf.cache=false
第三步)創(chuàng)建thymeleaf模板文件 創(chuàng)建success.html,放入classpath:/templates/文件夾下
xml 代碼解讀復(fù)制代碼<!DOCTYPE html>
<!-- 導(dǎo)入thymeleaf的名稱空間 -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>成功頁面!</h2>
<!-- th:text將div里面的文本內(nèi)容設(shè)置為name代表的數(shù)據(jù) -->
<div th:text="${name}"></div>
</body>
</html>
第四步)編寫控制器
// 這里需要使用@Controller,而不是@RestController
@Controller
@RequestMapping("/api")
public class Hello {
@ResponseBody
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@RequestMapping("/success")
public String success(Model model) {
// classpath:/templates/success.html
model.addAttribute("name","alice");
return "success";
}
}
第五步)訪問頁面 訪問http://localhost:8080/api/success,可以看到html頁面內(nèi)容
1)th:text:改變當(dāng)前元素里面的文本內(nèi)容(th:任意html屬性:來替換原生屬性的值)
2)表達式
properties 代碼解讀復(fù)制代碼【 Simpleexpressions:(表達式語法) 】
1、Variable Expressions: ${...}:獲取變量值(OGNL)
1)、獲取對象的屬性、調(diào)用方法
2)、使用內(nèi)置的基本對象:
#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)、內(nèi)置的一些工具對象:
#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 aresult of an iteration).
2、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>
3、Message Expressions: #{...}:獲取國際化內(nèi)容
4、Link URL Expressions: @{...}:定義URL;
例子:@{/order/process(execId=${execId},execType='FAST')}
5、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:(數(shù)學(xué)運算)】
Binary operators: + , ‐ , * , / , %
Minus sign (unary operator): ‐
【Booleanoperations:(布爾運算)】
Binary operators: and , or
Boolean negation (unary operator): ! , not
【Comparisonsandequality:(比較運算)】
Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )
【Conditionaloperators:條件運算(三元運算符)】
If‐then: (if) ? (then)
If‐then‐else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
【Specialtokens:(特殊操作) 】
No‐Operation: _ 代表空操作,如在三元運算符的冒號后面使用
Spring Boot 自動配置好了SpringMVC。以下是SpringBoot對SpringMVC的默認配置(WebMvcAutoConfiguration):
擴展方式:編寫一個配置類(@Configuration),是WebMvcConfigurerAdapter類型,不能標(biāo)注@EnableWebMvc。 既保留了所有的自動配置,也能用我們擴展的配置(SpringMVC的自動配置和我們的擴展配置都會起作用)
// 使用WebMvcConfigurerAdapter可以來擴展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
// 添加視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
// 瀏覽器發(fā)送 /other 請求來到 success
registry.addViewController("/other").setViewName("success");
}
}
瀏覽器訪問 http://localhost:8080/other , 可以看到成功映射到了success頁面
@EnableWebMvc(不推薦使用) SpringBoot對SpringMVC的自動配置不需要了,所有都是我們自己配置。所有的SpringMVC的自動配置都失效了。我們需要在配置類中添加@EnableWebMvc即可
// 使用WebMvcConfigurerAdapter可以來擴展SpringMVC的功能
@Configuration
// 全面接管SpringMVC
@EnableWebMvc
public class MyMvcConfig extends WebMvcConfigurerAdapter {
// 添加視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
// 瀏覽器發(fā)送 /other 請求來到 success
registry.addViewController("/other").setViewName("success");
}
}
接管前通過http://localhost:8080/static.html可以訪問靜態(tài)頁面,全面接管后靜態(tài)頁面的規(guī)則就失效了,我們就無法直接訪問了
模式: 1)、SpringBoot在自動配置很多組件的時候,先看容器中有沒有用戶自己配置的 (@Bean、@Component)。如果有就用用戶配置的,如果沒有才自動配置。如果有些組件可以有多個(如ViewResolver),則將用戶配置的和自己默認的組合起來; 2)、在SpringBoot中會有非常多的xxxConfigurer幫助我們進行擴展配置 3)、在SpringBoot中會有很多的xxxCustomizer幫助我們進行定制配置
方法1:在controller中添加訪問路徑的匹配規(guī)則
@RequestMapping({"/", "/index.html"})
public String index() {
return "index";
}
方法2:在配置類中注冊組件到容器
// 使用WebMvcConfigurerAdapter可以來擴展SpringMVC的功能
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
// 添加視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/other").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;
}
}
第一步:編寫國際化配置文件,抽取頁面需要顯示的國際化消息
第二步:SpringBoot自動配置好了管理國際化資源文件的組件 我們的配置文件可以直接放在類路徑下叫messages.properties,或者在application.properties里配置路徑
# 國際化配置的路徑
spring.messages.basename=i18n.login
第三步:使用#{}可以在頁面上獲取國際化的值
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<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="">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html" th:action="@{/user/login}" method="post">
<img class="mb-4" th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/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>
<!--判斷-->
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
<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 class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" name="password" 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>
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
</form>
</body>
</html>
第四步:點擊鏈接切換國際化
自己實現(xiàn)一個LocaleResolver,然后在配置類中注冊組件到容器
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
實現(xiàn)效果:
@Controller
public class Login {
// @RequestMapping(value = "/user/login", method = RequestMethod.POST)
@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) && "1234".equals(password)) {
session.setAttribute("loginUser", username);
return "redirect:/main.html";
} else {
map.put("msg", "用戶名密碼錯誤");
return "login";
}
}
}
配置類中添加一個試圖映射
java
代碼解讀
復(fù)制代碼registry.addViewController("/main.html").setViewName("dashboard");
錯誤消息顯示:
java
代碼解讀
復(fù)制代碼<pstyle="color:red"th:text="${msg}"th:if="${not#strings.isEmpty(msg)}"></p>
攔截器
// 登陸檢查
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目標(biāo)方法執(zhí)行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
//未登陸,返回登陸頁面
request.setAttribute("msg","沒有權(quán)限請先登陸");
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);
// 靜態(tài)資源; *.css , *.js
// SpringBoot已經(jīng)做好了靜態(tài)資源映射
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
}
三種引入公共片段的th屬性:
html 代碼解讀復(fù)制代碼<body>
<!--引入抽取的topbar-->
<!--模板名:會使用thymeleaf的前后綴配置規(guī)則進行解析-->
<div th:replace="commons/bar::topbar"></div>
<div class="container-fluid">
<div class="row">
<!--引入側(cè)邊欄-->
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2><a class="btn btn-sm btn-success" href="emp" th:href="@{/emp}">員工添加</a></h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<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}"></td>
<td>[[${emp.lastName}]]</td>
<td th:text="${emp.email}"></td>
<td th:text="${emp.gender}==0?'女':'男'"></td>
<td th:text="${emp.department.departmentName}"></td>
<td th:text="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
<td>
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">編輯</a>
<button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">刪除</button>
</td>
</tr>
</tbody>
</table>
</div>
</main>
<form id="deleteEmpForm" method="post">
<input type="hidden" name="_method" value="delete"/>
</form>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="asserts/js/jquery-3.2.1.slim.min.js" th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
<script type="text/javascript" src="asserts/js/popper.min.js" th:src="@{/webjars/popper.js/1.11.1/dist/popper.js}"></script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js" th:src="@{/webjars/bootstrap/4.0.0/js/bootstrap.js}"></script>
<!-- Icons -->
<script type="text/javascript" src="asserts/js/feather.min.js" th:src="@{/asserts/js/feather.min.js}"></script>
<script>
feather.replace()
</script>
<script>
$(".deleteBtn").click(function(){
//刪除當(dāng)前員工的
$("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit();
return false;
});
</script>
</body>
請求添加頁面
//來到員工添加頁面
@GetMapping("/emp")
public String toAddPage(Model model){
//來到添加頁面,查出所有的部門,在頁面顯示
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("depts",departments);
return "emp/add";
}
添加頁面的表單(見下方修改) 員工添加功能
//員工添加
//SpringMVC自動將請求參數(shù)和入?yún)ο蟮膶傩赃M行一一綁定;要求請求參數(shù)的名字和javaBean入?yún)⒌膶ο罄锩娴膶傩悦且粯拥?@PostMapping("/emp")
public String addEmp(Employee employee){
//來到員工列表頁面
System.out.println("保存的員工信息:"+employee);
//保存員工
employeeDao.save(employee);
// redirect: 表示重定向到一個地址 /代表當(dāng)前項目路徑
// forward: 表示轉(zhuǎn)發(fā)到一個地址
return "redirect:/emps";
}
查詢員工信息并回顯
//來到修改頁面,查出當(dāng)前員工,在頁面回顯
@GetMapping("/emp/{id}")
public String toEditPage(@PathVariable("id") Integer id,Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("emp",employee);
//頁面要顯示所有的部門列表
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("depts",departments);
//回到修改頁面(add是一個修改添加二合一的頁面);
return "emp/add";
}
修改和添加是同一個頁面:
<!--需要區(qū)分是員工修改還是添加;-->
<form th:action="@{/emp}" method="post">
<!--發(fā)送put請求修改員工數(shù)據(jù)-->
<!--
1、SpringMVC中配置HiddenHttpMethodFilter;(SpringBoot自動配置好的)
2、頁面創(chuàng)建一個post表單
3、創(chuàng)建一個input項,name="_method";值就是我們指定的請求方式
-->
<input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>
<input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}">
<div class="form-group">
<label>LastName</label>
<input name="lastName" type="text" class="form-control" placeholder="zhangsan" th:value="${emp!=null}?${emp.lastName}">
</div>
<div class="form-group">
<label>Email</label>
<input name="email" type="email" class="form-control" placeholder="zhangsan@atguigu.com" th:value="${emp!=null}?${emp.email}">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="1" th:checked="${emp!=null}?${emp.gender==1}">
<label class="form-check-label">男</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp!=null}?${emp.gender==0}">
<label class="form-check-label">女</label>
</div>
</div>
<div class="form-group">
<label>department</label>
<!--提交的是部門的id-->
<select class="form-control" name="department.id">
<option th:selected="${emp!=null}?${dept.id == emp.department.id}" th:value="${dept.id}" th:each="dept:${depts}" th:text="${dept.departmentName}">1</option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input name="birth" type="text" class="form-control" placeholder="zhangsan" th:value="${emp!=null}?${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}">
</div>
<button type="submit" class="btn btn-primary" th:text="${emp!=null}?'修改':'添加'">添加</button>
</form>
修改功能
//員工修改;需要提交員工id;
@PutMapping("/emp")
public String updateEmployee(Employee employee){
System.out.println("修改的員工數(shù)據(jù):"+employee);
employeeDao.save(employee);
return "redirect:/emps";
}
<button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">刪除</button>
<script>
$(".deleteBtn").click(function(){ //刪除當(dāng)前員工。先修改action地址再提交
$("#deleteEmpForm").attr("action",$(this).attr("del_uri")).submit();
return false;
});
</script>
刪除功能方法:
//員工刪除
@DeleteMapping("/emp/{id}")
public String deleteEmployee(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
瀏覽器返回一個默認的錯誤頁面
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Jun 11 10:32:29 CST 2023
There was an unexpected error (type=Not Found, status=404).
客戶端請求默認返回JSON數(shù)據(jù)提示錯誤
{
"timestamp": "2023-06-11T02:37:03.631+00:00",
"status": 404,
"error": "Not Found",
"path": "/hello1"
}
一但系統(tǒng)出現(xiàn)4xx或者5xx之類的錯誤,ErrorPageCustomizer就會生效(定制錯誤的響應(yīng)規(guī)則),就會來到/error請求,就會被BasicErrorController處理
@Value("${error.path:/error}")
private String path = "/error";
// 系統(tǒng)出現(xiàn)錯誤以后來到error請求進行處理;(web.xml注冊的錯誤頁面規(guī)則)
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//默認SpringBoot可以去找到一個頁面? error/404
String errorViewName = "error/" + viewName;
//模板引擎可以解析這個頁面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
.getProvider(errorViewName, this.applicationContext);
if (provider != null) {
//模板引擎可用的情況下返回到errorViewName指定的視圖地址
return new ModelAndView(errorViewName, model);
}
//模板引擎不可用,就在靜態(tài)資源文件夾下找errorViewName對應(yīng)的頁面 error/404.html
return resolveResource(errorViewName, model);
}
1)有模板引擎的情況下:error/狀態(tài)碼。將錯誤頁面命???為 錯誤狀態(tài)碼.html 放在模板引擎文件夾里面的error文件夾下,發(fā)生此狀態(tài)碼的錯誤就會來到對應(yīng)的頁面; 我們可以使用 4xx 和 5xx 作為錯誤頁面的文件名來匹配這種類型的所有錯誤。精確優(yōu)先(優(yōu)先尋找精確的狀態(tài)碼.html) 頁面能獲取的信息:timestamp:時間戳、status:狀態(tài)碼、error:錯誤提示、exception:異常對象、message:異常消息、errors:JSR303數(shù)據(jù)校驗的錯誤都在這里 2)沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態(tài)資源文件夾下找; 3)以上都沒有錯誤頁面,就是默認來到SpringBoot默認的錯誤提示頁面;
1、方式1:自定義異常處理&返回定制json數(shù)據(jù)
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
@ExceptionHandler({UserNotExistException.class})
public Map<String, Object> handleException(Exception e) {
Map<String, Object> map = new HashMap<>();
map.put("code", "user.notexist");
map.put("message", e.getMessage());
return map;
}
}
缺點:沒有自適應(yīng)效果(瀏覽器和客戶端請求返回的都是JSON數(shù)據(jù))
2、轉(zhuǎn)發(fā)到/error進行自適應(yīng)響應(yīng)效果處理
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler({UserNotExistException.class})
public String handleException(Exception e, HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
request.setAttribute("javax.servlet.error.status_code", 500);
map.put("code", "user.notexist");
map.put("message", e.getMessage());
// 轉(zhuǎn)發(fā)到 /error
return "forward:/error";
}
}
SpringBoot默認使用Tomcat作為嵌入式的Servlet容器
方式1:修改和server有關(guān)的配置(ServerProperties【本質(zhì)也是EmbeddedServletContainerCustomizer】)
properties 代碼解讀復(fù)制代碼server.port=8081
server.context‐path=/crud
server.tomcat.uri‐encoding=UTF‐8
//通用的Servlet容器設(shè)置
server.xxx
//Tomcat的設(shè)置
server.tomcat.xxx
方式2:編寫一個EmbeddedServletContainerCustomizer:嵌入式的Servlet容器的定制器,來修改Servlet容器的配置
@Bean //一定要將這個定制器加入到容器中
publicEmbeddedServletContainerCustomizerembeddedServletContainerCustomizer(){
return new EmbeddedServletContainerCustomizer() {
//定制嵌入式的Servlet容器相關(guān)的規(guī)則
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(8083);
}
};
}
由于SpringBoot默認是以jar包的方式啟動嵌入式的Servlet容器來啟動SpringBoot的web應(yīng)用,沒有web.xml文件。 注冊三大組件(Servlet、Filter、Listener)用以下方式: ServletRegistrationBean
@Configuration
public class MyServerConfig {
// 注冊三大組件
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(), "/myServlet");
return registrationBean;
}
}
// 請求 http://localhost:8080/myServlet 就會出現(xiàn)MyServlet中返回的內(nèi)容
FilterRegistrationBean
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
registrationBean.setUrlPatterns(Arrays.asList("/hello", "/myServlet"));
return registrationBean;
}
// 請求 http://localhost:8080/myServlet 就會出現(xiàn)MyFilter的doFilter()中輸出的內(nèi)容
ServletListenerRegistrationBean
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
// 輸出結(jié)果:
contextInitialized---web應(yīng)用啟動
contextDestroyed---web應(yīng)用關(guān)閉 // 這里是在點擊暫停的時候
Tomcat(默認使用)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
// 引入web模塊默認就是使用嵌入式的Tomcat作為Servlet容器;
</dependency>
Jetty(開發(fā)長連接應(yīng)用)
<dependency>
<artifactId>spring‐boot‐starter‐jetty</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
Undertow(不支持JSP)
<dependency>
<artifactId>spring‐boot‐starter‐undertow</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
Docker是一個開源的應(yīng)用容器引擎,是一個輕量級容器技術(shù)。Docker支持將軟件編譯成一個鏡像,然后在鏡像中各種軟件做好配置,將鏡像發(fā)布出去,其他使用者可以直接使用這個鏡像;運行中的這個鏡像稱為容器,容器啟動是非常快速的。
使用Docker的步驟: 1)安裝Docker 2)去Docker倉庫找到這個軟件對應(yīng)的鏡像 3)使用Docker運行這個鏡像,這個鏡像就會生成一個Docker容器 4)對容器的啟動停止就是對軟件的啟動停止
安裝教程可參考:www.runoob.com/docker/maco…
shell
代碼解讀
復(fù)制代碼$ docker info
操作 | 命令 | 說明 |
檢索 | docker search 關(guān)鍵字 eg:docker search redis | 我們經(jīng)常去docker hub上檢索鏡像的詳細信息,如鏡像的TAG |
拉取 | docker pull 鏡像名:tag | :tag是可選的,tag表示標(biāo)簽,多為軟件的版本,默認是latest |
列表 | docker images | 查看所有本地鏡像 |
刪除 | docker rmi image-id | 刪除指定的本地鏡像 |
流程:軟件鏡像(QQ安裝程序)-->運行鏡像-->產(chǎn)生一個容器(正在運行的軟件,運行的QQ)
操作 | 命令 | 說明 |
運行 | docker run --name container-name -d image-name eg:docker run –name myredis –d redis | -name:自定義容器名 -d:后臺運行 image-name:指定鏡像模板 |
列表 | docker ps(查看運行中的容器) | 加上-a可以查看所有容器 |
停止 | docker stop container-name/container-id | 停止當(dāng)前運行的容器 |
啟動 | docker start container-name/container-id | 啟動容器 |
刪除 | docker rm container-id | 刪除指定容器 |
端口映射 | -p 6379:6379 eg:docker run -d -p 6379:6379 --name myredis docker.io/redis | -p: 主機端口(映射到)容器內(nèi)部的端口 ‐d:后臺運行 |
容器日志 | docker logs container-name/container-id |
更多命令可查看:docs.docker.com/engine/refe…
示例(tomcat):
shell 代碼解讀復(fù)制代碼% docker images //查看鏡像列表
% docker search tomcat //搜索鏡像
% docker pull tomcat //拉取鏡像
% docker run --name myTomcat -d tomcat:latest //根據(jù)鏡像啟動容器
% docker ps //查看運行中的容器
------輸出------
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
700a4fa11db6 tomcat:latest "catalina.sh run" 25 seconds ago Up 24 seconds 8080/tcp myTomcat
% docker stop 700a4fa11db6[容器ID] //停止運行中的容器
% docker ps -a //查看所有的容器
------輸出------
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
700a4fa11db6 tomcat:latest "catalina.sh run" 5 minutes ago Exited (143) About a minute ago myTomcat
% docker start 700a4fa11db6[容器ID] //啟動容器
% docker rm 700a4fa11db6[容器ID] //刪除一個容器
% docker run -d -p 8888:8080 tomcat //啟動一個做了端口映射的tomcat
‐d:后臺運行
‐p: 將主機的端口映射到容器的一個端口 主機端口:容器內(nèi)部的端口
------docker ps 輸出------
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8dbc9df132b4 tomcat "catalina.sh run" 19 seconds ago Up 19 seconds 0.0.0.0:8888->8080/tcp eloquent_moore
% dockerlogscontainer‐name/container‐id //查看容器的日志
示例(mysql):
shell 代碼解讀復(fù)制代碼% docker pull mysql
% docker run --name mysql01 -e MYSQL_ROOT_PASSWORD=123456 -d mysql //啟動mysql
------輸出------
c9c10a720ba86f440737503396019c80ad0de88b8ae659e19214d8eda3253481
幾個其他的高級操作:
docker run --name mysql03 ‐v /conf/mysql:/etc/mysql/conf.d ‐e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
把主機的/conf/mysql文件夾掛載到mysql docker容器的/etc/mysql/conf.d文件夾里面
改mysql的配置文件就只需要把mysql配置文件放在自定義的文件夾下(/conf/mysql)
docker run --name some‐mysql ‐e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag --character‐set‐server=utf8mb4 ‐‐collation‐server=utf8mb4 --collation -server=utf8mb4_unicode_ci
指定mysql的一些配置參數(shù)
對于數(shù)據(jù)訪問層,無論是SQL還是NOSQL,Spring Boot默認采用整合Spring Data的方式進行統(tǒng)一處理,添加大量自動配置,屏蔽了很多設(shè)置。引入各種xxxTemplate、xxxRepository來簡化我們對數(shù)據(jù)訪問層的操作。對我們來說只需要進行簡單的設(shè)置即可。 JDBC、MyBatis、JPA
配置:
properties 代碼解讀復(fù)制代碼spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jdbc
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
測試代碼:
@SpringBootTest
class SpringDemo08JdbcApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() {
// 默認使用的是 class com.zaxxer.hikari.HikariDataSource 數(shù)據(jù)源
System.out.println(dataSource.getClass());
}
}
數(shù)據(jù)源的相關(guān)配置都在DataSourceProperties源代碼里面
// 源碼
@ConfigurationProperties(
prefix = "spring.datasource"
)
SpringBoot默認可以支持:org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource、自定義數(shù)據(jù)源類型。
配置文件里增加如下配置:
properties 代碼解讀復(fù)制代碼#spring.datasource.initialization-mode=always 此行已失效,使用下面的
spring.sql.init.mode=always
編寫SQL并放在resources文件夾下面
啟動springboot工程,刷新數(shù)據(jù)庫,可以看到表成功創(chuàng)建(下次啟動還是會創(chuàng)建,所以最好創(chuàng)建完畢后刪除sql文件)
編寫測試查詢代碼
@SpringBootTest
class SpringDemo08JdbcApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from Skynet_test");
System.out.println(list);
// [{id=46, date=2023-06-01, APPversion=1.2.3, uv=123456, tag=gray, platform=Android,
// create_time=2023-06-01, last_modify=2023-06-01, version=1.2}]
}
}
引入依賴
xml 代碼解讀復(fù)制代碼<!--引入自定義數(shù)據(jù)源druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.8</version>
</dependency>
修改配置文件
properties 代碼解讀復(fù)制代碼spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jdbc
spring.datasource.username=root
spring.datasource.password=root1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource // 切換數(shù)據(jù)源
測試代碼
@Test
void contextLoads() {
System.out.println(dataSource.getClass()); // class com.alibaba.druid.pool.DruidDataSource
}
配置生效:
@Configuration
public class DruidConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
// 這樣在配置文件中配置druid的一些屬性就可以生效了
}
引入上方的druid數(shù)據(jù)源 配置文件:
properties 代碼解讀復(fù)制代碼spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jdbc
spring.datasource.username=root
spring.datasource.password=root1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
建表語句:
sql 代碼解讀復(fù)制代碼CREATE TABLE `department` (
`id` int NOT NULL AUTO_INCREMENT,
`departmentName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
CREATE TABLE `employee` (
`id` int NOT NULL AUTO_INCREMENT,
`lastName` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`gender` int DEFAULT NULL,
`d_id` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
創(chuàng)建JavaBean:Employee & Department
@Mapper //指定這是一個操作數(shù)據(jù)庫的mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("insert into department(departmentName) values (#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}
測試驗證:
@RestController
public class DepartmentController {
@Autowired
DepartmentMapper departmentMapper;
@GetMapping("/dept/{id}")
public Department getDepartment(@PathVariable("id") Integer id) {
return departmentMapper.getDeptById(id);
// 測試鏈接:http://localhost:8080/dept/1
// 返回:{"id":1,"departmentName":"開發(fā)部"}
}
@GetMapping("/dept")
public Department insertDepartment(Department department) {
departmentMapper.insertDept(department);
return department;
// 測試鏈接:http://localhost:8080/dept?departmentName=開發(fā)部
// 返回:{"id":1,"departmentName":"開發(fā)部"}
}
}
如果此時數(shù)據(jù)庫里字段是(department_name),查詢結(jié)果就展示不出來名字了:{"id":1,"departmentName":null}。如何開啟駝峰命名法配置?方法是自定義MyBatis的配置規(guī)則,給容器中添加一個ConfigurationCustomizer:
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true); // 開啟駝峰命名
}
};
}
}
另一個問題是,每個mapper上都需要標(biāo)注@Mapper注解,自動掃描配置呢?
@MapperScan(value = "com.example.spring_demo09_mybatis.mapper") // 批量掃描所有的Mapper接口
@SpringBootApplication
public class SpringDemo09MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDemo09MybatisApplication.class, args);
}
}
@Mapper
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
public void insertEmp(Employee employee);
}
mybatis配置文件:
java 代碼解讀復(fù)制代碼<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
java 代碼解讀復(fù)制代碼<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.spring_demo09_mybatis.mapper.EmployeeMapper">
<!-- public Employee getEmpById(Integer id);-->
<select id="getEmpById" resultType="com.example.spring_demo09_mybatis.bean.Employee">
SELECT * FROM employee WHERE id=#{id}
</select>
<!--public void insertEmp(Employee employee);-->
<insert id="insertEmp">
INSERT INTO employee(lastName,email,gender,d_id) VALUES (#{lastName},#{email},#{gender},#{dId})
</insert>
</mapper>
修改Spring配置文件增加如下內(nèi)容:
java 代碼解讀復(fù)制代碼#mybatis
#指定全局配置文件的位置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
#指定sql映射文件的位置
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
測試方法:
java 代碼解讀復(fù)制代碼@GetMapping("/emp/{id}")
public Employee getEmp(@PathVariable("id") Integer id) {
return employeeMapper.getEmpById(id);
// 測試鏈接:http://localhost:8080/emp/1
// 返回:{"id":1,"lastName":"Wang","gender":1,"email":"1111@qq.com","dId":1}
}
使用參考:mybatis.org/spring-boot…
Spring Data 項目的目的是為了簡化構(gòu)建基于 Spring 框架應(yīng)用的數(shù)據(jù)訪問技術(shù),包括非關(guān)系數(shù)據(jù)庫、 Map-Reduce 框架、云數(shù)據(jù)服務(wù)等等,另外也包含對關(guān)系數(shù)據(jù)庫的訪問支持。 SpringData 為我們提供使用統(tǒng)一的API來對數(shù)據(jù)訪問層進行操作,這主要是Spring Data Commons項目來實現(xiàn)的。Spring Data Commons讓我們在使用關(guān)系型或者非關(guān)系型數(shù)據(jù)訪問技術(shù)時都基于Spring提供的統(tǒng)一標(biāo)準,標(biāo)準包含了CRUD(創(chuàng)建、獲取、更新、刪除)、查詢、 排序和分頁的相關(guān)操作。
統(tǒng)一的Repository接口:
提供數(shù)據(jù)訪問模板類 xxxTemplate,如:MongoTemplate、RedisTemplate等
1)、編寫一個bean實體類和數(shù)據(jù)表進行映射,并且配置好映射關(guān)系;
package com.example.spring_demo10_jpa.entity;
import javax.persistence.*;
// 使用JPA注解配置映射關(guān)系
@Entity //告訴JPA這是一個實體類(和數(shù)據(jù)表映射的類)
@Table(name = "tbl_user") // @Table來指定和哪個數(shù)據(jù)表對應(yīng),如果省略默認表名就是user
public class User {
@Id // 代表這是一個主鍵
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增主鍵
private Integer id;
@Column(name = "name", length = 50) // 這是和數(shù)據(jù)表對應(yīng)的一個列
private String name;
@Column // 省略默認列名就是屬性名
private String email;
}
2)、編寫一個Dao接口來操作實體類對應(yīng)的數(shù)據(jù)表(Repository)
// 繼承JpaRepository來完成對數(shù)據(jù)庫的操作
public interface UserRepository extends JpaRepository<User, Integer> {
}
3)、基本的配置
properties 代碼解讀復(fù)制代碼#jpa
#更新或者創(chuàng)建數(shù)據(jù)表結(jié)構(gòu)
spring.jpa.hibernate.ddl-auto=update
#控制臺新鮮事SQL
spring.jpa.show-sql=true
4)、啟動工程,自動生成數(shù)據(jù)表:
5)、測試
@RestController
public class UserController {
@Autowired
UserRepository userRepository;
// @GetMapping("/user/{id}")
// public User getUser(@PathVariable("id") Integer id){
// User user = userRepository.findOne(id);
// return user;
// }
@GetMapping("/user")
public User insertUser(User user){
User save = userRepository.save(user);
return save;
}
}
請求http://localhost:8080/user?name=haha&email=qqqq@qq.com會進行日志輸出: Hibernate: insert into tbl_user (email, name) values (?, ?)
SpringApplication.run(主程序類) 1、 創(chuàng)建SpringApplication對象; 這一步主要是加載并保存所有的 ApplicationContextInitializer 和 ApplicationListener,并獲取到主程序類 2、運行run()方法; 回調(diào)所有的SpringApplicationRunListener的starting、準備環(huán)境、創(chuàng)建ioc容器對象(web環(huán)境容器和普通環(huán)境容器)
1、準備環(huán)境
2、刷新啟動IOC容器
3、回調(diào)容器中所有的ApplicationRunner、CommandLineRunner的run方法
4、監(jiān)聽器SpringApplicationRunListener回調(diào)finished
編寫自動配置:
@Configuration //指定這個類是一個配置類
@ConditionalOnXXX //在指定條件成立的情況下自動配置類生效
@AutoConfigureAfter //指定自動配置類的順序
@Bean //給容器中添加組件
@ConfigurationPropertie結(jié)合相關(guān)xxxProperties類來綁定相關(guān)的配置
@EnableConfigurationProperties//讓xxxProperties生效加入到容器中
自動配置類要能加載,將需要啟動就加載的自動配置類,配置在META‐INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
設(shè)計模式: 啟動器starter只用來做依賴導(dǎo)入;專門寫一個自動配置模塊,啟動器依賴這個自動配置模塊;自定義啟動器名-spring-boot-starter
作者:島雨QA 鏈接:https://juejin.cn/post/7254384256280035388
近項目需求,寫了一個類似百度搜索框的功能。
把代碼整理了一遍,然后分享出來給大家看看,如果有不對的地方請多指教。
實現(xiàn)效果
使用的語言:html,css,JavaScript,jQuery
代碼部分
html部分:
js部分:
全部代碼:
1 wang編輯器效果圖
1、npm安裝
安裝過程比較簡單,不做重復(fù),說一下使用過程遇到的問題
插入hr
import E from 'wangeditor'
mounted () {
const editor = new E('#div1')
const menuKey = 'hrMenuKey'
const { BtnMenu } = E
// 第一,菜單 class ,Button 菜單繼承 BtnMenu class
class HrMenu extends BtnMenu {
constructor (editor) {
// data-title屬性表示當(dāng)鼠標(biāo)懸停在該按鈕上時提示該按鈕的功能簡述
const $elem = E.$(
`<div class="w-e-menu" data-title="分割線">
<i class='w-e-icon-split-line'></i>
</div>`
)
super($elem, editor)
}
// 菜單點擊事件
clickHandler () {
editor.cmd.do('insertHtml', '<hr>')
}
tryChangeActive () {
// 激活菜單
// 1. 菜單 DOM 節(jié)點會增加一個 .w-e-active 的 css class
// 2. this.this.isActive === true
this.active()
// // 取消激活菜單
// // 1. 菜單 DOM 節(jié)點會刪掉 .w-e-active
// // 2. this.this.isActive === false
// this.unActive()
}
}
// 注冊菜單
E.registerMenu(menuKey, HrMenu)
editor.config.placeholder = ''
editor.config.uploadImgServer = '/public/sss/admin.php/ajaxweb/uppic.html'
editor.config.uploadImgMaxSize = 1024 * 1024
editor.config.uploadImgAccept = ['jpg', 'jpeg', 'png', 'gif']
editor.config.height = 300
editor.config.focus = true
editor.config.menus = [
'source',
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'indent',
'lineHeight',
'foreColor',
'backColor',
'link',
'list',
'justify',
'quote',
'image',
'video',
'table',
'undo',
'redo']
editor.create()
}
查看源碼
圖2 查看源碼效果圖
實現(xiàn)目標(biāo):
點擊查看的時候,遮蓋其它的按鈕,防止查看源碼的時候,點擊了別的按鈕進行了誤操作。
新加的菜單默認都是在最后全屏前邊,分割線還可以,但是查看源碼我個人還是習(xí)慣在最前邊,使用的是jquery prepend感覺更加簡單一些,代碼如下:
import $ from 'jquery'
mounted () {
$(document).ready(function () {
$('#div1 .w-e-toolbar').prepend('<div class=\'w-e-menu\' style=\'z-index:991;\' data-title=\'查看源碼\'><a style=\' display:block;width:100%;height:100%;\' ct=1 id=\'viewsource\'><i class=\'fa fa-file-text-o\'></i></a></div>')
$(document).delegate('#viewsource', 'click', function () {
var editorHtml = editor.txt.html()
// console.log($(this).attr('ct'))
if (parseInt($(this).attr('ct')) === 1) {
$('#div1 .w-e-toolbar').prepend('<div id=\'zzc\' style=\'position:absolute;left:0;top:0;z-index:99;background-color:rgba(0,0,0,0.5);width:100%;height:40px;\'></div>')
$(this).parent().parent().parent().find('.w-e-text').css('width', $('.w-e-text').width() + 'px')
editorHtml = editorHtml.replace(/</g, '<').replace(/>/g, '>').replace(/ /g, ' ')
$(this).attr('ct', '2')
$(this).css({'background-color': '#EEE'})
} else {
editorHtml = editor.txt.text().replace(/</ig, '<').replace(/>/ig, '>').replace(/ /ig, ' ')
$(this).attr('ct', '1')
$(this).parent().parent().parent().find('.w-e-text').css('width', '100%')
$(this).parent().parent().find('#zzc').remove()
$(this).css({'background-color': '#FFF'})
}
editor.txt.html(editorHtml)
// editor.change && editor.change()
})
})
}
說明:
彈出的窗口,點擊關(guān)閉無效不能關(guān)閉
圖3 彈出菜單無法關(guān)閉
如圖,點擊關(guān)閉的時候會切換到了網(wǎng)絡(luò)圖片的表單,這應(yīng)該是菜單同級別,遮蓋了關(guān)閉的按鈕,所以我們要寫css樣式加上z-index使關(guān)閉的菜單在其他的上層;
css代碼
.w-e-icon-close{
display:block;
z-index:999999 !important;
}
2、cdn引用js
我是下載到本地的
圖4 多圖上傳F12查看效果
圖片上傳,如果選擇多個圖片,可能會出現(xiàn)以上圖片的情況style="font-size: 14px; font-family: "Helvetica Neue", Helvetica, "PingFang SC", Tahoma, Arial, sans-serif; max-width: 100%;"
復(fù)制html發(fā)現(xiàn)是如下代碼:
<img src="/public/upload/image/20211201/111.jpg" style="font-size: 14px; font-family: & quot;Helvetica Neue& quot;, Helvetica, & quot;PingFang SC& quot;, Tahoma, Arial, sans-serif; max-width: 100%;">
很明顯style內(nèi)的 css樣式,不是應(yīng)該出現(xiàn)的,沒有找到在哪里修改。
雙引號換成了& quot;如果不用查看源碼,頁面直接顯示沒有問題,但是查看源碼,切換回來以后,會發(fā)現(xiàn)圖片亂了,所以查看源碼的時候,需要把& quot;替換成空。
以下使用jquery實現(xiàn)自定義菜單(查看源碼、插入分割線):
import $ from 'jquery'
mounted () {
$(document).ready(function () {
// 查看源碼菜單
$('#div1 .w-e-toolbar').prepend('<div class=\'w-e-menu\' style=\'z-index:991;\' data-title=\'查看源碼\'><a style=\' display:block;width:100%;height:100%;\' ct=1 id=\'viewsource\'><i class=\'fa fa-file-text-o\'></i></a></div>')
// 分割線菜單
var menl=$('#div1 .w-e-toolbar .w-e-menu').length;
$("#div1 .w-e-toolbar .w-e-menu").eq(menl-1).before('<div class=\'w-e-menu\' data-title=\'分割線\'><a style=\'display:block;width:100%;height:100%;\' id=\'splitline\'><i class=\'w-e-icon-split-line\'></i></a></div>')
// 查看源碼點擊
$(document).delegate('#viewsource', 'click', function () {
var editorHtml = editor.txt.html()
// console.log($(this).attr('ct'))
if (parseInt($(this).attr('ct')) === 1) {
$('#div1 .w-e-toolbar').prepend('<div id=\'zzc\' style=\'position:absolute;left:0;top:0;z-index:99;background-color:rgba(0,0,0,0.5);width:100%;height:40px;\'></div>')
$(this).parent().parent().parent().find('.w-e-text').css('width', $('.w-e-text').width() + 'px')
editorHtml = editorHtml.replace(/</g, '<').replace(/>/g, '>').replace(/ /g, ' ').replace(/& quot;/g, '')
$(this).attr('ct', '2')
$(this).css({'background-color': '#EEE'})
} else {
editorHtml = editor.txt.text().replace(/</ig, '<').replace(/>/ig, '>').replace(/ /ig, ' ')
$(this).attr('ct', '1')
$(this).css('border', '0px solid #DDD')
$(this).parent().parent().parent().find('.w-e-text').css('width', '100%')
$(this).parent().parent().find('#zzc').remove()
$(this).css({'background-color': '#FFF'})
}
editor.txt.html(editorHtml)
// editor.change && editor.change()
})
//分割線插入hr點擊
$(document).delegate('#splitline', 'click', function () {
editor.cmd.do('insertHtml', '<hr>');
});
})
}
如果我們把插入分割線的代碼單獨拿出來,只是下面幾行,相對使用官方提供的方法會簡單很多
// 插入分割線菜單
var menl=$('#div1 .w-e-toolbar .w-e-menu').length;
$('#div1 .w-e-toolbar .w-e-menu').eq(menl-1).before('<div class=\'w-e-menu\' data-title=\'分割線\'><a style=\'display:block;width:100%;height:100%;\' id=\'splitline\'><i class=\'w-e-icon-split-line\'></i></a></div>')
// 分割線插入 hr點擊事件
$(document).delegate('#splitline', 'click', function () {
editor.cmd.do('insertHtml', '<hr>');
});
說明:
editorHtml = editorHtml.replace(/</g, '<').replace(/>/g, '>').replace(/ /g, ' ').replace(/& quot;/g, '')
附錄一下jquery after,before,append,prepend用法:
向class=w-e-toolbar的div頭部插入html
$(" .w-e-toolbar").prepend("<div >頭部插入html</div>")
向class=w-e-toolbar的div底部插入html
$(" .w-e-toolbar").append("<div >底部插入html</div>")
向class=w-e-toolbar的div之前插入html
$(" .w-e-toolbar").before("<div >之前插入html</div>")
向class=w-e-toolbar的div之后插入html
$(" .w-e-toolbar").after("<div >后面插入html</div>")
可以做一下延伸:像我們上邊用到的向第幾個元素之后或者之前插入代碼。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。