1. 简介

  layui(谐音:类UI)是一款采用自身模块规范编写的前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式,门槛极低,拿来即用。其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代码到API的每一处细节都经过精心雕琢,非常适合界面的快速开发。

  (1)为服务端程序员量身定做的低门槛开箱即用的前端UI解决方案;

  (2)兼容IE6/7除外的全部浏览器;

  (3)采用经典模块化,避免工具的复杂配置,回归简单;

  (4)更多请浏览Layui官网:https://www.layui.com/

2. 初始化数据库

  创建数据库layuidemo,并初始化表结构:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for t_sys_user
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user` (
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户名称',
`nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户昵称',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户密码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of t_sys_user
-- ----------------------------
INSERT INTO `t_sys_user` VALUES (1, 'user', 'C3Stones', '$2a$10$WXEPqxjMwY6d6A0hkeBtGu.acRRWUOJmX7oLUuYMHF1VWWUm4EqOC');
INSERT INTO `t_sys_user` VALUES (2, 'system', '管理员', '$2a$10$dmO7Uk9/lo1D5d1SvCGgWuB050a0E2uuBDNITEpWFiIfCg.3UbA8y'); SET FOREIGN_KEY_CHECKS = 1;

3. 示例代码

  建议下载示例工程,参考搭建自己的示例工程。

  • 创建项目

  • 修改pom.xml
<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.0</modelVersion>
<groupId>com.c3stones</groupId>
<artifactId>spring-boot-layui-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-layui-demo</name>
<description>SpringBoot+Mybatis-Plus+Layui Demo</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.8.RELEASE</version>
<relativePath />
</parent> <dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
  • 创建配置文件application.yml
server:
port: 8080
servlet:
session:
timeout: 1800s spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/layuidemo?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
username: root
password: 123456
thymeleaf:
prefix: classpath:/view/
suffix: .html
encoding: UTF-8
servlet:
content-type: text/html
# 生产环境设置true
cache: false # Mybatis-plus配置
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
global-config:
db-config:
id-type: AUTO
configuration:
# 打印sql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 信息安全
security:
web:
excludes:
- /login
- /logout
- /images/**
- /jquery/**
- /layui/**
xss:
enable: true
excludes:
- /login
- /logout
- /images/*
- /jquery/*
- /layui/*
sql:
enable: true
excludes:
- /images/*
- /jquery/*
- /layui/*
csrf:
enable: true
excludes:
  • 创建Mybatis-Plus配置类(配置分页)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; /**
* Mybatis-Plus配置类
*
* @author CL
*
*/
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class MybatisPlusConfig { /**
* 注入分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
  • 创建响应实体
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; /**
* 响应实体
*
* @author CL
*
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Response<T> { /**
* 响应码
*/
private int code; /**
* 响应消息体
*/
private String msg; /**
* 响应数据
*/
private T data; /**
* 失败响应
*
* @param msg 响应消息体
* @return
*/
public static <T> Response<T> error(String msg) {
return new Response<T>(500, msg, null);
} /**
* 成功响应
*
* @param data 响应数据
* @return
*/
public static <T> Response<T> success(T data) {
return new Response<T>(200, null, data);
} /**
* 成功响应
*
* @param msg 响应消息体
* @return
*/
public static <T> Response<T> success(String msg) {
return new Response<T>(200, msg, null);
} /**
* 成功响应
*
* @param msg 响应消息体
* @param data 响应数据
* @return
*/
public static <T> Response<T> success(String msg, T data) {
return new Response<T>(200, msg, data);
} }
  • 创建全局异常处理类
