使用Spring Boot
- 創(chuàng)建Spring Boot應(yīng)用草戈,選擇我們需要的模塊。
- Spring Boot已經(jīng)默認(rèn)將這些場景給配置好了炕婶。只需要在配置文件中指定少量配置就可以運行起來姐赡。
- 自己編寫業(yè)務(wù)代碼。
自動配置原理:
這個場景Spring Boot幫我們配置了什么柠掂?能不能修改项滑?能修改哪些配置?能不能擴(kuò)展涯贞?……
xxxAutoConfiguration:幫我們給容器中自動配置組件枪狂。
xxxxProperties:配置類來封裝配置文件中的內(nèi)容。
Spring Boot對靜態(tài)資源的映射規(guī)則
- 所有的/webjars/**宋渔,都去classpath:/META-INF/resources/webjars/找資源州疾。
webjars:以jar包的反式引入靜態(tài)資源。webjars官網(wǎng)
例如:jquery的webjars
jquery的webjars.png
訪問他的路徑為:
localhost:8080/webjars/jquery/3.5.1/jquery.js - "/**"訪問當(dāng)前項目下的任何資源(靜態(tài)資源的文件夾)
類路徑指:main下的java文件夾或resources文件夾
"classpath:/META-INF/resources/":類路徑下的/META-INF/resources/
"classpath:/resources/":類路徑下的/resources/
"classpath:/static/":類路徑下的/static/ 一般放css,js等
"classpath:/public/":類路徑下的/public/
"/":當(dāng)前項目的根目錄路徑
localhost:8080/xxxx ----> 沒人處理就會去靜態(tài)資源中去找對應(yīng)的資源
- 歡迎頁:靜態(tài)資源文件夾下的所有index.html頁面皇拣。被"/**"映射严蓖。
- 所有的**/favicon.ico 都是在靜態(tài)資源文件下找。命名為:favicon.ico
########自己定義靜態(tài)資源文件夾
spring.web.resources.static-locations=classpath:/hello/
########spring.web.resources是一個數(shù)組氧急,可以寫多個文件夾颗胡,用逗號分隔開
模板引擎
JSP、Velocity吩坝、Freemarker毒姨、Thymelef(Spring Boot推薦使用的)、……
Spring Boot推薦的模板引擎:Thymelef
語法更簡單钉寝、功能更強大弧呐。
使用方法
1. 引入Thymelef:
<!--引入spring-boot中的thymeleaf模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2. 使用Thymelef中的&語法
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enableSpringElCompiler;
private boolean renderHiddenMarkersBeforeCheckboxes;
private boolean enabled;
private final ThymeleafProperties.Servlet servlet;
private final ThymeleafProperties.Reactive reactive;
只要我們把html放在classpath:/templates/鸳址,thymeleaf就能自動渲染。
使用:
- 導(dǎo)入thymeleaf的命名空間
<html lang="en" xmlns:th="http://www.thymeleaf.org">
- 使用thymeleaf的語法:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>成功</title>
</head>
<body>
<h1>成功</h1>
<!--th:text 將div中的文本內(nèi)容設(shè)置為-->
<div th:text="${hello}">這是顯示歡迎信息</div>
</body>
</html>
- 語法規(guī)則
- th:text 改變當(dāng)前元素里面的文本內(nèi)容泉懦。
可以使用th:任意html屬性。使用th:任意屬性來替換原生對應(yīng)屬性疹瘦。
thymeleaf標(biāo)簽.png - 表達(dá)式語法崩哩?
變量表達(dá)式:$ {...}
1.獲取對象的屬性、調(diào)用方法
2.使用內(nèi)置對象
3.內(nèi)置的工具對象
選擇變量表達(dá)式:\* {...}:和${…}在功能上是一樣
補充:配合 th:object=${" "}使用
消息表達(dá)式:#{...}:獲取國際化內(nèi)容
鏈接網(wǎng)址表達(dá)式:@{…}:定義url鏈接
@{localhost:8080/order/buy(name=${obj.name,type=true})}
片段表達(dá)式:~{…}
<div th:insert="~{commons :: main}">…</div>
表達(dá)式支持:
1.字面量
2.文本操作
字符串連接:+
文本替換:|The name is ${name}|
3.數(shù)學(xué)運算
二進(jìn)制運算符:+ 言沐、 - 邓嘹、 \* 、 / 险胰、 %
4.負(fù)號(一元運算符):-
5.布爾運算
二進(jìn)制運算符:and汹押、or
布爾否定(一元運算符):!、not
6.比較和相等運算符
比較運算符:> 起便、< 棚贾、> =、< =(gt榆综、lt妙痹、ge、le)
相等運算符:==鼻疮、!=(eq怯伊、ne)
7.條件運算符:(三元運算)
If-then:(if) ? (then)
If-then-else:(if) ? (then) :(else)
Default:(value) ?: (defaultvalue)
8.特殊符號
啞操作符:_
測試一:
//控制層
//查出用戶數(shù)據(jù),在頁面展示
@RequestMapping("/success")
public String success(Map<String, Object> map) {
map.put("hello", "<h1>你好</h1>");
map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
return "success";
}
//頁面
<!DOCTYPE html>
<!--聲明命名空間 xmlns:th="http://www.thymeleaf.org" -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>成功</title>
</head>
<body>
<!--對應(yīng)<h1>你好<h1>-->
<div th:text="${hello}"></div>
<!--用utext會轉(zhuǎn)義特殊字符及html標(biāo)簽中的<h1>你好<h1>-->
<div th:utext="${hello}"></div>
<br>
<!--遍歷數(shù)組 ["zhangsan","lisi","王五",3]-->
<!--th:each=""每次遍歷都會生成一個標(biāo)簽 3個h4-->
<h4 th:each="user:${users}" th:text="${user}"></h4>
<br>
<h4>
<!--th:each=""每次遍歷都會生成一個標(biāo)簽 3個span-->
<span th:each="user:${users}"> [[${user}]] </span>
</h4>
</body>
</html>
測試二:改變thymeleaf文件的默認(rèn)位置判沟,外加一些spring Boot中thymeleaf的屬性
########設(shè)置日志的級別
logging.level.cn.fantuan=trace
########設(shè)置控制臺打印的日志格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} | %highlight(%-5level) | %boldYellow(%thread) %logger === %highlight(%msg%n)
########設(shè)置靜態(tài)資源的文件路徑
spring.web.resources.static-locations=classpath:/webapp/
#########使用了thymeleaf之后mvc的視圖解析器就沒有好大的作用了
#########設(shè)置視圖解析器的前綴
#spring.mvc.view.prefix=/pages/
#########設(shè)置視圖解析器的后綴
#spring.mvc.view.suffix=.html
########設(shè)置thymeleaf可以解析的視圖名稱的逗號分隔列表,指的是html文件名稱
#spring.thymeleaf.view-names=success,*
########關(guān)閉頁面緩存
spring.thymeleaf.cache=false
########構(gòu)建URL時附加到查看名稱的前綴耿芹。
spring.thymeleaf.prefix=classpath:/templates/pages/
########構(gòu)建URL時附加到查看名稱的后綴。
spring.thymeleaf.suffix=.html
########啟用模板緩存挪哄。
#spring.thymeleaf.cache = true
########在呈現(xiàn)模板之前檢查模板是否存在吧秕。
#spring.thymeleaf.check-template = true
########檢查模板位置是否存在。
#spring.thymeleaf.check-template-location = true
########Content-Type值中燥。
#spring.thymeleaf.content-type = text / html
########啟用MVC Thymeleaf視圖分辨率寇甸。
#spring.thymeleaf.enabled = true
########模板編碼。
#spring.thymeleaf.encoding = UTF-8
########應(yīng)該從解決方案中排除的視圖名稱的逗號分隔列表疗涉。
#spring.thymeleaf.excluded-view-names =
########應(yīng)用于模板的模板模式拿霉。另請參見StandardTemplateModeHandlers。
#spring.thymeleaf.mode = HTML5
########在構(gòu)建URL時預(yù)先查看名稱的前綴咱扣。
#spring.thymeleaf.prefix = classpath:/ templates /
########構(gòu)建URL時附加到查看名稱的后綴绽淘。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表闹伪。/ templates / #在構(gòu)建URL時先查看名稱的前綴沪铭。
#spring.thymeleaf.view-names =
########構(gòu)建URL時附加到查看名稱的后綴壮池。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表杀怠。/ templates / #在構(gòu)建URL時先查看名稱的前綴椰憋。
#spring.thymeleaf.view-names =
########構(gòu)建URL時附加到查看名稱的后綴。
#spring.thymeleaf.suffix = .html
########鏈中模板解析器的順序赔退。
#spring.thymeleaf.template-resolver-order =
########可以解析的視圖名稱的逗號分隔列表橙依。
#spring.thymeleaf.view-names =
#########控制器
package cn.fantuan.springboot02.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Arrays;
import java.util.Map;
@Controller
public class HelloController {
//控制層
//查出用戶數(shù)據(jù),在頁面展示
@RequestMapping("/suc")
public String success(Map<String, Object> map) {
System.out.println("success");
map.put("hello", "<h1>你好</h1>");
map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
return "success";
}
@RequestMapping("/vip")
public String vip(Map<String, Object> map) {
System.out.println("vip");
map.put("hello", "<h1>你好</h1>");
map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
return "vip/vip";
}
@RequestMapping("/user")
public String user(Map<String, Object> map) {
System.out.println("user");
map.put("hello", "<h1>你好</h1>");
map.put("users", Arrays.asList("zhangsan","lisi","王五",3));
return "user/user";
}
}
文件目錄層級關(guān)系
擴(kuò)展Spring MVC:
<!--請求處理-->
<mvc:view-controller path="/hello" view-name="success"/>
<!--攔截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello"/>
<bean></bean>
</mvc:interceptor>
</mvc:interceptors>
編寫一個配置類(@Configuration),是WebMvcConfigurer類型的硕旗。不能標(biāo)準(zhǔn)@EnableWebMvc注解 窗骑。
既保留了所有的自動配置,也能用我們來擴(kuò)展配置漆枚。
package cn.fantuan.springboot03webrestcrud.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//使用WebMvcConfigurer可以用來擴(kuò)展SpringMvc的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//瀏覽器發(fā)送/hellos請求创译,來到success
//可以直接用這種方法來處理只是跳轉(zhuǎn)頁面的請求
registry.addViewController("/hellos").setViewName("success");
}
}
原理:
- WebMvcAutoConfiguration是SpringMVC的自動配置類
- 在做其他自動配置時
@Configuration(proxyBeanMethods = false)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
//從容器中獲取所有的WebMvcConfigurer賦值到configurers里面
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
//一個參考實現(xiàn)褐奴,將所有的WebMvcConfigurer相關(guān)的配置都一起調(diào)用
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
}
}
- 容器中所有的WebMvcConfigurer都會一起起作用旱眯。
- 我們自己寫的配置類也會被調(diào)用。
效果:
SpringMVC的自動配置和擴(kuò)展配置都會起作用财喳。
全面接管SpringMVC:
Spring Boot對SpringMVC的自動配置不需要了碘橘,所有的都是我們自己配互订。
我們只需要加一個@EnableWebMvc注解在配置類即可。
不推薦使用@EnableWebMvc來全面接管痘拆。
package cn.fantuan.springboot03webrestcrud.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//Spring Boot自動配置的SpringMVC就失效了仰禽,全部由自己配置
@EnableWebMvc
//使用WebMvcConfigurer可以用來擴(kuò)展SpringMvc的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//瀏覽器發(fā)送/hellos請求,來到success
//可以直接用這種方法來處理只是跳轉(zhuǎn)頁面的請求
registry.addViewController("/hellos").setViewName("success");
}
}
國際化
- 編寫國際化配置文件
- 使用ResourceBundleMessageSource管理國際化資源文件
- 在頁面中使用fmt.message取出國際化資源文件內(nèi)容
步驟:
-
編寫國際化配置文件纺蛆,抽取頁面需要顯示的國際化信息
國際化.png - springBoot自動配置好了國際化資源文件的組件
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = {"messageSource"},search = SearchStrategy.CURRENT)
@AutoConfigureOrder(-2147483648)
@Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class})
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = new Resource[0];
public MessageSourceAutoConfiguration() {}
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
protected static class ResourceBundleCondition extends SpringBootCondition {
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap();
protected ResourceBundleCondition() {}
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
ConditionOutcome outcome = (ConditionOutcome)cache.get(basename);
if (outcome == null) {
outcome = this.getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) {
Builder message = ConditionMessage.forCondition("ResourceBundle", new Object[0]);
String[] var4 = StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename));
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
String name = var4[var6];
Resource[] var8 = this.getResources(context.getClassLoader(), name);
int var9 = var8.length;
for(int var10 = 0; var10 < var9; ++var10) {
Resource resource = var8[var10];
if (resource.exists()) {
return ConditionOutcome.match(message.found("bundle").items(new Object[]{resource}));
}
}
}
//指定自己寫的國際化配置文件吐葵,去掉語言國家代碼的
return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll());
}
private Resource[] getResources(ClassLoader classLoader, String name) {
String target = name.replace('.', '/');
try {
return (new PathMatchingResourcePatternResolver(classLoader)).getResources("classpath*:" + target + ".properties");
} catch (Exception var5) {
return MessageSourceAutoConfiguration.NO_RESOURCES;
}
}
}
}
########配置文件設(shè)置國際化配置文件路徑
spring.messages.basename=i18n.login
- 去頁面獲取國際化的值
########行內(nèi)寫法
[[#{login.username}]]
########普通寫法
th:text="#{login.password}"
th:placeholder="#{login.code}"
出現(xiàn)亂碼?桥氏?
效果:根據(jù)瀏覽器語言設(shè)置的信息切換了國際化
原理:
國際化Locale(區(qū)域信息對象)温峭;LocaleResolver(獲取區(qū)域信息對象)
@Bean
@ConditionalOnMissingBean
public LocaleResolver localeResolver() {
if (this.webProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.webProperties.getLocale());
} else if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
Locale locale = this.webProperties.getLocale() != null ? this.webProperties.getLocale() : this.mvcProperties.getLocale();
localeResolver.setDefaultLocale(locale);
return localeResolver;
}
}
//默認(rèn)的就是根據(jù)請求頭帶來的區(qū)域信息獲取Locale進(jìn)行國際化
點擊鏈接卻換國際化
package cn.fantuan.springboot04weblayuimini.component;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
/**
* 可以在鏈接上攜帶區(qū)域信息
*/
public class MyLocaleResolver implements LocaleResolver {
//解析區(qū)域信息
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String l = httpServletRequest.getParameter("l");
//設(shè)置區(qū)域信息為系統(tǒng)默認(rèn)的
Locale locale=Locale.getDefault();
//判斷鏈接是否帶由區(qū)域信息
if(!StringUtils.isEmpty(l)){
String[] split = l.split("_");
//帶由區(qū)域信息就覆蓋系統(tǒng)默認(rèn)的區(qū)域信息
locale = new Locale(split[0], split[1]);
}
return locale;
}
//設(shè)置區(qū)域信息
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
//給容器中添加自己的區(qū)域信息
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
頁面代碼:
<a th:href="@{/login.html(l='en_US')}" th:text="#{login.forgetPassword}" class="forget-password">忘記密碼?</a>