技术栈:spring boot,mybatis,thymeleaf,MySQL等
实现的功能:管理员登录,员工的增删查改
工具 | 版本 |
---|---|
JDK | 1.8 |
mysql | 8.0 |
navicat for mysql | 11 |
IDEA | 2019.1 |
maven | 3.6.0 |
springboot | 2.2.5 |
源码地址:springboot-start
Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。
微服务是一种架构风格,它要求我们在开发一个应用的时候,这个应用必须构建成一系列小服务的组合;可以通过http的方式进行互通。
新建数据库
department表
/*
Navicat MySQL Data Transfer
Source Server : 本地连接
Source Server Version : 80014
Source Host : localhost:3306
Source Database : study-springboot
Target Server Type : MYSQL
Target Server Version : 80014
File Encoding : 65001
Date: 2020-03-06 15:19:11
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dname` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1017 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES ('1001', '软件工程');
INSERT INTO `department` VALUES ('1002', '数字媒体');
INSERT INTO `department` VALUES ('1003', '计算机科学');
INSERT INTO `department` VALUES ('1004', '网络工程');
INSERT INTO `department` VALUES ('1005', '信息管理');
INSERT INTO `department` VALUES ('1006', '大数据');
INSERT INTO `department` VALUES ('1007', '信息技术');
INSERT INTO `department` VALUES ('1008', '自动化');
INSERT INTO `department` VALUES ('1009', '通信');
INSERT INTO `department` VALUES ('1010', '英语学');
INSERT INTO `department` VALUES ('1011', '商务英语');
INSERT INTO `department` VALUES ('1012', '旅游学');
INSERT INTO `department` VALUES ('1013', '工商管理');
INSERT INTO `department` VALUES ('1014', '行政管理');
INSERT INTO `department` VALUES ('1015', '经济学');
INSERT INTO `department` VALUES ('1016', '土木建筑');
employee表
/*
Navicat MySQL Data Transfer
Source Server : 本地连接
Source Server Version : 80014
Source Host : localhost:3306
Source Database : study-springboot
Target Server Type : MYSQL
Target Server Version : 80014
File Encoding : 65001
Date: 2020-03-06 15:19:18
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ename` varchar(20) COLLATE utf8mb4_general_ci NOT NULL,
`gender` int(2) NOT NULL,
`dpid` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `id` (`dpid`),
CONSTRAINT `id` FOREIGN KEY (`dpid`) REFERENCES `department` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=163 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES ('134', '张三1', '1', '1001');
INSERT INTO `employee` VALUES ('135', '李四', '0', '1003');
INSERT INTO `employee` VALUES ('136', '王五', '1', '1005');
INSERT INTO `employee` VALUES ('137', '赵六', '1', '1004');
INSERT INTO `employee` VALUES ('138', '佩奇', '0', '1006');
INSERT INTO `employee` VALUES ('139', '吉吉国王', '1', '1002');
INSERT INTO `employee` VALUES ('140', '露娜', '0', '1001');
INSERT INTO `employee` VALUES ('141', '张伟', '1', '1013');
INSERT INTO `employee` VALUES ('142', '王伟', '1', '1007');
INSERT INTO `employee` VALUES ('143', '王芳', '0', '1014');
INSERT INTO `employee` VALUES ('144', '王秀英', '0', '1005');
INSERT INTO `employee` VALUES ('145', '张明', '0', '1015');
INSERT INTO `employee` VALUES ('146', '王静', '0', '1013');
INSERT INTO `employee` VALUES ('147', '刘洋', '1', '1010');
INSERT INTO `employee` VALUES ('148', '李杰', '1', '1011');
INSERT INTO `employee` VALUES ('149', '张燕', '0', '1008');
INSERT INTO `employee` VALUES ('150', '王秀兰', '0', '1014');
INSERT INTO `employee` VALUES ('151', '李丽', '0', '1015');
INSERT INTO `employee` VALUES ('152', '李霞', '0', '1013');
INSERT INTO `employee` VALUES ('153', '刘敏', '0', '1012');
INSERT INTO `employee` VALUES ('154', '张军', '1', '1009');
INSERT INTO `employee` VALUES ('155', '王品', '1', '1011');
INSERT INTO `employee` VALUES ('156', '张洁', '0', '1007');
INSERT INTO `employee` VALUES ('157', '熊大', '1', '1008');
INSERT INTO `employee` VALUES ('158', '熊二', '1', '1001');
INSERT INTO `employee` VALUES ('162', '光头强', '1', '1015');
loginuser表
/*
Navicat MySQL Data Transfer
Source Server : 本地连接
Source Server Version : 80014
Source Host : localhost:3306
Source Database : study-springboot
Target Server Type : MYSQL
Target Server Version : 80014
File Encoding : 65001
Date: 2020-03-04 22:32:17
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for loginuser
-- ----------------------------
DROP TABLE IF EXISTS `loginuser`;
CREATE TABLE `loginuser` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) COLLATE utf8mb4_general_ci NOT NULL,
`password` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ----------------------------
-- Records of loginuser
-- ----------------------------
INSERT INTO `loginuser` VALUES ('1', 'admin', 'admin');
INSERT INTO `loginuser` VALUES ('2', '张三', '1');
INSERT INTO `loginuser` VALUES ('3', '1', '1');
在idea里面新建一个springboot项目
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<groupId>cn.xiaovgroupId>
<artifactId>springboot-startartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springboot-startname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.10version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
导入静态资源,主要的几个页面。
新建一个domain包,在编写Employee和Department类以及LoginUser类,然后生成get和set方法以及toString方法。
package cn.xiaov.domain;
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = -2409001679665488385L;
private Integer id;
private String ename;
private Integer gender;
private Integer dpid;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getDpid() {
return dpid;
}
public void setDpid(Integer dpid) {
this.dpid = dpid;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", ename='" + ename + '\'' +
", gender=" + gender +
", dpid=" + dpid +
'}';
}
}
package cn.xiaov.domain;
import java.io.Serializable;
public class Department implements Serializable {
private static final long serialVersionUID = 2805528070551144200L;
private Integer id;
private String dname;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Department{" +
"id=" + id +
", dname='" + dname + '\'' +
'}';
}
}
package cn.xiaov.domain;
import java.io.Serializable;
public class LoginUser implements Serializable {
private static final long serialVersionUID = -4476776387474146618L;
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "LoginUser{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
#数据库配置
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/study_ssm
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#首页
server.servlet.context-path=/
#禁用模板缓存
spring.thymeleaf.cache=false
新建一个config包,新建一个MyMvcConfig类
package cn.xiaov.Config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login.html").setViewName("index");
}
}
这样就可以访问首页了,在浏览器中输入:http://localhost:8080/index.html或者http://localhost:8080就可以访问到index.html.
重要:先在IDEA中统一设置properties的编码问题!
setting>Editor>File Encodings 将此页面的所有编码改成UTF-8
特别是下面一个properties Files,并勾选后面的Transparent.
在resources下新建一个名为 i18n 的文件夹。
再新建一个login.properties的文件,继续新建login_zh_CN.properties,以及login_en_US.properties文件。
然后新建login.tip,login.username,login.password,login.remember,login.btn。
总而言之,3个文件的内容为:
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
在application.properties中配置国际化文件类路径:
#国际化文件
spring.messages.basename=i18n.login
更改index.html中form表单的内容。
使用#{}表示与国际化相关的内容。行类直接用th:text=“#{login.username}”,行外用[[#{login.remember}]]
<form class="form-signin" th:action="@{/user/login}" method="post">
<img class="mb-4" th: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 inh1>
<input type="text" name="username" class="form-control" placeholder="Username" th:placeholder="#{login.username}" required="" autofocus="">
<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 inbutton>
<p class="mt-5 mb-3 text-muted">© 2017-2018p>
<a class="btn btn-sm">中文a>
<a class="btn btn-sm">Englisha>
form>
在浏览器中输入:http://localhost:8080/index.html或者http://localhost:8080 如果你的浏览器设置的是中文的话,直接就是中文显示了,如果你的浏览器是英文的话,就是英文界面了。
但是我们想要自己实现中英文切换的语言需求呢。
需要在链接中添加参数
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">Englisha>
需要在config中新建一个MyLocaleResolver
实现提取地区参数的功能
package cn.xiaov.Config;
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;
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
String lang=httpServletRequest.getParameter("l");
Locale locale=Locale.getDefault();
if (!StringUtils.isEmpty(lang)){
//不为空,携带地区参数
String[] split = lang.split("_");
locale= new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
并将这个组件加入到spring容器中,在MyMvcConfig中添加
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
在浏览器中输入:http://localhost:8080 ,点击下方中文会切换到中文,点击下方英文会切换到英文。
在index.html中导入thymeleaf依赖,
xmlns:th=“http://www.thymeleaf.org”
根据thymeleaf的知识修改index.html的内容。
将所有链接换成@{}的形式,例如:
//修改前
<link href="asserts/css/bootstrap.min.css}" rel="stylesheet">
//修改后
<link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
在输入框中加入name属性(重要)
将action换成自己需要的action,将请求换成post请求。
编写loginController,在里面调用service层的方法,service层再调用dao层的方法。如果登录成功就将用户名存入session中。
为了避免代码的重复提交,我们在登陆成功后希望直接重定向到dashboard.html页面,所以我们再配置试图解析。在controller中成功返回dashboard,我们可以返回main.xml。
return "redirect:/main.html";
此时我们需要在MyMvcConfig中添加路径映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
这样重定位的main.html就被映射到dashboard.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 Bootstraptitle>
<link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
<link 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}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign inh1>
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}">p>
<input type="text" th:name="username" class="form-control" placeholder="Username" required="" autofocus="">
<input type="password" th:name="password" class="form-control" placeholder="Password" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
label>
div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign inbutton>
<p class="mt-5 mb-3 text-muted">© 2017-2018p>
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">Englisha>
form>
body>
html>
package cn.xiaov.controller;
import cn.xiaov.domain.LoginUser;
import cn.xiaov.service.LoginUserService;
import org.springframework.beans.factory.annotation.Autowired;
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;
import java.util.List;
@Controller
@RequestMapping("/user")
public class loginController {
@Autowired
LoginUserService loginUserService;
@PostMapping("/login")
public String login(LoginUser user, Model model, HttpSession session) {
String username = user.getUsername();
String password = user.getPassword();
//用户名为空
if (StringUtils.isEmpty(username)) {
model.addAttribute("msg", "用户名为空");
return "index";
}
//密码为空
if (StringUtils.isEmpty(password)) {
model.addAttribute("msg", "密码为空");
return "index";
}
//有密码,有账号
List<LoginUser> users = loginUserService.findByUserName(username);
//用户名不存在
if (users == null || users.size() == 0) {
model.addAttribute("msg", "用户名不存在");
return "index";
}
//超过1个
if (users.size() > 1) {
model.addAttribute("msg", "查询错误");
return "index";
}
// 密码错误
if (!password.equals(users.get(0).getPassword())) {
model.addAttribute("msg", "密码错误");
return "index";
}
//密码正确
//将姓名添加到session域中
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}
}
package cn.xiaov.service;
import cn.xiaov.domain.LoginUser;
import java.util.List;
public interface LoginUserService {
List< LoginUser> findByUserName(String username);
}
package cn.xiaov.service.impl;
import cn.xiaov.dao.LoginUserDao;
import cn.xiaov.domain.LoginUser;
import cn.xiaov.service.LoginUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LoginUserServiceImpl implements LoginUserService {
@Autowired
LoginUserDao loginUserDao;
@Override
public List< LoginUser> findByUserName(String username) {
return loginUserDao.findByUserName(username);
}
}
package cn.xiaov.dao;
import cn.xiaov.domain.LoginUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface LoginUserDao {
@Select("select * from loginuser where username=#{username}")
List< LoginUser> findByUserName(String username);
}
这样登录功能就大概的实现了。在浏览器中输入:http://localhost:8080/index.html或者http://localhost:8080,填入账号admin,密码admin,就可以登录成功,否者就会登录失败,返回用户名不存在,密码错误等等。虽然现在dashboard.html可能不好看,但是可以访问到是事实了。原因是应该springboot拦截了静态资源,后期可以取消拦截的。设置好main.html后浏览器地址就不再是http://localhost:8080/user/login 了,而是http://localhost:8080/main.html,通过http://localhost:8080/main.html同样可以访问进入的系统。
但是事实并不是这样,一个系统怎么可能不用登录就可以进去呢,这明显不符合常理,所以我们在登陆前要拦截一部分请求。
在config中新建LoginHandlerInterceptor类
package cn.xiaov.config;
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 loginUser = request.getSession().getAttribute("loginUser");
if (loginUser==null){
//没有登陆
request.setAttribute("msg","没有权限");
request.getRequestDispatcher("/login.html").forward(request,response);
return false;
}else{
//成功登录
return true;
}
}
}
并在MyMvcConfig中加入,设置拦截所有,并排除一部分请求
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/","/login.html","/user/login","/asserts/**");
}
在浏览器中输入:http://localhost:8080 ,输入账号admin,密码admin,可访问主页面。
//从session中拿出
<--更改前
class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Company namea>
-->
<-- 更改后 -->
<a class="#">[[${session.loginUser}]]a>
在html中更改请求路径
<a class="nav-link" th:href="@{/user/logout}">注销a>
在loginController中编写
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:/login.html";
}
在侧边栏更改部分中文即可
我这里只实现了员工管理和首页两个模块
在templates文件夹下新建commons文件夹,再新建一个common.html文件和一个common.css。
将nav标签的东西全部提取出来,需要在原来代码使用
<div th:replace="~{commons/common::topbar}">div>
<div th:replace="~{commons/common::sidebar}">div>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<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="#">[[${session.loginUser}]]a>
<input class="form-control form-control-dark w-100" type="text" th:placeholder="查找" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" th:href="@{/user/logout}">注销a>
li>
ul>
nav>
<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 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>
首页<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>
员工管理
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 reportsspan>
<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>
html>
@-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;
}
在浏览器中输入:http://localhost:8080 ,输入账号admin,密码admin,仍然可访问主页面。
新建EmployeeController类
当选中员工管理一栏的时候会查询出所有员工信息。所以在模板页面应该改动如下:
<a class="nav-link" th:href="@{/emps}">
controller收到请求后调用employeeService和departmentService,因为在employee中存放的只有department的id,所以需要在departmentService有一个findById()的方法。在这里一定是departmentService.findById(emp.getDpid());
package cn.xiaov.controller;
import cn.xiaov.domain.Department;
import cn.xiaov.domain.Employee;
import cn.xiaov.service.DepartmentService;
import cn.xiaov.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@Autowired
DepartmentService departmentService;
@RequestMapping("/emps")
public String toEmpList(Model model) {
Map<Integer, String> dept = new HashMap<>();
List<Employee> employees = employeeService.findAll();
for (Employee emp :
employees) {
Department department = departmentService.findById(emp.getDpid());
dept.put(department.getId(), department.getDname());
}
model.addAttribute("emps", employees);
model.addAttribute("dept", dept);
return "emp/list";
}
}
package cn.xiaov.service;
import cn.xiaov.domain.Department;
public interface DepartmentService {
Department findById(Integer id);
}
package cn.xiaov.service;
import cn.xiaov.domain.Department;
public interface DepartmentService {
Department findById(Integer id);
}
package cn.xiaov.service;
import cn.xiaov.domain.Employee;
import java.util.List;
public interface EmployeeService {
List<Employee> findAll();
}
package cn.xiaov.service.impl;
import cn.xiaov.dao.EmployeeDao;
import cn.xiaov.domain.Employee;
import cn.xiaov.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public List<Employee> findAll() {
return employeeDao.findAll();
}
}
package cn.xiaov.dao;
import cn.xiaov.domain.Department;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface DepartmentDao {
@Select("select * from department where id=#{id}")
Department findById(Integer id);
}
package cn.xiaov.dao;
import cn.xiaov.domain.Department;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface DepartmentDao {
@Select("select * from department where id=#{id}")
Department findById(Integer id);
}
将会返回两个数据给前端,
model.addAttribute("emps", employees);
model.addAttribute("dept", dept);
就是emps存放查询出来的员工信息,dept存放查询出来的部门信息。
<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 Bootstraptitle>
<link href="asserts/css/bootstrap.min.css" rel="stylesheet">
<link href="asserts/css/dashboard.css" rel="stylesheet">
<link th:href="@{/commons/common.css}" rel="stylesheet" type="text/css">
head>
<body>
<div th:replace="~{commons/common::topbar}">div>
<div class="container-fluid">
<div class="row">
<div th:replace="~{commons/common::sidebar}">div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加a>h2>
<div class="table-responsive">
<table class="table table-striped table-sm" id="tb">
<thead>
<tr>
<th>编号th>
<th>姓名th>
<th>性别th>
<th>部门th>
<th>操作th>
tr>
thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}">td>
<td th:text="${emp.getEname()}">td>
<td th:text="${emp.getGender()==0?'女':'男'}">td>
<td th:text="${dept.get(emp.getDpid())}">td>
<td >
<a class="btn btn-sm btn-primary" href="#">编辑a>
<a class="btn btn-sm btn-danger" href="#">删除a>
td>
tr>
tbody>
table>
div>
main>
div>
div>
<script type="text/javascript" th:src="@{/asserts/js/jquery-3.2.1.slim.min.js}">script>
<script type="text/javascript" th:src="@{/asserts/js/popper.min.js}">script>
<script type="text/javascript" th:src="@{/asserts/js/bootstrap.min.js}">script>
<script type="text/javascript" th:src="@{/asserts/js/feather.min.js}">script>
<script>
feather.replace()
script>
<script type="text/javascript" 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>
在浏览器中输入:http://localhost:8080 ,输入账号admin,密码admin,可访问主页面,点击员工管理可以查询到所有员工的信息。
在bootstrap官网上下载bootstrap-table,并将bootstrap-table.min.js和bootstrap-table-zh-CN.min.js放入js文件夹中,将bootstrap-table.css放入css文件夹中,另外下载jquery.js放入js文件夹中。
导入上述文件到list.html文件中
<script type="text/javascript" th:src="@{/asserts/js/jquery.js}">script>
<link th:href="@{/asserts/css/bootstrap-table.css}" rel="stylesheet" type="text/css">
<script type="text/javascript" th:src="@{/asserts/js/bootstrap-table.min.js}">script>
<script type="text/javascript" th:src="@{/asserts/js/bootstrap-table-zh-CN.min.js}">script>
再加入一串js代码初始化:
<script>
$("#tb").bootstrapTable({
pagination: true, //是否显示分页条
pageSize: 5, //默认一页显示的行数
paginationLoop: false, //是否开启分页条无限循环,最后一页时点击下一页是否转到第一页
pageList: [5, 10, 20] //选择每页显示多少行
});
script>
在浏览器中输入:http://localhost:8080 ,输入账号admin,密码admin,点击员工管理可以查询到所有员工分页的信息。
首先你需要一个添加数据的页面,add.html
其实可以复制list.html并且只需要更改main里面的内容即可,在网上下载一个模板添加上去就ok了
<form>
<div class="form-group">
<label>LastNamelabel>
<input type="text" class="form-control" placeholder="xiaoV">
div>
<div class="form-group">
<label>Emaillabel>
<input type="email" class="form-control" placeholder="[email protected]">
div>
<div class="form-group">
<label>Genderlabel><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>departmentlabel>
<select class="form-control">
<option>1option>
<option>2option>
<option>3option>
<option>4option>
<option>5option>
select>
div>
<div class="form-group">
<label>Birthlabel>
<input type="text" class="form-control" placeholder="xiaoV">
div>
<button type="submit" class="btn btn-primary">添加button>
form>
去掉不用的就可以了。
在controller中编写部分代码,点击list上面的按钮来到add.html,记得查询dept,我们需要做下拉框,需要所有的部门信息。来到add.html后,开始编写前端代码。
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<form th:action="@{/emp/add}" method="post">
<div class="form-group">
<label>姓名label>
<input type="text" th:name="ename" class="form-control" placeholder="姓名">
div>
<div class="form-group">
<label>性别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>部门label>
<select class="form-control" th:name="dpid">
<option th:each="dept:${departments}" th:text="${dept.getDname()}" th:value="${dept.getId()}">option>
select>
div>
<button type="submit" class="btn btn-primary">添加button>
form>
main>
点击添加按钮后,提交表单。在controller中添加add方法,更改数据库。
@RequestMapping("/emp/toadd")
public String toEmpAdd(Model model) {
List<Department> departments = departmentService.findAll();
model.addAttribute("departments", departments);
return "emp/add";
}
@RequestMapping("/emp/add")
public String addEmp(Employee employee) {
employeeService.save(employee);
return "redirect:/emps";
}
调用了Service中的方法,需要在service中添加
void save(Employee employee);
@Override
public void save(Employee employee) {
employeeDao.save(employee);
}
调用了dao中的方法,需要在dao中添加
/**
* 保存账户
*/
@Insert("insert into employee(ename,gender,dpid) values(#{ename},#{gender},#{dpid})")
void save(Employee employee);
<a class="btn btn-sm btn-danger" th:href="@{/emp/delete/} + ${emp.id}">删除a>
首先在list.html文件里面的路径设置一下,然后编写controller
@RequestMapping("/emp/delete/{id}")
public String deleteEmp(@PathVariable("id") Integer id) {
employeeService.delete(id);
return "redirect:/emps";
}
调用了Service中的方法,需要在service中添加
void delete(Integer id);
@Override
public void delete(Integer id) {
employeeDao.delete(id);
}
调用了dao中的方法,需要在dao中添加
/**
* 删除
* @param id
*/
@Delete("delete from employee where id=#{id}")
void delete(Integer id);
添加一个update.html页面,可以直接复制add.html页面,修改部分代码即可。
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<form th:action="@{/emp/update}" method="post">
<input th:name="id" type="hidden" th:value="${emp.getId()}">
<div class="form-group">
<label>姓名label>
<input type="text" th:name="ename" class="form-control" th:value="${emp.getEname()}"/>
div>
<div class="form-group">
<label>性别label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" th:checked="${emp.getGender()==1}" 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" th:checked="${emp.getGender()==0}" type="radio" name="gender" value="0">
<label class="form-check-label">女label>
div>
div>
<div class="form-group">
<label>部门label>
<select class="form-control" th:name="dpid" th:checked="${emp.getDpid()}">
<option th:each="dept:${departments}" th:text="${dept.getDname()}" th:value="${dept.getId()}">option>
select>
div>
<button type="submit" class="btn btn-primary">修改button>
form>
main>
<a class="btn btn-sm btn-primary" th:href="@{/emp/update/}+${emp.id}">编辑a>
首先在list.html文件里面的路径设置一下,然后编写controller
@RequestMapping("/emp/update/{id}")
public String toUpdateEmp(@PathVariable("id") Integer id, Model model) {
Employee employee = employeeService.findById(id);
List<Department> departments = departmentService.findAll();
model.addAttribute("emp", employee);
model.addAttribute("departments", departments);
return "emp/update";
}
@RequestMapping("/emp/update")
public String updateEmp(Employee employee) {
employeeService.update(employee);
return "redirect:/emps";
}
调用了Service中的方法,需要在service中添加
Employee findById(Integer id);
void update(Employee employee);
@Override
public void update(Employee employee) {
employeeDao.update(employee);
}
@Override
public Employee findById(Integer id) {
return employeeDao.findById(id);
}
调用了dao中的方法,需要在dao中添加
/**
* 根据id查询
* @param id
* @return
*/
@Select("select * from employee where id =#{id}")
Employee findById(Integer id);
/**
* 修改
* @param employee
*/
@Update("update employee set ename=#{ename},gender=#{gender},dpid=#{dpid} where id=#{id}")
void update(Employee employee);
重点记得一定要在update.html中添加
<input th:name="id" type="hidden" th:value="${emp.getId()}">
不然就能查询出id,后台打印的时候也只是空值。
我们只需要在模板目录下添加一个error文件夹,文件夹中存放我们相应的错误页面,比如404.html 或者 4xx.html 等等,SpringBoot就会帮我们自动使用了!