import javax.servlet.http.HttpServletRequest;

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; /**
* 全局异常处理
*
* @author CL
*
*/
@Controller
public class WebExceptionAdvice implements ErrorController { /**
* 获得异常路径
*/
@Override
public String getErrorPath() {
return "error";
} /**
* 异常处理,跳转到响应的页面
*
* @param request
* @param model
* @return
*/
@RequestMapping(value = "error")
public String handleError(HttpServletRequest request, Model model) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
model.addAttribute("message", throwable != null ? throwable.getMessage() : null);
switch (statusCode) {
case 400:
return "error/400";
case 403:
return "error/403";
case 404:
return "error/404";
default:
return "error/500";
}
} }
  • 创建实体
import java.io.Serializable;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; /**
* 系统用户信息
*
* @author CL
*
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "t_sys_user")
@EqualsAndHashCode(callSuper = false)
public class User implements Serializable { private static final long serialVersionUID = 1L; /**
* 用户ID
*/
@TableId(type = IdType.AUTO)
private Integer id; /**
* 用户名称
*/
private String username; /**
* 用户昵称
*/
private String nickname; /**
* 用户密码
*/
@JsonIgnore
private String password; }
  • 创建Mapper
import org.apache.ibatis.annotations.Mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.c3stones.entity.User; /**
* 系统用户Mapper
*
* @author CL
*
*/
@Mapper
public interface UserMapper extends BaseMapper<User> { }
  • 创建Service
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.c3stones.entity.User; /**
* 系统用户Service
*
* @author CL
*
*/
public interface UserService extends IService<User> { /**
* 查询列表数据
*
* @param user 系统用户
* @param current 当前页
* @param size 每页显示条数
* @return
*/
public Page<User> listData(User user, long current, long size); /**
* 检验用户名称是否唯一
*
* @param userName 用户名称
* @return
*/
public Boolean checkUserName(String userName); }
  • 创建Service实现
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.c3stones.entity.User;
import com.c3stones.mapper.UserMapper;
import com.c3stones.service.UserService; import cn.hutool.core.util.StrUtil; /**
* 系统用户Service实现
*
* @author CL
*
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { /**
* 查询列表数据
*
* @param user 系统用户
* @param current 当前页
* @param size 每页显示条数
* @return
*/
@Override
public Page<User> listData(User user, long current, long size) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
if (null != user.getId()) {
queryWrapper.eq("id", user.getId());
}
if (StrUtil.isNotBlank(user.getUsername())) {
queryWrapper.like("username", user.getUsername());
}
if (StrUtil.isNotBlank(user.getNickname())) {
queryWrapper.like("nickname", user.getNickname());
}
return baseMapper.selectPage(new Page<>(current, size), queryWrapper);
} /**
* 检验用户名称是否唯一
*
* @param userName 用户名称
* @return
*/
@Override
public Boolean checkUserName(String userName) {
if (StrUtil.isNotBlank(userName)) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("username", userName);
Integer count = baseMapper.selectCount(queryWrapper);
return (count != null && count > 0) ? false : true;
}
return false;
} }
  • 创建登录Controller
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.c3stones.common.Response;
import com.c3stones.entity.User;
import com.c3stones.service.UserService; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt; /**
* 系统登录Controller
*
* @author CL
*
*/
@Controller
public class LoginController { @Autowired
private UserService userService; /**
* 登录页
*
* @return
*/
@GetMapping(value = { "login", "" })
public String login() {
return "login";
} /***
* 登录验证
*
* @param user 系统用户
* @return
*/
@PostMapping(value = "login")
@ResponseBody
public Response<User> login(User user, HttpSession session) {
if (StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPassword())) {
return Response.error("用户名或密码不能为空");
}
User queryUser = new User();
queryUser.setUsername(user.getUsername());
queryUser = userService.getOne(new QueryWrapper<>(queryUser));
if (queryUser == null || !StrUtil.equals(queryUser.getUsername(), user.getUsername())
|| !BCrypt.checkpw(user.getPassword(), queryUser.getPassword())) {
return Response.error("用户名或密码错误");
}
session.setAttribute("user", queryUser);
return Response.success("登录成功", queryUser);
} /**
* 登出
*
* @param httpSession
* @return
*/
@GetMapping(value = "logout")
public String logout(HttpSession httpSession) {
httpSession.invalidate();
return "redirect:/login";
} }
  • 创建登录拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; /**
* 登录拦截器
*
* @author CL
*
*/
@Component
public class LoginInterceptor implements HandlerInterceptor { /**
* 拦截处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Object user = request.getSession().getAttribute("user");
if (null == user) {
response.sendRedirect("/login");
}
return true;
} }
  • 配置登录拦截器
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import lombok.Setter; /**
* Web配置类
*
* @author CL
*
*/
@Configuration
@ConfigurationProperties(prefix = "security.web")
public class WebConfigurer implements WebMvcConfigurer { /**
* 忽略的URL
*/
@Setter
private List<String> excludes; /**
* 配置拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns(excludes);
} }
  • 创建首页Contrller
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; /**
* 系统首页Controller
*
* @author CL
*
*/
@Controller
public class IndexController { /**
* 首页
*
* @return
*/
@GetMapping(value = "index")
public String index(Model model, HttpSession httpSession) {
model.addAttribute("user", httpSession.getAttribute("user"));
return "index";
} /**
* 控制台
*
* @return
*/
@GetMapping(value = "view")
public String view() {
return "pages/view";
} }
  • 创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; /**
* 启动类
*
* @author CL
*
*/
@SpringBootApplication
public class Application { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} }
  • 拷贝静态资源

