Web 專案 tiger 之3 登入與攔截
阿新 • • 發佈:2019-02-14
本文導讀
登 錄
UserController
package com.lct.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession; /** * Created by Administrator on 2018/7/28 0028. * 使用者控制器層 */ @Controller @RequestMapping("user") public class UserController { /** * 使用者登入 * * @param username 賬號 * @param password 密碼 * @param model 使用者設值返回頁面 * @param httpSession 設值登入的 使用者session * @return 登入成功 必須重定向,/userList的對映在 com.lct.component.MyWebMvcConfigurerAdapter 類中配置好了 * @PostMapping ("login") 相當於 @RequestMapping(value = "login",method = RequestMethod.POST) 的簡寫 * 同理還有 @GetMapping 、@PutMapping 、@DeleteMapping */ @PostMapping("login") public String login(String username, String password, Model model, HttpSession httpSession) { /** * 當賬號不為空,密碼為 123456 時,模擬登入成功,否則失敗時重定向返回登入頁面 * 重定向時 要以 "/" 開頭表示應用根地址 */ if (!StringUtils.isEmpty(username) && "123456".equals(password)) { httpSession.setAttribute("userName", username); return "redirect:/userList"; } else { //登入失敗仍然重定向到登入頁面,index是之後要配置的請求路徑之一 return "redirect:/index"; } } }
WebMvcConfigurer
package com.lct.component; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * Created by Administrator on 2018/7/29 0029. * WebMvc 擴充套件配置類 * Spring Boot 2.0以前可以使用 繼承 WebMvcConfigurerAdapter 抽象類,但2.0版本以後,此類過時了不再推薦使用 * 解決方案是 直接實現 WebMvcConfigurer介面即可,因為 WebMvcConfigurerAdapter類同樣是實現 WebMvcConfigurer介面 */ @Configuration public class MyWebMvcConfigurer implements WebMvcConfigurer { /** * 新增檢視跳轉控制器 * 當請求為 localhost:8080/tiger/userList 時。自動對映到 類路徑下的templates下的 userList.html頁面 * 當請求為 localhost:8080/tiger/index 時。自動對映到 類路徑下的templates下的 index.html頁面 * * @param registry */ @Override public void addViewControllers(ViewControllerRegistry registry) { /** 往前端 Thymeleaf 模板引擎時,開頭不要加 "/" ,因為它預設配置的字首就是: * spring.thymeleaf.prefix=classpath:/templates/ */ registry.addViewController("/userList").setViewName("userList"); registry.addViewController("/index").setViewName("index"); } }
html 頁面
- <form>標籤的action值指向後臺的登入地址;同時加了一行登入錯誤時的提示資訊
<!DOCTYPE html> <!--xmlns寫上之後 Thymeleaf就會有提示,更加方便--> <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 如果沒有匯入bootstrap的webjars包,則不要使用th:href覆蓋掉原來靜態資料夾目錄下的檔案--> <link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet"> <!-- Custom styles for this template 理解原來之後就知道,下面th:href取值就是覆蓋掉預設的href屬性值,好處是可以不和前端人員程式碼發生衝突 thymeleaf的@{}表示式會自動加上"/應用上下文路徑"字首,這就避免了傳統jsp中的${request.context.path}這種操作了 --> <link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet"> </head> <body class="text-center"> <form class="form-signin" 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> <!--登入失敗提示:判斷,如果存在 message 訊息,不為null也不為空,則顯示--> <p style="color: red" th:text="${message}" th:if="${not #strings.isEmpty(message)}"></p> <label class="sr-only" th:text="#{login_name}">Username</label> <input type="text" name="username" class="form-control" th:placeholder="#{login_name}" placeholder="Username" required="" autofocus=""> <label class="sr-only" th:text="#{login_password}">Password</label> <input type="password" name="password" class="form-control" placeholder="Password" required="" th:placeholder="#{login_password}"> <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_button}">Sign in</button> <p class="mt-5 mb-3 text-muted">© 2017-2018</p> <a class="btn btn-sm" th:href="@{/(l=zh_CN)}">中文</a> <a class="btn btn-sm" th:href="@{/(l=en_US)}">English</a> </form> </body> </html>
執行測試
攔 截
- 登入做完之後,就應該做攔截了,要不然,直接輸入登入以外的後臺地址,照樣可以進入
LoginHandlerInterceptor
package com.lct.component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Administrator on 2018/7/29 0029.
* 登入攔截器
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("userName");
/**
* 已經成功登入,則放行;否則重定向到登入頁面
*/
System.out.println("----" + user + " ::: " + request.getRequestURL());
if (user == null) {
response.sendRedirect("/tiger/index");
return false;
}
return true;
}
}
註冊攔截器
- spring boot 2.x依賴的spring 5.x版本,相對於spring boot 1.5.x依賴的spring 4.3.x版本而言,針對資源的攔截器初始化時有區別
- 使用spring 5.x時,靜態資源也會執行自定義的攔截器,因此在配置攔截器的時候需要指定排除靜態資源的訪問路徑
Spring Boot 2.0 之前
package com.lct.component;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* Created by Administrator on 2018/7/29 0029.
* WebMvc 擴充套件配置類
* Spring Boot 2.0以前可以使用 繼承 WebMvcConfigurerAdapter 抽象類,但2.0版本以後,此類過時了不再推薦使用
* 解決方案是 直接實現 WebMvcConfigurer介面即可,因為 WebMvcConfigurerAdapter類同樣是實現 WebMvcConfigurer介面
*/
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
/**
* 新增檢視跳轉控制器
* 當請求為 localhost:8080/tiger/userList 時。自動對映到 類路徑下的templates下的 userList.html頁面
* 當請求為 localhost:8080/tiger/index 時。自動對映到 類路徑下的templates下的 index.html頁面
*
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
/** 往前端 Thymeleaf 模板引擎時,開頭不要加 "/" ,因為它預設配置的字首就是:
* spring.thymeleaf.prefix=classpath:/templates/
*/
registry.addViewController("/userList").setViewName("userList");
registry.addViewController("/index").setViewName("index");
}
/**
* 註冊攔截器
* .addPathPatterns("/**"):表示攔截整個應用中的所有請求
* .excludePathPatterns("/user/login", "/index"):表示排除這些規則的請求不做攔截,因為 /index是去登入頁的,/user/login是使用者提交登入的,所以都不能攔截
* 如果是 Spring Boot2以前,宣告攔截哪些請求,不攔截哪些請求,這樣就可以了,對於所有靜態資源目錄下的靜態資源,它是不會去攔截的
* 即 classpath:/META‐INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/"下的資源都不會被攔截
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index", "/user/login");
}
}
Spring Boot 2.0 之後
/**
* 註冊攔截器
* 而Spring Boot 2及以後開始,預設情況下,Spring Boot 會攔截所有請求,包括靜態資源請求
* 所以這樣寫時,執行之後所有靜態資源都會被攔截
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index", "/user/login");
}
}
- 因為靜態資源在後臺被攔截了
----null ::: http://localhost:8080/tiger/webjars/bootstrap/4.0.0/css/bootstrap.css
----null ::: http://localhost:8080/tiger/asserts/css/signin.css
----null ::: http://localhost:8080/tiger/asserts/img/bootstrap-solid.svg
- 所以現在只需要把它們排除在攔截的路徑外即可
/**
* 註冊攔截器
* 而Spring Boot 2及以後開始,預設情況下,Spring Boot 會攔截所有請求,包括靜態資源請求
* 所以要將靜態資源路徑排除在攔截的請求路徑之內
* /webjars/**:所有 http://localhost:8080/tiger/asserts/** 不再攔截 tiger是應用上下文路徑
* /asserts/**:所有 http://localhost:8080/tiger/asserts/** 不再攔截 tiger是應用上下文路徑
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index", "/user/login")
.excludePathPatterns("/webjars/**", "/asserts/**");
}
自定義資源對映
- classpath:/META‐INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/ ,當靜態資源位於 Spring Boot 預設約定的這4個目錄下時,則都可以使用在註冊攔截器的同時將靜態資源排除在外即可,如下的 asserts 與 webjars
/**
* 註冊攔截器
* 而Spring Boot 2及以後開始,預設情況下,Spring Boot 會攔截所有請求,包括靜態資源請求
* 所以要將靜態資源路徑排除在攔截的請求路徑之內
* /webjars/**:所有 http://localhost:8080/tiger/asserts/** 不再攔截 tiger是應用上下文路徑
* /asserts/**:所有 http://localhost:8080/tiger/asserts/** 不再攔截 tiger是應用上下文路徑
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index", "/user/login")
.excludePathPatterns("/webjars/**", "/asserts/**");
}
- 假如現在有另外的靜態資源目錄不是位於約定的那4個目錄下,而是位於類路徑下的其它目錄怎麼辦呢?如下所示的“uploadFiles”目錄,這個時候再使用上面的方式是不行的,因為uploadFiles本身就不是在約定的靜態目錄下
/**
* 自定義資源對映 addResourceHandlers
* registry.addResourceHandler("/uploadFiles/**"): 新增靜態資源對映路徑,和上面的 .excludePathPatterns 原來是一樣的
* addResourceLocations("classpath:/uploadFiles/"):新增靜態資源路徑,即說明自定義的靜態資源目錄在哪裡
* 效果就是:訪問 http://localhost:8080/tiger/uploadFiles/** 時都會被當做靜態資源而不被攔截,tiger是應用上下檔案
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploadFiles/**").addResourceLocations("classpath:/uploadFiles/");
}
執行測試
- 在登入後的 userList.html 頁面,將登入的使用者賬號獲取並顯示出來
<!-- 獲取session中的值,替換登入的使用者賬號-->
<a class="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" th:text="${session.userName}">Company name</a>
---後臺攔截如下----
2018-07-29 11:52:24.211 INFO 13904 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 11 ms
----null ::: http://localhost:8080/tiger/userList
----華安 ::: http://localhost:8080/tiger/userList