'layui的一個登錄和權限示例'

XML Tomcat 勞累的p7前端程序員 2019-08-20
"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

layui的一個登錄和權限示例

"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

layui的一個登錄和權限示例

layui的一個登錄和權限示例

其中resources資源文件裡的layui文件夾下就是layui的所有文件,內容需要到官網下載,解壓後全部複製即可

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.haijunyin</groupId>
<artifactId>layuidemo-permission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>layuidemo-permission</name>
<description>Demo project for Spring Boot</description>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除內置容器,排除內置容器導出成war包可以讓外部容器運行spring-boot項目-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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.properties

#thymelea模板配置
xspring.thymeleaf.prefi=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#熱部署文件,頁面不產生緩存,及時更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

LayuidemoPermissionApplication.java

package com.haijunyin.layuidemo.permission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 繼承SpringBootServletInitializer,因為繼承SpringBootServletInitializer是繼承WebApplicationInitializer的,而servlet容器啟動的時候
* 會將WebApplicationInitializer相關的所有子類實例化(這也是servlet3.0以上的版本提供支持),所以我們還需要在pom.xml
* 文件中導入servlet3.0及以上的版本
*/
@ComponentScan(value = "com.haijunyin.layuidemo.permission")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAsync
public class LayuidemoPermissionApplication extends SpringBootServletInitializer{
@Override
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(LayuidemoPermissionApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(LayuidemoPermissionApplication.class, args);
}
}

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

DefineAdapter.java,攔截器配置

package com.haijunyin.layuidemo.permission.config;
import com.haijunyin.layuidemo.permission.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class DefineAdapter implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//登錄攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除不被攔截的資源
List<String> excludePaths = new ArrayList<>();
//layui的靜態文件
excludePaths.add("/layui/**");
//靜態頁面
excludePaths.add("/**/*.html");
//登錄
excludePaths.add("/");
excludePaths.add("/login");
// excludePaths.add("/error");
registry.addInterceptor(loginInterceptor).
addPathPatterns("/**").excludePathPatterns(excludePaths);
}
}

AdminController.java

package com.haijunyin.layuidemo.permission.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "admin")
public class AdminController {
@RequestMapping(value = "list",method = RequestMethod.GET)
public String list(){
return "權限List測試";
}
}

LoginController.java

package com.haijunyin.layuidemo.permission.controller;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@Autowired
private AdminUserService adminUserService;
/**
* 設置默認打開地址http://localhost:8020的跳轉(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,跳轉到登錄頁
*/
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(HttpServletRequest request, ModelMap modelMap){
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
return "login";
}
}
/**
* 登錄(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,驗證密碼,如果密碼正確,跳轉到index.html, 則把用戶信息放入session,並把adminUserInfo返回前端渲染
* 如果密碼錯誤,跳轉到login.html
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "userPwd", required = false) String userPwd,
@RequestParam(value = "verifyCode", required = false) String verifyCode,
HttpServletRequest request,
ModelMap modelMap){
//先驗證session,再驗證密碼
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
//驗證密碼
AdminUserInfo adminUserInfo0 = adminUserService.findByUserName(userName);
System.out.println("驗證登錄...userName="+userName+"userPwd="+userPwd+"verifyCode="+verifyCode);
if(adminUserInfo0.getUserPwd().equals(userPwd)){
//用戶信息放入session
System.out.println("登錄...成功..." + "用戶名:" + userName);
request.getSession().setAttribute("adminUserInfo", adminUserInfo0);
modelMap.addAttribute("adminUserInfo",adminUserInfo0);
return "index";
}else{
System.out.println("登錄...密碼輸入錯誤..." + "用戶名:" + userName);
return "login";
}
}
}
}

LoginInterceptor.java,登錄攔截器,用於攔截處理登錄和為登錄狀態下的ajax請求

package com.haijunyin.layuidemo.permission.interceptor;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Service
public class LoginInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
//未登錄去登錄
if(null == adminUserInfo){
//注意:這裡需要寫上"/login",而不是"login",否則重定向的地址只會替換最後一個"/"後面的字符串
response.sendRedirect("/login");
}
return true;
}
}

AdminMenuInfo.java,子菜單信息,權限需要真正控制的信息

package com.haijunyin.layuidemo.permission.module;
public class AdminMenuInfo {
/** 子菜單唯一ID,在頁面上面會以它做唯一區分的,對應到相應子窗口的lay-id屬性 */
private String filterId;
/** 子菜單名,對應子窗口的title */
private String menuName;
/** 子菜單URL,對應子窗口的鏈接html,點擊子菜單後,會打開一個iframe並鏈接到此url */
private String menuUrl;
public AdminMenuInfo(){
}
public AdminMenuInfo(String filterId, String menuName, String menuUrl){
this.filterId = filterId;
this.menuName = menuName;
this.menuUrl = menuUrl;
}
public String getFilterId() {
return filterId;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
}

AdminParentInfo.java,父菜單信息

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminParentMenuInfo {
private String parentMenuName;
private List<AdminMenuInfo> adminMenuInfos;
public AdminParentMenuInfo(){
}
public AdminParentMenuInfo(String parentMenuName, List<AdminMenuInfo> adminMenuInfos){
this.parentMenuName = parentMenuName;
this.adminMenuInfos = adminMenuInfos;
}
public String getParentMenuName() {
return parentMenuName;
}
public void setParentMenuName(String parentMenuName) {
this.parentMenuName = parentMenuName;
}
public List<AdminMenuInfo> getAdminMenuInfos() {
return adminMenuInfos;
}
public void setAdminMenuInfos(List<AdminMenuInfo> adminMenuInfos) {
this.adminMenuInfos = adminMenuInfos;
}
}