      将示例工程的resource目录下的static文件夹及其子文件拷贝到本工程对应文件夹下。
  • 创建前端页面文件夹

      在resource目录下创建view文件夹,工程的所有页面都会写在此文件夹下(和配置文件中的spring.thymeleaf.prefix对应)。
  • 创建登录页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>C3Stones</title>
<link th:href="@{/images/favicon.ico}" rel="icon">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/login.css}" rel="stylesheet" />
<link th:href="@{/layui/css/view.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/jquery/jquery-2.1.4.min.js}"></script>
</head>
<body class="login-wrap">
<div class="login-container">
<form class="login-form">
<div class="input-group text-center text-gray">
<h2>欢迎登录</h2>
</div>
<div class="input-group">
<input type="text" id="username" class="input-field">
<label for="username" class="input-label">
<span class="label-title">用户名</span>
</label>
</div>
<div class="input-group">
<input type="password" id="password" class="input-field">
<label for="password" class="input-label">
<span class="label-title">密码</span>
</label>
</div>
<button type="button" class="login-button">登录<i class="ai ai-enter"></i></button>
</form>
</div>
</body>
</html>
<script>
layui.define(['element'],function(exports){
var $ = layui.$;
$('.input-field').on('change',function(){
var $this = $(this),
value = $.trim($this.val()),
$parent = $this.parent();
if(!isEmpty(value)){
$parent.addClass('field-focus');
}else{
$parent.removeClass('field-focus');
}
})
exports('login');
}); // 登录
var layer = layui.layer;
$(".login-button").click(function() {
var username = $("#username").val();
var password = $("#password").val();
if (isEmpty(username) || isEmpty(password)) {
layer.msg("用户名或密码不能为空", {icon: 2});
return ;
} var loading = layer.load(1, {shade: [0.3, '#fff']});
$.ajax({
url : "[[@{/}]]login",
data : {username : username, password : password},
type : "post",
dataType : "json",
error : function(data) {
},
success : function(data) {
layer.close(loading);
if (data.code == 200) {
location.href = "[[@{/}]]index";
} else {
layer.msg(data.msg, {icon: 2});
}
}
});
}); function isEmpty(n) {
if (n == null || n == '' || typeof(n) == 'undefined') {
return true;
}
return false;
}
</script>
  • 创建系统框架页面,并初始化菜单
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>C3Stones</title>
<link th:href="@{/images/favicon.ico}" rel="icon">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/admin.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.js}"></script>
<script th:src="@{/layui/js/index.js}" data-main="home"></script>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header custom-header">
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item slide-sidebar" lay-unselect>
<a href="javascript:;" class="icon-font"><i class="ai ai-menufold"></i></a>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">[[${user?.nickname}]]</a>
<dl class="layui-nav-child">
<dd><a th:href="@{/logout}">退出</a></dd>
</dl>
</li>
</ul>
</div> <div class="layui-side custom-admin">
<div class="layui-side-scroll">
<div class="custom-logo">
<img alt="" th:src="@{/images/logo.jpg}">
<h1>C3Stones</h1>
</div>
<ul id="Nav" class="layui-nav layui-nav-tree">
<li class="layui-nav-item">
<a href="javascript:;">
<i class="layui-icon"></i>
<em>主页</em>
</a>
<dl class="layui-nav-child">
<dd><a th:href="@{/view}">控制台</a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">
<i class="layui-icon"></i>
<em>系统管理</em>
</a>
<dl class="layui-nav-child">
<dd><a th:href="@{/user/list}">用户管理</a></dd>
</dl>
</li>
</ul> </div>
</div> <div class="layui-body">
<div class="layui-tab app-container" lay-allowClose="true" lay-filter="tabs">
<ul id="appTabs" class="layui-tab-title custom-tab"></ul>
<div id="appTabPage" class="layui-tab-content"></div>
</div>
</div> <div class="layui-footer">
<p> 2020 - C3Stones Blog : <a href="https://www.cnblogs.com/cao-lei/" target="_blank">https://www.cnblogs.com/cao-lei/</a></p>
</div>
<div class="mobile-mask"></div>
</div>
</body>
</html>
  • 创建控制台页面

      在view文件夹下创建pages文件夹。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/view.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/jquery/jquery-2.1.4.min.js}"></script>
