我们在原来的基础上又新加了一个页面,就是用户的个人信息页面person:
源码为:
<template>
<div>
<el-card style="width: 40%; margin: 10px">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="form.username" disabled></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" show-password></el-input>
</el-form-item>
<el-form-item label="昵称">
<el-input v-model="form.nickName"></el-input>
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="form.age"></el-input>
</el-form-item>
<el-form-item label="性别">
<el-input v-model="form.sex"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address"></el-input>
</el-form-item>
</el-form>
<div>
<el-button type="primary" @click="update">保存</el-button>
</div>
</el-card>
</div>
</template>
<script>
import request from "../utils/request";
export default {
name: "Person",
data(){
return {
form:{
},
}
},
methods:{
update(){
request.put("/api/user",this.form).then(res => {
console.log(res)
if(this.code === '0'){
this.$messageBox({
type: "success",
message: "更新成功"
})
sessionStorage.setItem("user",JSON.stringify(this.form))
}else{
this.$message({
type:"error",
message: res.msg
})
}
})
}
}
}
</script>
<style scoped>
</style>
然后我们要去写我们的路由:
现在点击个人信息,就可以弹出信息页面了。然后我们现在发现我们的项目的路由每次都要在前面加个/api,感觉很繁琐,解决办法是我们在request.js的文件下,加上一句话,如下图:
现在我们写的路由都不需要加/api了,baseURL会帮我们自动拼接上去,但是我们之前写的都是加了的,改的话很麻烦,但是Idea提供了一个全局修改的功能,就是在我们要选中修改的地方,按control+shift+r,就可以进行全局修改了。
那么接下来我们去实现菜单的路由跳转,这怎么实现其实很简单,比如在我们的Aside侧边栏组件里面,我们有这样的一个设置:
default-active和index是一一对应的,正是这种一一对应的关系所以在进来Home时“用户管理”会有高亮状态:
所以这里我们默认用户界面是高亮的就行,但这里的Home.vue组件的设置其实是不太合理的,因为这只是一个用户管理,并不是我们的项目主页,所以我们可以把这个Home组件的名字给改一下,shift+f6更改为User.vue:
访问:
那么我们现在怎么去实现点击菜单实现路由跳转呢?
很简单,有一个值叫router我们用就行了,如下图:
当然因为目前我们只有一个页面,所以看不出什么效果,所以我们现在再写一个页面,叫Book.vue:
然后配置路由,记得页面内路由切换应该在子路由当中实现:
然后我们记得在侧边栏中加上新增的菜单,index所指的位置就是页面的路由:
现在我们访问页面就可以发现,点击哪个菜单,页面就往哪里跳转:
然后现在的问题是,我们每回登录都是直接就进来了用户管理的界面,连登录都不需要,因为没有登录的原因所以右上角也并不会有用户信息显示,哪怕我们的用户信息已经存在了sessionStorage。
除了Person.vue里面需要保存sessionStorage,Login.vue里面也需要对应的改变,新写的Login页面源代码如下:
<template>
<!--将整个浏览器页面放在一个大div里
width: 100%表示这个让div撑满全屏
height: 100vh同上,一个撑满高度一个撑满宽度-->
<div style="width: 100%; height: 100vh;background: darkslateblue; overflow: hidden">
<!--margin: 参数1 参数2; 参数1表示上下距离,参数2表示左右距离,auto表示自动匹配
如果页面产生了空白,就在外层最大的div上加一个overflow,设置为hidden即可-->
<div style="width: 400px; margin: 150px auto">
<!--font-size表示字体大小,text-align表示字体居中-->
<div style="color: #cccccc; font-size: 30px; text-align: center; padding: 30px 0">
欢迎登录
</div>
<!--然后去element上copy一个表单-->
<el-form ref="form" :model="form" size="normal" :rules="rules">
<el-form-item prop="username">
<el-input prefix-icon="el-icon-user-solid" v-model="form.username"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input prefix-icon="el-icon-lock" v-model="form.password" show-password></el-input>
</el-form-item>
</el-form>
<el-form ref="form" :model="form" size="normal">
<el-button style="width: 100%" type="primary" @click="login">登录</el-button>
</el-form>
</div>
</div>
</template>
<script>
import request from "../utils/request";
export default {
name: "Login",
data(){
return{
form:{
},
rules:{
username:[
{
required: true,message:"请输入用户名",trigger:'blur'},
],
password:[
{
required: true,message:"请输入密码",trigger:'blur'},
]
}
}
},
created(){
sessionStorage.removeItem("user")
},
methods: {
login() {
//发送请求之前先加这个判断,不为空且满足规则时才发送请求
this.$refs['form'].validate((valid) => {
if (valid) {
request.post("/user/login",this.form).then(res => {
if(res.code === "0"){
this.$messageBox({
type: "success",
message: "登录成功"
})
//缓存用户信息
sessionStorage.setItem("user",JSON.stringify(res.data))
// 登录成功之后进行页面跳转,跳转到主页
this.$router.push("/")
}else{
this.$messageBox({
type: "error",
message: res.msg
})
}
})
}
})
}
}
}
</script>
<style scoped>
</style>
那么我们怎么去进行拦截使其只有登录了才能够访问我们的界面呢?其实也很简单,在我们的request.js里面其实已经定义好了拦截器,不管我们发送什么请求它都会进入到我们的拦截器里面:
因为都会被拦截,所以我们现在在这里面进行一个判断,取出登录中提交的user数据:
现在不管访问哪个页面都一定会经过登录页面了,但是我们页面的右上角的下拉框那里还没有解决,我们需要让他动态的与所登录的用户相绑定才行,这里就直接放源码了:
<template>
<!--管理系统的第一部分,头部部分,用一个大的div来做导航栏,后台管理四个字在左边,下拉框放右边-->
<div style="height: 50px; line-height: 50px; border-bottom: 1px solid #ccc; display: flex">
<div style="width: 200px; padding-left: 30px; font-weight: bold; color: dodgerblue">后台管理</div>
<div style="flex: 1"></div>
<div style="width: 100px">
<el-dropdown>
<span class="el-dropdown-link">
{
{
user.nickName }}
<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="$router.push('/person')">个人信息</el-dropdown-item>
<el-dropdown-item @click="$router.push('/login')">退出系统</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script>
export default {
name: "Header",
props:['user'],
data(){
return{
user:{
}
}
},
created(){
let userStr = sessionStorage.getItem("user") || "{}"
this.user = JSON.parse(userStr)
}
}
</script>
<style scoped>
</style>
这样就连起来啦:
现在我们来充实一下Book.vue里面的内容,我们可以直接把User.vue里面的东西复制过去,记得改变组件名以及路由位置还有表单的一些东西:
<template>
<!--padding设置一点内边距-->
<div style="padding: 10px">
<!--功能区域-->
<div style="margin: 10px 0">
<el-button type="primary" @click="add">新增</el-button>
<el-button type="primary">导入</el-button>
<el-button type="primary">导出</el-button>
</div>
<!--搜索区域-->
<div style="margin: 10px 0">
<el-input v-model="search" placeholder="请输入关键字" style="width: 20%" clearable/>
<el-button type="primary" style="margin-left: 5px" @click="load">搜索</el-button>
</div>
<!--后面的width可以不写,浏览器会自适应
stripe是斑马纹效果-->
<el-table :data="tableData" border stripe style="width: 100%">
<!--sortable让日期排序-->
<el-table-column prop="id" label="ID" sortable/>
<el-table-column prop="name" label="书名"/>
<el-table-column prop="price" label="单价" />
<el-table-column prop="author" label="作者"/>
<el-table-column prop="createTime" label="出版日期"/>
<el-table-column fixed="right" label="操作">
<template #default="scope">
<el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
<!--弹出消息确认框-->
<el-popconfirm
confirm-button-text="是的,没错"
cancel-button-text="妈的,我再想想"
icon="el-icon-info"
icon-color="red"
title="确定删除吗?" @confirm="handleDelete(scope.row.id)">
<template #reference>
<el-button size="mini" type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!--分页功能区域-->
<div style="margin: 10px 0">
<el-pagination
v-model:currentPage="currentPage4"
:page-sizes="[5,10,20]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange">
</el-pagination>
</div>
<!--弹窗输入用户信息-->
<el-dialog v-model="dialogVisible" title="提示" width="30%">
<!--定义表单在这个弹出框内以收集新增的用户信息-->
<el-form :model="form" label="用户名">
<el-form-item label="书名">
<el-input v-model="form.name" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="价格">
<el-input v-model="form.price" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="作者">
<el-input v-model="form.author" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="出版时间">
<el-data-picker v-model="form.createTime" value-format="YYYY-MM-DD" time="date" style="width: 80%" clearable></el-data-picker>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import request from "../utils/request";
export default {
name: 'Book',
components: {
},
data() {
return {
form: {
},
dialogVisible: false,
search: '',
//当前页
currentPage4: 1,
pageSize: 10,
total: 0,
tableData: [
],
}
},
//表示在页面被加载的时候,在这个方法里面的方法就全部调用
created() {
this.load()
},
methods: {
//查询方法
load(){
request.get("/book",{
params: {
pageNum: this.currentPage4,
pageSize: this.pageSize,
search: this.search
}
}).then(res => {
console.log(res)
this.tableData = res.data.records
this.total = res.data.total
})
},
add(){
this.dialogVisible = true;
//清空表单域
this.form = {
};
},
save(){
if(this.form.id){
//更新操作
request.put("/book",this.form).then(res => {
console.log(res)
if(res.code == '0'){
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "success",
message: "更新成功"
})
}else{
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "error",
message: res.msg
})
}
})
this.load() //每一次更新后都自动刷新表格
this.dialogVisible = false //关闭弹窗
}else{
//新增操作
request.post("/book",this.form).then(res => {
console.log(res)
if (res.code == '0') {
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "success",
message: "新增成功"
})
} else {
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "error",
message: res.msg
})
}
this.load() //每次新增完都自动刷新表格
this.dialogVisible = false //关闭弹窗
}
)}
},
handleEdit(row){
this.form = JSON.parse(JSON.stringify(row))
this.dialogVisible = true
},
handleDelete(id){
console.log(id)
request.delete("/book/"+id).then(res =>{
if (res.code == '0') {
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "success",
message: "删除成功"
})
} else {
//element给我们提供了一个可以供显示的结果的东西,如下
this.$messageBox({
type: "error",
message: res.msg
})
}
this.load() //删除之后重新加载表格的数据
})
},
handleSizeChange(pageSize){
// 改变当前每页的数据条数时触发
this.pageSize = pageSize
this.load()
},
handleCurrentChange(pageNum){
// 改变当前页码时触发
this.currentPage4 = pageNum
this.load()
}
}
}
</script>
再去写我们的BookMapper:
再写controller层:
package com.why.demo.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.why.demo.common.Result;
import com.why.demo.entity.Book;
import com.why.demo.entity.User;
import com.why.demo.mapper.BookMapper;
import com.why.demo.mapper.UserMapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController //返回json格式字符串的注解
@RequestMapping("/book")
public class BookController {
//理论上应该用三层架构,controller调用service,service调用dao的,这里图方便就直接在controller调了
@Resource
BookMapper bookMapper;
//新增用户
@PostMapping
//@RequestBody就是把前台传过来的json数据转换成Java对象
public Result save(@RequestBody Book book){
bookMapper.insert(book);
return Result.success();
}
//删除用户,根据id删除
@DeleteMapping("/{id}")
//@PathVariable就是把前台通过{id}占位符传过来的数据解析成Long类型的id值
public Result delete(@PathVariable Long id){
bookMapper.deleteById(id);
return Result.success();
}
//更新用户,即访问/user即可
@PutMapping
//@RequestBody就是把前台传过来的json数据转换成Java对象
public Result update(@RequestBody Book book){
bookMapper.updateById(book);
return Result.success();
}
//查询用户,用Get命令,且是分页查询
/**
* 分页查询,需要前台传过来三个参数,@RequestParm注解就是解析参数用的,如果不加后面的defaultValue设置
* 默认的话,则请求时必须携带三个参数,不然就会报404错误
* 第一个参数pageNum就是当前页的页码
* 第二个参数pageSize就是每页多少条数据
* 第三个参数search就是查询的关键字
* @param pageNum
* @param pageSize
* @param search
* @return
*/
@GetMapping
public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "") String search){
//下面这些操作都是Mp提供的,不懂的就需要自己去了解学习了
//分页模糊查询,结果放在Result里面直接返回出去
return Result.success(bookMapper.selectPage(new Page<>(pageNum, pageSize),Wrappers.<Book>lambdaQuery().like(Book::getName,search)));
}
}
路由是我们之前就写好了的,这里可以直接访问测试了,登录进入主页,找到书籍管理,点击新增:
可以看见新增成功:
上面时间的显示好像有问题,日期的格式问题我们可以这样解决:
就不会有时间格式问题了,或者也可以在yaml配置文件里面进行全局配置:
然后解决一下默认的高亮问题:
<template>
<div>
<el-menu
style="width: 200px; min-height: calc(100vh - 50px)"
:default-active="path"
router
class="el-menu-vertical-demo">
<el-sub-menu index="1">
<template #title>系统管理</template>
<el-menu-item index="/user">用户管理</el-menu-item>
</el-sub-menu>
<el-menu-item index="/book">书籍管理</el-menu-item>
</el-menu>
</div>
</template>
<script>
export default {
name: "Aside",
data(){
return {
path: this.$router.path //设置默认高亮的菜单
}
},
created(){
}
}
</script>
<style scoped>
</style>
先到这,后续学习了再继续写。