AdminUserInfo.java,用戶信息,用戶登陸後會放入session

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminUserInfo {
private long id;
private String userName;
private String userPwd;
private List<AdminParentMenuInfo> adminParentMenuInfos;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public List<AdminParentMenuInfo> getAdminParentMenuInfos() {
return adminParentMenuInfos;
}
public void setAdminParentMenuInfos(List<AdminParentMenuInfo> adminParentMenuInfos) {
this.adminParentMenuInfos = adminParentMenuInfos;
}
}

AdminUserService.java

package com.haijunyin.layuidemo.permission.services;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
public interface AdminUserService {
AdminUserInfo findByUserName(String userName);
}

AdminUserServiceImpl.java,用戶登陸信息加載,實際開發過程中,信息都是從數據庫中讀取的,設計用戶-角色-資源的模型結構,本文不做敘述,

package com.haijunyin.layuidemo.permission.services.impl;
import com.haijunyin.layuidemo.permission.module.AdminMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminParentMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class AdminUserServiceImpl implements AdminUserService {
@Override
public AdminUserInfo findByUserName(String userName) {
AdminUserInfo userInfo = new AdminUserInfo();
userInfo.setId(1);
userInfo.setUserName("yhj");
userInfo.setUserPwd("123456");
List<AdminParentMenuInfo> adminParentMenuInfos = new ArrayList<>();
//權限管理
List<AdminMenuInfo> adminMenuInfos1 = new ArrayList<>();
AdminMenuInfo adminMenuInfo1 = new AdminMenuInfo("filter1","用戶","admin/admin_user_list.html");
adminMenuInfos1.add(adminMenuInfo1);
AdminMenuInfo adminMenuInfo2 = new AdminMenuInfo("filter2", "角色","admin/admin_role_list.html");
adminMenuInfos1.add(adminMenuInfo2);
AdminParentMenuInfo adminParentMenuInfo1 = new AdminParentMenuInfo("權限管理",adminMenuInfos1);
adminParentMenuInfos.add(adminParentMenuInfo1);
//訂單管理
List<AdminMenuInfo> adminMenuInfos2 = new ArrayList<>();
AdminMenuInfo adminMenuInfo11 = new AdminMenuInfo("filter3", "訂單列表","order/order_list.html");
adminMenuInfos2.add(adminMenuInfo11);
AdminMenuInfo adminMenuInfo22 = new AdminMenuInfo("filter4", "訂單推送","order/order_send.html");
adminMenuInfos2.add(adminMenuInfo22);
AdminParentMenuInfo adminParentMenuInfo2 = new AdminParentMenuInfo("訂單管理",adminMenuInfos2);
adminParentMenuInfos.add(adminParentMenuInfo2);
userInfo.setAdminParentMenuInfos(adminParentMenuInfos);
return userInfo;
}
}

運行結果

瀏覽器中輸入地址

http://localhost:8020/

彈出登陸頁面

"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

layui的一個登錄和權限示例

layui的一個登錄和權限示例

其中resources資源文件裡的layui文件夾下就是layui的所有文件,內容需要到官網下載,解壓後全部複製即可

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.haijunyin</groupId>
<artifactId>layuidemo-permission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>layuidemo-permission</name>
<description>Demo project for Spring Boot</description>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除內置容器,排除內置容器導出成war包可以讓外部容器運行spring-boot項目-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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.properties

#thymelea模板配置
xspring.thymeleaf.prefi=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#熱部署文件,頁面不產生緩存,及時更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

LayuidemoPermissionApplication.java

package com.haijunyin.layuidemo.permission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 繼承SpringBootServletInitializer,因為繼承SpringBootServletInitializer是繼承WebApplicationInitializer的,而servlet容器啟動的時候
* 會將WebApplicationInitializer相關的所有子類實例化(這也是servlet3.0以上的版本提供支持),所以我們還需要在pom.xml
* 文件中導入servlet3.0及以上的版本
*/
@ComponentScan(value = "com.haijunyin.layuidemo.permission")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAsync
public class LayuidemoPermissionApplication extends SpringBootServletInitializer{
@Override
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(LayuidemoPermissionApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(LayuidemoPermissionApplication.class, args);
}
}

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

DefineAdapter.java,攔截器配置

package com.haijunyin.layuidemo.permission.config;
import com.haijunyin.layuidemo.permission.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class DefineAdapter implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//登錄攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除不被攔截的資源
List<String> excludePaths = new ArrayList<>();
//layui的靜態文件
excludePaths.add("/layui/**");
//靜態頁面
excludePaths.add("/**/*.html");
//登錄
excludePaths.add("/");
excludePaths.add("/login");
// excludePaths.add("/error");
registry.addInterceptor(loginInterceptor).
addPathPatterns("/**").excludePathPatterns(excludePaths);
}
}

AdminController.java

package com.haijunyin.layuidemo.permission.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "admin")
public class AdminController {
@RequestMapping(value = "list",method = RequestMethod.GET)
public String list(){
return "權限List測試";
}
}

