文章目录
七、小项目
1.准备工作
将写好的登录页面login.html放入静态资源文件夹内,准备作为首页,并且设置一个原首页。
login登录代码会贴在第二步的最后
dashboard登录后界面的代码会贴在第四步最后
list员工列表界面贴在第五步最上
2.设置首页
首先我们设置了一个空页面index.html作为我们的首页,然后通过他去转换到我们的login页面
设置页面的转换
@RequestMapping({"/index","/"})
public String index(){
return "login";
}
注
在这里不加@ResponseBody的原因是,此注解的作用是把return的数据以json数据类型返回到HTTP response body中(一般用于异步交互),而不会被解析为页面跳转行为,如果我们加上了此注解,则会直接显示login这五个char,所以在这里不能加
但是如果我们每次进行login页面访问的都是都需要刷新一遍数据,未免有点太麻烦了,所以可以addViewController添加视图映射,让启动的时候自动就映射到login页面。
然后不要忘记把刚才写的注释掉
// 所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean
public WebMvcConfigurer webMvcConfigurer() {
WebMvcConfigurer webMvcConfigurer = new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
}
};
return webMvcConfigurer;
}
然后在这里我们还要修改一下资源引用,平时SpringBoot是默认从静态资源文件夹获取到的,在这里我们在引用一下webjars,用th:href的好处就是:如果有一天项目的访问名变了,就比如我们是在application.properties中加了个server.context-path=/xx,也就是说,给这个域名加了个前缀,如果我们不用th:href,他是不会帮我们加上的,但是用了,就会默认把/xx加上,防止我们出404的问题
而这里填入th:href的具体方法是:
找到前面link href的路径在webjars的目录下,添加进来
然后运行一下确保无误
3.国际化
首先先在resource目录下创建国际化配置文件
切换到Resource Bundle模式
接着在properties文件内配置上
spring.messages.basename=i18n.login
编写之后SpringBoot会自动配置好管理国际化资源文件的组件。
接下来要让我们的页面获取到国际化的值
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<label class="sr-only" th:text="#{login.username}">Username</label>
<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>
修改之后运行,会发现虽然页面接收到了我们国际化的信息,但是却都是乱码
这时我们只需要给properties设置编码格式,并且自动转为ASCII码即可
之后运行,简易的页面就有了
接下来我们要通过一个超链接去转换国际化的选项,放在一个想要放置的位置即可
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
之后我们再运行首页,会发现点击超链接,地址名会改变成对应区域的链接,由于我们还使用了thymeleaf,所以都不需要去用问号代替参数了,直接用小括号,小括号内的值就是value,但这时我们还无法做到通过链接来达到国际化,所以我们就应该写一个区域信息解析器
/**
* 可以连接上携带区域信息
*/
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[] split = l.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
当我们写完区域信息解析器后发现,并没有生效,是因为在LocaleResover的底层源代码中,我们发现有一个@ConditionalOnMissingBean,它的意思是在我们没有区域信息解析器的时候才会去添加,而我们的底层代码中,又有一个AcceptHeaderLocaleResolver会被默认使用到,而且也在自动配置中,所以会默认直接使用这个区域信息解析器,而无法使用到我们手写的。
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.mvc",
name = {"locale"}
)
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
} else {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}
}
所以在配置类中将组件手动添加进去
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
之后就可以运行了,我们发现,国际化的登录页面就完成了
附上登录页面代码
<!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.0.0/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" 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>
<label class="sr-only" th:text="#{login.username}">Username</label>
<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">© 2019-2020</p>
<a class="btn btn-sm" )}">中文</a>
<a class="btn btn-sm" )}">English</a>
</form>
</body>
</html>
4.登录功能
开发期间为了方便实时查看修改的结果:
1.禁用模板引擎的缓存,可以在application.properties中加上
#禁用模板引擎缓存
spring.thymeleaf.cache=false
2.页面修改以后Ctrl+F9,重新编译
首先在login.html中使用thymeleaf模拟一个以post形式的login的登录请求
然后对我们的login请求写一个登录验证方法
@Controller
public class LoginController {
@PostMapping(value = "/user/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Map<String,Object> map){
if (!StringUtils.isEmpty(username) && "123456".equals(password)) {
//登陆成功
return "dashboard";
}else {
map.put("msg", "用户名或者密码错误");
return "login";
}
}
}
这样就可以和方法映射上了。
但是我们不能让表单重复提交,所以可以重定向到一个main页面,使用redirect:/main.html然后把页面通过视图映射,映射到我们刚刚的dashboard即可。
@Bean
public WebMvcConfigurer webMvcConfigurer() {
WebMvcConfigurer webMvcConfigurer = new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
};
return webMvcConfigurer;
}
@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) && "123456".equals(password)) {
session.setAttribute("loginUser",username);
//登陆成功
return "redirect:/main.html";
}else {
map.put("msg", "用户名或者密码错误");
return "login";
}
}
}
然后我们登录,发现无法识别username,这是因为我们没有在login内指明我们传给map的key值,也就是username,所以要在下面声明一下username和password
但是如果我们password输入错误了,也需要给予server端一个提示说输入错误了,所以要在login中,在Please Sign in这一行加上
<!--判断计算,当if成立,其他标签才能生效,原理是标签的优先级-->
<p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
这时我们已经可以登录到dashboard页面了,但是这时,有一个问题,我们可以通过地址跨过验证界面,跳到登录后的界面,这时,我们就需要设置一个拦截器了,把登录过的username放进一个HTTPSession的对象中存起来,其他的用户会被拦截。
书写拦截器代码
/**
* 登录检查,没有登录的用户无法进入登录后的页面
*/
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","You have no authority,Please login again");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}
else {
//已登录,放行请求
return true;
}
}
@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 {
}
}
在WebMvcConfigurerAdapter中注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器,静态资源已经被SpringBoot做完了静态资源映射,所以不用排除掉了
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
这里稍微啰嗦一下,一定要注意 / 这里作者被坑过很多次,经常报405的错误
dashboard代码
<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<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" rel="stylesheet" th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.css}">
<!-- Custom styles for this template -->
<link href="asserts/css/dashboard.css" rel="stylesheet" th:href="@{/assert/css/dashboard.css}">
<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 class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-home">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<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-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
Customer
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Year-end sale
</a>
</li>
</ul>
</div>
</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.CRUD-员工列表
<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<html lang="en">
<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" rel="stylesheet">
<!-- Custom styles for this template -->
<link 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 class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-home">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
Customers
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<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-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Year-end sale
</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2>Section title</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,001</td>
<td>Lorem</td>
<td>ipsum</td>
<td>dolor</td>
<td>sit</td>
</tr>
<tr>
<td>1,002</td>
<td>amet</td>
<td>consectetur</td>
<td>adipiscing</td>
<td>elit</td>
</tr>
<tr>
<td>1,003</td>
<td>Integer</td>
<td>nec</td>
<td>odio</td>
<td>Praesent</td>
</tr>
<tr>
<td>1,003</td>
<td>libero</td>
<td>Sed</td>
<td>cursus</td>
<td>ante</td>
</tr>
<tr>
<td>1,004</td>
<td>dapibus</td>
<td>diam</td>
<td>Sed</td>
<td>nisi</td>
</tr>
<tr>
<td>1,005</td>
<td>Nulla</td>
<td>quis</td>
<td>sem</td>
<td>at</td>
</tr>
<tr>
<td>1,006</td>
<td>nibh</td>
<td>elementum</td>
<td>imperdiet</td>
<td>Duis</td>
</tr>
<tr>
<td>1,007</td>
<td>sagittis</td>
<td>ipsum</td>
<td>Praesent</td>
<td>mauris</td>
</tr>
<tr>
<td>1,008</td>
<td>Fusce</td>
<td>nec</td>
<td>tellus</td>
<td>sed</td>
</tr>
<tr>
<td>1,009</td>
<td>augue</td>
<td>semper</td>
<td>porta</td>
<td>Mauris</td>
</tr>
<tr>
<td>1,010</td>
<td>massa</td>
<td>Vestibulum</td>
<td>lacinia</td>
<td>arcu</td>
</tr>
<tr>
<td>1,011</td>
<td>eget</td>
<td>nulla</td>
<td>Class</td>
<td>aptent</td>
</tr>
<tr>
<td>1,012</td>
<td>taciti</td>
<td>sociosqu</td>
<td>ad</td>
<td>litora</td>
</tr>
<tr>
<td>1,013</td>
<td>torquent</td>
<td>per</td>
<td>conubia</td>
<td>nostra</td>
</tr>
<tr>
<td>1,014</td>
<td>per</td>
<td>inceptos</td>
<td>himenaeos</td>
<td>Curabitur</td>
</tr>
<tr>
<td>1,015</td>
<td>sodales</td>
<td>ligula</td>
<td>in</td>
<td>libero</td>
</tr>
</tbody>
</table>
</div>
</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>
需求:
<1>RestfulCRUD
URI(路径格式):/资源名称/资源标识 HTTP请求方式区分对资源CRUD操作
<2>请求
实现:
<1>员工列表
先把要跳转的list页面在dashboard.html中找到位置,然后用thymeleaf模板引擎定义RequestMapping属性,方便后面设置请求能够顺利到达页面
然后写一个映射方法能通过点击Customer到达list.html的方法
我们在return的时候不需要写上templates就是因为在ThymeleafProperties配置中已经为我们默认配置了这个路径头。
@Controller
public class EmployeeController {
@Autowired
EmployeeDao employeeDao;
//查询员工返回列表页面
@GetMapping("/emps")
public String list(Model model){
Collection<Employee> all = employeeDao.getAll();
// 存放在请求域中
model.addAttribute("emps", all);
//thymeleaf默认自动拼串
//classpath:/templates/xxxx.html
return "emp/list";
}
}
运行之后,点击刚才设置的Employee Manage,发现可以成功到达页面
<2>thymeleaf公共页面元素抽取
1.抽取片段
使用
th:fragment=""来抽取公共片段
假设在div标签中,设置了这个属性
<div th:fragment="temp">
Hello world
</div>
2.引入片段
引入片段有两种方法
~{templatename:selector}
模板名::选择器
~{templatename::fragmentname}
模板名::片段名
<div>
<th:insert="~{footer :: copy}">
</div>
3.实践(1,2)
现在要把dashboard的顶部栏,给list页面使用
这是dashboard的顶部栏
这是list的顶部栏,现在我们要实现,使用上面介绍的公共元素抽取和引用的方法,来实现统一,同时也节省了写代码的时间
,首先来抽取元素
从dashboard中找到了顶部栏的源代码,并且加上我们的fragment属性和属性名topbar
然后再去list页面找它的顶部栏进行替换
替换完成,开始测试
测试成功
注:
1.insert的功能片段在div标签中
2.引入功能的标签除了insert还有两种
th:insert :将公共片段整个插入到声明引入的元素中
th:replace : 将声明引入的元素替换为公共部分
th:include :将被引入的片段的内容含进这个标签中
然后我们用replace 的方法替换侧边栏,并且使用id选择器进行属性的引入
首先找到dashboard的侧边栏,标记id=“sidebar”
然后去list页面
找到对应的sidebar
去除52-174行然后进行替换,替换完成之后进行测试
测试成功
4.参数化的片段签名
现在我们发现,虽然已经成功引入了公共的模板,但是并没有高亮,然后我们来设置页面高亮,可以发现,只需要在对应的属性标签上使用active属性,就可以实现选项高亮,但是我们在真正点入页面的时候,大部分的选项卡应该是只有鼠标点上去才会变成高亮,所以我们现在将要实现这个功能
我们在1 2中声明th:fragment中都是只标记模板名,现在可以填入两个参数,那么在这个片段中就可以使用 这两个参数,然后在模板引用的时候也可以通过设置的两个参数进行导入。但是在声明fragment的时候也可以不生命具体的参数,而引入的时候也可以直接声明+引用
接下来我们在templates文件夹下创建一个commons目录,用来存放公共模板,并且新建一个html,在里面注入公共模板的代码
<div th:replace="~{commons/bar :: topbar}"></div>
<div th:replace="~{commons/bar :: #sidebar}"></div>
然后将模板引入代码对应的填到dashboard和list对应位置中
重新进行测试,发现没有问题
现在要实现进入到Employee Manage界面之后可以通过点击dashboard能够返回到原来的emps界面,我们来到bar进行thymeleaf模板引擎的引入
然后重新测试,没毛病。
现在实现选项卡的高亮功能,让只有鼠标在选中的时候才会高亮,原理就是,因为高亮是设置到a标签的class属性上,所以只需要用th:class引入判断即可
先来设置dashboard
<div th:replace="commons/bar::#sidebar(activeUrl='main.html')"></div>
然后设置list
<div th:replace="~{commons/bar :: #sidebar(activeUrl='emps')}"></div>
重新进行a标签的书写,这时我们还没有指明activeUrl是干什么的
于是来到bar页面
<a class="nav-link active" th:class="${activeUrl == 'main.html'?'nav-link active':'nav-link'}"
<a class="nav-link active" th:class="${activeUrl=='emps'?'nav-link active':'nav-link'}"
来到对应的地方去设置
<3>遍历取出员工数据
来到list页面
删除假数据tbody标签,然后自己手写一个tbody
我们的目的是通过tbody在里面放的一个遍历,达到输出所有员工数据的功能。
<tr th:each="emp:${emps}">
<td th:text="${emp.id}"></td>
<td>[[${emp.lastName}]]</td>
<td th:text="${emp.email}"></td>
<td th:text="${emp.gender}==1?'male':'female'"></td>
<td th:text="${emp.department.departmentName}"></td>
<td th:text="${emp.birth}"></td>
</tr>
然后顺手在上面标记一下列名就好
<tr>
<th>#</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>departmentName</th>
<th>birth</th>
</tr>
测试一下
测试成功。
然后我们做一点优化,我们已经发现员工的生日信息和我们平时的格式不太一样,现在我们通过
来完成日期格式化
<td th:text="${#dates.format(emp.birth,'yyyy-MM-dd HH:mm')}"></td>
更改成功。
<4>crud
4.1 Add
我们通过在td标签内添加按钮来实现对员工列表的crud操作。
首先添加按钮对应刚才添加的每一行的员工信息,到循环体中
<td>
<button class="btn btn-sm btn-primary">edit</button>
<button class="btn btn-sm btn-danger">delete</button>
</td>
然后再增加一个员工添加的按钮在list里
下面我们需要通过点击员工添加按钮来到一个新的页面完成业务的实现,所以,要把员工添加变成一个button,因为是a标签,所以发送get请求,来到emp界面
<h2 a class="btn btn-sm btn-success" href="emp" th:href="@{/emp}">员工添加</a></h2>
添加页面,以list页面做修改当做添加页面
然后我们就可以通过点击员工添加来到一个新的添加页面了,而添加的表格模板来自于
<form>
<div class="form-group">
<label>LastName</label>
<input type="text" class="form-control" placeholder="zhangsan">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="zhangsan@atguigu.com">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="1">
<label class="form-check-label">男</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="0">
<label class="form-check-label">女</label>
</div>
</div>
<div class="form-group">
<label>department</label>
<select class="form-control">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input type="text" class="form-control" placeholder="zhangsan">
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
然后我们测试一下可以成功。
下面我们要新添加一个功能,让点完员工添加之后能够通过显示部门然后再添加员工
首先要把department的信息以集合的方式用get请求传到add界面内,让add界面能够顺利使用
@GetMapping("/emp")
public String toAddEmp(Model model) {
//连接到员工添加页面,然后再之前显示部门信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("depts", departments);
return "emp/add";
}
我们要显示出部门的信息,就要使用到option属性,并且直接遍历每一个部门的Name
用thymeleaf模板去遍历我们的department的信息,然后用th:text显示departmentName信息,供添加的时候去选择。
然后点击页面下面的添加,来进行添加请求,添加请求,就要用action属性,以post请求去请求到。
//SpringMVC自动将请求参数和入参对象的属性一一绑定,要求了请求参数的名字和javaBean入参的对象里面的属性名是一样的
@PostMapping("/emp")
public String addEmp(Employee employee){
//redirect:重定向 代表当前项目路径
//forward:转发 获取路径,转发器
return "forward:/emps";
}
然后回到add页面找到表单去进行提交属性的定义,(name,email…)
然后回来我们的EmployeeController.java去进行保存
@PostMapping("/emp")
public String addEmp(Employee employee){
System.out.println("The message:"+employee);
//保存
employeeDao.save(employee);
//redirect:重定向 代表当前项目路径
//forward:转发 获取路径,转发器
return "redirect:/emps";
}
切记:日期格式一定要对,否则405
4.2 Edit
我们的Edit操作类似于Add操作,但是接下来有一个难点
我们的id在遍历的过程中是在不断变化的,所以无法直接在进行请求的时候直接标注,只能用拼接的方法进行请求。请求路径必然是/emp,而后面带的变量id就要使用{id}进行请求了,然后我们来写页面跳转的代码
//来到修改页面,查出当前员工,在页面回显
//获取请求路径下的参数,使用PathVariable
@GetMapping("/emp/{id}")
public String toEdit(@PathVariable("id") Integer id,Model model) {
Employee employee = employeeDao.get(id);
model.addAttribute("emp", employee);
//部门列表的选择实现
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("depts", departments);
return "emp/add";
}
现在为了能够方便修改,所以让我们在add界面要修改的对应地方加上th:value表示选中内容即可,比如
th:value="${emp.id}"
其中,在遍历阶段,要写成
<option th:selected="${dept.id==emp.department.id}" th:each="dept:${depts}" th:value="${dept.id}" th:text="${dept.departmentName}" >1</option>
在二选一的时候要用
<input class="form-check-input" type="radio" name="gender" value="0" th:checked="${emp.gender==0}">
修改完了之后重新测试Edit按钮发现成功
但是发现添加又出了问题,因为这是二合一页面
所以接下来要这样
在刚才所有添加的方便修改的地方加上
${emp!=null}?
页面做好之后接下来要发送修改请求
因为只有在Edit的时候才会修改,所以也要加一个判断,形似上边的修改,但是这次直接用了th:if
<input type="hidden" name="_method" value="put" th:if="emp!=null"/>
然后在后端写好put请求修改后的跳转页面,不然会报405,说不支持put请求,因为我们的表单只支持get post
//员工修改,也应该提交员工id
@PutMapping("/emp")
public String updateEmp(Employee employee){
System.out.println("update:"+employee);
employeeDao.save(employee);
return "redirect:/emps";
}
这时候我们发现Console 的id=null,是因为我们没有把无法修改的id值进行返回,所以要默认进行返回
<input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}"/>
4.3 Delete
首先和Edit一样,针对员工id值发送对应的delete操作,以字符串拼接和delete请求去发送
然后来到后台去写delete请求的跳转
//员工删除
@DeleteMapping("/emp/{id}")
public String DeleteEmp(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
这时候我们发现按钮变为form表单了,并且测试成功
在这里 crud操作也就完成了