一.解决index.html访问
  
在SpringBoot中默认访问的首页是静态资源文件夹下的index.html,无法被Thymeleaf模板引擎解析,因此我们可以定义一个controller将默认请求定位到模板引擎下的index.html:

     /*让SpringBoot可以查找到我们当前真实的index.html,而不是默认静态资源文件夹下的,因为静态资源文件夹下的
* index.html将无法被模板引擎解析*/
@RequestMapping({"/", "/index.html"})
public String index() {
return "index";
}

  --但是我们一直使用这样一个方法来解决资源映射的问题显得十分麻烦,我们可以使用自动以ViewCOntroller的方法来进行请求映射:

 package com.zhiyun.springboot.web_restfulcrud.config;

 import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /**
* @author : S K Y
* @version :0.0.1
* 扩展SpringMVC的功能
*/
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter { //所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器中
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
String[] all = {
"/", "/index", "index.html"
};
for (String content : all) {
registry.addViewController(content).setViewName("index");
}
}
};
}
}

二.登录界面的国际化
  在以往的SpringMVC开发中,需要完成以下步骤:
  1.编写国际化配置文件
  2.使用ResourcesBundleMessageSource来管理国际化资源文件
  3.在页面使用fmt:message取出国际化的内容
  在SpringBoot中完成国际化配置:
  1.编写国际化配置文件,抽取页面所需要显示的国际化内容

  2.SpringBoot自动配置好了管理国际化资源文件的组件

     /**
* Comma-separated list of basenames (essentially a fully-qualified classpath
* location), each following the ResourceBundle convention with relaxed support for
* slash based locations. If it doesn't contain a package qualifier (such as
* "org.mypackage"), it will be resolved from the classpath root.
*/
private String basename = "messages";      //我们的的配置文件可以放在类路径下的classpath:messages.properties中
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();    
if (StringUtils.hasText(this.basename)) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(this.basename)));
}
if (this.encoding != null) {
messageSource.setDefaultEncoding(this.encoding.name());
}
messageSource.setFallbackToSystemLocale(this.fallbackToSystemLocale);
messageSource.setCacheSeconds(this.cacheSeconds);
messageSource.setAlwaysUseMessageFormat(this.alwaysUseMessageFormat);
return messageSource;
}

  --指定基础名:  # 指定基础名 spring: messages: basename: i18n.login 
  --页面获取国际化文件的值:

     <body class="text-center">
<form class="form-signin" action="dashboard.html">
<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" class="form-control" placeholder="Username" required="" autofocus=""
th:placeholder="#{login.username}">
<label class="sr-only" th:text="#{login.password}"> Password</label>
<input type="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.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>

  --修改文件编码防止乱码:

  3.实现中英文自行切换的功能:
  国际化Locale(区域信息对象):LocaleResolver 获取区域信息对象:

         @Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties
.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
}

  --默认的区域信息解析器是根据请求头带来的区域信息获取locale来进行国际化:

  --编写自定义的LocaleResolver,我们可以在请求参数中携带当前的地域信息:

             <a class="btn btn-sm" th:href="@{/index.html(language=zh_CN)}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(language=us_EN)}">English</a>
 package com.zhiyun.springboot.web_restfulcrud.component;

 import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale; /**
* @author : S K Y
* @version :0.0.1
* 我们可以在连接上携带区域信息
*/
public class MyLocaleResolver implements LocaleResolver {
private Logger logger = LoggerFactory.getLogger(this.getClass()); @Override
public Locale resolveLocale(HttpServletRequest request) {
String language = request.getParameter("language");
logger.debug("当前的区域信息: " + language);
Locale locale = null;
if (!StringUtils.isEmpty(language)) {
String[] all = language.split("_");
locale = new Locale(all[1], all[0]);
logger.debug("locale: " + locale);
} else {
locale = Locale.getDefault(); //获取系统默认的
}
return locale;
} @Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { }
}

  --将自定义的LocaleResolver添加到Spring容器中

     //使用自定义的LocaleResolver
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}