LoginController.java

package com.haijunyin.layuidemo.permission.controller;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@Autowired
private AdminUserService adminUserService;
/**
* 設置默認打開地址http://localhost:8020的跳轉(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,跳轉到登錄頁
*/
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(HttpServletRequest request, ModelMap modelMap){
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
return "login";
}
}
/**
* 登錄(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,驗證密碼,如果密碼正確,跳轉到index.html, 則把用戶信息放入session,並把adminUserInfo返回前端渲染
* 如果密碼錯誤,跳轉到login.html
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "userPwd", required = false) String userPwd,
@RequestParam(value = "verifyCode", required = false) String verifyCode,
HttpServletRequest request,
ModelMap modelMap){
//先驗證session,再驗證密碼
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
//驗證密碼
AdminUserInfo adminUserInfo0 = adminUserService.findByUserName(userName);
System.out.println("驗證登錄...userName="+userName+"userPwd="+userPwd+"verifyCode="+verifyCode);
if(adminUserInfo0.getUserPwd().equals(userPwd)){
//用戶信息放入session
System.out.println("登錄...成功..." + "用戶名:" + userName);
request.getSession().setAttribute("adminUserInfo", adminUserInfo0);
modelMap.addAttribute("adminUserInfo",adminUserInfo0);
return "index";
}else{
System.out.println("登錄...密碼輸入錯誤..." + "用戶名:" + userName);
return "login";
}
}
}
}

LoginInterceptor.java,登錄攔截器,用於攔截處理登錄和為登錄狀態下的ajax請求

package com.haijunyin.layuidemo.permission.interceptor;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Service
public class LoginInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
//未登錄去登錄
if(null == adminUserInfo){
//注意:這裡需要寫上"/login",而不是"login",否則重定向的地址只會替換最後一個"/"後面的字符串
response.sendRedirect("/login");
}
return true;
}
}

AdminMenuInfo.java,子菜單信息,權限需要真正控制的信息

package com.haijunyin.layuidemo.permission.module;
public class AdminMenuInfo {
/** 子菜單唯一ID,在頁面上面會以它做唯一區分的,對應到相應子窗口的lay-id屬性 */
private String filterId;
/** 子菜單名,對應子窗口的title */
private String menuName;
/** 子菜單URL,對應子窗口的鏈接html,點擊子菜單後,會打開一個iframe並鏈接到此url */
private String menuUrl;
public AdminMenuInfo(){
}
public AdminMenuInfo(String filterId, String menuName, String menuUrl){
this.filterId = filterId;
this.menuName = menuName;
this.menuUrl = menuUrl;
}
public String getFilterId() {
return filterId;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
}

AdminParentInfo.java,父菜單信息

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminParentMenuInfo {
private String parentMenuName;
private List<AdminMenuInfo> adminMenuInfos;
public AdminParentMenuInfo(){
}
public AdminParentMenuInfo(String parentMenuName, List<AdminMenuInfo> adminMenuInfos){
this.parentMenuName = parentMenuName;
this.adminMenuInfos = adminMenuInfos;
}
public String getParentMenuName() {
return parentMenuName;
}
public void setParentMenuName(String parentMenuName) {
this.parentMenuName = parentMenuName;
}
public List<AdminMenuInfo> getAdminMenuInfos() {
return adminMenuInfos;
}
public void setAdminMenuInfos(List<AdminMenuInfo> adminMenuInfos) {
this.adminMenuInfos = adminMenuInfos;
}
}

AdminUserInfo.java,用戶信息,用戶登陸後會放入session

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminUserInfo {
private long id;
private String userName;
private String userPwd;
private List<AdminParentMenuInfo> adminParentMenuInfos;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public List<AdminParentMenuInfo> getAdminParentMenuInfos() {
return adminParentMenuInfos;
}
public void setAdminParentMenuInfos(List<AdminParentMenuInfo> adminParentMenuInfos) {
this.adminParentMenuInfos = adminParentMenuInfos;
}
}

AdminUserService.java

package com.haijunyin.layuidemo.permission.services;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
public interface AdminUserService {
AdminUserInfo findByUserName(String userName);
}

AdminUserServiceImpl.java,用戶登陸信息加載,實際開發過程中,信息都是從數據庫中讀取的,設計用戶-角色-資源的模型結構,本文不做敘述,

