該登錄功能需要實現的需求如下:
1、輸入用戶名密碼,如果驗證通過,進入首頁,並顯示登錄的用戶名
2、如果驗證不通過,則重新進入登錄頁面,並顯示“用戶名密碼錯誤”
3、如果未經登錄,不能直接訪問首頁等靜態資源,也不能直接調用Controller層的方法,都需要轉發到登錄頁面,並提示“沒有權限,請先登錄”
具體實現如下:
1、定義登錄頁面
<!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>
<!-- @{}的形式是鏈接資源文件或者訪問某個請求路徑 -->
<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}" rel="stylesheet">
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<!--此處要寫成method="POST",不能寫成th:method="POST"-->
<form class="form-signin" action="dashboard.html" th:action="@{/user/login}" method="POST">
<img class="mb-4" 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>
<span style="color:red" th:text="${msg}" ></span>
<label class="sr-only" th:text="#{login.username}">Username</label>
<!--要寫上name="username",否則訪問LoginController方法時,沒有傳username會報錯-->
<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>
<!--要寫成th:href="@{/index(l='zh_CN')}",而不能寫成th:href="@{/login.html(l='zh_CN')}",
因為直接定位到靜態資源的話是不會走自己定義的區域解析器的,
另外thymeleaf模板引擎是用中括號中放key=value的形式傳參數-->
<a class="btn btn-sm" th:href="@{/index(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index(l='en_US')}">English</a>
</form>
</body>
</html>
2、定義Controller處理登錄請求
package com.myself.controller;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Controller
public class LoginConcroller {
// @RequestMapping
// @GetMapping
// @DeleteMapping
// @RequestMapping
@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中加入登錄用戶名,用於在成功的首頁中展示
session.setAttribute("loginUser",username);
//此處用重定向,會被我們定義的視圖解析器解析,尋找對應dashboard.html
return "redirect:/main.html";
}else{
//登錄失敗,設置失敗信息並返回登錄頁面
map.put("msg","用戶名密碼錯誤");
//由於此處不是重定向,所以相當於根據字符串直接去templates下找login.html
//所以不能寫成返回"/"或者"/index.html",否則會報找不到頁面
return "login";
}
}
}
3、定義登錄成功后進入的首頁
展示登錄用戶名
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
4、定義攔截器用於在調用一些功能前先判斷用戶是否登錄,如果未登錄,則轉發到登錄頁面
package com.myself.component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object obj = request.getSession().getAttribute("loginUser");
if(obj == null){
//沒有登錄,設置錯誤信息並轉發到登錄頁面
request.setAttribute("msg","沒有權限請先登陸");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
//已登錄,放行
return true;
}
}
}
5、在定義的配置類中以@Bean的形式加入WebMvcConfigurerAdapter組件,其中需要實現這個組件的
addInterceptors(InterceptorRegistry registry) 方法,在這里指定我們定義的攔截器攔截哪些請求,不攔截哪些請求
package com.myself.config;
import com.myself.component.LoginHandlerInterceptor;
import com.myself.component.MyLocaleResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
// @Override
// public void addViewControllers(ViewControllerRegistry registry) {
// registry.addViewController("/index").setViewName("login");
// }
//
// //注冊攔截器
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
//
// registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
// .excludePathPatterns("/index.html","/","/user/login","/webjars/**","/**/*.css", "/**/*.js");
// }
//使用WebMvcConfigurerAdapter來擴展SpringMVC的功能
//所有的WebMvcConfigurerAdapter都會生效
//注意要寫在標有@Configuration的類中,要在方法上標上@Bean注解
@Bean
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter webMvcConfigurerAdapter = new WebMvcConfigurerAdapter(){
//視圖空值器,用於定義訪問哪些路徑時定位到哪些視圖
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//訪問http://localhost:8080/ 和 http://localhost:8080/index.html都會尋找靜態資源下的templates/login.html
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
//訪問"/main.html"會尋找靜態資源下的templates/login.html
registry.addViewController("/main.html").setViewName("dashboard");
}
//注冊攔截器,用於攔截用戶需要先登錄才能訪問資源
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/webjars/**","/**/*.css", "/**/*.js");
}
};
return webMvcConfigurerAdapter;
}
//定義區域解析器,解析國際化中英文切換
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
測試:
1、訪問Controller中的方法會被轉發到登錄頁面

2、訪問css靜態資源文件可以訪問

3、未登錄直接訪問首頁,會被轉發到登錄頁面

4、用戶名密碼輸入錯誤,會被轉發到登錄頁面,並提示錯誤信息

5、用戶名密碼輸入正確,進入首頁,變顯示登錄用戶名

若有理解不到之處,望指教!
