准备工作
页面downloadboostrap的官方实例页面,方便练习
资源来自:https://getbootstrap.com/docs/4.3/examples/
资源的目录如下:
1.controller层
package com.changyue.springbootresetfucrud.controller;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
import java.util.Map;
/**
* @program: spring-boot-restful-crud
* @description: 用户控制器
* @author: YuanChangYue
* @create: 2019-08-13 17:59
*/
@Controller
public class LoginController {
/**
* 用户登录
*
* @param username 用户名 默认测试 123
* @param password 密码 默认测试 123
* @param map map
* @param httpSession session
* @return 页面名称
*/
@PostMapping("/user/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Map<String, Object> map, HttpSession httpSession) {
if ("123".equals(username) && "123".equals(password)) {
//将用户名放入session中,拦截器会根据这判断是否登录,从而进行拦截
httpSession.setAttribute("loginUser", username);
//防止表单的重复提交
return "redirect:/main.html";
} else {
//错误信息
map.put("msg", "密码或者账号错误");
return "login";
}
}
}
2.拦截器
package com.changyue.springbootresetfucrud.component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @program: spring-boot-restful-crud
* @description: 登录拦截器
* @author: YuanChangYue
* @create: 2019-08-13 17:59
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
/**
* controller 之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获得登录凭证
Object loginUser = request.getSession().getAttribute("loginUser");
//是否登录过
if (loginUser == null) {
//没有登录 拦截下来 返回登录界面
request.setAttribute("msg", "没有权限,请登录!");
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
} else {
//放行
return true;
}
}
}
3. 自定义SpringMVC 配置类
根据官方的文档
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration
class of type WebMvcConfigurer
but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
, or ExceptionHandlerExceptionResolver
, you can declare a WebMvcRegistrationsAdapter
instance to provide such components.
主要关键点:
- 编写一个配置类,需要加上
@Configuration
注解, - 需要继承
WebMvcConfigurer
接口 - 不能有
@EnableWebMvc
注解
package com.changyue.springbootresetfucrud.config;
import com.changyue.springbootresetfucrud.component.LoginHandlerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* @program: spring-boot-restful-crud
* @description: SpringMVC 配置类 视图和拦截器等注册
* @author: YuanChangYue
* @create: 2019-08-13 17:59
*/
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Bean
public WebMvcConfigurer WebMvcConfigurer() {
return new WebMvcConfigurer() {
/**
* 添加视图映射
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
/**
* 添加拦截器
* 除了登录界面,首页和静态资源
* 其他资源进行拦截
* 意图是验证用户是否在登录的情况下进去内部
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/user/login", "/asserts/**", "/webjars/**");
}
};
}
}
4. 页面
登录页面 login.html
<!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/4.3.1/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:href="@{/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" th:placeholder="#{login.username}" class="form-control" name="username" placeholder="Username"
required=""
autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" class="form-control" th:placeholder="#{login.password}" name="password"
placeholder="Password" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me">[[#{login.rememer}]]
</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="@{/templates/login.html(l='zh_CH')}">中文</a>
<a class="btn btn-sm" th:href="@{/templates/login.html(l='en_US')}">English</a>
</form>
</body>
</html>
内部控制台 dashboard.html
<!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>Dashboard Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.3.1/css/bootstrap.css} " rel="stylesheet">
<!-- Custom styles for this template -->
<link href="asserts/css/dashboard.css" th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
<style type="text/css">
/* Chart.js */
@-webkit-keyframes chartjs-render-animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
@keyframes chartjs-render-animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
.chartjs-render-monitor {
-webkit-animation: chartjs-render-animation 0.001s;
animation: chartjs-render-animation 0.001s;
}
</style>
</head>
<body>
<nav th:insert="commons/bar::topnav"></nav>
<div class="container-fluid">
<div class="row">
<nav th:insert="commons/bar::sidebar(active='Dashboard')"></nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;">
<div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
<div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div>
</div>
<div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
<div style="position:absolute;width:200%;height:200%;left:0; top:0"></div>
</div>
</div>
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group mr-2">
<button class="btn btn-sm btn-outline-secondary">Share</button>
<button class="btn btn-sm btn-outline-secondary">Export</button>
</div>
<button class="btn btn-sm btn-outline-secondary dropdown-toggle">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
This week
</button>
</div>
</div>
<canvas class="my-4 chartjs-render-monitor" id="myChart" width="1076" height="454" style="display: block; width: 1076px; height: 454px;"></canvas>
</main>
</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" ></script>
<script type="text/javascript" src="asserts/js/popper.min.js" ></script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js" ></script>
<!-- Icons -->
<script type="text/javascript" src="asserts/js/feather.min.js" ></script>
<script>
feather.replace()
</script>
<!-- Graphs -->
<script type="text/javascript" src="asserts/js/Chart.min.js" ></script>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
datasets: [{
data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
lineTension: 0,
backgroundColor: 'transparent',
borderColor: '#007bff',
borderWidth: 4,
pointBackgroundColor: '#007bff'
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
}
}]
},
legend: {
display: false,
}
}
});
</script>
</body>
</html>
5. 实现效果
登录页面
登录错误密码
登录错误提示
登录成功
直接登录
直接登录提示