package com.haijunyin.layuidemo.permission.services.impl;
import com.haijunyin.layuidemo.permission.module.AdminMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminParentMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class AdminUserServiceImpl implements AdminUserService {
@Override
public AdminUserInfo findByUserName(String userName) {
AdminUserInfo userInfo = new AdminUserInfo();
userInfo.setId(1);
userInfo.setUserName("yhj");
userInfo.setUserPwd("123456");
List<AdminParentMenuInfo> adminParentMenuInfos = new ArrayList<>();
//權限管理
List<AdminMenuInfo> adminMenuInfos1 = new ArrayList<>();
AdminMenuInfo adminMenuInfo1 = new AdminMenuInfo("filter1","用戶","admin/admin_user_list.html");
adminMenuInfos1.add(adminMenuInfo1);
AdminMenuInfo adminMenuInfo2 = new AdminMenuInfo("filter2", "角色","admin/admin_role_list.html");
adminMenuInfos1.add(adminMenuInfo2);
AdminParentMenuInfo adminParentMenuInfo1 = new AdminParentMenuInfo("權限管理",adminMenuInfos1);
adminParentMenuInfos.add(adminParentMenuInfo1);
//訂單管理
List<AdminMenuInfo> adminMenuInfos2 = new ArrayList<>();
AdminMenuInfo adminMenuInfo11 = new AdminMenuInfo("filter3", "訂單列表","order/order_list.html");
adminMenuInfos2.add(adminMenuInfo11);
AdminMenuInfo adminMenuInfo22 = new AdminMenuInfo("filter4", "訂單推送","order/order_send.html");
adminMenuInfos2.add(adminMenuInfo22);
AdminParentMenuInfo adminParentMenuInfo2 = new AdminParentMenuInfo("訂單管理",adminMenuInfos2);
adminParentMenuInfos.add(adminParentMenuInfo2);
userInfo.setAdminParentMenuInfos(adminParentMenuInfos);
return userInfo;
}
}

運行結果

瀏覽器中輸入地址

http://localhost:8020/

彈出登陸頁面

layui的一個登錄和權限示例

輸入用戶名,密碼(123456),出現首頁

"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

layui的一個登錄和權限示例

layui的一個登錄和權限示例

其中resources資源文件裡的layui文件夾下就是layui的所有文件,內容需要到官網下載,解壓後全部複製即可

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.haijunyin</groupId>
<artifactId>layuidemo-permission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>layuidemo-permission</name>
<description>Demo project for Spring Boot</description>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除內置容器,排除內置容器導出成war包可以讓外部容器運行spring-boot項目-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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.properties

#thymelea模板配置
xspring.thymeleaf.prefi=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#熱部署文件,頁面不產生緩存,及時更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

LayuidemoPermissionApplication.java

package com.haijunyin.layuidemo.permission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 繼承SpringBootServletInitializer,因為繼承SpringBootServletInitializer是繼承WebApplicationInitializer的,而servlet容器啟動的時候
* 會將WebApplicationInitializer相關的所有子類實例化(這也是servlet3.0以上的版本提供支持),所以我們還需要在pom.xml
* 文件中導入servlet3.0及以上的版本
*/
@ComponentScan(value = "com.haijunyin.layuidemo.permission")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAsync
public class LayuidemoPermissionApplication extends SpringBootServletInitializer{
@Override
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(LayuidemoPermissionApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(LayuidemoPermissionApplication.class, args);
}
}

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

DefineAdapter.java,攔截器配置

package com.haijunyin.layuidemo.permission.config;
import com.haijunyin.layuidemo.permission.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class DefineAdapter implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//登錄攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除不被攔截的資源
List<String> excludePaths = new ArrayList<>();
//layui的靜態文件
excludePaths.add("/layui/**");
//靜態頁面
excludePaths.add("/**/*.html");
//登錄
excludePaths.add("/");
excludePaths.add("/login");
// excludePaths.add("/error");
registry.addInterceptor(loginInterceptor).
addPathPatterns("/**").excludePathPatterns(excludePaths);
}
}

AdminController.java

package com.haijunyin.layuidemo.permission.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "admin")
public class AdminController {
@RequestMapping(value = "list",method = RequestMethod.GET)
public String list(){
return "權限List測試";
}
}

LoginController.java

package com.haijunyin.layuidemo.permission.controller;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@Autowired
private AdminUserService adminUserService;
/**
* 設置默認打開地址http://localhost:8020的跳轉(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,跳轉到登錄頁
*/
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(HttpServletRequest request, ModelMap modelMap){
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
return "login";
}
}
/**
* 登錄(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,驗證密碼,如果密碼正確,跳轉到index.html, 則把用戶信息放入session,並把adminUserInfo返回前端渲染
* 如果密碼錯誤,跳轉到login.html
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "userPwd", required = false) String userPwd,
@RequestParam(value = "verifyCode", required = false) String verifyCode,
HttpServletRequest request,
ModelMap modelMap){
//先驗證session,再驗證密碼
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
//驗證密碼
AdminUserInfo adminUserInfo0 = adminUserService.findByUserName(userName);
System.out.println("驗證登錄...userName="+userName+"userPwd="+userPwd+"verifyCode="+verifyCode);
if(adminUserInfo0.getUserPwd().equals(userPwd)){
//用戶信息放入session
System.out.println("登錄...成功..." + "用戶名:" + userName);
request.getSession().setAttribute("adminUserInfo", adminUserInfo0);
modelMap.addAttribute("adminUserInfo",adminUserInfo0);
return "index";
}else{
System.out.println("登錄...密碼輸入錯誤..." + "用戶名:" + userName);
return "login";
}
}
}
}

LoginInterceptor.java,登錄攔截器,用於攔截處理登錄和為登錄狀態下的ajax請求

package com.haijunyin.layuidemo.permission.interceptor;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Service
public class LoginInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
//未登錄去登錄
if(null == adminUserInfo){
//注意:這裡需要寫上"/login",而不是"login",否則重定向的地址只會替換最後一個"/"後面的字符串
response.sendRedirect("/login");
}
return true;
}
}

AdminMenuInfo.java,子菜單信息,權限需要真正控制的信息

package com.haijunyin.layuidemo.permission.module;
public class AdminMenuInfo {
/** 子菜單唯一ID,在頁面上面會以它做唯一區分的,對應到相應子窗口的lay-id屬性 */
private String filterId;
/** 子菜單名,對應子窗口的title */
private String menuName;
/** 子菜單URL,對應子窗口的鏈接html,點擊子菜單後,會打開一個iframe並鏈接到此url */
private String menuUrl;
public AdminMenuInfo(){
}
public AdminMenuInfo(String filterId, String menuName, String menuUrl){
this.filterId = filterId;
this.menuName = menuName;
this.menuUrl = menuUrl;
}
public String getFilterId() {
return filterId;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
}

