基于vue + spring boot学生宿舍管理
1、环境准备
1、安装node.js
2、安装vue-cli
3、安装 vs code开发工具
2、下载node.js
浏览器打开 https://nodejs.org/zh-cn/download/ 进入下载
1.2点击【以往的版本】进入所示列表界面,选择自己所需要的版本进行下载安装
3、vue-cli安装
1.2.1检查node.js是否安装
通过命令提示符,node -v npm -v查看,如果没有请先安装node.js,如下图,说明已经安装node.js
1.2.2.把npm换成cnpm
命令工具输入 npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完成 输入 cnpm -v 查看是否安装成功
卸载cnpm npm uninstall cnpm -g
1.2.3.安装vue-cli
cnpm install -g @vue/cli
1.2.4.查看vue-cli是否安装成功
vue -V
注意 V是大写的
4、vs code安装
第03讲 vue-admin-template下载
1、vue-element-admin介绍
vue-element-admin 是一个后台前端解决方案,它基于 vue 和 element-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
建议
本项目的定位是后台集成方案,不太适合当基础模板来进行二次开发。因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余。如果你的项目不关注这方面的问题,也可以直接基于它进行二次开发。
- 集成方案: vue-element-admin
- 基础模板: vue-admin-template
- 桌面终端: electron-vue-admin
- Typescript 版: vue-typescript-admin-template (鸣谢: @Armour)
- Others: awesome-project
vue-element-admin和vue-admin-template区别
1、vue-admin-template是vue-element-admin的简化版,适合企业搭建项目;并且简化版有两个版本,注意选择;
2、vue-element-admin 定位是后台集成方案,不太适合当基础模板来进行二次开发。因为本项目集成了很多你可能用不到的功能,会造成不少的代码冗余
2、vue-admin-template下载
在线演示地址
https://panjiachen.github.io/vue-admin-template/#/login?redirect=%2Fdashboard
下载地址
https://gitee.com/panjiachen/vue-admin-template/blob/master/README-zh.md
3、运行项目
1.安装依赖 npm install
2.运行项目 npm run dev
4、运行项目报错解决
1. error Multiple spaces found before '//需要添加该项,否则上级不...' no-multi-spaces错误
找到项目的.eslintrc.js配置文件把rules:中的 'no-multi-spaces': 'off' //关闭空格的检查
2. error Trailing spaces not allowed no-trailing-spaces错误
找到项目的.eslintrc.js配置文件在rules:中添加 'no-trailing-spaces': 'error', // 行末不要空格
第04讲 配置左侧导航菜单
1、修改应用的名称
找到src目录下的settings.js配置文件,修改为如下所示
module.exports = {
title: '学生宿舍管理系统',
/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: true, //固定头部
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: true //显示图标
}
2、修改右侧的下拉菜单
找到src/layout/components下的Navbar.vue文件,把el-dropdown-menu修改为如下所示代码
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<el-dropdown-item divided>
<span style="display:block;">重置密码</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
<span style="display:block;">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
3、修改Dashboard为首页
3.1、修改router下的router.js里面的dashboard的title为 首页
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
}
3.2、修改components/Breadcrumb/index.vue中的 title 为首页
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched)
}
4、新建模块页面,并创建页面对应的路由
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true if set true, item will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu
* if not set alwaysShow, when item has more than one children route,
* it will becomes nested mode, otherwise not show the root menu
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
}
*/
/**
* constantRoutes
* a base page that does not have permission requirements
* all roles can be accessed
*/
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard' }
}]
}
]
/**
* asyncRoutes
* the routes htat need to be dynamically loaded based on user roles
*/
export const asyncRoutes ='/system [
{
component:Layout,
alwaysShowh:true,
{
path: '/colloge',
icomponent:dLayout,
alwaysShow1,true name: 'colloge',
meta: da{ ti:l "2'学院管理', icon: 'el-icon5s2help' },
children: [
{
path: '/collogeList',
pa'/sysRoleLth:'用户管理's'icon:,
'table' }
children: [
{
path: '/sysUserList',
name
'sysRoleList' path: '/sysMenuList',
name: 'collogeList',
component: () => import('@/views/system/sysMenuList'),
meta: { title: '菜单管理', icon: 'tree' }
}
]
{
path: '/majorList',
name: 'majorList'
component: () => import('@/views/colloge/majorList'),
meta: { title: '专业管理', icon: 'tree' }
},
{
path: '/classList',
name: 'classList',
component: () => import('@/views/colloge/collogeList'),
},
mett: '学院管理', icoa: {
'table' }
},
}
</script>
<style lang="scss" scoped>
</style>
3.2、在src/views下新建colloge文件夹,并新建如下页面
1、collogeList.vue页面
<template>
<div>学院管理</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped>
</style>
2、majorList.vue页面
<template>
<div>专业管理</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped>
</style>
3、classList.vue页面
<template>
<div>班级管理</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped>
</style>
constantRoutes
})
constroutes:
#router#=#cre# "Router()
// Detail see20https://github.com/vuejs/vue-router/issues/0234#issuecomment-31794
465efunctionxresetRouter()port {
const newRoutern=acreateRouter()
merouter.matcher:= newRouter.matcher"// reset王router
}
export def虎ult router
##### 4、新建上面路由中对应的组件页面
###### 4.1、在src/views下新建syste"目录
1.新建sysM,nuList.vue组件
```js
<template>
<div>
菜单管理component: () => import('@/views/colloge/classList'),
meta: { title: '班级管理', icon: 'tree' }
}
]
children: [
用理 </div>
</template>
<script>
{
export default }
]
const createRouter = () =>inewdRouter({
: // mo3e1,'history' // require service support scrollBehavior: () => ({ y: 0 }),
date: "2016-05-01",
<div> name: "王小虎",
addresysRoleList.vue组件
```js
<template>
<div>
角色管理
},
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true </div>
</template>
<script>
id: 3export default {
2,
}
</script>
<style lang="scss" scoped>
</style>
3.新建sysUserList.vue组件
<template>
date: 5、菜单改为打开一个
找到src/layout下的components目录,修改SideBar目录下的index.vue中的 :unique-opened="true"
#### 第05讲 项目添加添加tagsview选项卡
###### 1、添加TagsView文件
把vue-element-admin项目中的src\layout\components下的TagsView文件夹复制到vue-admin-template的 src\layout\components下
把vue-element-admin\src\store\modules\tagsView.js 复制到vue-admin-template\srcstore\modules\
###### 2、修改 vue-admin-template\src\layout\components\AppMain.vue文件
```js
<template>
<section class="app-main">
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
],
},
{
id: 4,
date: "2016-05-03",
<transition name="fade-transform":"mode=王out-in,> <!-- <router-view :key="key" /> -->
<keep-alive :include="cachedrVisws上>
<router-view :key="key" },/> ],</keep-alive> </transition>
</section>
</template>
<script> } export default {
name:}"AppMain"
mcoopned(: {
cachedViews) {
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.path;
},
},
};
</script>
<style scoped>
.app-main {
/*50 = navbar */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header + .app-main {
padding-top: 50px;
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>
3、修改vue-admin-template\src\layout\components\index.js
新增如下行:
export { default as TagsView } from './TagsView'
4、修改 vue-admin-template\src\layout\index.vue
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
</div>
<tags-view />
<app-main />
</div>
</div>
</template>
<script>
import { Navbar, Sidebar, AppMain,TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
export default {
name: 'Layout',
components: {
Navbar,
Sidebar,
AppMain,
TagsView
},
mixins: [ResizeMixin],
computed: {
sidebar() {
return this.$store.state.app.sidebar
},
device() {
return this.$store.state.app.device
},
fixedHeader() {
return this.$store.state.settings.fixedHeader
},
classObj() {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar{
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px)
}
.mobile .fixed-header {
width: 100%;
}
</style>
5、修改 vue-admin-template\src\store\getters.js,
新增
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews
}
export default getters
6、修改 vue-admin-template\src\store\index.js
引入 import tagsView from ‘./modules/tagsView’
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
import settings from './modules/settings'
import user from './modules/user'
import tagsView from './modules/tagsView'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app,
settings,
user,
tagsView
},
getters
})
export default store
7、运行报错
解决方式
删除vue-admin-template\src\layout\components\TagsView\index.vue中routes方法
8、解决开启头部固定,不会显示 TagsView的问题
如果settings里面开启的如下所示,TagsView将不会显示
fixedHeader: true,
8.1、修改vue-admin-template\src\settings.js 添加
tagsView: true,
8.2、修改vue-admin-template\src\store\modules\settings.js
import defaultSettings from '@/settings'
const { showSettings, fixedHeader, sidebarLogo,tagsView } = defaultSettings
const state = {
showSettings: showSettings,
fixedHeader: fixedHeader,
sidebarLogo: sidebarLogo,
tagsView: tagsView,
}
const mutations = {
CHANGE_SETTING: (state, { key, value }) => {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(key)) {
state[key] = value
}
}
}
const actions = {
changeSetting({ commit }, data) {
commit('CHANGE_SETTING', data)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
8.3、修改 vue-admin-template\src\layout\components\AppMain.vue文件的样式如下
主要是有hasTagsView样式的时候
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<!-- <router-view :key="key" /> -->
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
</section>
</template>
<script>
export default {
name: "AppMain",
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.path;
},
},
};
</script>
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header+.app-main {
padding-top: 50px;
}
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
}
.fixed-header+.app-main {
padding-top: 84px;
}
}
</style>
<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>
8.4、修改 vue-admin-template\src\layout\index.vue如下
主要是通过needTagsView进行判断
<template>
<div :class="classObj" class="app-wrapper">
<div
v-if="device === 'mobile' && sidebar.opened"
class="drawer-bg"
@click="handleClickOutside"
/>
<sidebar class="sidebar-container" />
<div :class="{ hasTagsView: needTagsView }" class="main-container">
<div :class="{ 'fixed-header': fixedHeader }">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
</div>
<!-- <div class="hasTagsView main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
</div>
<tags-view />
<app-main />
</div> -->
</div>
</template>
<script>
import { Navbar, Sidebar, AppMain, TagsView } from "./components";
import ResizeMixin from "./mixin/ResizeHandler";
export default {
name: "Layout",
components: {
Navbar,
Sidebar,
AppMain,
TagsView,
},
mixins: [ResizeMixin],
computed: {
sidebar() {
return this.$store.state.app.sidebar;
},
device() {
return this.$store.state.app.device;
},
fixedHeader() {
return this.$store.state.settings.fixedHeader;
},
needTagsView() {
return this.$store.state.settings.tagsView;
},
classObj() {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === "mobile",
};
},
},
methods: {
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
},
};
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
.mobile .fixed-header {
width: 100%;
}
</style>
9、解决刷新浏览器,TagsView选项卡丢失问题
找到 src\views\layout\components\TagsView.vue 组件
9.1、在methods方法中添加如下方法
// 解决刷新浏览器tabs选项卡丢失问题
beforeUnload() {
// 监听页面刷新
window.addEventListener("beforeunload", () => {
// visitedViews数据结构太复杂无法直接JSON.stringify处理,先转换需要的数据
let tabViews = this.visitedViews.map((item) => {
return {
fullPath: item.fullPath,
hash: item.hash,
meta: { ...item.meta },
name: item.name,
params: { ...item.params },
path: item.path,
query: { ...item.query },
title: item.title,
};
});
sessionStorage.setItem("tabViews", JSON.stringify(tabViews));
});
// 页面初始化加载判断缓存中是否有数据
let oldViews = JSON.parse(sessionStorage.getItem("tabViews")) || [];
if (oldViews.length > 0) {
this.$store.state.tagsView.visitedViews = oldViews;
}
},
9.2、mounted()生命周期函数中添加刷新选项卡方法
mounted() {
this.initTags();
this.addTags();
// 解决刷新选项卡丢失问题
this.beforeUnload();
},
10、解决选项卡为【首页】不能关闭的问题
在router中的index.js找到首页路由配置项,并在 meta中添加 affix: true 如下meta配置所示
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '首页', icon: 'dashboard', affix: true }
}]
}
第06讲 权限相关数据库设计
采用RBAC模型
1、用户表字段(sys_user)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|---|---|---|---|---|
user_id | int | 11 | 是 | 否 | 用户id |
username | varchar | 64 | 否 | 是 | 登录账户 |
password | varchar | 128 | 否 | 是 | 登录密码 |
phone | varchar | 13 | 否 | 是 | 用户电话 |
varchar | 36 | 否 | 是 | 邮箱 | |
sex | varchar | 2 | 否 | 是 | 0:男 1:女 |
is_admin | tinyint | 2 | 否 | 是 | 是否为超级管理员 1:是 0:否 |
is_account_non_expired | tinyint | 2 | 否 | 是 | 帐户是否过期(1 未过期,0已过期) |
is_account_non_locked | tinyint | 2 | 否 | 是 | 帐户是否被锁定(1 未锁定,0已锁定) |
is_credentials_non_expired | tinyint | 2 | 否 | 是 | 密码是否过期(1 未过期,0已过期) |
is_enabled | tinyint | 2 | 否 | 是 | 帐户是否可用(1 可用,0 删除用户) |
nick_name | varchar | 36 | 否 | 是 | 姓名 |
create_time | datetime | 否 | 是 | 创建时间 | |
update_time | datetime | 否 | 是 | 更新时间 |
2、用户角色表(sys_user_role)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|---|---|---|---|---|
user_role_id | int | 11 | 是 | 否 | 主键 |
user_id | int | 11 | 否 | 否 | 用户id |
role_id | int | 11 | 否 | 否 | 角色id |
3、角色表字段(sys_role)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|---|---|---|---|---|
role_id | int | 11 | 是 | 否 | 角色id |
role_name | varchar | 64 | 否 | 是 | 角色名称 |
role_type | varchar | 2 | 否 | 是 | 角色类型 1:系统用户 2:学生 |
remark | varchar | 128 | 否 | 是 | 备注 |
create_time | datetime | 否 | 是 | 创建时间 | |
update_time | datetime | 否 | 是 | 更新时间 |
4、角色菜单表(sys_role_menu)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|---|---|---|---|---|
role_menu_id | int | 11 | 是 | 否 | 主键 |
menu_id | int | 11 | 否 | 否 | 菜单id |
role_id | int | 11 | 否 | 否 | 角色id |
5、菜单表字段(sys_menu)
字段名称 | 数据类型 | 字段大小 | 是否主键 | 是否为空 | 备注 |
---|---|---|---|---|---|
menu_id | int | 11 | 是 | 否 | 菜单id |
parent_id | int | 11 | 否 | 是 | 父级菜单id |
title | varchar | 64 | 否 | 是 | 菜单名称 |
code | varchar | 64 | 否 | 是 | 权限字段 |
name | varchar | 36 | 否 | 是 | 路由name |
path | varchar | 36 | 否 | 是 | 路由path |
url | varchar | 128 | 否 | 是 | 组件路径 |
type | varchar | 2 | 否 | 是 | 类型(0 目录 1菜单,2按钮) |
icon | varchar | 36 | 否 | 是 | 菜单图标 |
parent_name | varchar | 64 | 否 | 是 | 上级菜单名称 |
order_num | int | 11 | 否 | 是 | 序号 |
create_time | datetime | 否 | 是 | 创建时间 | |
update_time | datetime | 否 | 是 | 更新时间 |
/*==============================================================*/
/* DBMS name: MySQL 5.0 */
/* Created on: 2021-10-12 14:54:17 */
/*==============================================================*/
drop table if exists sys_menu;
drop table if exists sys_role;
drop table if exists sys_role_menu;
drop table if exists sys_user;
drop table if exists sys_user_role;
/*==============================================================*/
/* Table: sys_menu */
/*==============================================================*/
create table sys_menu
(
menu_id int not null auto_increment comment '菜单id',
parent_id int comment '父级菜单id',
title varchar(36) comment '菜单名称',
code varchar(36) comment '权限字段',
name varchar(36) comment '路由name',
path varchar(36) comment '路由path',
url varchar(128) comment '组件路径',
type varchar(2) comment '类型(0 目录 1菜单,2按钮)',
icon varchar(36) comment '菜单图标',
parent_name varchar(36) comment '上级菜单名称',
order_num int comment '序号',
create_time datetime comment '创建时间',
update_time datetime comment '更新时间',
primary key (menu_id)
);
/*==============================================================*/
/* Table: sys_role */
/*==============================================================*/
create table sys_role
(
role_id int not null auto_increment comment '角色id',
role_name varchar(36) comment '角色名称',
role_type varchar(2) comment '角色类型 1:系统用户 2:学生',
remark varchar(64) comment '备注',
create_time datetime comment '创建时间',
update_time datetime comment '更新时间',
primary key (role_id)
);
/*==============================================================*/
/* Table: sys_role_menu */
/*==============================================================*/
create table sys_role_menu
(
role_menu_id int not null auto_increment comment '主键',
role_id int comment '角色id',
menu_id int comment '菜单id',
primary key (role_menu_id)
);
/*==============================================================*/
/* Table: sys_user */
/*==============================================================*/
create table sys_user
(
user_id int not null auto_increment comment '用户id',
username varchar(36) comment '登录账户',
password varchar(128) comment '密码',
phone varchar(13) comment '13',
email varchar(36) comment '邮箱',
sex varchar(2) comment '性别',
is_admin varchar(2) comment '是否是管理员',
is_account_non_expired int comment '帐户是否过期(1 未过期,0已过期)',
is_account_non_locked int comment '帐户是否被锁定(1 未锁定,0已锁定)',
is_credentials_non_expired int comment '密码是否过期(1 未过期,0已过期)',
is_enabled int comment '帐户是否可用(1 可用,0 删除用户)',
nick_name varbinary(36) comment '姓名',
create_time datetime comment '创建时间',
update_time datetime comment '更新时间',
primary key (user_id)
);
/*==============================================================*/
/* Table: sys_user_role */
/*==============================================================*/
create table sys_user_role
(
user_role_id int not null auto_increment comment '主键',
user_id int comment '用户id',
role_id int comment '角色id',
primary key (user_role_id)
);
第07讲 后台多模块系统搭建
开发环境配置:
1、JDK安装配置
2、IDEA安装
3、maven安装
4、MySql安装
5、数据库可视化工具 Navicat安装
maven配置
1、配置本地仓库地址: <localRepository>D:\javaDe\apache-maven-3.5.4\repo</localRepository>
2、修改为阿里镜像:
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
1、项目依赖版本号**
JDk1.8及以上、Maven3.5以上、MySq5.7以上
2、项目结构
itmk-base-parent | 父模块,pom类型、统一管理子模块 |
---|---|
itmk-base-common | 公共模块、如通用工具的封装等 |
itmk-base-web | 前端接口模块,提供api接口 |
3、创建itmk-base-parent父模块
1、打开IDEA,file -> new - > project
2、选择左侧Maven,Project SDK选择1.8及以上,点击Next
3、Name里面输入模块名称,Location选择项目存储路径,GroupId:输入包名,同一个项目,各个模块的包名一致 ArtifactId: 模块名称;点击Finish
4、由于itmk-base-parent作为父模块,把生成的模块中的src删除;
4、创建itmk-base-common模块
1.在父模块itmk-base-parent上右键->New->Module,如下所示
2.选择Maven,SDK选择1.8及以上,点击Next
3.Name:输入模块名称 itmk-base-common,点击Finish
5、创建itmk-base-web模块
1.itmk-base-parent模块右键,点击New->Module
2.选择Maven,SDK选择1.8及以上,点击 Next
3.Name填入模块名称,点击Finish
4.项目最终模块
第08讲 引入各个模块依赖
1、修改package类型
修改父模块 itmk-base-parent的pom.xml打包类型为 pom;
itmk-base-common的pom.xml打包类型为 jar;
itmk-base-wem的pom.xml打包类型为jar
2、itmk-base-parent 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>
<groupId>com.itmk</groupId>
<artifactId>itmk-base-parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>itmk-base-common</module>
<module>itmk-base-web</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
</parent>
<properties>
<java.version>1.8</java.version>
<swagger2.version>3.0.0</swagger2.version>
<lombok-version>1.18.12</lombok-version>
<mybatis-plus.version>3.4.2</mybatis-plus.version>
<druid.version>1.2.1</druid.version>
<kaptcha.version>2.3.2</kaptcha.version>
<fastjson.version>1.2.68</fastjson.version>
<commons-lang.version>2.6</commons-lang.version>
<commons-collections.version>3.2.2</commons-collections.version>
<commons-io.version>2.6</commons-io.version>
<mysql-connection.version>8.0.21</mysql-connection.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connection.version}</version>
<scope>runtime</scope>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- kaptcha 图形验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!-- JSON转换工具类依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons-collections.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${swagger2.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3、itmk-base-common 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">
<parent>
<artifactId>itmk-base-parent</artifactId>
<groupId>com.itmk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>itmk-base-common</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- swagger api文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<!-- jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- 工具类依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
</project>
4、itmk-base-web 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">
<parent>
<artifactId>itmk-base-parent</artifactId>
<groupId>com.itmk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>itmk-base-web</artifactId>
<dependencies>
<dependency>
<groupId>com.itmk</groupId>
<artifactId>itmk-base-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web启动器,对springmvc,serlvet等支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--数据库依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-plus启动器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- swagger api文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.4.RELEASE</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skipTests>true</skipTests> <!--打包过程默认关掉单元测试 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
第09讲 整合MyBatis Plus
mybatis plus官方教程**
https://mp.baomidou.com/guide/
1、新建application.yml文件
1.1、在itmk-base-web模块resources文件下新建 application-test.yml文件
#端口号配置
server:
port: 8089
#数据库连接配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sys_wygl?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456
#mybatis plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
#配置mybatis plus 在更新时只更新非空和非NULL的字段
update-strategy: not_empty
logging:
pattern:
console: '%d{yyyy-MM-dd} [%thread] %-5level %logger- %msg%n'
1.2、在itmk-base-web模块resources文件下新建 application.yml文件
spring:
profiles:
active: test
2、配置MyBatis Plus配置文件
package com.itmk.config.mybatis;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.itmk.*.*.mapper")
public class MyBatisPlusConfig {
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
3、封装返回值
在itmk-base-common下新建 com.itmk.utils包
package com.itmk.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ResultVo<T> {
private String msg;
private int code;
private T data;
}
4、返回状态码定义
在itmk-base-common模块新建com.itmk.status包,然后新建 StatusCode类,如下所示
package com.itmk.status;
/**
* 返回状态码
*/
public class StatusCode {
//返回成功
public static final int SUCCESS_CODE = 200;
//错误状态码
public static final int ERROR_CODE = 500;
//无权限
public static final int NO_LOGIN = 600;
public static final int NO_AUTH = 700;
}
5、返回工具类的封装
在itmk-base-common模块下的com.itmk.utils包中新建ResultUtils类
package com.itmk.utils;
import com.itmk.status.StatusCode;
/**
* 数据返回工具类
*/
public class ResultUtils {
/**
* 无参数返回
* @return
*/
public static ResultVo succcess() {
return Vo(null, StatusCode.SUCCESS_CODE, null);
}
public static ResultVo success(String msg){
return Vo(msg,StatusCode.SUCCESS_CODE,null);
}
/**
* 返回带参数
* @param msg
* @param data
* @return
*/
public static ResultVo success(String msg,Object data){
return Vo(msg,StatusCode.SUCCESS_CODE,data);
}
public static ResultVo success(String msg,int code,Object data){
return Vo(msg,code,data);
}
public static ResultVo Vo(String msg, int code, Object data) {
return new ResultVo(msg, code, data);
}
/**
* 错误返回
* @return
*/
public static ResultVo error(){
return Vo(null,StatusCode.ERROR_CODE,null);
}
public static ResultVo error(String msg){
return Vo(msg,StatusCode.ERROR_CODE,null);
}
public static ResultVo error(String msg,int code,Object data){
return Vo(msg,code,data);
}
public static ResultVo error(String msg,int code){
return Vo(msg,code,null);
}
public static ResultVo error(String msg,Object data){
return Vo(msg, StatusCode.ERROR_CODE,data);
}
}
第10讲 用户管理列表页面制作
1、sysUserList.vue页面编写
<template>
<el-main>
<!-- 搜索栏 element ui的标签,就当做普通的div就可以,只是他添加了一些属性
:model: form表单绑定的数据,通常是一个对象
:rules: form表单验证的规则
ref : 类似div的id,是唯一的
label-width:表单文字标签的宽度
:inline : 是否同一行显示
size: 表单内组件的大小
-->
<el-form
:model="listParm"
ref="searchRef"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item>
<el-input
placeholder="请输入姓名"
v-model="listParm.nickName"
></el-input>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入电话" v-model="listParm.phone"></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button style="color: #ff7670" icon="el-icon-close" @click="resetBtn">重置</el-button>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table :height='tableHeight' :data="tableData" border stripe>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column prop="date" label="日期"></el-table-column>
<el-table-column label="操作" align="center" width="180">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10,20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total" background>
</el-pagination>
</el-main>
</template>
<script>
export default {
data() {
return {
//表格高度
tableHeight:0,
//列表查询的参数
listParm: {
phone: "",
nickName: "",
currentPage:1,
pageSize:10,
total:0
},
//表格的数据
tableData: [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀区金沙江路 1518 弄",
},
{
id: 2,
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀区金沙江路 1517 弄",
},
{
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
children: [
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀区金沙江路 1519 弄",
},
],
},
{
id: 4,
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀区金沙江路 1516 弄",
},
],
};
},
methods: {
//重置按钮
resetBtn(){
},
//搜索按钮
searchBtn(){
},
//新增按钮
addBtn() {},
//编辑按钮
editBtn(row) {},
//删除按钮
deleteBtn(row) {},
//页容量改变触发
sizeChange(val){
},
//页数改变触发
currentChange(val){
}
},
mounted(){
this.$nextTick(() =>{
this.tableHeight = window.innerHeight -220
})
}
};
</script>
<style lang="scss" scoped>
</style>
2、分页插件显示中文
在main.js中引入如下,注释原来的local
// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
import locale from 'element-ui/lib/locale/lang/zh-CN'
第11讲 通用弹框组件封装
知识点:
父组件向子组件传值 :属性绑定
子组件调用父组件的方法 : $emit向父组件触发事件
1.封装效果
2.对话框官网
https://element.eleme.cn/#/zh-CN/component/dialog
3.对话框封装
在components下新建system目录,然后新建SysDialog.vue组件,然后把官网弹框代码复制进去
<!--弹出框组件
参数说明:
title:弹出框标题
visible:控制弹出框的显示和影藏
width:弹出框的宽度,百分百,0~100的整数
before-close:弹出框右上角关闭事件
close-on-click-modal:防止点击弹出框以外的区域造成弹出框关闭
-->
<template>
<div>
<el-dialog
top="5vh"
:title="title"
:visible.sync="visible"
:width="width + 'px'"
:before-close="onClose"
:close-on-click-modal="false"
>
<div class="containner" :style="{ height: height + 'px' }">
<slot name="content"></slot>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="onClose">取 消</el-button>
<el-button type="primary" @click="onConfirm">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: "标题",
},
visible: {
type: Boolean,
default: false,
},
width: {
type: Number,
default: 600,
},
height: {
type: Number,
default: 250,
},
},
data() {
return {};
},
methods: {
onClose() {
this.$emit("onClose");
},
onConfirm() {
this.$emit("onConfirm");
},
},
};
</script>
<style lang="scss" scoped>
.containner{
overflow-x: initial;
overflow-y: auto;
}
.el-dialog__wrapper {
::v-deep .el-dialog {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
.el-dialog__header {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
background-color: #1890ff;
.el-dialog__title {
color: #fff;
font-size: 15px;
font-weight: 700;
}
.el-dialog__close {
color: #fff;
}
}
.el-dialog__body {
padding: 10px 10px !important;
}
.el-dialog__footer {
border-top: 1px solid #e8eaec !important;
padding: 10px !important;
}
}
}
</style>
4.测试官网对话框
找到sysUserList.vue组件,然后引入SysDialog.vue组件,并注册SysDialog组件
<template>
<div>
<sys-dialog
:title="addDialog.title"
:visible="addDialog.visible"
:width="addDialog.width"
:height="addDialog.height"
@onClose="onColse"
@onConfirm="onConfirm"
>
<div slot="content">弹框内容</div>
</sys-dialog>
</div>
</template>
<script>
import SysDialog from "@/components/system/SysDialog";
export default {
components: {
SysDialog
},
data(){
return{
addDialog: {
title: "新增用",
visible: false,
width: 600,
height: 250,
},
}
},
methods:{
//弹框取消事件
onColse() {
this.addDialog.visible = false;
},
//弹框确认事件
onConfirm() {
this.addDialog.visible = false;
},
}
};
</script>
<style lang="scss" scoped>
</style>
第12讲 新增用户页面布局讲解
1、解决点击弹框外关闭问题
1、添加 :close-on-click-modal='false' 属性
2、新增表单
3、代码
<!-- 新增或编辑弹框组件 -->
<sys-dialog
:title="dialog.title"
:visible="dialog.visible"
:width="dialog.width"
:height="dialog.height"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<!-- form表单
el-form : 当做普通的form标签
model : 表单数据对象
ref : 相当于div的id,唯一的
rules : 表单验证规则
label-width : 表单域标签的宽度
inline : 是否在同一行显示,如果和el-row使用的时候,不需要添加该属性
size : 尺寸
el-form-item : 当做普通的div,
-->
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="60px"
size="small"
style="margin-right: 20px"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="姓名">
<el-input v-model="addModel.nickName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="电话">
<el-input v-model="addModel.phone"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="邮箱">
<el-input v-model="addModel.email"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="性别">
<el-radio-group v-model="addModel.sex">
<el-radio :label="'0'">男</el-radio>
<el-radio :label="'1'">女</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="账户">
<el-input v-model="addModel.username"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item label="密码">
<el-input v-model="addModel.password"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
第13讲 表单验证规则
1、表单验证的关键
1、给表单添加ref属性
2、给el-form-item添加prop属性
3、定义表单验证的规则
4、表单提交时,通过 this.$refs.表单的ref.validate()
第14讲 用户管理接口开发
1、新建用户实体类
新建com.itmk.web.sys_user.entity包,然后新建SysUser实体类
package com.itmk.web.sys_user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("sys_user")
public class SysUser {
@TableId(type = IdType.AUTO)
private Long userId;
private String username;
private String password;
private String phone;
private String email;
private String sex;
private String isAdmin;
//帐户是否过期(1 未过期,0已过期)
private boolean isAccountNonExpired = true;
//帐户是否被锁定(1 未锁定,0已锁定)
private boolean isAccountNonLocked = true;
//密码是否过期(1 未过期,0已过期)
private boolean isCredentialsNonExpired = true;
//帐户是否可用(1 可用,0 删除用户)
private boolean isEnabled = true;
private String nickName;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
}
2、新建mapper接口
package com.itmk.web.sys_user.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_user.entity.SysUser;
public interface SysUserMapper extends BaseMapper<SysUser> {
}
3、新建mapper接口映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_user.mapper.SysUserMapper">
</mapper>
4、新建service层
package com.itmk.web.sys_user.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
public interface SysUserService extends IService<SysUser> {
IPage<SysUser> list(PageParm parm);
}
参数接收类
package com.itmk.web.sys_user.entity;
import lombok.Data;
@Data
public class PageParm {
private Long currentPage;
private Long pageSize;
private String phone;
private String nickName;
}
实现类
package com.itmk.web.sys_user.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
import com.itmk.web.sys_user.mapper.SysUserMapper;
import com.itmk.web.sys_user.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
@Override
public IPage<SysUser> list(PageParm parm) {
//构造分页对象
IPage<SysUser> page = new Page<>();
page.setSize(parm.getPageSize());
page.setCurrent(parm.getCurrentPage());
QueryWrapper<SysUser> query = new QueryWrapper<>();
if(StringUtils.isNotEmpty(parm.getNickName())){
query.lambda().like(SysUser::getNickName,parm.getNickName());
}
if(StringUtils.isNotEmpty(parm.getPhone())){
query.lambda().like(SysUser::getPhone,parm.getPhone());
}
return this.baseMapper.selectPage(page,query);
}
@Override
@Transactional
public void add(SysUser user) {
//新增用户
int insert = this.baseMapper.insert(user);
//保存角色
if(insert > 0){
SysUserRole role = new SysUserRole();
role.setRoleId(user.getRoleId());
role.setUserId(user.getUserId());
sysUserRoleService.save(role);
}
}
@Override
@Transactional
public void edit(SysUser user) {
//编辑
int i = this.baseMapper.updateById(user);
//角色 :先删除,再插入
if(i > 0){
//先删除原来的角色
QueryWrapper<SysUserRole> query = new QueryWrapper<>();
query.lambda().eq(SysUserRole::getUserId,user.getUserId());
sysUserRoleService.remove(query);
//保存
SysUserRole role = new SysUserRole();
role.setUserId(user.getUserId());
role.setRoleId(user.getRoleId());
sysUserRoleService.save(role);
}
}
}
9、SysUserController控制器
package com.itmk.web.sys_user.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.sys_role.entity.SysRole;
import com.itmk.web.sys_role.service.SysRoleService;
import com.itmk.web.sys_user.entity.PageParm;
import com.itmk.web.sys_user.entity.SysUser;
import com.itmk.web.sys_user.service.SysUserService;
import com.itmk.web.sys_user_role.entity.SysUserRole;
import com.itmk.web.sys_user_role.service.SysUserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/api/user")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
@Autowired
privas.generateToken(map);
//构造返回值
LoginResult result = new LoginResult();
result.setUserId(user.getUserId());
result.setToken(token);
result.setUsername(user.getUsername());
return ResultUtils.success("登录成功", result);
}
}
package com.itmk.web.login.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class LoginParm {
private String username;
private String password;
private String userType;
}
package com.itmk.web.login.entity;
import lombok.Data;
/**
* @Author java实战基地
* @Version 3501754007
*/
@Data
public class LoginResult {
private Long userId;
private String username;
private String token;
}
第32讲 登录接口对接
登录流程图
1、api/user.js添加loginApi()方法
import request from '@/utils/request'
import http from '@/utils/http'
export function login(data) {
return request({
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
method: 'post'
})
}
//获取用户列表
export const getListApi = async(parm) =>{
return await http.get("/api/user/list",parm)
}
//新增
export const addUserApi = async(parm) =>{
return await http.post("/api/user",parm)
}
//编辑
export const editUserApi = async(parm) =>{
return await http.put("/api/user",parm)
}
//删除
export const deleteUserApi = async(parm) =>{
return await http.delete("/api/user",parm)
}
//角色列表
export const getRoleListApi = async()=>{
return await http.get("/api/user/roleList")
}
//获取角色
export const getRoleApi = async(parm)=>{
return await http.get("/api/user/role",parm)
}
//登录对接
export const loginApi = async(parm)=>{
return await http.post("/api/login/login",parm)
}
2、utils下的auth.js添加存储用户id的方法
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
const userIdKey = 'userId'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
//存储用户id
export function setUserId(userId) {
return sessionStorage.setItem(userIdKey, userId)
}
export function getUserId() {
return sessionStorage.getItem(userIdKey)
}
export function removeUserId() {
return sessionStorage.remove(userIdKey);
}
//sessionStorage清空
export function clearSession() {
return sessionStorage.clear()
}
3、store/user.js中的login修改为如下
// user login
login({ commit }, userInfo) {
const { username, password,userType } = userInfo
return new Promise((resolve, reject) => {
loginApi({ username: username.trim(), password: password ,userType:userType}).then(response => {
console.log(response)
const { data } = response
// commit('SET_TOKEN', data.token)
commit('SET_TOKEN', 'admin-token')
setToken(data.token)
resolve()
//构造查询条件
}).catch(error => {
reject(error)
})
})
},
4、登录页面
<template>
<div class="logincontainer">
<el-form
class="loginForm"
:model="addModel"
ref="loginForm"
:rules="rules"
:inline="false"
size="normal"
>
<el-form-item>
<span class="loginTitle">高校宿舍管理系统</span>
</el-form-item>
<el-form-item prop="username">
<el-input
placeholder="请输入账户"
v-model="addModel.username"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请输入密码"
v-model="addModel.password"
></el-input>
</el-form-item>
<el-form-item prop="userType">
<el-radio-group v-model="addModel.userType">
<el-radio :label="0">学生</el-radio>
<el-radio :label="1">管理员</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-row :gutter="20">
<el-col :span="12" :offset="0">
<el-button class="mybtn" type="primary" @click="onSubmit"
>登录</el-button
>
</el-col>
<el-col :span="12" :offset="0">
<el-button class="mybtn">取消</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
addModel: {
username: "",
password: "",
userType: "",
},
rules: {
username: [
{
trigger: "change",
required: true,
message: "请输入账户",
},
],
password: [
{
trigger: "change",
required: true,
message: "请输入密码",
},
],
userType: [
{
trigger: "change",
required: true,
message: "请选择用户类型",
},
],
},
};
},
methods: {
onSubmit() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.$store.dispatch("user/login", this.addModel).then(() => {
this.$router.push({ path: this.redirect || "/" });
});
}
});
},
},
};
</script>
<style lang="scss" scoped>
.logincontainer {
height: 100%;
background: #fff;
background-image: url("../../assets/images/login_bg.png");
display: flex;
align-items: center;
justify-content: center;
background-size: 100% 100%;
.loginForm {
height: 350px;
width: 450px;
background: #fff;
padding: 35px 20px;
border-radius: 10px;
.loginTitle {
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
font-weight: 600;
color: #409eff;
}
.mybtn {
width: 100%;
}
}
}
</style>
第33讲 分配权限树回显接口开发
1、SysMenuService接口新增getMenuByUserId()方法和getMenuByRoleId()方法
//根据用户id查询权限
List<SysMenu> getMenuByUserId(Long userId);
//根据角色id查询权限
List<SysMenu> getMenuByRoleId(Long roleId);
SysMenuServiceImpl实现类
@Override
public List<SysMenu> getMenuByUserId(Long userId) {
return this.baseMapper.getMenuByUserId(userId);
}
@Override
public List<SysMenu> getMenuByRoleId(Long roleId) {
return this.baseMapper.getMenuByRoleId(roleId);
}
2、SysMenuMapper接口新增getMenuByUserId()方法和getMenuByRoleId()方法
//根据用户id查询权限
List<SysMenu> getMenuByUserId(@Param("userId") Long userId);
//根据角色id查询权限
List<SysMenu> getMenuByRoleId(@Param("roleId") Long roleId);
3、SysMenuMapper.xml映射文件
<select id="getMenuByUserId" resultType="com.itmk.web.sys_menu.entity.SysMenu">
select m.* from sys_user_role as ur
left join sys_role as r on ur.role_id = r.role_id
left join sys_role_menu as rm on r.role_id = rm.role_id
left join sys_menu as m on rm.menu_id = m.menu_id
where ur.user_id =#{userId}
order by m.order_num asc
</select>
<select id="getMenuByRoleId" resultType="com.itmk.web.sys_menu.entity.SysMenu">
select m.* from sys_role_menu as rm , sys_menu as m
where rm.menu_id = m.menu_id and rm.role_id =#{roleId}
</select>
4、新建AssignVo实体类
package com.itmk.web.sys_role.entiy;
import com.itmk.web.sys_menu.entity.SysMenu;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AssignVo {
//当前用户拥有的菜单
private List<SysMenu> menuList = new ArrayList<>();
//被分配的角色拥有的菜单id
private Object[] checkList;
}
5、SysRoleService接口新增getAssignShow()方法
参数实体类
package com.itmk.web.sys_role.entiy;
import lombok.Data;
@Data
public class AssignParm {
private Long userId;
private Long roleId;
}
//角色权限的回显
AssignVo getAssignShow(AssignParm parm);
实现类
@Override
public AssignVo getAssignShow(AssignParm parm) {
//查询当前用户的信息
SysUser user = sysUserService.getById(parm.getUserId());
//菜单数据
List<SysMenu> list = null;
if(user.getIsAdmin().equals("1")){ //如果是超级管理员,拥有所有的权限
QueryWrapper<SysMenu> query = new QueryWrapper<>();
query.lambda().orderByAsc(SysMenu::getOrderNum);
list = sysMenuService.list(query);
}else{
list = sysMenuService.getMenuByUserId(user.getUserId());
}
//组装树
List<SysMenu> menuList = MakeTree.makeMenuTree(list, 0L);
//查询角色原来的菜单
List<SysMenu> roleList = sysMenuService.getMenuByRoleId(parm.getRoleId());
List<Long> ids = new ArrayList<>();
Optional.ofNullable(roleList).orElse(new ArrayList<>()).stream().filter(item -> item != null).forEach(item ->{
ids.add(item.getMenuId());
});
//组装数据
AssignVo vo = new AssignVo();
vo.setMenuList(menuList);
vo.setCheckList(ids.toArray());
return vo;
}
6、SysRoleController控制器添加getAssingShow()方法
//查询角色权限树的回显
@GetMapping("/getAssingShow")
public ResultVo getAssingShow(AssignParm parm) {
AssignVo show = sysRoleService.getAssignShow(parm);
return ResultUtils.success("查询成功", show);
}
第34讲 分配权限回显对接
1、api/role.js添加assignRoleApi()方法
import http from '@/utils/http'
//列表
export const getListApi = async(parm) =>{
return await http.get("/api/role/list",parm)
}
//新增
export const addRoleApi = async(parm) =>{
return await http.post("/api/role",parm)
}
//编辑
export const editRoleApi = async(parm) =>{
return await http.put("/api/role",parm)
}
//删除
export const deleteRoleApi = async(parm) =>{
return await http.delete("/api/role",parm)
}
//分配权限回显
export const assignRoleApi = async(parm)=>{
return await http.get("/api/role/getAssingShow",parm)
}
2、sysRoleList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form
:model="listParm"
ref="searchRef"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="searchBtn" icon="el-icon-search">搜索</el-button>
<el-button @click="resetBtn" style="color: #ff7670" icon="el-icon-close"
>重置</el-button
>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
size="small"
:data="tableData"
border
stripe
>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="角色备注"></el-table-column>
<el-table-column label="操作" align="center" width="300">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="ediBtn(scope.row)"
>编辑</el-button
>
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="assignBtn(scope.row)"
>分配权限</el-button
>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 或分页组件 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:width="dialog.width"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
<!-- el-form :当做一个普通的form标签
el-input : 相当于 普通的 input标签
el-form-item : 表单的每一项
model : 表单绑定的数据
ref : 相当于一个div的id , 唯一的
rules : 表单验证规则
label-width : 表单域标签的宽度
inline : 是否在同一行显示,如果和el-row使用时,不需要该属性
size : 尺寸
-->
background
>
</el-pagination>
<!-- 新增编辑弹框 -->
<sys-dialog
:title="dialog.title"
style="margin-right: 40px"
:visible="dialog.visible"
:height="dialog.height"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="nickName" label="姓名">
<el-input v-model="addModel.nickName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="phone" label="电话">
<el-input v-model="addModel.phone"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="邮箱">
<el-input v-model="addModel.email"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="sex" label="性别">
<el-radio-group v-model="addModel.sex">
<el-radio :label="'0'">男</el-radio>
<el-radio :label="'1'">女</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="username" label="账户">
<el-input v-model="addModel.username"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '0'" :span="12" :offset="0">
<el-form-item prop="password" label="密码">
<el-input v-model="addModel.password"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import { getListApi, addUserApi, editUserApi } from "@/api/user";
//引入弹框组件
import SysDialog from "@/components/dialog/SysDialog.vue";
export default {
//注册弹框组件
components: {
SysDialog,
},
data() {
return {
//表单验证规则
rules: {
nickName: [
{
trigger: "blur",
required: true,
message: "请填写姓名",
},
],
phone: [
{
trigger: "blur",
required: true,
message: "请填写电话",
},
],
sex: [
{
trigger: "blur",
required: true,
message: "请选择性别",
},
],
username: [
{
trigger: "blur",
required: true,
message: "请填写账户",
},
],
password: [
{
trigger: "blur",
required: true,
message: "请填写密码",
},
],
},
//表单绑定的数据
addModel: {
type: "",
userId: "",
nickName: "",
phone: "",
email: "",
sex: "",
username: "",
password: "",
},
//弹框属性
dialog: {
title: "",
visible: false,
width: 630,
height: 200,
},
//表格的高度
tableHeight: 0,
listParm: {
total: 0,
pageSize: 10, //默认每页显示10条数据
currentPage: 1,
nickName: "",
phone: "",
},
tableData: [],
};
},
created() {
this.getList();
},
methods: {
async getList() {
let res = await getListApi(this.listParm);
console.log("请求成功");
console.log(res);
if (res && res.code == 200) {
this.tableData = res.data.records;
this.listParm.total = res.data.total;
}
},
//弹框的确定
onConfirm() {
//表单验证
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addUserApi(this.addModel);
} else {
res = await editUserApi(this.addModel);
}
if (res && res.code == 200) {
//刷新表单
this.getList();
this.$message({ type: "success", message: res.msg });
}
}
});
},
//弹框的取消
onClose() {
this.dialog.visible = false;
},
//页数改变时触发
currentChange(val) {},
//页容量改变时触发
sizeChange(val) {},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑用户";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//把当前要编辑的数据复制到表单数据域
this.$objCoppy(row, this.addModel);
//设置编辑标识
this.addModel.type = "1";
},
//搜索按钮
searchBtn() {},
//搜索按钮
resetBtn() {},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//设置编辑标识
this.addModel.type = "0";
},
},
mounted() {
this.$nextTick(() => {
//计算表格的高度
this.tableHeight = window.innerHeight - 220;
});
},
};
</script>
<style lang="scss" scoped>
</style>
第18讲 删除、搜索功能对接
1、api/user下新建如下方法
//删除
export const deleteUserApi = async(parm) =>{
return await http.delete("/api/user",parm)
}
2、sysUserList.vue
<template>
<!-- 只需要把element的标签,当做一个普通的div -->
<el-main>
<!-- 搜索栏
:model: 表单绑定的数据,通常是一个对象
ref : 相当于一个div的id,唯一的
:rules : 表单验证的规则
label-width: 表单域标签的宽度,例如 '50px'
:inline : 是否在同一行显示
size: 尺寸
-->
<el-form
:model="listParm"
ref="form"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item>
<el-input
placeholder="请输入姓名"
v-model="listParm.nickName"
></el-input>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入电话" v-model="listParm.phone"></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search" @click="searchBtn">搜索</el-button>
<el-button icon="el-icon-close" style="color: #ff7670" @click="resetBtn"
>重置</el-button
>
<el-button type="primary" icon="el-icon-plus" @click="addBtn"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格
:data 表格的数据
-->
<el-table :height="tableHeight" :data="tableData" border stripe>
<el-table-column prop="nickName" label="姓名"></el-table-column>
<el-table-column prop="phone" label="电话"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="assignBtn(scope.row)"
>分配权限</el-button
>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
<!-- 新增或编辑弹框组件 -->
<sys-dialog
:title="dialog.title"
:width="dialog.width"
:visible="dialog.visible"
:height="dialog.height"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<!-- el-form :当做一个普通的form标签
el-input : 相当于 普通的 input标签
el-form-item : 表单的每一项
model : 表单绑定的数据
ref : 相当于一个div的id , 唯一的
rules : 表单验证规则
label-width : 表单域标签的宽度
inline : 是否在同一行显示,如果和el-row使用时,不需要该属性
size : 尺寸
-->
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
style="margin-right: 40px"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="nickName" label="姓名">
<el-input v-model="addModel.nickName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="phone" label="电话">
<el-input v-model="addModel.phone"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="邮箱">
<el-input v-model="addModel.email"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="sex" label="性别">
<el-radio-group v-model="addModel.sex">
<el-radio :label="'0'">男</el-radio>
<el-radio :label="'1'">女</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="username" label="账户">
<el-input v-model="addModel.username"></el-input>
</el-form-item>
</el-col>
<el-col v-if="addModel.type == '0'" :span="12" :offset="0">
<el-form-item prop="password" label="密码">
<el-input v-model="addModel.password"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import { getListApi, addUserApi, editUserApi, deleteUserApi } from "@/api/user";
//引入弹框组件
import SysDialog from "@/components/dialog/SysDialog.vue";
export default {
//注册弹框组件
components: {
SysDialog,
},
data() {
return {
//表单验证规则
rules: {
nickName: [
{
trigger: "blur",
required: true,
message: "请填写姓名",
},
],
phone: [
{
trigger: "blur",
required: true,
message: "请填写电话",
},
],
sex: [
{
trigger: "blur",
required: true,
message: "请选择性别",
},
],
username: [
{
trigger: "blur",
required: true,
message: "请填写账户",
},
],
password: [
{
trigger: "blur",
required: true,
message: "请填写密码",
},
],
},
//表单绑定的数据
addModel: {
type: "",
userId: "",
nickName: "",
phone: "",
email: "",
sex: "",
username: "",
password: "",
},
//弹框属性
dialog: {
title: "",
visible: false,
width: 630,
height: 200,
},
//表格的tableData: [],
};
},
created() {
this.getList();
},
methods: {
async getList() {
let res = await getListApi(this.listParm);
console.log("请求成功");
console.log(res);
if (res && res.code == 200) {
this.tableData = res.data.records;
this.listParm.total = res.data.total;
}
},
//弹框的leType: "",
remark: "",
},
//弹框属性
dialog: {
height: 150,
visible: false,
title: "",
},
//表格高度
tableHeight: 0,
//搜索栏数据
listParm: {
roleName: "",
cu确定
onConfirm() {
//表单验证
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addUserApi(this.addModel);
} else {
res = await editUserApi(this.addModel);
}
if (res && res.code == 200) {
//刷新表单
this.getList();
this.$message({ type: "success", message: res.msg });
}
}
});
},
//弹框的取消
onClose() {
this.dialog.visible = false;
},
//页数改变时触发
currentChange(val) {
this.listParm.currentPage = val;
this.getList();
},
//页容量改变时触发
sizeChange(val) {
this.listParm.pageSize = val;
this.getList();
},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑用户";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//把当前要编辑的数据复制到表单数据域
this.$objCoppy(row, this.addModel);
//设置编辑标识
this.addModel.type = "1";
},
//删除按钮
async deleteBtn(row) {
let confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteUserApi({ userId: row.userId });
if (res && res.code == 200) {
//刷新表单
this.getList();
this.$message({ type: "success", message: res.msg });
}
}
},
//搜索按钮
searchBtn() {
this.getList();
},
//搜索按钮
resetBtn() {
this.listParm.nickName = "";
this.listParm.phone = "";
this.getList();
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增用户";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
//设置编辑标识
this.addModel.type = "0";
},
},
mounted() {
this.$nextTick(() => {
//计算表格的高度
this.tableHeight = window.innerHeight - 220;
});
},
};
</script>
<style lang="scss" scoped>
</style>
第19讲 角色管理模块接口开发
1、新建实体类
package com.itmk.web.sys_role.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName("sys_role")
public class SysRole {
@TableId(type = IdType.AUTO)
private Long roleId;
private String roleName;
private String roleType;
private String remark;
private Date createTime;
private Date updateTime;
}
列表参数接收
package com.itmk.web.sys_role.entity;
import lombok.Data;
@Data
public class RoleParm {
private Long currentPage;
private Long pageSize;
private String roleName;
}
2、新建mapper
package com.itmk.web.sys_role.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_role.entity.SysRole;
public interface SysRoleMapper extends BaseMapper<SysRole> {
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_role.mapper.SysRoleMapper">
</mapper>
3、service层
package com.itmk.web.sys_role.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_role.entity.RoleParm;
import com.itmk.web.sys_role.entity.SysRole;
public interface SysRoleService extends IService<SysRole> {
IPage<SysRole> list(RoleParm parm);
}
实现类
package com.itmk.web.sys_role.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_role.entity.RoleParm;
import com.itmk.web.sys_role.entity.SysRole;
import com.itmk.web.sys_role.mapper.SysRoleMapper;
import com.itmk.web.sys_role.service.SysRoleService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
@Override
public IPage<SysRole> list(RoleParm parm) {
//构造分页对象
IPage<SysRole> page = new Page<>();
page.setSize(parm.getPageSize());
page.setCurrent(parm.getCurrentPage());
//构造查询条件
QueryWrapper<SysRole> query = new QueryWrapper<>();
if(StringUtils.isNotEmpty(parm.getRoleName())){
query.lambda().like(SysRole::getRoleName,parm.getRoleName());
}
return this.baseMapper.selectPage(page,query);
}
}
4、控制器
package com.itmk.web.sys_role.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.sys_role.entity.RoleParm;
import com.itmk.web.sys_role.entity.SysRole;
import com.itmk.web.sys_role.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@RestController
@RequestMapping("/api/role")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
//新增角色
@PostMapping
public ResultVo addRole(@RequestBody SysRole role){
role.setCreateTime(new Date());
boolean save = sysRoleService.save(role);
if(save){
return ResultUtils.success("新增成功!");
}
return ResultUtils.error("新增失败!");
}
//编辑角色
@PutMapping
public ResultVo editRole(@RequestBody SysRole role){
role.setUpdateTime(new Date());
boolean save = sysRoleService.updateById(role);
if(save){
return ResultUtils.success("编辑成功!");
}
return ResultUtils.error("编辑失败!");
}
//删除角色
@DeleteMapping("/{roleId}")
public ResultVo deleteRole(@PathVariable("roleId") Long roleId){
boolean b = sysRoleService.removeById(roleId);
if(b){
return ResultUtils.success("删除成功!");
}
return ResultUtils.error("删除失败!");
}
//角色列表
@GetMapping("/list")
public ResultVo getList(RoleParm parm){
IPage<SysRole> list = sysRoleService.list(parm);
return ResultUtils.success("查询成功",list);
}
}
第20讲角色管理列表制作
1、src/api新建role.js
import http from '@/utils/http'
//获取列表
export const getListApi = async(parm) =>{
return await http.get("/api/role/list",parm)
}
2、sysRoleList.vue页面
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="listParm" ref="searchRef" :inline="true" size="small">
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search">搜索</el-button>
<el-button icon="el-icon-close" style="color: #ff7670">重置</el-button>
<el-button type="primary" icon="el-icon-plus">新增</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table :height="tableHeight" :data="tableData" border stripe>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="备注"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" size="small" @click="editBtn(scope.row)"
>编辑</el-button
>
<el-button type="danger" size="small" @click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
</el-main>
</template>
<script>
import { getListApi } from "@/api/role";
export default {
data() {
return {
//表格高度
tableHeight: 0,
//搜索栏数据
listParm: {
roleName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
//表格数据
tableData: [],
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//获取列表
async getList() {
let res = await getListApi(this.listParm);
if (res && res.code == 200) {
//设置表格数据
console.log(res);
this.tableData = res.data.records;
this.listParm.total = res.data.total;
}
},
//页数改变时触发
currentChange(val) {},
//页容量改变时触发
sizeChange(val) {},
//删除按钮
deleteBtn(row) {},
//编辑按钮
editBtn(row) {},
},
};
</script>
<style lang="scss" scoped>
</style>
第21讲 新增、编辑制作与对接
1、src/api/role.js添加如下方法
//新增
export const addRoleApi = async(parm) =>{
return await http.post("/api/role",parm)
}
//编辑
export const editRoleApi = async(parm) =>{
return await http.put("/api/role",parm)
}
2、sysRoleList.vue
<template>
<el-main>
<!-- 搜索栏 -->
<el-form :model="listParm" ref="searchRef" :inline="true" size="small">
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button icon="el-icon-search">搜索</el-button>
<el-button icon="el-icon-close" style="color: #ff7670">重置</el-button>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table :height="tableHeight" :data="tableData" border stripe>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="备注"></el-table-column>
<el-table-column label="操作" align="center" width="180">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="small" @click="editBtn(scope.row)"
>编辑</el-button
>
<el-button type="danger" icon="el-icon-delete" size="small" @click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
<!-- 新增、编辑 -->
<sys-dialog
:title="dialog.title"
:visible="dialog.visible"
:height="dialog.heightsys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="roleName" label="角色名称">
<el-input v-model="addModel.roleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="roleType" label="角色类型">
<el-select v-model="addModel.roleType" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="角色备注">
<el-input v-model="addModel.remark"></el-input>
</el-form-item>
</el-col>
</el-rowame" label="学院名称">
<el-input
v-model="addModel.collageName"
placeholder="请输入学院名称"
></el-input>
</el-form-item>
<el-form-item label="序号">
<el-input
v-model="addModel.orderNum"
placeholder="请输入序号"
></el-input>
</el-form-item>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import { getListApi, addRoleApi, editRoleApi } from "@/api/role";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
//角色类型
options: [
{
value: "1",
label: "系统用户",
},
{
value: "2",
label: "学生",
},
{
value: "3",
label: "教师",
},
],
//表单验证
rules: {
roleName: [
{
required: true,
message: "请输入角色名称",
trigger: "blur",
},
],
roleType: [
{
required: true,
message: "请选择角色类型",
trigger: "blur",
},
],
},
//新增表单绑定的数据
addModel: {
type: "", //0:新增 1:编辑
roleId: "",
roleName: "",
roleType: "",
remark: "",
},
//弹框属性
dialog: {
height: 150,
visible: false,
title: "",
},
//表格高度
tableHeight: 0,
//搜索栏数据
listParm: {
roleName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
//表格数据
tableData: [],
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增角色";
this.dialog.visible = true;
//清空表单
this.$resetForm('addRef',this.addModel)
//设置为新增
this.addModel.type = '0'
},
//弹框确定
onConfirm() {
//表单验证
this.$refs.addRef.validate(async(valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addRoleApi(this.addModel);
} else {
res = await editRoleApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message({ type: "success", message: res.msg });
//刷新列表
this.getList();
}
}
});
this.dialog.visible = false;
},
//弹框关闭
onClose() {
this.dialog.visible = false;
},
//获取列表
async getList() {
let res = await getListApi(this.listParm);
if (res && res.code == 200) {
//设置表格数据
console.log(res);
this.tableData = res.data.records;
this.listParm.total = res.data.total;
}
},
//页数改变时触发
currentChange(val) {},
//页容量改变时触发
sizeChange(val) {},
//删除按钮
deleteBtn(row) {},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = '编辑角色'
this.dialog.visible = true;
//清空表单
this.$resetForm('addRef',this.addModel)
//设置为编辑
this.addModel.type = '1'
//把当前要编辑的数据设置到表单数据域
this.$objCoppy(row,this.addModel)
},
},
};
</script>
<style lang="scss" scoped>
</style>
第22讲 删除、搜索功能对接
1、src/api/role.js添加如下方法
//删除
export const deleteRoleApi = async(parm) =>{
return await http.delete("/api/role",parm)
}
2、sysRoleList.vue
<template>
<el-main>
<!-- 搜索栏 -->
<el-form
:model="listParm"
ref="searchRef"
label-width="80px"
:inline="true"
size="small"
>
<el-form-item>
<el-input
placeholder="请输入角色名称"
v-model="listParm.roleName"
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="searchBtn" icon="el-icon-search">搜索</el-button>
<el-button @click="resetBtn" style="color: #ff7670" icon="el-icon-close"
>重置</el-button
>
<el-button type="primary" @click="addBtn" icon="el-icon-plus"
>新增</el-button
>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table
:height="tableHeight"
size="small"
:data="tableData"
border
stripe
>
<el-table-column prop="roleName" label="角色名称"></el-table-column>
<el-table-column prop="remark" label="角色备注"></el-table-column>
<el-table-column label="操作" align="center" width="180">
<template slot-scope="scope">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="editBtn(scope.row)"
>编辑</el-button
>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
size="small"
@click="deleteBtn(scope.row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="sizeChange"
@current-change="currentChange"
:current-page.sync="listParm.currentPage"
:page-sizes="[10, 20, 40, 80, 100]"
:page-size="listParm.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="listParm.total"
background
>
</el-pagination>
<!-- 新增编辑弹框 -->
<sys-dialog
:title="dialog.title"
:visible="dialog.visible"
:height="dialog.heightsys-dialog
:title="addDialog.title"
:height="addDialog.height"
:width="addDialog.width"
:visible="addDialog.visible"
@onClose="onClose"
@onConfirm="onConfirm"
>
<div slot="content">
<el-form
:model="addModel"
ref="addRef"
:rules="rules"
label-width="80px"
size="small"
>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item prop="roleName" label="角色名称">
<el-input v-model="addModel.roleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" :offset="0">
<el-form-item prop="roleType" label="角色类型">
<el-select v-model="addModel.roleType" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="0">
<el-form-item label="角色备注">
<el-input v-model="addModel.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</sys-dialog>
</el-main>
</template>
<script>
import SysDialog from "@/components/dialog/SysDialog.vue";
import { getListApi, addRoleApi, editRoleApi, deleteRoleApi } from "@/api/role";
import { getList } from "@/api/table";
export default {
// 注册组件
components: {
SysDialog,
},
data() {
return {
//角色类型
options: [
{
value: "1",
label: "系统用户",
},
{
value: "2",
label: "学生",
},
e: [
{
trigger: "blur",
required: true,
message: "请填写角色名称",
},
],
roleTyp0,
//表单验证规则
rules: {
collageName: [
{
trigger: "blur",
required: true,
message: "请选择角色类型",
},
],
},
//表单数据
addModel: {
type: "", // 0 新增 1: 编辑
roleId: "",
roleName: "",
roleType: "",
remark: "",
},
//弹框属性
dialog: {
height: 150,
visible: false,
title: "",
},
//表格的高度
tableHeight: 0,
//表格数据
tableData: [],
//列表参数
listParm: {
rolageName: "",
currentPage: 1,
pageSize: 10,
total: 0,
},
};
},
mounted() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - 220;
});
},
created() {
this.getList();
},
methods: {
//弹框关闭
onClose() {
this.dialog.visible = false;
},
//弹框确定
onConfirm() {
this.$refs.addRef.validate(async (valid) => {
if (valid) {
let res = null;
if (this.addModel.type == "0") {
res = await addRoleApi(this.addModel);
} else {
res = await editRoleApi(this.addModel);
}
if (res && res.code == 200) {
//信息提示
this.$message({ type: "success", message: res.msg });
//刷新列表
this.getList();
this.dialog.visible = false;
}
}
});
},
//获取表格数据
async getList() {
let res = await getListApi(this.listParm);
if (res && res.code == 200) {
console.log(res);
//赋值给表格
this.tableData = res.data.records;
this.total = res.data.total;
}
},
//页数改变时触发
currentChange(val) {},
//页容量改变时触发
sizeChange(val) {},
//删除按钮
async deleteBtn(row) {
//提示
const confirm = await this.$myconfirm("确定删除该数据吗?");
if (confirm) {
let res = await deleteRoleApi({ roleId: row.roleId });
if (res && res.code == 200) {
//信息提示
this.$message({ type: "success", message: res.msg });
//刷新列表
this.getList();
}
}
},
//编辑按钮
editBtn(row) {
//设置弹框属性
this.dialog.title = "编辑角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.type = "1";
//把当前编辑的数据放到表单数据里面
this.$objCoppy(row, this.addModel);
},
//新增按钮
addBtn() {
//设置弹框属性
this.dialog.title = "新增角色";
this.dialog.visible = true;
//清空表单
this.$resetForm("addRef", this.addModel);
this.addModel.type = "0";
},
//重置按钮
resetBtn() {
//表单清空
this.listParm.roleName = ''
this.getList();
},
//搜索按钮
searchBtn() {
this.getList();
},
},
};
</script>
<style lang="scss" scoped>
</style>
第23讲 菜单管理模块接口开发
1、新建实体类
package com.itmk.web.sys_menu.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Data
@TableName("sys_menu")
public class SysMenu {
@TableId(type = IdType.AUTO)
private Long menuId;
private Long parentId;
private String title;
private String code;
private String name;
private String path;
private String url;
//类型(0 目录 1菜单,2按钮)
private String type;
private String icon;
private String parentName;
private Long orderNum;
private Date createTime;
private Date updateTime;
//该字段不属于数据库表,需要排除
@TableField(exist = false)
private List<SysMenu> children = new ArrayList<>();
}
2、新建mapper
package com.itmk.web.sys_menu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itmk.web.sys_menu.entity.SysMenu;
public interface SysMenuMapper extends BaseMapper<SysMenu> {
}
映射文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.sys_menu.mapper.SysMenuMapper">
</mapper>
3、新建service
package com.itmk.web.sys_menu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itmk.web.sys_menu.entity.SysMenu;
import java.util.List;
public interface SysMenuService extends IService<SysMenu> {
List<SysMenu> menuList();
}
实现类
package com.itmk.web.sys_menu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itmk.web.sys_menu.entity.MakeTree;
import com.itmk.web.sys_menu.entity.SysMenu;
import com.itmk.web.sys_menu.mapper.SysMenuMapper;
import com.itmk.web.sys_menu.service.SysMenuService;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
@Override
public List<SysMenu> menuList() {
//查询列表
QueryWrapper<SysMenu> query = new QueryWrapper<>();
query.lambda().orderByAsc(SysMenu::getOrderNum);
List<SysMenu> menuList = this.baseMapper.selectList(query);
//组装树
List<SysMenu> list = MakeTree.makeMenuTree(menuList, 0L);
return list;
}
}
package com.itmk.web.sys_menu.entity;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class MakeTree {
public static List<SysMenu> makeMenuTree(List<SysMenu> menuList, Long pid) {
List<SysMenu> list = new ArrayList<>();
Optional.ofNullable(menuList).orElse(new ArrayList<>())
.stream()
.filter(item -> item != null && item.getParentId() == pid)
.forEach(dom -> {
SysMenu menu = new SysMenu();
BeanUtils.copyProperties(dom, menu);
//查询该项的下级菜单
List<SysMenu> sysMenus = makeMenuTree(menuList, dom.getMenuId());
menu.setChildren(sysMenus);
list.add(menu);
});
return list;
}
}
4、新建控制器
package com.itmk.web.sys_menu.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.sys_menu.entity.SysMenu;
import com.itmk.web.sys_menu.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/api/menu")
public class SysMenuController {
@Autowired
private SysMenuService sysMenuService;
//新增
@PostMapping
public ResultVo addMenu(@RequestBody SysMenu menu){
menu.setCreateTime(new Date());
boolean save = sysMenuService.save(menu);
if(save){
return ResultUtils.success("新增成功!");
}
return ResultUtils.error("新增失败!");
}
//编辑
@PutMapping
public ResultVo editMenu(@RequestBody SysMenu menu){
menu.setUpdateTime(new Date());
boolean save = sysMenuService.updateById(menu);
if(save){
return ResultUtils.success("编辑成功!");
}
return ResultUtils.error("编辑失败!");
}
//删除
@DeleteMapping("/{menuId}")
public ResultVo deleteMenu(@PathVariable("menuId") Long menuId){
//判断是否有下级,有下级,不能删除
QueryWrapper<SysMenu> query = new QueryWrapper<>();
query.lambda().eq(SysMenu::getParentId,menuId);
List<SysMenu> list = sysMenuService.list(query);
if(list.size() > 0){
return ResultUtils.error("该菜单存在下级,不能删除!");
}
boolean save = sysMenuService.removeById(menuId);
if(save){
return ResultUtils.success("删除成功!");
}
return ResultUtils.error("删除失败!");
}
//菜单列表
public ResultVo getList(){
List<SysMenu> list = sysMenuService.menuList();
return ResultUtils.success("查询成功",list);
}
}
点击获取
完整源代码+万字文档
点击跳转下一讲
【第24讲到第44讲】基于vue + spring boot学生宿舍管理系统
点击获取
完整源代码+万字文档