VUE
目录
创建vue
我们再导入的时候选择第一个,第二个是压缩过得,会少的提示
注意文件名不可以为中文
webStorm 创建方式
vue 有两种方法
这里推荐上面注释掉的方法
这两种都是一样的,就是后面的东西只适配上面的一种
简写单击时间
这些都是不传值的方法
这里的方法的两种写法
下面是传值方法
双击事件
值改变时间
失去焦点
这里是输入了1,然后点击勒空白页面
键盘事件
输入值后按回车
练习 计数器
题目
css
body{
background-color: #f5f5f5;
}
#app {
width: 480px;
height: 80px;
margin: 200px auto;
}
.input-num {
margin-top:20px;
height: 100%;
display: flex;
border-radius: 10px;
overflow: hidden;
box-shadow: 4px 4px 4px #adadad;
border: 1px solid #c7c7c7;
background-color: #c7c7c7;
}
.input-num button {
width: 150px;
height: 100%;
font-size: 40px;
color: #ad2a27;
cursor: pointer;
border: none;
outline: none;
background-color:rgba(0, 0, 0, 0);
}
.input-num span {
height: 100%;
font-size: 40px;
flex: 1;
text-align: center;
line-height: 80px;
font-family:auto;
background-color: white;
}
img{
float: right;
margin-top: 50px;
}
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>计数器</title>
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<!-- html结构 -->
<div id="app">
<!-- 计数器功能区域 -->
<div class="input-num">
<button >
-
</button>
<span>1</span>
<button >
+
</button>
</div>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 编码 -->
<script>
// 创建Vue实例
</script>
</body>
</html>
答案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
<title>计数器</title>
<link rel="stylesheet" href="./css/index.css"/>
</head>
<body>
<!-- html结构 -->
<div id="app">
<!-- 计数器功能区域 -->
<div class="input-num">
<!-- <button @click="deletenum">-->
<button @click="num--">
-
</button>
<span>{{num}}</span>
<!-- <button @click="addnum">-->
<button @click="num++">
+
</button>
</div>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 编码 -->
<script>
// 创建Vue实例
new Vue({
el:"#app",
data: {
num:1
},
<!--复杂版-->
// methods: {
// deletenum() {
// // 数字减一
// // num = num - 1;
// this.num--;
// },
// addnum() {
// // 数字加一
// num = num + 1;
// }
// }
})
</script>
</body>
</html>
数据绑定
双向绑定
实例1
实例2
这里点击按钮后所有的值会变成你好
对象数组
获取对象中对象的值
数组取值
遍历数组
循环行
h1
循环列
实例 记事本
页面
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>小黑记事本</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="googlebot" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="./css/index.css" />
</head>
<body>
<!-- 主体区域 -->
<section id="todoapp">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input autofocus="autofocus" autocomplete="off" placeholder="请输入任务"
class="new-todo" />
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" >
<div class="view">
<span class="index"></span>
<label></label>
<button class="destroy" @click=""></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<footer class="footer" >
<span class="todo-count">
<strong>1</strong> items left
</span>
<button class="clear-completed">
Clear
</button>
</footer>
</section>
<!-- 底部 -->
<footer class="info">
</footer>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
</script>
</body>
</html>
js
const app = new Vue({
el: "#todoapp",
data: {
// 总数据
todoList: ["吃饭饭", "睡觉觉", "写代码"],
// 输入的内容
inputValue: "",
},
// 方法
methods: {
// 增加任务
addTodo() {
this.todoList.push(this.inputValue);
},
// 删除任务
delTodo(index) {
this.todoList.splice(index, 1);
},
clearTodo() {
this.todoList = [];
}
}
});
css
html,
body {
margin: 0;
padding: 0;
}
body {
background: #fff;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
#todoapp {
background: #fff;
margin: 180px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: gray;
}
#todoapp h1 {
position: absolute;
top: -160px;
width: 100%;
font-size: 60px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, .8);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 16px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
.toggle-all {
width: 1px;
height: 1px;
border: none; /* Mobile Safari */
opacity: 0;
position: absolute;
right: 100%;
bottom: 100%;
}
.toggle-all + label {
width: 60px;
height: 34px;
font-size: 0;
position: absolute;
top: -52px;
left: -13px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
.toggle-all + label:before {
content: "❯";
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked + label:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
max-height: 420px;
overflow: auto;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
height: 60px;
box-sizing: border-box;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list .view .index {
position: absolute;
color: gray;
left: 10px;
top: 20px;
font-size: 16px;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle {
opacity: 0;
}
.todo-list li .toggle + label {
/*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center left;
}
.todo-list li .toggle:checked + label {
background-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E");
}
.todo-list li label {
word-break: break-all;
padding: 15px 15px 15px 60px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: "×";
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: "";
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 50px auto 0;
color: #bfbfbf;
font-size: 15px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio: 0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}
下面是页面截图,可以参考
答案
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>小黑记事本</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="googlebot" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="./css/index.css" />
</head>
<body>
<!-- 主体区域 -->
<section id="todoapp">
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input autofocus="autofocus" autocomplete="off" placeholder="请输入任务"
class="new-todo" v-model="testmsg" @keyup.enter="addtestmsg"/>
</header>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list">
<li class="todo" v-for="(x,i) in arr">
<div class="view">
<span class="index">{{i+1}}.</span>
<label>{{x}}</label>
<button class="destroy" @click="deleteArr(i)"></button>
</div>
</li>
</ul>
</section>
<!-- 统计和清空 -->
<footer class="footer" >
<span class="todo-count">
<strong>{{arr.length}}}</strong> items left
</span>
<button class="clear-completed" @click="clearArr">
Clear
</button>
</footer>
</section>
<!-- 底部 -->
<footer class="info">
{{testmsg}}--{{arr}}
</footer>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
<script>
new Vue({
el:'#todoapp',
data:{
testmsg:'',
arr:[]
},
methods:{
addtestmsg(){
// 添加数据到最后一位
this.arr.push(this.testmsg)
},
clearArr(){
// 清空数组
this.arr = [];
},
deleteArr(v){
console.log(v)
this.arr.splice(v,1)
}
}
})
</script>
</body>
</html>
if 语句
if else
v-show
两者区别
if - else 的dom 对象是没有的,if -else 有多重分支
v-show 是有dom 对象的 ,v-show 是没有多重分支的
如下图
下面提供代码可以自行尝试
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<!-- if (表达式) true 执行 判断 -->
<h1 v-if="true">hello......1</h1>
<h1 v-if="1 == 1">hello.......2</h1>
<h1 v-if="1 > 2">hello.......3</h1>
<!-- if else 分支判断 -->
<h1 v-if="num == 1"> if else .....1</h1>
<h1 v-else-if ="num == 2"> if else .....2</h1>
<h1 v-else-if ="num == 3"> if else .....3</h1>
<h1 v-else> if else .....4</h1>
<!-- v-show 显示隐藏 -->
<!-- 1 不同 if 有多重判断 show 没有 -->
<!-- 2 if 如果false dom没有了 show 如果false 的 dom 还是存在的 只是样式隐藏 -->
<h1 v-show="true">v-show...1</h1>
<br>
<button @click="flagif = true">显示v-if</button>
<!-- true的 反 就是false false 的反值 就是true -->
<button @click="flagif = !flagif">显示v-if</button>
<h1 v-if="flagif">hello</h1>
<br>
<button @click="flagshow = !flagshow">显示v-show</button>
<h1 v-show="flagshow">v-show...2</h1>
</div>
<script>
new Vue({
el:"#app",
data:{
num:4,
flagif:false,
flagshow:false
},
methods:{
}
})
</script>
</body>
</html>
图片
上上面那张图片,会有问题,因为当数组长度到达-1或者数组的长度是就会出问题
改进版
详情代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>图片切换</title>
<link rel="stylesheet" href="./css/index.css" />
</head>
<body>
<div id="mask">
<div class="center">
<h2 class="title">
深圳创维校区环境{{index}}
</h2>
<!-- 图片 -->
<!-- <img alt="" src="images/02.jpg" /> -->
<img alt="" :src="imgArr[index]" />
<!-- 左箭头 -->
<!-- <a href="javascript:void(0)" v-show="index!=0" @click="prev" class="left">
<img src="./images/prev.png" alt="" />
</a> -->
<!-- <a href="javascript:void(0)" v-if="true" @click="index--" class="left"> -->
<a href="javascript:void(0)" v-if="true" @click="index > 0 ?index-- : index = 10" class="left">
<img src="./images/prev.png" alt="" />
</a>
<!-- 右箭头 -->
<!-- index <10? index++ : index ?之前 index <10 表达式 为真的 就执行 :前面的 否则执行后面的 -->
<!-- if else if(index <10){index++}else{index} -->
<a href="javascript:void(0)" v-show="true" @click="index <10? index++ : index = 0" class="right">
<img src="./images/next.png" alt="" />
</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
el: "#mask",
data: {
imgArr: [
"./images/00.jpg",
"./images/01.jpg",
"./images/02.jpg",
"./images/03.jpg",
"./images/04.jpg",
"./images/05.jpg",
"./images/06.jpg",
"./images/07.jpg",
"./images/08.jpg",
"./images/09.jpg",
"./images/10.jpg",
],
index: 0
},
methods: {
prev: function() {
},
next: function() {
}
},
})
</script>
</body>
</html>
表单
演示代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<h1>用户注册</h1>
用户名:<input placeholder="请输入用户名" v-model="userinfo.username" />
<br>
性别:<input type="radio" value="男" name="sex" v-model="userinfo.sex" />男
<input type="radio" value="女" name="sex" v-model="userinfo.sex" />女
<br>
爱好:<input type="checkbox" value="游戏" v-model="userinfo.hobby" />游戏
<input type="checkbox" value="篮球" v-model="userinfo.hobby" />篮球
<input type="checkbox" value="足球" v-model="userinfo.hobby" />足球
<input type="checkbox" value="电影" v-model="userinfo.hobby" />电影
<br>
班级:<select v-model="userinfo.cla" >
<option value="班级1">班级1</option>
<option value="班级2">班级2</option>
<option value="班级3">班级3</option>
</select>
<br>
自我介绍:<textarea rows="5" cols="30" v-model="userinfo.remark" ></textarea>
<br>
生日:<input type="date" v-model="userinfo.udate" />
<br>
<button @click="registerUser">注册</button>
<br>
</div>
<script>
new Vue({
el:"#app",
data:{
// 数据绑定 v-model
userinfo:{
username:'',
sex:'',
hobby:[],
cla:'',
remark:'',
udate:''
}
},
methods:{
registerUser(){
console.log("用户信息:",this.userinfo)
}
}
})
</script>
</body>
</html>
跨越
一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
二、什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url 被请求页面url 是否跨域 原因
http://www.test.com/ http://www.test.com/index.html 否 同源(协议、域名、端口号相同)
http://www.test.com/ https://www.test.com/index.html 跨域 协议不同(http/https)
http://www.test.com/ http://www.baidu.com/ 跨域 主域名不同(test/baidu)
http://www.test.com/ http://blog.test.com/ 跨域 子域名不同(www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ 跨域 端口号不同(8080/7001)
三、非同源限制
【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
【2】无法接触非同源网页的 DOM
【3】无法向非同源地址发送 AJAX 请求
示例
不包含注册
前端页面
注意需要这些文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="js/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="js/jquery-1.8.2.min.js" type="text/javascript"></script>
</head>
<body>
<div id="app">
<h1>用户注册</h1>
用户名:<input placeholder="请输入用户名" v-model="userinfo.username" />
<br>
性别:<input type="radio" value="男" name="sex" v-model="userinfo.sex" />男
<input type="radio" value="女" name="sex" v-model="userinfo.sex" />女
<br>
爱好:<input type="checkbox" value="游戏" v-model="userinfo.hobby" />游戏
<input type="checkbox" value="篮球" v-model="userinfo.hobby" />篮球
<input type="checkbox" value="足球" v-model="userinfo.hobby" />足球
<input type="checkbox" value="电影" v-model="userinfo.hobby" />电影
<br>
班级:<select v-model="userinfo.cla" >
<option value="班级1">班级1</option>
<option value="班级2">班级2</option>
<option value="班级3">班级3</option>
</select>
<br>
自我介绍:<textarea rows="5" cols="30" v-model="userinfo.remark" ></textarea>
<br>
生日:<input type="date" v-model="userinfo.udate" />
<br>
<button @click="registerUser">注册</button>
<br>
</div>
<script>
new Vue({
el:"#app",
data:{
// 数据绑定 v-model
userinfo:{
username:'',
sex:'',
hobby:[],
cla:'',
remark:'',
udate:''
}
},
methods:{
registerUser(){
console.log("用户信息:",this.userinfo)
// 1 jquery ajax 异步请求
$.ajax({
// url 服务器的 接口地址
url:'http://localhost:8080/users/add',
// data 参数
data:this.userinfo,
// 回调函数 服务器返回的数据
success:function(d){
console.log(d)
}
})
}
}
})
</script>
</body>
</html>
后端代码
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 https://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.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>vue-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>vue-java</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
跨域请求设置
CrossConfig
package com.example.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Description
* @Autor 伍军
* @Date 2021/9/13 15:01
* @Version 1.0
**/
@Configuration
//@EnableTransactionManagement
public class CrossConfig implements WebMvcConfigurer {
@Override
// java 配置 跨域请求的设置
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")/*所有的当前站点的请求地址,都支持跨域访问*/
.allowedOrigins("*")/*所有的外部域都可跨域访问*/
//.allowedOriginPatterns("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")/*哪些请求 需要跨域配置*/
.allowCredentials(false) /*是否支持跨域用户凭证*/
.maxAge(3600)/*超时时长设置为6分钟。 时间单位是秒。*/
.allowedHeaders("*");/*请求体的头部*/
}
// @Bean
// public PaginationInterceptor paginationInterceptor(){
// return new PaginationInterceptor();
// }
//
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
//
// @Bean
// public MybatisPlusInterceptor mybatisPlusInterceptor(){
// MybatisPlusInterceptor mi = new MybatisPlusInterceptor();
// mi.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// return mi;
// }
//
// @Value("${staticpath}")
// String urlpath;
// @Value("${uploadpath}")
// String localpath;
//
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// System.out.println(urlpath);
// System.out.println(localpath);
// // addResourceHandler 请求路径
// // addResourceLocations 具体的文件路径
// registry.addResourceHandler(urlpath).addResourceLocations(localpath);
registry.addResourceHandler("/file/**").addResourceLocations("file:D:/img/");
// }
}
MybatisConfig
ssm xml 配置文件
package com.example.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
// == ssm 中 xml 配置文件
public class MybatisConfig {
// @Bean
<bean>
// public PaginationInnerInterceptor paginationInnerInterceptor(){
// return new PaginationInnerInterceptor();
// }
@Bean
public MybatisPlusInterceptor plusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
TestController
package com.example.controller;
import com.example.model.Users;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*
* 用来测试 vue 用户注册 异步请求
* */
@RestController
// controller responesbody
@RequestMapping("/users")
public class TestController {
@RequestMapping("/add")
public boolean register(Users users){
System.out.println(users);
return false;
}
}
UserControlle
package com.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.dao.UserDao;
import com.example.model.UserInfoTest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
// @RestController = @controller + @ responsebody
@RestController
public class UserControlle {
@Resource
UserDao userDao;
@RequestMapping("/list")
public Object list(String name,Integer rows,Integer page){
System.out.println("list............"+name+rows+page);
QueryWrapper<UserInfoTest> qw = new QueryWrapper<>();
if("".equals(name) || name == null){
}else{
// like 模糊查询
qw.like("name",name);
}
// List<UserInfo> userInfos = userDao.selectList(qw);
// 分页方法 selectpage
Page<UserInfoTest> pages = new Page<>(page,rows);// page 表示当前的页数 rows 表示返回的数据个数
Page<UserInfoTest> userInfoPage = userDao.selectPage(pages, qw);
return userInfoPage;
}
}
UserInfoTest
这些是bean ,这里需要 这个插件
package com.example.model;
import lombok.Data;
@Data
public class UserInfoTest {
private Integer id;
private String name;
private String pwd;
}
package com.example.model;
import lombok.Data;
import java.util.List;
@Data
public class Users {
private Integer id;
private String username ;
private String sex;
private List<String> hobby;
private String cla;
private String remark;
private String udate;
}
配置文件
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test220707?serverTimezone=GMT
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root123
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
vue 脚手架
上面的项目不是独立的项目,不可以独立运行
选择版本进行安装
安装完后
设置缓存文件夹
npm config set cache “D:\Program Files\nodejs\node_cache”
npm config set prefix “D:\Program Files\nodejs\node_global”
npm config set cache “D:\Program Files\nodejs\node_cache” 报错 有两个原因 1 nodejs安装有问题 2 cmd 命令行 系统 必须用管理员打开
镜像下载
npm install -g cnpm --registry=https://registry.npm.taobao.org
这样就好了
设置环境变量
安装vue
cnpm install vue -g
安装vue 命令行工具,即 vue-cli 脚手架
cnpm install vue-cli -g
存放项目
创建项目
vue init webpack 项目名称
完成后回车,会自动下载项目
直接点击这个就可以进入了
手动输入也可以
http://localhost:8080/#/
修改端口号避免和idea 重复
autoOpenBrowser 这个是自动打开游览器 把这个改成 true
文件
导入axios 和 vue-router
npm install vue-router
cnpm install axios
import Axios from 'axios'
// vue 自定义的一个变量 把引入进来的Axios赋值给变量 代码用变量来使用
Vue.prototype.$axios = Axios;
创建文件
login.vue 文件
<template>
<div>
用户名: <input type="text" placeholder="请输入用户名">
密码: <input type="text" placeholder="请输入密码">
</div>
</template>
<script>
export default {
name: "login"
}
</script>
<style scoped>
</style>
这样打开是什么都没有的
添加路由
需要添加 index.js 里面的路径
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import login from '@/components/login'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/login',
name: 'login',
component: login
}
]
})
可以看见都有了
然后在使用异步
这里不适用ajax,用刚刚导入的 axios
写了 err 后会在控制台输出
完整代码
<template>
<div>
用户名: <input type="text" placeholder="请输入用户名" v-model="user.name">
密码: <input type="text" placeholder="请输入密码" v-model="user.pwd">
<button @click="login">登录</button>
</div>
</template>
<script>
export default {
methods: {
login() {
console.log(this.user)
this.$axios.get("http://localhost:8080/login"
,{params:this.user}).then(function (d){
console.log(d) // success
if (d.data){
location.href = "/"
}else{
alert("登录失败")
}
},function (e){
console.log(e) // err
})
}
},
mounted() {
},
data() {
return {
msg: "123",
user:{
name:'',
pwd:''
}
}
}
}
</script>
<style scoped>
</style>
使用最上面的项目 vue -java
在userController里添加代码
@RequestMapping("/login")
public boolean login(Userinfotest userInfo) {
System.out.println(userInfo);
// 获取登录信息 查询数据库 如果登陆成功 返回true 失败 返回false
QueryWrapper<Userinfotest> qw = new QueryWrapper<>();
qw.eq("name", userInfo.getName());
qw.eq("pwd", userInfo.getPwd());
Userinfotest userInfo1 = userDao.selectOne(qw);
if (userInfo1 == null) {
return false;
}
return true;
}
路径
修改登录页面
页面文件见
vue 修改登录页面文件123
import './assets/css/global.css'
import './assets/fonts/iconfont.css'
这里样式还是不行,需要添加东西
cnpm i element-ui -S
在 main.js 里面添加代码
//引入element-ui 组件
import ElementUI from 'element-ui'
//引入element-ui 的样式
import 'element-ui/lib/theme-chalk/index.css'
//全局加载element-ui 组件
Vue.use(ElementUI)
登录和注册页面
<template>
<div class="login_container">
<!-- 登录盒子 -->
<div class="login_box">
<!-- 头像 -->
<div class="avatar_box">
<img src="../assets/logo.png" alt="">
</div>
<!-- 登录表单 -->
<el-form :model="loginForm" ref="LoginFormRef" label-width="0px" class="login_form">
<!-- 用户名 -->
<el-form-item prop="username">
<el-input placeholder="请输入用户名" v-model="loginForm.username" prefix-icon="iconfont icon-user"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<el-input placeholder="请输入密码" type="password" v-model="loginForm.password"
prefix-icon="iconfont icon-3702mima"></el-input>
</el-form-item>
<el-form-item prop="checkcode">
<el-input placeholder="请输入验证码" v-model="checkcode" prefix-icon="iconfont icon-3702mima"></el-input>
</el-form-item>
<canvas class="mycanvas" width="80" height="30" @click="changecode">抱歉,您的浏览器不支持canvas元素,换个浏览器试试?</canvas>
{{ message }}
<!-- 按钮 -->
<el-form-item class="btns">
<el-button type="primary" @click="login">登录</el-button>
<el-button type="info" @click="resetLoginForm">重置</el-button>
<el-button type="primary" @click="toregister">注册</el-button>
</el-form-item>
</el-form>
</div>
<!-- 添加用户dialog对话框 -->
<!-- :visible.sync v-if v-show -->
<el-dialog align="left" title="添加用户" :visible.sync="addUserVisible" width="50%" @close="">
<!--主体部分 -->
<el-form status-icon ref="addUserFormRel" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名" prop="userName">
<el-input v-model="addUserForm.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="userPwd">
<el-input type="password" v-model="addUserForm.password" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addUserVisible = false">取 消</el-button>
<el-button type="primary" @click="adduser">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
//数据绑定
loginForm: {
id: "1",
username: 'admin',
password: '123'
},
checkcode: "",
value: "",
code: "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
message: "",
addUserVisible: false,
addUserForm: {
username: "",
password: "",
},
}
},
//添加行为,
methods: {
adduser() {
console.log(this.addUserForm)
let url = "http://localhost:8080/adduser";
this.$axios.get(url, {params: this.addUserForm}).then(
(d) => {
if (d.data) {
alert("添加成功");
} else {
alert("添加失败");
}
this.addUserVisible = false;
}
)
},
getrolelist() {
},
toregister() {
//this.getrolelist();
this.addUserVisible = true;
},
login() {
console.log(this.loginForm)
console.log("----" + this.checkcode)
console.log("****" + this.value)
if (this.checkcode.toLowerCase() === this.value.toLowerCase()) {
this.message = "验证码正确"
// 异步请求
let url = "http://localhost:8080/login";
this.$axios.get(url, {params: this.loginForm}).then(
(d) => {
// d 服务器返回的数据
console.log(d)
if (d.data == '' || d.data == null) {
this.message = "用户名或者密码错误"
} else {
this.message = "登录成功"
// location.href="/"
this.$router.push({path: "/home", query: d.data})
}
}
);
} else {
this.message = "验证码错误"
}
},
resetLoginForm() {
this.loginForm.username = "";
this.loginForm.password = "";
this.checkcode = '';
},
changecode() {
this.fourCode();
},
randomColor() {
//得到随机的颜色值
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
return "rgb(" + r + "," + g + "," + b + ")";
},
fourCode() {
this.value = "";
for (let a = 0; a < 4; a++) {
this.value += this.code1();
}
this.doDraw();
},
code1() {
let index = Math.floor(Math.random() * (this.code.length - 1) + 1);
return this.code[index];
},
doDraw() {
var x = 20;
var y = 20 + Math.random() * 8;
var deg = (Math.random() * 30 * Math.PI) / 180;
// 获取canvas
var canvas = document.getElementsByClassName("mycanvas");
canvas[0].width = canvas[0].width; //清空画布
canvas[0].height = canvas[0].height;
var canvas_width = canvas[0].width;
var canvas_height = canvas[0].height;
var context = canvas[0].getContext("2d");
context.font = "bold 23px 微软雅黑";
context.fillText(this.value, 15, 30);
context.translate(x, y); //canvas原点的偏移量
context.rotate(deg); //旋转度数
context.fillStyle = this.randomColor(); //设置颜色
context.strokeStyle = this.randomColor(); //设置颜色
context.rotate(-deg);
context.translate(-x, -y);
for (var i = 0; i <= 15; i++) {
//验证码上显示线条
context.strokeStyle = this.randomColor(); //轮廓风格
context.beginPath();
context.moveTo(
Math.random() * canvas_width,
Math.random() * canvas_height
);
context.lineTo(
Math.random() * canvas_width,
Math.random() * canvas_height
);
context.stroke();
}
for (var i = 0; i <= 30; i++) {
//验证码上显示小点
context.strokeStyle = this.randomColor();
context.beginPath(); //新建一条路径
var x = Math.random() * canvas_width;
var y = Math.random() * canvas_height;
context.moveTo(x, y); //吧画笔移动到指定位置
context.lineTo(x + 1, y + 1); //想指定位置移动
context.stroke();
}
},
},
mounted() {
this.fourCode();
this.checkcode = this.value
}
}
</script>
<style scoped>
.login_container {
background-color: #2b5b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
}
.avatar_box img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
.mycanvas {
border: 1px solid rgb(199, 198, 198);
border-radius: 20%;
}
</style>
后台代码
@RequestMapping("/login")
public Userinfotest login(Userinfotest userInfo) {
System.out.println(userInfo);
// 获取登录信息 查询数据库 如果登陆成功 返回true 失败 返回false
QueryWrapper<Userinfotest> qw = new QueryWrapper<>();
qw.eq("username", userInfo.getUsername());
qw.eq("password", userInfo.getPassword());
return userDao.selectOne(qw);
}
主页
<template>
<div class="home-container">
<el-container>
<el-header>
<div>
<img src="../assets/logo.png" />
<span>租房管理系统</span>
<span>用户名:{{user.username}}</span>
</div>
<el-button @click="loginOut">退出</el-button>
</el-header>
<el-container>
<el-aside :width="isCollapse ? '60px':'200px'">
<div style="color: #fff;" @click="isCollapse=!isCollapse">|||</div>
<!-- 导航菜单 -->
<el-menu default-active="2" class="el-menu-vertical-demo" background-color="#333744" text-color="#fff"
:unique-opened="true" :collapse="isCollapse" :router="true" :default-active="activePath"
:collapse-transition="false" active-text-color="#ffd04b">
<!-- 一级菜单 -->
<el-submenu :index="item.menu.menuId+''" v-for="item in menulists" :key="item.menu.menuId">
<template slot="title">
<i :class="objicon[item.menu.menuId]"></i>
<span>{{item.menu.menuName}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item :index="'/'+item2.menuUrl" v-for="item2 in item.children" :key="item2.menuId"
@click="activeSave('/'+item2.menuUrl)">
<template slot="title">
<i class="el-icon-menu"></i>
<span> {{item2.menuName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
//左侧菜单
menulists: [{menu:{menuId:1,menuName:'菜单1'},children:[{menuId:4,menuName:'菜单4',menuUrl:''}]},
{menu:{menuId:2,menuName:'菜单2'} ,children:[{menuId:3,menuName:'菜单3',menuUrl:''}],
}],
objicon: {
"125": 'iconfont icon-icon_user',
"103": 'iconfont icon-shangpin',
"101": 'iconfont icon-danju',
"102": 'iconfont icon-tijikongjian',
"145": 'iconfont icon-baobiao'
},
//是否水平折叠菜单
isCollapse: false,
//当前激活的路径
activePath: '',
user:{}
}
},
methods: {
getPowerByUserId() {
},
//退出登录
loginOut() {
window.sessionStorage.clear();
this.$router.push({
path: '/login'
})
},
//点击导航,有激活的状态
activeSave(path) {
this.activePath = path;
window.sessionStorage.setItem('activePath', path);
},
},
mounted() {
this.user =this.$route.query;
console.log("----",this.user)
}
}
</script>
<style scoped="scoped">
.home-container {
height: 100%;
background: #c4c4c4;
}
.el-container {
height: 100%;
}
.el-header {
background: #333744;
display: flex;
justify-content: space-between;
color: #fff;
font-size: 20px;
}
.el-header img {
vertical-align: middle;
width: 60px;
height: 65px;
}
.el-aside {
background: #333744;
height: 100%;
box-sizing: border-box;
}
.el-main {
background: #ececec;
}
</style>
首页菜单
创建类
UserController
添加后端代码
创建Power 类
package com.example.model;
import lombok.Data;
@Data
public class Power {
private Integer powerId;
private String powerName;
private String powerUrl;
private Integer parentId;
private Integer indexId;
}
// CREATE TABLE `power` (
// `power_id` int(11) NOT NULL AUTO_INCREMENT,
// `power_name` varchar(255) DEFAULT NULL COMMENT '菜单名称',
// `power_url` varchar(255) DEFAULT NULL COMMENT '菜单路径',
// `parent_id` int(11) DEFAULT NULL COMMENT '父类id',
// `index_id` int(11) DEFAULT NULL COMMENT '每一级菜单的下标',
// PRIMARY KEY (`power_id`) USING BTREE
// ) ENGINE=InnoDB
在userDao里面添加方法
package com.example.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.model.Power;
import com.example.model.Userinfotest;
import java.util.List;
public interface UserDao extends BaseMapper<Userinfotest> {
List<Power> getPowerByUserId(Integer userId);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.dao.UserDao">
<select id="getPowerByUserId" resultType="com.example.model.Power">
select u.*, p.*
from user_info u
LEFT JOIN user_role ur on u.id = ur.user_id
LEFT JOIN role r on r.role_id = ur.role_id
LEFT JOIN role_power rp on r.role_id = rp.role_id
LEFT JOIN power p on p.power_id = rp.power_id
where u.id = #{userId}
order by u.id
</select>
</mapper>
修改后端代码
// 通过用户id 查询对应的菜单
@RequestMapping("getPowerByUserId")
public List<Menu> getPowerByUserId(Integer userId) {
System.out.println("用户id:" + userId);
// 获取菜单的方法
List<Power> list = userDao.getPowerByUserId(userId);
// list.forEach(System.out::println);
List<Menu> menus = new ArrayList<>();
// 如果查询不到任何菜单 就直接返回null
if ( list == null || list.size() < 1 ){
return null;
}
for (Power p1 : list) {
if (p1 == null || p1.getPowerId() == null){
break;
}
// 把一级菜单 添加到 返回对象里面
if (p1.getParentId() == 0) {
Menu menu = new Menu();
MenuInfo menuInfo1 = new MenuInfo(); // 一级菜单的对象
menuInfo1.setMenuId(p1.getPowerId());
menuInfo1.setMenuName(p1.getPowerName());
// : 1 ,用户管理,null,0,1
menu.setMenu(menuInfo1);
List<MenuInfo> children = new ArrayList<>();
// 把二级菜单放到对应的一级菜单
for (Power p2 : list) {
// 二级菜单
if (p2.getParentId() != 0 && p2.getParentId() == p1.getPowerId()) {
MenuInfo menuInfo2 = new MenuInfo();
menuInfo2.setMenuId(p2.getPowerId());
menuInfo2.setMenuName(p2.getPowerName());
menuInfo2.setMenuUrl(p2.getPowerUrl());
// 2,用户列表,userlist,1,1
children.add(menuInfo2);
}
}
menu.setChildren(children);
menus.add(menu);
}
}
return menus;
}
用户列表
power
<template>
<div>
<!-- 面包屑内容 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>管理模块</el-breadcrumb-item>
<el-breadcrumb-item>菜单权限列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 主体内容 -->
<el-card>
<!-- 搜索区域 -->
<el-row>
<el-col :span="6">
<el-input placeholder="请输入权限名" v-model="queryInfo.menuName" class="input-with-select" clearable
@clear="getMenuList">
<el-button slot="append" icon="el-icon-search" @click="getMenuList2"></el-button>
</el-input>
</el-col>
<el-col :span="2">
<el-button type="primary" @click="openaddmenu">添加菜单权限</el-button>
</el-col>
<el-col :span="2">
-
</el-col>
</el-row>
<!-- 列表用户内容区域 -->
<el-table :data="menuList" border style="width: 100%">
<el-table-column type="index" label="编号" width="60">
<template slot-scope="scope">
<!-- scope.$index 当前循环的 每一次index值 从0开始 -->
<span>1</span>
</template>
</el-table-column>
<el-table-column prop="menuName" label="菜单名称" width="120">
</el-table-column>
<el-table-column prop="menuUrl" label="菜单路径" width="120">
</el-table-column>
<el-table-column prop="" label="父级名称" width="120">
<!-- levelfirstlist 一级菜单 -->
<template slot-scope="scope" >
<div v-for="x in levelfirstlist" v-if="x.menuId == scope.row.menuPid" >
{{x.menuName}}
</div>
</template>
</el-table-column>
<el-table-column prop="" label="菜单级别" width="200">
<template slot-scope="scope">
{{scope.row.menuLevel == 1?'一级菜单':'二级菜单'}}
</template>
</el-table-column>
<el-table-column prop="menuIndex" label="顺序id" width="120">
</el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="mini" @click="toedituser(scope.row)"></el-button>
<!-- <el-popconfirm title="确定删除吗"> -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteUser(scope.row)"></el-button>
<!-- </el-popconfirm> -->
</template>
</el-table-column>
</el-table>
<!-- 分页功能 -->
<el-pagination align="left" @size-change="SizeChange" @current-change="CurrentChange"
:current-page="queryInfo.page" :page-sizes="[1,2,3,5]" :page-size="queryInfo.rows"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</el-card>
<!-- 添加用户dialog对话框 -->
<!-- :visible.sync v-if v-show -->
<el-dialog align="left" title="添加权限" :visible.sync="addUserVisible" width="50%" @close="">
<!--主体部分 -->
<el-form status-icon label-width="100px" class="demo-ruleForm">
<el-form-item label="菜单名称" >
<el-input v-model="addmenuForm.menuName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单级别" >
<el-radio v-model="addmenuForm.menuPid" label="0" :disabled="editMenudis" >一级菜单</el-radio>
<el-radio v-model="addmenuForm.menuPid" label="1" :disabled="editMenudis">二级菜单</el-radio>
</el-form-item>
<el-form-item label="一级菜单" v-if="addmenuForm.menuPid != 0" >
<!-- <el-radio v-for="x in levelfirstlist" v-model="addmenuForm.menuPidval"
:label="x.menuId" :key="x.menuId"
>{{x.menuName}}</el-radio> -->
<el-radio v-if="addmenuPid" v-for="x in levelfirstlist" v-model="addmenuEx"
:label="x" :key="x.menuId"
>{{x.menuName}}</el-radio>
<el-radio v-if="editmenuPid" v-for="x in levelfirstlist" v-model="addmenuForm.menuPidval"
:label="x.menuId" :key="x.menuId"
>{{x.menuName}}</el-radio>
</el-form-item>
<el-form-item label="菜单路径" v-if="addmenuForm.menuPid != 0">
<el-input v-model="addmenuForm.menuUrl" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addUserVisible = false">取 消</el-button>
<el-button type="primary" @click="addmenu">确 定</el-button>
</span>
{{addmenuForm}}
</el-dialog>
<!-- {{levelfirstlist}} -->
</div>
</template>
<script>
export default {
data() {
return {
//搜索的neirong
searchVal: '',
//用户列表参数
queryInfo: {
menuName: '',
page: 1,
rows: 5
},
//用户列表
menuList: null,
//总的数据条数
total: 0,
addUserVisible: false,
addmenuForm: {
menuId:"",
menuName: "",
menuPid: '0',
menuPidval:'',
menuUrl:'',
menuLevel:'1',
menuIndex:''
},
addmenuEx:{},
levelfirstlist:[], // 所有的一级菜单
powerVisible:false,
url:'',
editMenudis:false,
addmenuPid:false,
editmenuPid:false
}
},
mounted() {
this.getMenuList();
this.getlevellist(1);
},
methods: {
getlevellist(v){
},
toedituser(v){
this.editMenudis = true;
this.addmenuPid = false;
this.editmenuPid = true;
this.addUserVisible = true;
this.addmenuForm.menuId = v.menuId;
this.addmenuForm.menuName = v.menuName;
this.addmenuForm.menuUrl = v.menuUrl;
this.addmenuForm.menuLevel = v.menuLevel;
this.addmenuForm.menuIndex = v.menuIndex;
this.url = '/api/user/updateMenu';
if(v.menuLevel == '1'){ // 一级菜单
this.addmenuForm.menuPid = v.menuPid+'';
this.addmenuForm.menuPidval = '';
}else{ // 二级菜单
// 把 父级id 赋值给 powerParentidval
console.log(v.menuPid);
this.addmenuForm.menuPidval = v.menuPid;
// 把二级猜的 父类id 赋值 1
this.addmenuForm.menuPid = '1';
this.addmenuEx = ''
}
},
deleteUser(v){
let that = this;
this.$confirm('此操作将永久删除该菜单, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { // lambo 表达式 简写
//alert(1)
}).catch(function(){
//alert(2)
})
},
addmenu() {
if (this.addmenuForm.menuName.trim() == '' || this.addmenuForm.menuPid.trim() == '') {
//this.message = "用户名或者密码为空";
alert("菜单名称或者父类菜单为空");
return;
}
let that = this;
// 调用后台 注册接口
console.log(this.addmenuForm);
console.log(this.url);
if(this.addmenuEx == null || this.addmenuEx == ''){
}else{
this.addmenuForm.menuPidval = this.addmenuEx.menuId;
this.addmenuForm.menuIndex = this.addmenuEx.menuIndex;
}
},
openaddmenu() {
this.addUserVisible = true;
this.addmenuForm.menuName = '';
this.addmenuForm.menuPid = '0';
this.addmenuForm.menuPidval = '';
this.addmenuForm.menuUrl = '';
this.url = '/api/user/addmenu';
this.addmenuForm.menuId = '';
this.addmenuForm.menuIndex = '';
this.editMenudis = false;
this.addmenuPid = true;
this.editmenuPid = false;
},
getMenuList2() {
this.queryInfo.page = 1;
this.getMenuList();
},
// 获取用户列表
},
//每页数据条数改变时触发
SizeChange(newval) {
this.queryInfo.rows = newval;
this.getMenuList();
},
//当前页面改变时触发
CurrentChange(newval) {
this.queryInfo.page = newval;
this.getMenuList();
},
}
}
</script>
<style>
</style>
role
<template>
<div>
<!-- 面包屑内容 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>管理模块</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 主体内容 -->
<el-card>
<!-- 列表用户内容区域 -->
<el-table :data="roleList" border style="width: 100%">
<el-table-column type="index" label="编号" width="60">
<template slot-scope="scope">
<!-- scope.$index 当前循环的 每一次index值 从0开始 -->
<span>1</span>
</template>
</el-table-column>
<el-table-column prop="roleName" label="角色名" width="120">
</el-table-column>
<el-table-column prop="menuName" label="权限名" width="400">
</el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<!-- </el-popconfirm> -->
<el-tooltip class="item" effect="dark" content="分配权限" placement="top">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="toroleUser(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 分配角色diaolog对话框 -->
<el-dialog align="left" title="分配权限" :visible.sync="editRoleVisible" width="50%">
<!--主体部分 -->
<div>
<p>当前的角色:<strong>{{roleForm.roleName}}</strong></p>
<p>当前的角色权限:<strong>{{roleForm.menuName}}</strong></p>
<span class="demonstration">请选择角色对应的菜单权限</span>
<el-cascader
:options="options"
:props="props"
v-model="selval"
clearable></el-cascader>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="editRoleVisible = false">取 消</el-button>
<el-button type="primary" @click="editRollist">确 定</el-button>
</span>
{{selval}}
</el-dialog>
<!-- {{checkedsecondpower}}</br>
{{secondpower}}</br>
{{secondpowerids}}</br> -->
</div>
</template>
<script>
export default {
data() {
return {
//角色列表
roleList: null,
editRoleVisible:false,
roleForm:{
roleName:'',
roleId:'',
menuName:''
},
selval:[],
props: { multiple: true }, // 表示多选
options: [] // 数据源
}
},
mounted() {
this.getRolePowerList();
this.getMenulist();
},
methods: {
// getnodevalue(v){
// console.log(v)
// },
// 查询所有的菜单
getMenulist(){
},
toroleUser(v){
this.editRoleVisible = true;
this.roleForm.menuName = v.menuName;
this.roleForm.roleName = v.roleName;
this.roleForm.roleId = v.roleId;
// 点击分配角色时 把当前角色 默认的菜单 显示出来
// 用户管理,用户列表,角色列表,房东管理,房源列表,菜单列表 变成 [ [ 1, 2 ], [ 1, 4 ], [ 1, 5 ] ]
},
editRollist(){
// [ [ 1, 2 ], [ 1, 4 ], [ 1, 5 ] ] :this.selval 数组 第一个表示一级菜单id 第二个表示二级菜单id
},
// 获取角色列表
getRolePowerList() {
},
}
}
</script>
<style>
</style>
user
<template>
<div>
<!-- 面包屑内容 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>管理模块</el-breadcrumb-item>
<el-breadcrumb-item>用户列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 主体内容 -->
<el-card>
<!-- 搜索区域 -->
<el-row>
<el-col :span="6">
<el-input placeholder="请输入用户名" v-model="queryInfo.userName" class="input-with-select" clearable
@clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="getUserList2"></el-button>
</el-input>
</el-col>
<el-col :span="2">
<el-button type="primary" @click="openadduser">添加用户</el-button>
</el-col>
<el-col :span="2">
-
</el-col>
<el-col :span="2">
<el-button type="primary" @click="exportUser">导出用户</el-button>
</el-col>
</el-row>
<!-- 列表用户内容区域 -->
<el-table :data="userList" border style="width: 100%">
<el-table-column type="index" label="编号" width="60">
<template slot-scope="scope">
<!-- scope.$index 当前循环的 每一次index值 从0开始 -->
<span>1</span>
</template>
</el-table-column>
<el-table-column prop="userName" label="姓名" width="120">
</el-table-column>
<el-table-column prop="userPwd" label="密码" width="80">
</el-table-column>
<el-table-column prop="userCreateTime" label="创建时间" width="200">
</el-table-column>
<el-table-column prop="roleName" label="角色" width="120">
</el-table-column>
<el-table-column prop="deleted" label="状态">
<template slot-scope="scope">
<!-- <el-switch v-model="scope.row.mg_state" @change="editStatus(scope.row.id,scope.row.mg_state)"> </el-switch> -->
<!-- scope.row.status 的status 就是java类的属性 -->
<!-- scope.row.status == 1 这是返回的 布尔 true 或者 false -->
<!-- <el-switch @change=""> </el-switch> -->
<el-switch @change="updatestats(scope.row)" v-model="scope.row.deleted"
:active-value="0" :inactive-value="1"> </el-switch>
</template>
</el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="mini" @click="toedituser(scope.row)"></el-button>
<!-- <el-popconfirm title="确定删除吗"> -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteUser(scope.row.userId)"></el-button>
<!-- </el-popconfirm> -->
<el-tooltip class="item" effect="dark" content="分配角色" placement="top">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="toroleUser(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页功能 -->
<el-pagination align="left" @size-change="SizeChange" @current-change="CurrentChange"
:current-page="queryInfo.page" :page-sizes="[1,2,3,5]" :page-size="queryInfo.rows"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</el-card>
<!-- 添加用户dialog对话框 -->
<!-- :visible.sync v-if v-show -->
<el-dialog align="left" title="添加用户" :visible.sync="addUserVisible" width="50%" @close="">
<!--主体部分 -->
<el-form status-icon ref="addUserFormRel" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名" prop="userName">
<el-input v-model="addUserForm.userName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="性别" prop="userSex">
<el-switch v-model="addUserForm.userSex"
:active-value="0" :inactive-value="1"
active-text="女"
inactive-text="男"> </el-switch>
</el-form-item>
<el-form-item label="电话" prop="userTel">
<el-input v-model="addUserForm.userTel" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址" prop="userAddr">
<el-input v-model="addUserForm.userAddr" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="密码" prop="userPwd">
<el-input type="password" v-model="addUserForm.userPwd" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色" prop="roleId">
<el-radio-group v-model="addUserForm.roleId">
<el-radio v-for="x in rolelist"
:label="x.roleId" :key="x.roleId">{{x.roleName}}</el-radio>
<!-- <el-radio :label="2">房东</el-radio>
<el-radio :label="3">租户</el-radio> -->
</el-radio-group>
</el-form-item>
<el-form-item label="图像" prop="userImg">
<el-upload
class="avatar-uploader"
action="/api/user/userImg"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload">
<img v-if="addUserForm.userImg" :src="addUserForm.userImg" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addUserVisible = false">取 消</el-button>
<el-button type="primary" @click="adduser">确 定</el-button>
</span>
</el-dialog>
<!-- 修改用户dialog对话框 -->
<!-- :visible.sync v-if v-show -->
<el-dialog align="left" title="修改用户" :visible.sync="editUserVisible" width="50%" @close="">
<!--主体部分 -->
<el-form status-icon label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名" >
<el-input v-model="editUserForm.userName" disabled autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="原密码" >
<el-input type="password" v-model="editUserForm.oldpwd" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="新密码" >
<el-input type="password" v-model="editUserForm.oldselfpwd" autocomplete="off"></el-input>
</el-form-item>
<!-- <el-form-item label="创建时间" prop="userCreateTime">
<el-date-picker type="datetime" placeholder="选择日期" value-format="yyyy-MM-dd HH:mm:ss"
v-model="editUserForm.userCreateTime" style="width: 100%;" disabled></el-date-picker>
</el-form-item> -->
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="editUserVisible = false">取 消</el-button>
<el-button type="primary" @click="edituser">确 定</el-button>
</span>
</el-dialog>
<!-- 分配用户角色diaolog对话框 -->
<el-dialog align="left" title="分配用户角色" :visible.sync="editRoleVisible" width="50%">
<!--主体部分 -->
<div>
<p>当前的用户:<strong>{{roleForm.userName}}</strong></p>
<p>当前的角色:<strong>{{roleForm.roleName}}</strong></p>
<span>分配新角色:</span>
<el-select v-model="roleForm.roleId" slot="prepend" placeholder="请选择">
<!-- <el-option label="王者" value="王者"></el-option>
<el-option label="黄铜" value="黄铜"></el-option>
<el-option label="钻石" value="钻石"></el-option> -->
<el-option v-for="x in rolelist"
:label="x.roleName" :value="x.roleId" :key="x.roleId"></el-option>
</el-select>
<!-- {{selectVal}} -->
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="editRoleVisible = false">取 消</el-button>
<el-button type="primary" @click="editRollist">确 定</el-button>
</span>
</el-dialog>
<!-- <img :src="imageUrl"> -->
<!-- <img src="file:///D://img//1657089792394wzry001.jpg"> -->
</div>
</template>
<script>
export default {
data() {
return {
//搜索的neirong
searchVal: '',
//用户列表参数
queryInfo: {
userName: '',
page: 1,
rows: 3
},
//用户列表
userList: null,
//总的数据条数
total: 0,
addUserVisible: false,
addUserForm: {
userName: "",
userPwd: "",
userSex:1,
userTel:'',
userAddr:"",
roleId:4,
userImg:''
},
editUserVisible:false,
editUserForm: {
userId:"",
userName: "",
oldpwd: "",// 修改框中 输入的原密码
userPwd:"", // 数据库原来的密码
userCreateTime:"",
oldselfpwd:"" ,// 修改框中 输入的新密码,
version:0
},
editRoleVisible:false,
roleForm:{
roleId:"",
userId:"",
userName:"",
roleName:""
},
rolelist:[],
// imageUrl: ''
}
},
mounted() {
this.getUserList();
this.getrolelist();
},
methods: {
getrolelist(){
},
toroleUser(v){
this.editRoleVisible = true;
this.roleForm.userName = v.userName;
this.roleForm.roleName = v.roleName;
this.roleForm.userId = v.userId;
// this.getrolelist(); // 打开分配角色的窗口 查询 角色数据
},
editRollist(){
},
exportUser(){
let form = $("<form>"); //创建form标签
form.attr("style","display:none");
form.attr("method","get");//设置请求方式
form.attr("action","/api/user/exportUser"); //action属性设置请求路径
$("body").append(form); //页面添加form标签
form.submit();//表单提交即可下载!
},
toedituser(v){
this.editUserVisible = true;
this.editUserForm.userName = v.userName;
this.editUserForm.userId = v.userId;
this.editUserForm.userPwd = v.userPwd;
this.editUserForm.userCreateTime = v.userCreateTime;
this.editUserForm.version = v.version;
// data.replace(“,”,”+”);//只能替换掉第一个,号。result ==>”数据1+数据2,数据3”
// var reg = new RegExp(“,”,”g”);//g,表示全部替换。
// data.replace(reg,”+”);
// data.replace('-','年')
// this.editUserForm.createtime = v.createtime;
//this.editUserForm.createtime = '2022-04-06 16:07:14';
},
edituser(){
//var userinfo = JSON.parse(sessionStorage.getItem('user'));
if(this.editUserForm.oldpwd != this.editUserForm.userPwd){ // 输入的原密码和 登录的密码不同
alert('原密码输入错误');
return;
}
},
deleteUser(id){
let that = this;
this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { // lambo 表达式 简写
//alert(1)
}).catch(function(){
//alert(2)
})
},
updatestats(v){
console.log(v);
},
adduser() {
console.log(this.addUserForm)
if (this.addUserForm.userName.trim() == '' || this.addUserForm.userPwd.trim() == '') {
//this.message = "用户名或者密码为空";
alert("用户名或者密码为空");
return;
}
},
openadduser() {
//this.getrolelist();
this.addUserVisible = true;
},
getUserList2() {
this.queryInfo.page = 1;
this.getUserList();
},
// 获取用户列表
getUserList() {
},
//每页数据条数改变时触发
SizeChange(newval) {
this.queryInfo.rows = newval;
this.getUserList();
},
//当前页面改变时触发
CurrentChange(newval) {
this.queryInfo.page = newval;
this.getUserList();
},
handleAvatarSuccess(res, file) {
console.log(res)
console.log(file)
this.addUserForm.userImg = res.data;
// this.imageUrl = URL.createObjectURL(file.raw);
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
}
}
}
</script>
<style>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
添加路径
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import login from '@/components/Login.vue'
import home from '@/components/Home.vue'
import userList from '@/components/user/User.vue'
import power from '@/components/user/power.vue'
import role from '@/components/user/role.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/login',
name: '登录页面',
component: login
},
{
path: '/home',
name: '首页',
component: home,
children:[{
path: '/userList',
name: '用户列表',
component: userList
}]
}
]
})
设置拦截器(前置守卫)
把用户信息存到 session 作用域中
注意上面的 abc 这里为修改了一下
继续完成用户列表
导入其他的页面
编写方法
在数据库添加列
修改实体类
注意修改其他地方的名字
package com.example.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class UserInfo {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("username")
private String userName;
@TableField("password")
private String passPwd;
private Integer status;// '1 正常 2 停用',
@TableField("create_time")
private String userCreateTime;
private Integer version;
private String updateTime;
private Integer deleted;
private Integer userSex; // 0 女 1男
private String userTel;
private String userAddr;
}
分页
添加分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mi = new MybatisPlusInterceptor();
mi.addInnerInterceptor(new PaginationInnerInterceptor());
return mi;
}
User.vue
后端添加此方法
@RequestMapping("/getPowerByUserId")
public Page<UserInfo> list(QueryInfo queryInfo) {
System.out.println(queryInfo);
QueryWrapper<UserInfo> qw = new QueryWrapper<>();
qw.like("username",queryInfo.getUserName());
if (StringUtils.isNotBlank(queryInfo.getUserName())){
qw.like("username",queryInfo.getUserName());
}
// List<UserInfo> userInfos = userDao.selectList(qw);
Page<UserInfo> page = new Page<>(queryInfo.getPage(),queryInfo.getRows());
Page<UserInfo> page1 = userDao.selectPage(page, qw);
return page1;
}
再修改前端
// 获取用户列表
getUserList() {
let url = "http://localhost:8080/getUserList";
this.$axios.get(url,{params:this.queryInfo}).then(
(d)=>{
console.log(d)
this.userList = d.data.records;
this.total = d.data.total;
}
)
},
上面的方法是不会显示角色的,我们要显示角色要自己写分页
在userdao 添加接口
Page<UserInfo> selectPageUR(Page<UserInfo> page, @Param("ew") QueryWrapper<UserInfo> qw);
添加SQL 语句
<select id="selectPageUR" resultType="com.example.model.UserInfo">
select u.id, u.username as userName, u.password userPwd, u.create_time userCreateTime, u.deleted,
u.user_sex,u.user_tel,u.user_addr,
r.role_name from user_info as u
LEFT JOIN user_role ur on u.id = ur.user_id
LEFT JOIN role r on r.role_id = ur.role_id
${ew.customSqlSegment}
</select>
这里要添加属性到UserInfo 表
package com.example.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class UserInfo {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("username")
private String userName;
@TableField("password")
private String passPwd;
private Integer status;// '1 正常 2 停用',
@TableField("create_time")
private String userCreateTime;
private Integer version;
private String updateTime;
private Integer deleted;
private Integer userSex; // 0 女 1男
private String userTel;
private String userAddr;
// 告诉mybatis roleName 这个属性 不是userinfo 表的字段
@TableField(exist = false)
private String roleName;
}
添加信息
修改信息
删除信息
导出
导入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.11</version>
</dependency>
添加工具类
package com.example.util;
import com.example.model.UserInfo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
public class ExcelUtil {
/**
* 用户信息导出类
* @param response 响应
* @param fileName 文件名
* @param columnList 每列的标题名
* @param dataList 导出的数据
*/
public static void uploadExcelAboutUser(HttpServletResponse response, String fileName, List<String> columnList, List<List<String>> dataList){
//声明输出流
OutputStream os = null;
//设置响应头
setResponseHeader(response,fileName);
try {
//获取输出流
os = response.getOutputStream();
//内存中保留1000条数据,以免内存溢出,其余写入硬盘
SXSSFWorkbook wb = new SXSSFWorkbook(1000);
//获取该工作区的第一个sheet
Sheet sheet1 = wb.createSheet("sheet1");
int excelRow = 0;
//创建标题行
Row titleRow = sheet1.createRow(excelRow++);
for(int i = 0;i<columnList.size();i++){
//创建该行下的每一列,并写入标题数据
Cell cell = titleRow.createCell(i);
cell.setCellValue(columnList.get(i));
}
//设置内容行
if(dataList!=null && dataList.size()>0){
//序号是从1开始的
int count = 1;
//外层for循环创建行
for(int i = 0;i<dataList.size();i++){
Row dataRow = sheet1.createRow(excelRow++);
//内层for循环创建每行对应的列,并赋值
for(int j = -1;j<dataList.get(0).size();j++){//由于多了一列序号列所以内层循环从-1开始
Cell cell = dataRow.createCell(j+1);
if(j==-1){//第一列是序号列,不是在数据库中读取的数据,因此手动递增赋值
cell.setCellValue(count++);
}else{//其余列是数据列,将数据库中读取到的数据依次赋值
cell.setCellValue(dataList.get(i).get(j));
}
}
}
}
//将整理好的excel数据写入流中
wb.write(os);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭输出流
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void uploadExcelAboutUser2(HttpServletResponse response, String fileName, List<String> columnList, List<UserInfo> dataList){
//声明输出流
OutputStream os = null;
//设置响应头
setResponseHeader(response,fileName);
try {
//获取输出流
os = response.getOutputStream();
//内存中保留1000条数据,以免内存溢出,其余写入硬盘
SXSSFWorkbook wb = new SXSSFWorkbook(900);
//获取该工作区的第一个sheet
Sheet sheet1 = wb.createSheet("用户列表");
Sheet sheet2 = wb.createSheet("角色列表");
int excelRow = 0;
//创建标题行
Row titleRow = sheet1.createRow(excelRow++);
for(int i = 0;i<columnList.size();i++){
//创建该行下的每一列,并写入标题数据
Cell cell = titleRow.createCell(i);
cell.setCellValue(columnList.get(i));
}
//设置内容行
if(dataList!=null && dataList.size()>0){
//序号是从1开始的
int count = 1;
//外层for循环创建行
for(int i = 0;i<dataList.size();i++){
Row dataRow = sheet1.createRow(excelRow++);
UserInfo userInfo = dataList.get(i);
Cell cell0 = dataRow.createCell(0);
cell0.setCellValue(count++);
Cell cell1 = dataRow.createCell(1);
cell1.setCellValue(userInfo.getUserName());
Cell cell2 = dataRow.createCell(2);
// cell2.setCellValue(userInfo.getUserSex()==1?"男":"女");
cell2.setCellValue(userInfo.getUserPwd());
Cell cell3 = dataRow.createCell(3);
// cell2.setCellValue(userInfo.getUserSex()==1?"男":"女");
cell3.setCellValue(userInfo.getUserCreateTime());
}
}
//将整理好的excel数据写入流中
wb.write(os);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭输出流
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
设置浏览器下载响应头
*/
private static void setResponseHeader(HttpServletResponse response, String fileName) {
try {
try {
fileName = new String(fileName.getBytes(),"ISO8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setContentType("application/octet-stream;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename="+ fileName);
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
后端
分配角色
创建bean
package com.example.model;
import lombok.Data;
@Data
public class Role {
private Integer roleId;
private String roleName;
}
新建dao
RoleDao
package com.example.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.model.Role;
public interface RoleDao extends BaseMapper<Role> {
}
查询所有
package com.example.controller;
import com.example.dao.RoleDao;
import com.example.model.Role;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import java.util.List;
@Controller
@RequestMapping("/role")
public class RoleController {
@Resource
RoleDao roleDao;
@RequestMapping("/getrolelist")
public List<Role> getrolelist(){
List<Role> roles = roleDao.selectList(null);
return roles;
}
}
修改Role bean
package com.example.model;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
@Data
public class Role {
private Integer roleId;
private String roleName;
// 表示 id 不是角色边的字段 只是作为 java 类里面的属性使用
@TableField(exist = false)
private Integer id;
}
编写dao 层
package com.example.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.model.Role;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface RoleDao extends BaseMapper<Role> {
@Select("select count(1) from user_role where user_id = #{id}")
int selectURByUserId(Integer id);
@Update("update user_role set role_id = #{roleId} where user_id = #{id}")
void updateURByUserId(Role role);
@Insert("insert into user_role values(null,#{id},#{roleId})")
void insertURByUserId(Role role);
}
修改控制层代码
package com.example.controller;
import com.example.dao.RoleDao;
import com.example.model.Role;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/role")
public class RoleController {
@Resource
RoleDao roleDao;
// 显示
@RequestMapping("/getrolelist")
public List<Role> getrolelist(){
System.out.println("123");
List<Role> roles = roleDao.selectList(null);
return roles;
}
// 通过用户id 查询 user_role 关系表
@RequestMapping("/editRollist")
public boolean editRollist(Role role){
System.out.println(role);
boolean flag = false;
try {
// 通过用户id 查询 user_role 关系表
int count = roleDao.selectURByUserId(role.getId());
// 有数据 修改 角色 id
if (count > 0){
roleDao.updateURByUserId(role);
}else{
// 没有数据 新增一条关系数据
roleDao.insertURByUserId(role);
}
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
}
return flag;
}
}
修改前端代码
// 修改角色 点击确定 执行方法
editRollist() {
let url = "http://localhost:8080/role/editRollist"
this.$axios.get(url,{params:this.roleForm}).then((d) =>{
if(d.data){
alert("修改角色成功")
this.editRoleVisible = false;
this.getUserList()
}else{
alert("修改角色失败")
}
})
},
代码发邮箱
pom 里面的驱动
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.5.6</version>
</dependency>
工具类
package com.example.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
/**
* @Description
* @Autor 伍军
* @Date 2021/9/15 13:58
* @Version 1.0
**/
@Component
public class MyEmail {
//注入邮件发送类
@Resource
JavaMailSender javaMailSender;
@Value("${spring.mail.username}")
private String formEmail;
/**
* 发送邮件
* @param email 收件人的邮箱
* @param content 邮件正文
* @return
*/
public HashMap<String,Object> sendEmail(String email,String content,String title){
HashMap<String,Object> map = new HashMap<String,Object>();
try{
//创建一个邮件
SimpleMailMessage message = new SimpleMailMessage();
//写入收件人邮箱
message.setTo(email);
//写入发件人邮箱
message.setFrom(formEmail);
//写入邮件标题
message.setSubject(title);
//写入邮件正文
message.setText(content);
//发送邮件
javaMailSender.send(message);
map.put("info","发送成功");
}catch(Exception e){
e.printStackTrace();
map.put("info","发送失败");
}
return map;
}
// public void forSend(List<Auding> list){
// String title = "请尽快审核房屋提交信息";
// String content = "";
// for(Auding a : list){
// content = "这是要审核的房屋名称"+a.getAudeHouseName();
// sendEmail(a.getUserEmail(),content,title);
// }
// }
}
@Resource
MyEmail myEmail;
@RequestMapping("/sendEmail")
public void sendEmail(){
// 第一个参数 接受者的邮箱
myEmail.sendEmail("1243835377@qq.com","你好","测试邮箱");
}
如果你的配置文件是 por的话 使用这个配置文件
#邮箱配置
spring.mail.host=smtp.qq.com
spring.mail.username=767920412@qq.com
spring.mail.password=fobsqzeugtptbgaf
spring.mail.port=465
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.default-encoding=UTF-8
如果你的配置文件是 yml 的话 使用这个配置文件
mail:
host: smtp.qq.com
username: 767920412@qq.com
password: fobsqzeugtptbgaf
port: 465
properties:
mail:
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
default-encoding: utf-8
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/testvue?useSSL=false
username: root
password: root123
application:
name: provider-service
mail:
host: smtp.qq.com
username: 767920412@qq.com
password: fobsqzeugtptbgaf
port: 465
properties:
mail:
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
default-encoding: utf-8
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/*.xml
权限名
前端
<template>
<div>
<!-- 面包屑内容 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>管理模块</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 主体内容 -->
<el-card>
<!-- 列表用户内容区域 -->
<el-table :data="roleList" border style="width: 100%">
<el-table-column type="index" label="编号" width="60">
<template slot-scope="scope">
<!-- scope.$index 当前循环的 每一次index值 从0开始 -->
<span>{{scope.$index+1}}</span>
</template>
</el-table-column>
<el-table-column prop="roleName" label="角色名" width="120">
</el-table-column>
<el-table-column prop="menuName" label="权限名" width="400">
</el-table-column>
<el-table-column prop="address" label="操作">
<template slot-scope="scope">
<!-- </el-popconfirm> -->
<el-tooltip class="item" effect="dark" content="分配权限" placement="top">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="toroleUser(scope.row)"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 分配角色diaolog对话框 -->
<el-dialog align="left" title="分配权限" :visible.sync="editRoleVisible" width="50%">
<!--主体部分 -->
<div>
<p>当前的角色:<strong>{{roleForm.roleName}}</strong></p>
<p>当前的角色权限:<strong>{{roleForm.menuName}}</strong></p>
<span class="demonstration">请选择角色对应的菜单权限</span>
<el-cascader
:options="options"
:props="props"
v-model="selval"
clearable></el-cascader>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="editRoleVisible = false">取 消</el-button>
<el-button type="primary" @click="editRollist">确 定</el-button>
</span>
{{selval}}
</el-dialog>
<!-- {{checkedsecondpower}}</br>
{{secondpower}}</br>
{{secondpowerids}}</br> -->
</div>
</template>
<script>
export default {
data() {
return {
//角色列表
roleList: null,
editRoleVisible:false,
roleForm:{
roleName:'',
roleId:'',
menuName:''
},
selval:[],
props: { multiple: true }, // 表示多选
options: [{
value: 'zhinan',
label: '指南',
children: [{
value: 'shejiyuanze',
label: '设计原则',
// children:[
// {value:'key1',label:'value2',},
// {value:'key2',label:'value2',},
// ],
},
{
value: 'shejiyuanze2',
label: '设计原则2',
},
]
},
{
value: 'zhinan2',
label: '指南2',
}
], // 数据源
}
},
mounted() {
this.getRolePowerList();
this.getMenulist();
},
methods: {
// getnodevalue(v){
// console.log(v)
// },
// 查询所有的菜单
getMenulist(){
},
toroleUser(v){
this.editRoleVisible = true;
this.roleForm.menuName = v.menuName;
this.roleForm.roleName = v.roleName;
this.roleForm.roleId = v.roleId;
// 点击分配角色时 把当前角色 默认的菜单 显示出来
// 用户管理,用户列表,角色列表,房东管理,房源列表,菜单列表 变成 [ [ 1, 2 ], [ 1, 4 ], [ 1, 5 ] ]
},
editRollist(){
// [ [ 1, 2 ], [ 1, 4 ], [ 1, 5 ] ] :this.selval 数组 第一个表示一级菜单id 第二个表示二级菜单id
},
// 获取角色列表
getRolePowerList() {
let url = "http://localhost:8080/role/getrolelistPower"
this.$axios.get(url).then((d) =>{
this.roleList = d.data;
})
},
}
}
</script>
<style>
</style>
修改 Role bean 文件
package com.example.model;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
@Data
public class Role {
private Integer roleId;
private String roleName;
// 表示 id 不是角色边的字段 只是作为 java 类里面的属性使用
@TableField(exist = false)
private Integer id;
// 表示 id 不是角色表的字段 只是作为java类里面的属性使用
@TableField(exist = false)
private String menuName;
}
新建 sql 映射文件
RoleDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.dao.RoleDao">
<select id="getrolelistPower" resultType="com.example.model.Role">
select r.role_id,r.role_name, GROUP_CONCAT(p.power_name) menuName
from role r
LEFT JOIN role_power rp on r.role_id = rp.role_id
LEFT JOIN power p on p.power_id = rp.power_id
GROUP BY r.role_id,r.role_name
order by r.role_id
</select>
</mapper>
添加接口
RoleDao.java
List<Role> getrolelistPower();
添加控制层代码
@RequestMapping("/getrolelistPower")
public List<Role> getrolelistPower(){
return roleDao.getrolelistPower();
}
Spring Boot 添加定时器
开启自带的定时器功能
测试类