AdminParentInfo.java,父菜單信息

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminParentMenuInfo {
private String parentMenuName;
private List<AdminMenuInfo> adminMenuInfos;
public AdminParentMenuInfo(){
}
public AdminParentMenuInfo(String parentMenuName, List<AdminMenuInfo> adminMenuInfos){
this.parentMenuName = parentMenuName;
this.adminMenuInfos = adminMenuInfos;
}
public String getParentMenuName() {
return parentMenuName;
}
public void setParentMenuName(String parentMenuName) {
this.parentMenuName = parentMenuName;
}
public List<AdminMenuInfo> getAdminMenuInfos() {
return adminMenuInfos;
}
public void setAdminMenuInfos(List<AdminMenuInfo> adminMenuInfos) {
this.adminMenuInfos = adminMenuInfos;
}
}

AdminUserInfo.java,用戶信息,用戶登陸後會放入session

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminUserInfo {
private long id;
private String userName;
private String userPwd;
private List<AdminParentMenuInfo> adminParentMenuInfos;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public List<AdminParentMenuInfo> getAdminParentMenuInfos() {
return adminParentMenuInfos;
}
public void setAdminParentMenuInfos(List<AdminParentMenuInfo> adminParentMenuInfos) {
this.adminParentMenuInfos = adminParentMenuInfos;
}
}

AdminUserService.java

package com.haijunyin.layuidemo.permission.services;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
public interface AdminUserService {
AdminUserInfo findByUserName(String userName);
}

AdminUserServiceImpl.java,用戶登陸信息加載,實際開發過程中,信息都是從數據庫中讀取的,設計用戶-角色-資源的模型結構,本文不做敘述,

package com.haijunyin.layuidemo.permission.services.impl;
import com.haijunyin.layuidemo.permission.module.AdminMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminParentMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class AdminUserServiceImpl implements AdminUserService {
@Override
public AdminUserInfo findByUserName(String userName) {
AdminUserInfo userInfo = new AdminUserInfo();
userInfo.setId(1);
userInfo.setUserName("yhj");
userInfo.setUserPwd("123456");
List<AdminParentMenuInfo> adminParentMenuInfos = new ArrayList<>();
//權限管理
List<AdminMenuInfo> adminMenuInfos1 = new ArrayList<>();
AdminMenuInfo adminMenuInfo1 = new AdminMenuInfo("filter1","用戶","admin/admin_user_list.html");
adminMenuInfos1.add(adminMenuInfo1);
AdminMenuInfo adminMenuInfo2 = new AdminMenuInfo("filter2", "角色","admin/admin_role_list.html");
adminMenuInfos1.add(adminMenuInfo2);
AdminParentMenuInfo adminParentMenuInfo1 = new AdminParentMenuInfo("權限管理",adminMenuInfos1);
adminParentMenuInfos.add(adminParentMenuInfo1);
//訂單管理
List<AdminMenuInfo> adminMenuInfos2 = new ArrayList<>();
AdminMenuInfo adminMenuInfo11 = new AdminMenuInfo("filter3", "訂單列表","order/order_list.html");
adminMenuInfos2.add(adminMenuInfo11);
AdminMenuInfo adminMenuInfo22 = new AdminMenuInfo("filter4", "訂單推送","order/order_send.html");
adminMenuInfos2.add(adminMenuInfo22);
AdminParentMenuInfo adminParentMenuInfo2 = new AdminParentMenuInfo("訂單管理",adminMenuInfos2);
adminParentMenuInfos.add(adminParentMenuInfo2);
userInfo.setAdminParentMenuInfos(adminParentMenuInfos);
return userInfo;
}
}

運行結果

瀏覽器中輸入地址

http://localhost:8020/

彈出登陸頁面

layui的一個登錄和權限示例

輸入用戶名,密碼(123456),出現首頁

layui的一個登錄和權限示例

點擊權限管理或訂單管理,出現子窗口信息

"

搭建項目

項目架構是springboot+thymeleaf+layui,結構如下圖,文件有點多,分成兩張圖

layui的一個登錄和權限示例

layui的一個登錄和權限示例

其中resources資源文件裡的layui文件夾下就是layui的所有文件,內容需要到官網下載,解壓後全部複製即可

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.haijunyin</groupId>
<artifactId>layuidemo-permission</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>layuidemo-permission</name>
<description>Demo project for Spring Boot</description>
<packaging>war</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除內置容器,排除內置容器導出成war包可以讓外部容器運行spring-boot項目-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</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.properties

#thymelea模板配置
xspring.thymeleaf.prefi=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#熱部署文件,頁面不產生緩存,及時更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

LayuidemoPermissionApplication.java