<title></title>
</head>
<body class="layui-view-body">
<div class="layui-row" style="text-align: center;">
<div class="layui-col-md12" style="padding: 18% 0px 20px 0px;">
<font class="layui-text"><h1>欢迎使用</h1></font>
</div>
</div>
</body>
</html>
  • 登录测试

      浏览器访问:http://127.0.0.1:8080/,输入用户名密码:user/123456,或者system/123456,进行测试正常用户登录,并测试用户不存在、密码错误等异常。
  • 创建用户Controller
import javax.validation.constraints.NotNull;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.c3stones.common.Response;
import com.c3stones.entity.User;
import com.c3stones.service.UserService; import cn.hutool.crypto.digest.BCrypt; /**
* 系统用户Controller
*
* @author CL
*
*/
@Controller
@RequestMapping(value = "user")
public class UserController { @Autowired
private UserService userService; /**
* 查询列表
*
* @return
*/
@RequestMapping(value = "list")
public String list() {
return "pages/userList";
} /**
* 查询列表数据
*
* @param user 系统用户
* @param current 当前页
* @param size 每页显示条数
* @return
*/
@RequestMapping(value = "listData")
@ResponseBody
public Response<Page<User>> listData(User user, @RequestParam(name = "page") long current,
@RequestParam(name = "limit") long size) {
Page<User> page = userService.listData(user, current, size);
return Response.success(page);
} /**
* 删除
*
* @param user 系统用户
* @return
*/
@RequestMapping(value = "delete")
@ResponseBody
public Response<Boolean> delete(User user) {
Assert.notNull(user.getId(), "ID不能为空");
boolean result = userService.removeById(user.getId());
return Response.success(result);
} /**
* 修改
*
* @param user 系统用户
* @param model
* @return
*/
@RequestMapping(value = "edit")
public String edit(User user, Model model) {
Assert.notNull(user.getId(), "ID不能为空");
model.addAttribute("user", userService.getById(user.getId()));
return "pages/userEdit";
} /**
* 检验用户名称是否唯一
*
* @param userName 用户名称
* @return
*/
@RequestMapping(value = "check")
@ResponseBody
public Response<Boolean> checkUserName(@NotNull String username) {
Boolean checkResult = userService.checkUserName(username);
return Response.success(checkResult);
} /**
* 更新
*
* @param user 系统用户
* @return
*/
@RequestMapping(value = "update")
@ResponseBody
public Response<Boolean> update(User user) {
Assert.notNull(user.getId(), "ID不能为空");
boolean result = userService.updateById(user);
return Response.success(result);
} /**
* 新增
*
* @return
*/
@RequestMapping(value = "add")
public String add() {
return "pages/userAdd";
} /**
* 保存
*
* @param user 系统用户
* @return
*/
@RequestMapping(value = "save")
@ResponseBody
public Response<Boolean> save(User user) {
user.setPassword(BCrypt.hashpw(user.getPassword()));
boolean result = userService.save(user);
return Response.success(result);
} }
  • 创建用户列表及新增、编辑页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/view.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/jquery/jquery-2.1.4.min.js}"></script>