三.实现登录功能
  1.在开发期间,为方便开发,我们可以实现禁用缓存,实现热部署:在springBoot配置文件中使用spring.thymeleaf.cache=fasle禁用缓存,而后我们在修改代码之后可以使用ctrl+F9实现重新编译
  2.登录错误消息的显示:

     @PostMapping("/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("message", "用户名密码错误");
return "index";
}
}
             <!--只有当错误消息存在时,才显示-->
<p style="color: red" th:text="${message}" th:if="${ not #strings.isEmpty(message)}"></p>

  3.当我们正确登录后,跳转页面后使用F5刷新界面,会提示是否重复提交表单,我们可以使用重定向的方式来防止表单的重复提交:

     @Bean       //将组件注册在容器中
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//将以下路径都映射到登录界面
String[] all = {
"/", "/index", "index.html"
};
for (String content : all) {
registry.addViewController(content).setViewName("index");
}
//将以下路径映射到主页面
String[] main = {
"main.html"
};
for (String content : main) {
registry.addViewController(content).setViewName("dashboard");
}
}
};
}
     @PostMapping("/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 "redirect:/main.html";
} else {
//登录失败
map.put("message", "用户名密码错误");
return "index";
}
}

  4.但是此时如果我们直接访问/main.html就能访问到我们的地址,这样一来所做的登录操作就显得没有什么意义,我们可以使用拦截器来进行请求拦截,进行登录检查:

 package com.zhiyun.springboot.web_restfulcrud.component;

 import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; /**
* @author : S K Y
* @version :0.0.1
* 进行登录检查,没有登录的用户就无法访问后台的主页进行crud操作
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if (loginUser == null) { //当前未登录,返回登录页面
//将请求转发到登录界面
request.setAttribute("message", "请先登录!");
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 { }
}
 package com.zhiyun.springboot.web_restfulcrud.config;

 import com.zhiyun.springboot.web_restfulcrud.component.LoginHandlerInterceptor;
import com.zhiyun.springboot.web_restfulcrud.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.WebMvcConfigurerAdapter; /**
* @author : S K Y
* @version :0.0.1
* 扩展SpringMVC的功能
*/
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter { //所有的WebMvcConfigurerAdapter组件都会一起起作用
@Bean //将组件注册在容器中
public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
return new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//将以下路径都映射到登录界面
String[] all = {
"/", "/index", "index.html"
};
for (String content : all) {
registry.addViewController(content).setViewName("index");
}
//将以下路径映射到主页面
String[] main = {
"main.html"
};
for (String content : main) {
registry.addViewController(content).setViewName("dashboard");
}
}
};
} //使用自定义的LocaleResolver
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
} //注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//SpringBoot已经做好了静态资源映射,不需要来处理静态资源
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/index", "/user/login");
}
}

四.主页CRUD--员工列表
  1.Restful风格的crud:要满足Restful风格,即路径是URL格式:/资源名称/资源标识,HTTP的请求方法区分对资源的CRUD操作.
  2.查询:  普通crud(uri来区分操作,getEmp)  restful(emp-GET)
  3.添加:  普通crud(addEmp?xxx)      restful(emp-POST)
  4.修改:  普通crud(updateEmp?id=xxx&xxx=xxx)  restful(emp-PUT)
  5.删除:  普通crud(deleteEmp?id=xxx)        restful(emp-DELETE)
  本例的请求架构:
  请求类型            请求的URI            请求方式
  查询所有员工          emps               GET
  查询某个员工(单个)        emp/{id}                GET
  来到添加页面          emp                 GET
  添加员工            emp               POST
  来到修改页面(查+信息回显)      emp/{id}             GET
  修改员工            emp               PUT
  删除员工            emp/{id}             DELETE
  --员工列表:使用Thymeleaf公共页面元素抽取
  1.抽取公共片段:  
  <div th:fragment>
     内容
  </div th:fragment>
  2.引用公共片段(~{...}可以省略)
  <div th:insert="~{footer :: copy }"></div>
  ~{templatename :: selector}  模板名::选择器
  ~{templatename :: fragmentname}  模板名::片段名

  --我们可以发现会在其外层给嵌套一个div,这样的结构改变可能会造成一些不可预料的错误,三种引入公共片段的th属性:
  1.th:insert:  会在外部包裹当前的标签
  2.th:replace:  使用元素替换,即自定义便签将会替换成代码片段
  3.th:include:  包含,自定义标签中加入被引入标签的内部元素(被引入便签就会被删除)
  --引入片段的时候传入参数:
  --commons/bar.html

 <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--topbar-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0"