package com.haijunyin.layuidemo.permission;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 繼承SpringBootServletInitializer,因為繼承SpringBootServletInitializer是繼承WebApplicationInitializer的,而servlet容器啟動的時候
* 會將WebApplicationInitializer相關的所有子類實例化(這也是servlet3.0以上的版本提供支持),所以我們還需要在pom.xml
* 文件中導入servlet3.0及以上的版本
*/
@ComponentScan(value = "com.haijunyin.layuidemo.permission")
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAsync
public class LayuidemoPermissionApplication extends SpringBootServletInitializer{
@Override
public SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(LayuidemoPermissionApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(LayuidemoPermissionApplication.class, args);
}
}

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

admin_user_list.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<title>layui在線調試</title>
<link rel="stylesheet" href="../layui/css/layui.css" media="all">
<style>
body{margin: 10px;}
.demo-carousel{height: 200px; line-height: 200px; text-align: center;}
</style>
</head>
<body>
<table class="layui-hide" id="demo" lay-filter="test"></table>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<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 class="layui-tab layui-tab-brief" lay-filter="demo">
<ul class="layui-tab-title">
<li class="layui-this">演示說明</li>
<li>日期</li>
<li>分頁</li>
<li>上傳</li>
<li>滑塊</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show">
<div class="layui-carousel" id="test1">
<div carousel-item>
<div><p class="layui-bg-green demo-carousel">在這裡,你將以最直觀的形式體驗 layui!</p></div>
<div><p class="layui-bg-red demo-carousel">在編輯器中可以執行 layui 相關的一切代碼</p></div>
<div><p class="layui-bg-blue demo-carousel">你也可以點擊左側導航針對性地試驗我們提供的示例</p></div>
<div><p class="layui-bg-orange demo-carousel">如果最左側的導航的高度超出了你的屏幕</p></div>
<div><p class="layui-bg-cyan demo-carousel">你可以將鼠標移入導航區域,然後滑動鼠標滾輪即可</p></div>
</div>
</div>
</div>
<div class="layui-tab-item">
<div id="laydateDemo"></div>
</div>
<div class="layui-tab-item">
<div id="pageDemo"></div>
</div>
<div class="layui-tab-item">
<div class="layui-upload-drag" id="uploadDemo">
<i class="layui-icon"></i>
<p>點擊上傳,或將文件拖拽到此處</p>
</div>
</div>
<div class="layui-tab-item">
<div id="sliderDemo" style="margin: 50px 20px;"></div>
</div>
</div>
</div>
<blockquote class="layui-elem-quote layui-quote-nm layui-hide" id="footer">layui {{ layui.v }} 提供強力驅動</blockquote>
<script src="../layui/layui.js"></script>
<script>
layui.config({
version: '1545041465480' //為了更新 js 緩存,可忽略
});
layui.use(['laydate', 'laypage', 'layer', 'table', 'carousel', 'upload', 'element', 'slider'], function(){
var laydate = layui.laydate //日期
,laypage = layui.laypage //分頁
,layer = layui.layer //彈層
,table = layui.table //表格
,carousel = layui.carousel //輪播
,upload = layui.upload //上傳
,element = layui.element //元素操作
,slider = layui.slider //滑塊
//向世界問個好
layer.msg('Hello World');
//監聽Tab切換
element.on('tab(demo)', function(data){
layer.tips('切換了 '+ data.index +':'+ this.innerHTML, this, {
tips: 1
});
});
//執行一個 table 實例
table.render({
elem: '#demo'
,height: 420
,url: '/demo/table/user/' //數據接口
,title: '用戶表'
,page: true //開啟分頁
,toolbar: 'default' //開啟工具欄,此處顯示默認圖標,可以自定義模板,詳見文檔
,totalRow: true //開啟合計行
,cols: [[ //表頭
{type: 'checkbox', fixed: 'left'}
,{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left', totalRowText: '合計:'}
,{field: 'username', title: '用戶名', width:80}
,{field: 'experience', title: '積分', width: 90, sort: true, totalRow: true}
,{field: 'sex', title: '性別', width:80, sort: true}
,{field: 'score', title: '評分', width: 80, sort: true, totalRow: true}
,{field: 'city', title: '城市', width:150}
,{field: 'sign', title: '簽名', width: 200}
,{field: 'classify', title: '職業', width: 100}
,{field: 'wealth', title: '財富', width: 135, sort: true, totalRow: true}
,{fixed: 'right', width: 165, align:'center', toolbar: '#barDemo'}
]]
});
//監聽頭工具欄事件
table.on('toolbar(test)', function(obj){
var checkStatus = table.checkStatus(obj.config.id)
,data = checkStatus.data; //獲取選中的數據
switch(obj.event){
case 'add':
layer.msg('添加');
break;
case 'update':
if(data.length === 0){
layer.msg('請選擇一行');
} else if(data.length > 1){
layer.msg('只能同時編輯一個');
} else {
layer.alert('編輯 [id]:'+ checkStatus.data[0].id);
}
break;
case 'delete':
if(data.length === 0){
layer.msg('請選擇一行');
} else {
layer.msg('刪除');
}
break;
};
});
//監聽行工具事件
table.on('tool(test)', function(obj){ //注:tool 是工具條事件名,test 是 table 原始容器的屬性 lay-filter="對應的值"
var data = obj.data //獲得當前行數據
,layEvent = obj.event; //獲得 lay-event 對應的值
if(layEvent === 'detail'){
layer.msg('查看操作');
} else if(layEvent === 'del'){
layer.confirm('真的刪除行麼', function(index){
obj.del(); //刪除對應行(tr)的DOM結構
layer.close(index);
//向服務端發送刪除指令
});
} else if(layEvent === 'edit'){
layer.msg('編輯操作');
}
});
//執行一個輪播實例
carousel.render({
elem: '#test1'
,width: '100%' //設置容器寬度
,height: 200
,arrow: 'none' //不顯示箭頭
,anim: 'fade' //切換動畫方式
});
//將日期直接嵌套在指定容器中
var dateIns = laydate.render({
elem: '#laydateDemo'
,position: 'static'
,calendar: true //是否開啟公曆重要節日
,mark: { //標記重要日子
'0-10-14': '生日'
,'2018-08-28': '新版'
,'2018-10-08': '神祕'
}
,done: function(value, date, endDate){
if(date.year == 2017 && date.month == 11 && date.date == 30){
dateIns.hint('一不小心就月底了呢');
}
}
,change: function(value, date, endDate){
layer.msg(value)
}
});
//分頁
laypage.render({
elem: 'pageDemo' //分頁容器的id
,count: 100 //總頁數
,skin: '#1E9FFF' //自定義選中色值
//,skip: true //開啟跳頁
,jump: function(obj, first){
if(!first){
layer.msg('第'+ obj.curr +'頁', {offset: 'b'});
}
}
});
//上傳
upload.render({
elem: '#uploadDemo'
,url: '' //上傳接口
,done: function(res){
console.log(res)
}
});
slider.render({
elem: '#sliderDemo'
,input: true //輸入框
});
//底部信息
var footerTpl = lay('#footer')[0].innerHTML;
lay('#footer').html(layui.laytpl(footerTpl).render({}))
.removeClass('layui-hide');
});
</script>
</body>
</html>

DefineAdapter.java,攔截器配置

package com.haijunyin.layuidemo.permission.config;
import com.haijunyin.layuidemo.permission.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class DefineAdapter implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
//登錄攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//排除不被攔截的資源
List<String> excludePaths = new ArrayList<>();
//layui的靜態文件
excludePaths.add("/layui/**");
//靜態頁面
excludePaths.add("/**/*.html");
//登錄
excludePaths.add("/");
excludePaths.add("/login");
// excludePaths.add("/error");
registry.addInterceptor(loginInterceptor).
addPathPatterns("/**").excludePathPatterns(excludePaths);
}
}