<title></title>
</head>
<body class="layui-view-body">
<div class="layui-content">
<div class="layui-row">
<div class="layui-card">
<div class="layui-card-header">
<i class="layui-icon mr5"></i>用户管理
<button class="layui-btn layui-btn-xs layui-btn-normal pull-right mt10" data-type="add"><i class="layui-icon mr5"></i>新增</button>
</div>
<div class="layui-card-body">
<div class="searchTable">
用户ID:
<div class="layui-inline mr5">
<input class="layui-input" name="id" autocomplete="off">
</div>
用户名称:
<div class="layui-inline mr5">
<input class="layui-input" name="username" autocomplete="off">
</div>
用户昵称:
<div class="layui-inline mr10">
<input class="layui-input" name="nickname" autocomplete="off">
</div>
<button class="layui-btn" data-type="reload">查询</button>
<button class="layui-btn layui-btn-primary" data-type="reset">重置</button>
</div>
<table class="layui-hide" id="userDataTable" lay-filter="config"></table>
<script type="text/html" id="operation">
<a class="layui-btn layui-btn-xs" lay-event="edit">修改</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
</div>
</div>
</div>
</div>
</body>
<script>
var element = layui.element;
var table = layui.table;
var layer = layui.layer;
table.render({
id: 'userTable'
,elem: '#userDataTable'
,url: '[[@{/user/listData}]]'
,page: {
layout: ['prev', 'page', 'next', 'count', 'skip', 'limit']
,groups: 5
,first: false
,last: false
}
,cols: [
[
{field:'id', width: 50, title: 'ID'}
,{field:'username', title: '用户名称', align: 'center'}
,{field:'nickname', title: '用户昵称', align: 'center'}
,{title:'操作', align: 'center', toolbar: '#operation', width:150}
]
]
,response: {
statusCode: 200
}
,parseData: function(res){
return {
"code": res.code
,"msg": res.msg
,"count": res.data.total
,"data": res.data.records
};
}
}); active = {
add: function() {
layer.open({
type: 2,
area: ['80%', '80%'],
title: '新增',
content: '[[@{/}]]user/add'
});
},
reload: function() {
table.reload('userTable', {
page: {
curr: 1
}
,where: {
id : $("input[name='id']").val()
,username : $("input[name='username']").val()
,nickname : $("input[name='nickname']").val()
}
}, 'data');
},
reset: function() {
$(".layui-input").val("");
}
}; // 按钮事件
$('.layui-btn').on('click', function(){
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';
}); //监听行工具事件
table.on('tool(config)', function(obj){
var row = obj.data;
if(obj.event === 'del') {
layer.confirm("确认删除吗?", {icon: 3, title:'提示'}, function(index) {
layer.close(index);
$.ajax({
url : "[[@{/}]]user/delete",
data : {'id': row.id},
type : "post",
dataType : "json",
error : function(data) {
errorHandle(data);
},
success : function(data) {
$(".searchTable .layui-btn").eq(0).click();
}
});
});
} else if (obj.event === 'edit') {
layer.open({
type: 2,
area: ['80%', '80%'],
title: '修改',
content: '[[@{/}]]user/edit?id=' + row.id
});
}
}); //错误处理
function errorHandle(data) {
if (data.status == 404) {
layer.msg("请求资源不存在", {icon: 2});
} else {
layer.msg("服务端异常", {icon: 2});
}
return;
}
</script>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/view.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/jquery/jquery-2.1.4.min.js}"></script>
<script th:src="@{/jquery/jquery-form.js}"></script>
<title></title>
</head>
<body class="layui-view-body">
<div class="layui-row">
<div class="layui-card">
<form class="layui-form layui-card-body layui-form-pane" method="post" th:action="@{/user/save}">
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>用户名称</label>
<div class="layui-input-block">
<input type="text" name="username" lay-verify="username" placeholder="6-8位英文字母" maxlength="8" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>用户昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" lay-verify="required" maxlength="15" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>用户密码</label>
<div class="layui-input-inline">
<input type="password" name="password" required lay-verify="password" maxlength="8" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">请输入6-8位密码,且只能包含字母或数字</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>确认密码</label>
<div class="layui-input-inline">
<input type="password" name="confirmPwd" lay-verify="confirm" maxlength="8" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<button type="submit" class="layui-btn" lay-submit lay-filter="*">提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
</body>
<script>
var form = layui.form;
var layer = layui.layer; // 自定义检验
form.verify({
username: function(val) {
if (isEmpty(val)) {
return '必填项不能为空';
}
debugger;
var reg = /^[A-Za-z]{6,8}$/;
if (!reg.test(val)) {
return '用户名称不合法';
}
if (!checkUsername(val)) {
return '用户名称已存在';
}
},
password: [
/^[A-Za-z0-9]{6,8}$/
,'请输入6-8位密码,且只能包含字母或数字'
],
confirm: function(val) {
if (isEmpty(val)) {
return '必填项不能为空';
}
if (val != $("input[name='password']").val()) {
return '确认密码与用户密码不一致';
}
}
}); // 检测用户名称是否唯一
function checkUsername(username) {
var checkResult = true;
$.ajax({
url : "[[@{/}]]user/check",
data : {'username': username},
type : "post",
dataType : "json",
async: false,
error : function(data) {
errorHandle(data);
},
success : function(data) {
checkResult = data.data;
}
});
return checkResult;
} // 提交表单
form.on('submit(*)', function(data){
$(".layui-form").ajaxForm({
error: function(data){
errorHandle(data);
},
success: function(data) {
parent.location.reload();
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
});
}); //是否为空
function isEmpty(n) {
if (n == null || n == '' || typeof(n) == 'undefined') {
return true;
}
return false;
} // 错误处理
function errorHandle(data) {
if (data.status == 404) {
layer.msg("请求资源不存在", {icon: 2});
} else {
layer.msg("服务端异常", {icon: 2});
}
return;
}
</script>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link th:href="@{/layui/css/layui.css}" rel="stylesheet" />
<link th:href="@{/layui/css/view.css}" rel="stylesheet" />
<script th:src="@{/layui/layui.all.js}"></script>
<script th:src="@{/jquery/jquery-2.1.4.min.js}"></script>
<script th:src="@{/jquery/jquery-form.js}"></script>
<title></title>
</head>
<body class="layui-view-body">
<div class="layui-row">
<div class="layui-card">
<form class="layui-form layui-card-body layui-form-pane" method="post" th:action="@{/user/update}">
<div class="layui-form-item">
<label class="layui-form-label">用户ID</label>
<div class="layui-input-block">
<input type="text" name="id" th:value="${user?.id}" readonly="readonly" class="layui-input readonly">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>用户名称</label>
<div class="layui-input-block">
<input type="text" name="username" th:value="${user?.username}" lay-verify="username" placeholder="6-8位英文字母" maxlength="8" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><i>*</i>用户昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" th:value="${user?.nickname}" lay-verify="required" maxlength="15" lay-reqtext="用户昵称是必填项" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<button type="submit" class="layui-btn" lay-submit lay-filter="*">提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</form>
</div>
</div>
</body>
<script>
var form = layui.form;
var layer = layui.layer; // 自定义检验
form.verify({
username: function(val) {
if (isEmpty(val)) {
return '必填项不能为空';
}
if (val != '[[${user?.username}]]') {
var reg = /^[A-Za-z]{6,8}$/;
if (!reg.test(val)) {
return '用户名称不合法';
}
if (!checkUsername(val)) {
return '用户名称已存在';
}
} }
}); // 检测用户名称是否唯一
function checkUsername(username) {
var checkResult = true;
$.ajax({
url : "[[@{/}]]user/check",
data : {'username': username},
type : "post",
dataType : "json",
async: false,
error : function(data) {
errorHandle(data);
},
success : function(data) {
checkResult = data.data;
}
});
return checkResult;
} // 提交表单
form.on('submit(*)', function(data){
$(".layui-form").ajaxForm({
error: function(data){
errorHandle(data);
},
success: function(data) {
parent.location.reload();
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
}
});
}); // 是否为空
function isEmpty(n) {
if (n == null || n == '' || typeof(n) == 'undefined') {
return true;
}
return false;
} // 错误处理
function errorHandle(data) {
if (data.status == 404) {
layer.msg("请求资源不存在", {icon: 2});
} else {
layer.msg("服务端异常", {icon: 2});
}
return;
}
</script>
</html>
  • 创建全局异常页面(404、500等)

      在view文件夹下创建error文件夹,并创建404.html、500.html等。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>C3Stones</title>
<link th:href="@{/images/favicon.ico}" rel="icon">
<style>
body {
height: 300px;
background: url("/images/404.png") center no-repeat;
}
</style>
</head>
<body class="layui-layout-body">
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>C3Stones</title>
<link th:href="@{/images/favicon.ico}" rel="icon">
<style>
body {
height: 300px;
background: url("/images/500.png") center no-repeat;
}
</style>
</head>
<body class="layui-layout-body">
</body>
</html>

4. 项目地址

  spring-boot-layui-demo

SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)的更多相关文章

  1. springboot学习笔记:11.springboot+shiro+mysql+mybatis(通用mapper)+freemarker+ztree+layui实现通用的java后台管理系统(权限管理+用户管理+菜单管理)

    一.前言 经过前10篇文章,我们已经可以快速搭建一个springboot的web项目: 今天,我们在上一节基础上继续集成shiro框架,实现一个可以通用的后台管理系统:包括用户管理,角色管理,菜单管理 ...

  2. SpringBoot + Layui + JustAuth +Mybatis-plus实现可第三方登录的简单后台管理系统

    1. 简介   在之前博客:SpringBoot基于JustAuth实现第三方授权登录 和 SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)上改造 ...

  3. [.Net Core] 简单使用 Mvc 内置的 Ioc

    简单使用 Mvc 内置的 Ioc 本文基于 .NET Core 2.0. 鉴于网上的文章理论较多,鄙人不才,想整理一份 Hello World(Demo)版的文章. 目录 场景一:简单类的使用 场景二 ...

  4. [.Net Core] 简单使用 Mvc 内置的 Ioc(续)

    简单使用 Mvc 内置的 Ioc(续) 本文基于 .NET Core 2.0. 上一章<[.Net Core] 简单使用 Mvc 内置的 Ioc>已经对日常 Mvc 中的 Ioc 的简单用 ...

  5. 简单使用 Mvc 内置的 Ioc

    简单使用 Mvc 内置的 Ioc 本文基于 .NET Core 2.0. 鉴于网上的文章理论较多,鄙人不才,想整理一份 Hello World(Demo)版的文章. 目录 场景一:简单类的使用 场景二 ...

  6. ASP.NET MVC5 + EF6 + LayUI实战教程,通用后台管理系统框架(3)

    前言 本节将我们自己的CSS样式替换系统自带的 开始搭建 将脚本文件夹删掉,将内容文件夹里的内容删掉,将我们自己的CSS样式文件,全部复制到内容里边 新建家庭控制器 给家庭控制器添加索引视图 指数代码 ...

  7. ASP.NET MVC5+EF6+LayUI实战教程,通用后台管理系统框架(4)- 漂亮的登录界面

    前言 这一讲,给大家添加登录页面 实现 添加Login的Index视图 @{ Layout = null; } <!DOCTYPE html> <html class="l ...

  8. ASP.NET MVC5+EF6+LayUI实战教程,通用后台管理系统框架(1)

    文章转自:http://www.xuboyi.com/298.html 前言 网站运营有一段时间了,记录的内容都是杂七杂八的,思前想后,决定给大家分享一套ASP.Net的系列教程.手把手的做一套通用后 ...

  9. 简单后台管理系统框架--HTML练手项目2【Frameset】

    [本文为原创,转载请注明出处] 技术[HTML]   布局[Frameset] 无步骤 <!DOCTYPE html> <html lang="en"> & ...

  10. 【摸鱼神器】UCode Cms管理系统 内置超好用的代码生成器 解决多表连接痛点

    一.序言 UCode Cms管理系统是面向企业级应用软件开发的脚手架.当前版本1.3.4.快速体验: git clone https://gitee.com/decsa/demo-cms.git (一 ...

