所用Spring Boot源碼版本爲2.2.6
0x01.默認訪問首頁
- 達到沒有具體制定資源的情況下,默認訪問首頁。
1.Spring MVC方式:
- 在控制器類中,做一個資源映射:
@RequestMapping({"/","/index.html"})
public String index(){
return "login";
}
2.Spring Boot方式:
- 在自定義的配置類中,增加一個視圖解析器。
- 細節:在2.x版本的Spring Boot中mvc的配置類去實現
WebMvcConfigurer
接口,Spring Boot會自動將其中的解析器加入到容器中。
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/").setViewName("login");
registry.addViewController("/login.html").setViewName("login");
}
}
0x02.引用jar包中的靜態資源
- 使用thymeleaf表達式中的
@{}
修改相應標籤的href
屬性,指向webjars中相應的資源。
<link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}">
- 也可以使用
static
文件夾中的靜態資源。
<img class="mb" src="../asserts/img/bootstrap-solid.svg"
th:href="@{/asserts/img/bootstrap-solid.svg}" >
0x03.實現國際化
1.國際化配置文件:
- 抽取頁面中需要使用國際化的信息,寫在配置文件中。
2.使用ResourceBundleMessageSource管理國際化資源文件:
- SpringBoot自動配置好了管理國際化資源文件的組件。
- 差看國際化組件的自動配置類
MessageSourceAutoConfiguration
源碼:
- 說明,國際化配置文件的基礎名是
messages
,如果我們的配置文件直接放在類路徑下叫messages.properties,那麼Spring Boot就會自動幫我們配置,不需要自己進行配置。 - 如果自己進行配置,只需要Spring Boot的配置文件中指明就可以了。
3.頁面獲取國際化信息的值:
- 使用thymeleaf中的
#{}
語法獲取國際化的值。
Message Expressions: #{...}
- input輸入框不能使用th:text取值,text是標籤裏面的內容,input輸入框是字節數,沒有標籤體,需要使用 thymeleaf的行內表達式,雙中括號裏面寫表達式。
<p>Hello, [[${session.user.name}]]!</p>
- 這樣瀏覽器會根據語言信息進行解析。
4.解決亂碼:
- 全局設置默認自動轉碼。
5.點擊鏈接實現國際化:
- Spring Boot默認的是根據請求頭帶來的區域信息獲取Locale進行國際化。
- 如果需要達到點擊鏈接實現國際化,那麼我們不能使用Spring Boot的默認配置,需要自己進行配置,我們可以自定義一個區域信息解析器,並實現
LocaleResolver
接口。 - 在按鈕處添加請求:
<a class="btn btn-sm" th:href="@{/(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/(l='en_US')}">English</a>
//可以在鏈接上面攜帶區域信息
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String l = httpServletRequest.getParameter("l");
// 獲取系統默認的區域信息
Locale locale = Locale.getDefault();
// 如果參數帶了區域信息,則使用參數的
if (!StringUtils.isEmpty(l)) {
String[] s = l.split("_");
locale = new Locale(s[0], s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
- 在mvc的配置類裏面添加一個組件:
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
- 查看一下效果:
0x04.登錄攔截器
1.登錄Controller:
- 如果登錄成功,將用戶信息存入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)&&"atfwus".equals(password)){
//登錄成功,信息存入session
session.setAttribute("loginUser", username);
return "redirect:/main.html";
}else{
//登錄失敗
map.put("msg","用戶名或密碼錯誤!!!");
return "login";
}
}
}
2.編寫一個攔截器類:
- 編寫一個普通類實現HandlerInterceptor接口。
- 我們需要在接口調用之前攔截請求判斷用戶是否登陸,所以這裏需要使用 preHandle 方法,在裏面編寫寫驗證邏輯,最後返回 true 或者 false,確定請求是否合法。
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null) {
// 未登錄,返回登錄頁面
request.setAttribute("msg","請先登錄!!!");
request.getRequestDispatcher("/login.html").forward(request,response);
} else {
// 如果session裏有user,表示該用戶已經登陸,放行請求
return true;
}
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 {
}
}
3.配置攔截器類:
- 在mvc配置類中註冊自定義攔截器,添加攔截路徑和排除攔截路徑。
addPathPatterns("/**")
攔截所有的請求excludePathPatterns(“xxx”)
排除不需要攔截的請求。
//註冊攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/login.html","/","/asserts/**","/webjars/**","/user/login");
}
- 在這裏,攔截了除了登錄頁面
login.html
,默認頁面/
,靜態資源/asserts/**
,/webjars/**
的所有頁面。 - 我們可以測試到,在沒有登錄的情況下,直接訪問其它頁面會被攔截。
0x05.公共頁面元素抽取
- 利用thymeleaf對頁面的公共進行抽取。
1.抽取公共頁面:
- 使用
th:fragment=""
聲明被抽取的部分。
<div th:fragment="headr">
<div>//...
</div>
2.引入公共片段
-
th:insert:將公共片段整個插入到聲明引入的元素中。
~{templatename::fragmentname}
:模板名::片段名。~{templatename::selector}
:模板名::選擇器。- insert的公共片段在div標籤中,如果使用th:insert等屬性進行引入,可以不用寫
~{}
,行內寫法可以加上:[[~{}]];[(~{})]
。
-
th:replace:將聲明引入的元素替換爲公共片段。
-
th:include:將被引入的片段的內容包含進這個標籤中。
<footer th:fragment="headr">
ATFWUS
</footer>
引入方式
<div th:insert="footer :: headr"></div>
<div th:replace="footer :: headr"></div>
<div th:include="footer :: headr"></div>
效果1
<div>
<footer>
ATFWUS
</footer>
</div>
效果2
<footer>
ATFWUS
</footer>
效果3
<div>
ATFWUS
</div>
0x06.錯誤處理
1.Spring Boot 默認處理錯誤的機制
- Spring Boot遇到錯誤時返回一個默認的錯誤頁面,這個頁面包含了這些信息:
-
在
ErrorMvcAutoConfiguration
類中,進行了錯誤的自動配置,往容器中添加了以下組件。DefaultErrorAttributes
組件:幫我們在頁面共享信息;BasicErrorController
組件:處理默認/error請求;- E
rrorPageCustomizer
組件:出現錯誤以後來到error請求進行處理; DefaultErrorViewResolver
組件:一但系統出現4xx或者5xx之類的錯誤;ErrorPageCustomizer
就會生效(定製錯誤的響應規則);就會來到/error請求;就會被BasicErrorController處理;響應頁面,具體去哪個頁面是由DefaultErrorViewResolver解析得到的;
2.定製錯誤頁面:
- 有模板引擎的情況下;error/狀態碼; 【將錯誤頁面命名爲 錯誤狀態碼.html 放在模板引擎文件夾裏面的 error文件夾下】,發生此狀態碼的錯誤就會來到 對應的頁面;
-
我們可以使用4xx和5xx作爲錯誤頁面的文件名來匹配這種類型的所有錯誤,精確優先(優先尋找精確的狀態碼.html);
-
頁面能獲取的信息;
- timestamp:時間戳
- status:狀態碼
- error:錯誤提示
- exception:異常對象
- message:異常消息
- errors:JSR303數據校驗的錯誤都在這裏
-
- 沒有模板引擎(模板引擎找不到這個錯誤頁面),靜態資源文件夾下找;
- 以上都沒有錯誤頁面,就是默認來到SpringBoot默認的錯誤提示頁面;
3.定製錯誤的json數據:
- 將數據轉發到/error進行自適應響應效果處理。
@ExceptionHandler(UserNotExistException.class)//自定義異常
public String handleException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//傳入我們自己的錯誤狀態碼 4xx 5xx
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user.notexist");
map.put("message","出錯了!!!");
request.setAttribute("ext",map);
//轉發到/error
return "forward:/error";
}
- 出現錯誤以後,會來到/error請求,會被
BasicErrorController
處理,響應出去可以獲取的數據是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)規定的方法); - 如果我們要將數據攜帶出去,可以編寫一個ErrorController的實現類(或者編寫AbstractErrorController的子類),放到容器中,頁面上能用的數據,或者是json返回能用的數據都是通過errorAttributes.getErrorAttributes得到;容器中DefaultErrorAttributes.getErrorAttributes();默認進行數據處理的;
//給容器中加入我們自己定義的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("msg2","信息");
return map;
}
}
ATFWUS --Writing By 2020–04-28