AdminController.java

package com.haijunyin.layuidemo.permission.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "admin")
public class AdminController {
@RequestMapping(value = "list",method = RequestMethod.GET)
public String list(){
return "權限List測試";
}
}

LoginController.java

package com.haijunyin.layuidemo.permission.controller;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
@Autowired
private AdminUserService adminUserService;
/**
* 設置默認打開地址http://localhost:8020的跳轉(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,跳轉到登錄頁
*/
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(HttpServletRequest request, ModelMap modelMap){
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
return "login";
}
}
/**
* 登錄(需要在攔截器中排除)
* 1.已登錄,跳轉到index.html,把adminUserInfo返回前端渲染
* 2.未登錄,驗證密碼,如果密碼正確,跳轉到index.html, 則把用戶信息放入session,並把adminUserInfo返回前端渲染
* 如果密碼錯誤,跳轉到login.html
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String login(@RequestParam(value = "userName", required = false) String userName,
@RequestParam(value = "userPwd", required = false) String userPwd,
@RequestParam(value = "verifyCode", required = false) String verifyCode,
HttpServletRequest request,
ModelMap modelMap){
//先驗證session,再驗證密碼
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
if(null != adminUserInfo){
modelMap.addAttribute("adminUserInfo",adminUserInfo);
return "index";
}else{
//驗證密碼
AdminUserInfo adminUserInfo0 = adminUserService.findByUserName(userName);
System.out.println("驗證登錄...userName="+userName+"userPwd="+userPwd+"verifyCode="+verifyCode);
if(adminUserInfo0.getUserPwd().equals(userPwd)){
//用戶信息放入session
System.out.println("登錄...成功..." + "用戶名:" + userName);
request.getSession().setAttribute("adminUserInfo", adminUserInfo0);
modelMap.addAttribute("adminUserInfo",adminUserInfo0);
return "index";
}else{
System.out.println("登錄...密碼輸入錯誤..." + "用戶名:" + userName);
return "login";
}
}
}
}

LoginInterceptor.java,登錄攔截器,用於攔截處理登錄和為登錄狀態下的ajax請求

package com.haijunyin.layuidemo.permission.interceptor;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Service
public class LoginInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
AdminUserInfo adminUserInfo = (AdminUserInfo) session.getAttribute("adminUserInfo");
//未登錄去登錄
if(null == adminUserInfo){
//注意:這裡需要寫上"/login",而不是"login",否則重定向的地址只會替換最後一個"/"後面的字符串
response.sendRedirect("/login");
}
return true;
}
}

AdminMenuInfo.java,子菜單信息,權限需要真正控制的信息

package com.haijunyin.layuidemo.permission.module;
public class AdminMenuInfo {
/** 子菜單唯一ID,在頁面上面會以它做唯一區分的,對應到相應子窗口的lay-id屬性 */
private String filterId;
/** 子菜單名,對應子窗口的title */
private String menuName;
/** 子菜單URL,對應子窗口的鏈接html,點擊子菜單後,會打開一個iframe並鏈接到此url */
private String menuUrl;
public AdminMenuInfo(){
}
public AdminMenuInfo(String filterId, String menuName, String menuUrl){
this.filterId = filterId;
this.menuName = menuName;
this.menuUrl = menuUrl;
}
public String getFilterId() {
return filterId;
}
public void setFilterId(String filterId) {
this.filterId = filterId;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMenuUrl() {
return menuUrl;
}
public void setMenuUrl(String menuUrl) {
this.menuUrl = menuUrl;
}
}

AdminParentInfo.java,父菜單信息

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminParentMenuInfo {
private String parentMenuName;
private List<AdminMenuInfo> adminMenuInfos;
public AdminParentMenuInfo(){
}
public AdminParentMenuInfo(String parentMenuName, List<AdminMenuInfo> adminMenuInfos){
this.parentMenuName = parentMenuName;
this.adminMenuInfos = adminMenuInfos;
}
public String getParentMenuName() {
return parentMenuName;
}
public void setParentMenuName(String parentMenuName) {
this.parentMenuName = parentMenuName;
}
public List<AdminMenuInfo> getAdminMenuInfos() {
return adminMenuInfos;
}
public void setAdminMenuInfos(List<AdminMenuInfo> adminMenuInfos) {
this.adminMenuInfos = adminMenuInfos;
}
}

AdminUserInfo.java,用戶信息,用戶登陸後會放入session

package com.haijunyin.layuidemo.permission.module;
import java.util.List;
public class AdminUserInfo {
private long id;
private String userName;
private String userPwd;
private List<AdminParentMenuInfo> adminParentMenuInfos;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public List<AdminParentMenuInfo> getAdminParentMenuInfos() {
return adminParentMenuInfos;
}
public void setAdminParentMenuInfos(List<AdminParentMenuInfo> adminParentMenuInfos) {
this.adminParentMenuInfos = adminParentMenuInfos;
}
}

AdminUserService.java

package com.haijunyin.layuidemo.permission.services;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
public interface AdminUserService {
AdminUserInfo findByUserName(String userName);
}

AdminUserServiceImpl.java,用戶登陸信息加載,實際開發過程中,信息都是從數據庫中讀取的,設計用戶-角色-資源的模型結構,本文不做敘述,

package com.haijunyin.layuidemo.permission.services.impl;
import com.haijunyin.layuidemo.permission.module.AdminMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminParentMenuInfo;
import com.haijunyin.layuidemo.permission.module.AdminUserInfo;
import com.haijunyin.layuidemo.permission.services.AdminUserService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class AdminUserServiceImpl implements AdminUserService {
@Override
public AdminUserInfo findByUserName(String userName) {
AdminUserInfo userInfo = new AdminUserInfo();
userInfo.setId(1);
userInfo.setUserName("yhj");
userInfo.setUserPwd("123456");
List<AdminParentMenuInfo> adminParentMenuInfos = new ArrayList<>();
//權限管理
List<AdminMenuInfo> adminMenuInfos1 = new ArrayList<>();
AdminMenuInfo adminMenuInfo1 = new AdminMenuInfo("filter1","用戶","admin/admin_user_list.html");
adminMenuInfos1.add(adminMenuInfo1);
AdminMenuInfo adminMenuInfo2 = new AdminMenuInfo("filter2", "角色","admin/admin_role_list.html");
adminMenuInfos1.add(adminMenuInfo2);
AdminParentMenuInfo adminParentMenuInfo1 = new AdminParentMenuInfo("權限管理",adminMenuInfos1);
adminParentMenuInfos.add(adminParentMenuInfo1);
//訂單管理
List<AdminMenuInfo> adminMenuInfos2 = new ArrayList<>();
AdminMenuInfo adminMenuInfo11 = new AdminMenuInfo("filter3", "訂單列表","order/order_list.html");
adminMenuInfos2.add(adminMenuInfo11);
AdminMenuInfo adminMenuInfo22 = new AdminMenuInfo("filter4", "訂單推送","order/order_send.html");
adminMenuInfos2.add(adminMenuInfo22);
AdminParentMenuInfo adminParentMenuInfo2 = new AdminParentMenuInfo("訂單管理",adminMenuInfos2);
adminParentMenuInfos.add(adminParentMenuInfo2);
userInfo.setAdminParentMenuInfos(adminParentMenuInfos);
return userInfo;
}
}

運行結果

瀏覽器中輸入地址

http://localhost:8020/

彈出登陸頁面

layui的一個登錄和權限示例

輸入用戶名,密碼(123456),出現首頁

layui的一個登錄和權限示例

點擊權限管理或訂單管理,出現子窗口信息

layui的一個登錄和權限示例

總結

到此,Demo結束,可以看出一個完整的登陸和權限也是不簡單的,本文只是把主幹完成了,細節的東西沒用去設計,比如登陸頁的校驗、驗證碼,還有權限的表設計,等等,不過這些都不是問題了,後續只需要慢慢完善即可,我們通過這個Demo,已經成功地開啟了layui的大門

"

相關推薦

推薦中...