th:fragment="topbar">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#" th:href="@{/main.html}">[[
${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="#">Sign out</a>
</li>
</ul>
</nav>
<!--sidebar-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" th:class="${activeUri=='main.html'?'nav-link active':'nav-link'}"
href="#" th:href="@{/main.html}">
<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="#">
<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="#">
<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="#" th:href="@{/emps}"
th:class="${activeUri=='emps'?'nav-link active':'nav-link'}">
<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>
员工管理
</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-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="#">
<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="#">
<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="#">
<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="#">
<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="#">
<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="#">
<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>
</body>
</html>

   --dashboard.html

 <!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" th:href="@{/asserts/css/bootstrap.min.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>
<!--引入topbar-->
<div th:replace="~{commons/bar :: topbar}"></div>
<div class="container-fluid">
<div class="row">
<!--sidebar-->
<div th:replace="~{commons/bar :: sidebar(activeUri='main.html')}"></div>
<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"
th:src="@{/asserts/js/jquery-3.2.1.slim.min.js}"></script>
<script type="text/javascript" src="asserts/js/popper.min.js" th:src="@{/asserts/js/popper.min.js}"></script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js"
th:src="@{/asserts/js/bootstrap.min.js}"></script> <!-- Icons -->
<script type="text/javascript" src="asserts/js/feather.min.js"
th:src="@{/asserts/js/feather.min.js}"></script>
<script>
feather.replace()
</script> <!-- Graphs -->
<script type="text/javascript" src="asserts/js/Chart.min.js"
th: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>

  --emp/list.html

 <!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"> <!-- 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>
<!--引入抽取的topbar 顶部栏-->
<!--模板名: 会使用Thymeleaf的前后配置规则进行解析-->
<div th:replace="~{commons/bar :: topbar}"></div> <div class="container-fluid">
<div class="row">
<!--sidebar-->
<div th:replace="~{ commons/bar :: sidebar(activeUri='emps') }"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2>员工列表 <button class="btn btn-sm btn-success">添加</button></h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>姓名</th>
<th>邮箱</th>
<th>性别</th>
<th>部门</th>
<th>生日</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="item:${employees}">
<td th:text="${item.lastName}"></td>
<td th:text="${item.email}"></td>
<td th:text="${item.gender == 0 ? '女':'男'}"></td>
<td th:text="${item.department.departmentName}"></td>
<!--格式化日期-->
<td th:text="${#dates.format(item.birth,'yyyy-MM-dd HH:mm:ss')}"></td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</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>

五.实现新员工的添加
  
在进行员工添加的时候,一个核心的问题就是日期格式的转化,在SpringBoot中有如下的自动装配机制:

  --我们可以通过修改配置文件以'-'的日期格式来提交
  --add.html

 <!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" th:href="@{/asserts/css/bootstrap.min.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>
<!--引入抽取的topbar 顶部栏-->
<!--模板名: 会使用Thymeleaf的前后配置规则进行解析-->
<div th:replace="~{commons/bar :: topbar}"></div> <div class="container-fluid">
<div class="row">
<!--sidebar-->
<div th:replace="~{ commons/bar :: sidebar(activeUri='emps') }"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<form th:action="@{/emp}" method="POST">
<div class="form-group"><label>LastName</label>
<input type="text" class="form-control"
placeholder="zhangsan" name="lastName">
</div>
<div class="form-group"><label>Email</label>
<input type="email" class="form-control"
placeholder="zhangsan@atguigu.com"
name="email"></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"
name="department.id">
<!--所提交的应该是部门的ID-->
<option th:each="item:${depts}" th:text="${item.departmentName}" th:value="${item.id}">1
</option>
</select></div>
<div class="form-group"><label>Birth</label>
<!--日期的提交格式容易发生错误,例如提交格式可能为:
2019.1.1; 2019-1-1; 2019/1/1
SpringMvc将页面提交的值需要转化成为data类型,因此需要进行日期的格式化
默认日期是安装'/'来区分的-->
<input type="text" class="form-control"
placeholder="zhangsan" name="birth"></div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
</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>
     //来到员工添加页面
@GetMapping("/emp")
public String toAddPage(Model model) {
//查出所有的部门
model.addAttribute("depts", departmentDao.getDepartments());
return "emp/add";
} //添加员工
//SpringMVC自动将请求参数和入参对象的属性名一一绑定,请求参数的名字和javaBean入参的属性名是一样的
@PostMapping("/emp")
public String addEmp(Employee employee) {
logger.debug("当前的新员工: " + employee);
//保存员工
employeeDao.save(employee);
//来到员工列表
//redirect: 表示重定向到一个地址
//forward: 表示转发到一个地址
return "redirect:/emps";
}

六.员工修改
  我们期望在员工列表页面点击编辑则可以进行员工的修改操作:

 <!--需要区分当前是员工修改还是添加-->
<!--想要发送员工修改的PUT请求,需要在SpringMVC中配置:
1.SpringMVC中配置HiddenHttpMethodFilter(SpringBoot自动配置);
2.页面创建一个psot表单
3.创建一个input项,他的name必须等于_method,其值就是我们指定的请求方式,并且是一个hidden标签--> <form th:action="@{/emp}" method="POST">
<input th:type="hidden" th:name="_method" th:value="PUT" th:if="${employee != null}"/>
<!--在修改时需要提交员工的id-->
<input th:type="hidden" name="id" th:if="${employee != null}" th:value="${employee.id}"/> <div class="form-group"><label>LastName</label>
<input type="text" class="form-control"
placeholder="zhangsan" name="lastName"
th:value="${employee != null} ? ${employee.lastName}">
</div>
<div class="form-group"><label>Email</label>
<input type="email" class="form-control"
placeholder="zhangsan@atguigu.com"
name="email" th:value="${employee != null} ? ${employee.email}"></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"
th:checked="${employee != null} ? ${employee.gender == 1}"> <label
class="form-check-label">男</label></div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio"
th:checked="${employee != null} ? ${employee.gender == 0}"
name="gender" value="0"> <label
class="form-check-label">女</label></div>
</div>
<div class="form-group"><label>department</label>
<select class="form-control"
name="department.id">
<!--所提交的应该是部门的ID-->
<option th:each="item:${depts}" th:text="${item.departmentName}" th:value="${item.id}"
th:selected="${employee != null} ? ${employee.department.id == item.id}">1
</option>
</select></div>
<div class="form-group"><label>Birth</label>
<!--日期的提交格式容易发生错误,例如提交格式可能为:
2019.1.1; 2019-1-1; 2019/1/1
SpringMvc将页面提交的值需要转化成为data类型,因此需要进行日期的格式化
默认日期是安装'/'来区分的-->
<input type="text" class="form-control"
placeholder="zhangsan" name="birth"
th:value="${employee != null} ? ${#dates.format(employee.birth,'yyyy-MM-dd')}"></div>
<button type="submit" class="btn btn-primary" th:text=" ${employee != null ? '修改':'添加'}">添加
</button>
</form>
     @PutMapping("/emp")
public String updateEmployee(Employee employee) {
logger.debug("修改后的员工数据: " + employee);
employeeDao.save(employee);
return "redirect:/emps";
}

七.员工删除

  <script>
$(".deleteButton").click(function () {
var delete_uri = $(this).attr("delete_uri");
$("#deleteEmpForm").attr("action", delete_uri).submit();
//取消按钮的默认行为
return false;
})
</script>
    <td>
<a class="btn btn-sm btn-primary" th:href="@{/emp/} + ${item.id}" href="#">编辑</a>
<a type="submit" class="btn btn-sm btn-danger deleteButton"
th:attr="delete_uri=@{/emp/} + ${item.id}">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</main>
<form method="post" id="deleteEmpForm">
<input type="hidden" name="_method" value="DELETE"/>
</form>
     @DeleteMapping("/emp/{id}")
public String deleteEmployee(@PathVariable("id") Integer id) {
logger.debug("当前需要删除的员工id: " + id);
employeeDao.delete(id);
return "redirect:/emps";
}

SpringBoot(五) -- SpringBootWeb登录示例的更多相关文章

  1. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  2. Apache Shiro:【2】与SpringBoot集成完成登录验证

    Apache Shiro:[2]与SpringBoot集成完成登录验证 官方Shiro文档:http://shiro.apache.org/documentation.html Shiro自定义Rea ...

  3. SpringBoot(五)_表单验证

    SpringBoot(五)_表单验证 参数校验在我们日常开发中非常常见,最基本的校验有判断属性是否为空.长度是否符合要求等,在传统的开发模式中需要写一堆的 if else 来处理这些逻辑,很繁琐,效率 ...

  4. Struts2---配置文件讲解及简单登录示例

    bean 用于创建一个JavaBean实例 constant 用于Struts2默认行为标签 <!-- 配置web默认编码集,相当于HttpServletRequest.setChartacte ...

  5. 使用ajax 做注册登录示例,

    需求:使用AJAX 做一个注册登录示例, 如用户名已存在, 在填写用户名时给与提示. 1:首先创建一个新的django项目.做好配置 在settings.py文件里做好数据库配置: 1. 告诉Djan ...

  6. springboot入门系列(三):SpringBoot教程之RabbitMQ示例

    SpringBoot教程之RabbitMQ示例 SpringBoot框架已经提供了RabbitMQ的使用jar包,开发人员在使用RabbitMQ的时候只需要引用jar包简单的配置一下就可以使用Rabb ...

  7. Springboot实现验证码登录

    Springboot实现验证码登录 1.背景 本人近期正在完成毕业设计(旅游信息管理系统)的制作,采用的SpringBoot+Thymeleaf的模式.在登录网站时想要添加验证码验证,通过网上查找资料 ...

  8. Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...

  9. SpringBoot+MyBatis+Mysql 详细示例

    SpringBoot与MyBatis整合,底层数据库为mysql的使用示例  项目下载链接:https://github.com/DFX339/bootdemo.git   新建maven项目,web ...

随机推荐

  1. JavaScript设计模式 样例三 —— 装饰模式

    装饰模式(Decorator Pattern): 定义:在不改变原对象的情况下,动态的给对象添加一些额外的职责.就功能而言,装饰模式相比生成子类更为灵活. 目的:把类的核心职责和装饰功能区分开.可以去 ...

  2. Java_环境变量

    介绍 第一步:下载JDK 第二步:搭建环境,双击JDK安装程序 第三步:配置环境变量 第四步:检查JDK安装是否成功 介绍: .java 源文件 我们所编写的代码都在这个文件中 .class 字节码文 ...

  3. win10如何设置软件开机启动

    想要实现应用程序在所有的用户登录系统后都能自动启动,就把该应用程序的快捷方式放到“系统启动文件夹”里C:\ProgramData\Microsoft\Windows\Start Menu\Progra ...

  4. 【python实例】判断质数:for-break-else

    """ for 变量 in 容器: 遍历--break 如果执行到了break语句, 则else不会被执行 else: break语句没有被执行时, 执行else &qu ...

  5. Spring5最新完整教程IDEA版【通俗易懂2019.11月】

    1.Maven找包: spring-webmvc spring-jdbc 2.Spring的本质是控制反转,依靠依赖注入来实现.以一个servcie对象为例,即是service暴露注入接口(构造,se ...

  6. [luogu]P3941 入阵曲[前缀和][压行]

    [luogu]P3941 入阵曲 题目描述 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然 ...

  7. HDU-6704 K-th occurrence

    Description You are given a string S consisting of only lowercase english letters and some queries. ...

  8. 从MapGIS K9到MapGIS 10到MapGIS 10.3 Server

  9. [Codeforces 274E]:Mirror Room(模拟)

    题目传送门 题目描述 有一个$n\times m$的格子图,其中有一些是黑色的,另一些为白色.从某个白色格子的中心点向左上($NW$),左下($SW$),右上($NE$),右下($SE$)四个方向中的 ...

  10. ES6 模板语法和分隔符

    let user = 'Barret'; console.log(`Hi ${user}!`); // Hi Barret!