随机推荐

  1. 汇编语言CPU状态控制指令

    CPU状态控制指令 1.空操作指令NOP /该指令不执行任何操作,只是使IP加1,其机器码占有一个字节的存储单元,常用于程序调试./ 2.总线封锁前缀指令LOCK /该指令与其他指令联合使用,作为指令 ...

  2. 算法:矩阵连乘(Java)动态规划

    Description 给你2个矩阵A.B,我们使用标准的矩阵相乘定义C=AB如下: A数组中栏(column)的数目一定要等于B数组中列(row)的数目才可以做此2数组的相乘.若我们以rows(A) ...

  3. 精尽MyBatis源码分析 - MyBatis初始化(四)之 SQL 初始化(下)

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  4. CorelDRAW绘制的优秀人物肖像插画作品

    艺术创作 关于作者 Dmitry Demidenko (LINEKING),1986 年出生于俄罗斯的斯帕斯克达利尼.他自幼痴迷于绘画,而且对矢量图形很有天赋.他从一家小型省立印刷公司的小设计师做起, ...

  5. jenkins master/slave模式

    master是主机,只有master装jenkins slave是小弟机无需装jenkins,主要执行master分配的任务 一.新建slave 1.新建slave的方法:点击magian jenki ...

  6. linux(cemtos7.x)安装docker

    卸载旧版本 yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest ...

  7. Java基础教程——List(列表)

    集合概述 Java中的集合,指一系列存储数据的接口和类,可以解决复杂的数据存储问题. 导包:import java.util.*; 简化的集合框架图如下: List·列表 ArrayList List ...

  8. 为什么90%的大学都要求计算机专业学习C语言?

    编程语言是编程的工具,计算机相关专业的学生必须具备足够的编程能力.当然,关于"最好语言"的争论从来没有休止过,这里要强调一下:语言的选择真的没那么重要,学习语言的过程最重要是语言的 ...

  9. 【mq读书笔记】定时消息

    mq不支持任意的时间京都,如果要支持,不可避免的需要在Broker层做消息排序,加上持久化方面的考量,将不可避免地带来巨大的性能消耗,所以rocketMQ只支持特定级别的延迟消息. 在Broker短通 ...

  10. LaTeX中的数学公式的初步使用

    数学公式初步使用代码及注释: 显示效果: