🎉🎉欢迎来到我的CSDN主页!🎉🎉
🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚
🌟推荐给大家我的专栏《ELement》。🎯🎯
👉点击这里,就可以查看我的主页啦!👇👇
Java方文山的个人主页
🎁如果感觉还不错的话请给我点赞吧!🎁🎁
💖期待你的加入,一起学习,一起进步!💖💖
目录
一、前言
二、左侧动态树实现
2.1.后台数据接口定义
2.2.前端导航菜单绑定
2.3.根据数据渲染页面
2.4.动态路由实现
三、右侧内容数据表格
3.1.根据文档搭建页面
3.2.实现模糊查询
四、分页实现
一、前言
在上一篇博文我们搭建了首页导航和左侧菜单,但是我们的左侧菜单是死数据今天我们就来把死的变成活的,并且完成右侧内容的书籍数据表格的展示与分页效果,话不多说上代码!!
二、左侧动态树实现
2.1.后台数据接口定义
首先我们将后端的代码写好Controller层代码
package com.zking.ssm.controller;
import com.zking.ssm.model.Module;
import com.zking.ssm.model.RoleModule;
import com.zking.ssm.model.TreeNode;
import com.zking.ssm.service.IModuleService;
import com.zking.ssm.util.JsonResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/module")
public class ModuleController {
@Autowired
private IModuleService moduleService;
@RequestMapping("/queryRootNode")
@ResponseBody
public JsonResponseBody<List<Module>> queryRootNode(){
try {
List<Module> modules = moduleService.queryRootNode(-1);
return new JsonResponseBody<>("OK",true,0,modules);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("初始化首页菜单错误",false,0,null);
}
}
@RequestMapping("/queryElementTree")
@ResponseBody
public JsonResponseBody<List<TreeNode>> queryElementTree(){
try {
List<TreeNode> modules = moduleService.queryTreeNode(-1);
return new JsonResponseBody<>("OK",true,0,modules);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("初始化ElementUI的Tree组件错误",false,0,null);
}
}
@RequestMapping("/addRoleModule")
@ResponseBody
public JsonResponseBody<?> addRoleModule(RoleModule roleModule){
try {
moduleService.addRoleModule(roleModule);
return new JsonResponseBody<>("新增角色权限成功",true,0,null);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("新增角色权限失败",false,0,null);
}
}
@RequestMapping("/queryModuleByRoleId")
@ResponseBody
public JsonResponseBody<List<String>> queryModuleByRoleId(RoleModule roleModule){
try {
List<String> modules = moduleService.queryModuleByRoleId(roleModule);
return new JsonResponseBody<>("OK",true,0,modules);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("获取角色权限失败",false,0,null);
}
}
}
由此我们可知后端查询的树形菜单的接口为:http://localhost:8080/ssm/module/queryRootNode
2.2.前端导航菜单绑定
数据有了我们只用考虑怎么通过Vue拿到数据以及展示数据就可以了。
找到src下面的api目录下的action.js文件添加下列接口
'SYSTEM_USER_MODULE': '/module/queryRootNode', //左侧菜单
在LeftNav.vue中的钩子函数内编写方法去到后端拿取数据赋予变量
created() {
this.$root.Bus.$on('aaa', r => {
this.collapsed = r;
});
//加载页面先去后端拿数据
let url = this.axios.urls.SYSTEM_USER_MODULE;
this.axios.get(url, {}).then(r => {
this.menus=r.data.rows
}).catch(e => {
})
}
并在data中定义变量 menus:[]
menus:[]
2.3.根据数据渲染页面
去到我们ELement查找相应的代码进行cv,下面是我找好的你们直接用,我们现在只需要将后端获取到的数据在上面的代码中进行遍历即可。
<!-- 左侧菜单内容-->
<el-submenu v-for="m in menus" :index="'ind_'+m.id" :key="'key_'+m.id">
<template slot="title">
<i :class="m.icon"></i>
<span>{{m.text}}</span>
</template>
<el-menu-item v-for="ms in m.modules" :index="ms.url" :key="'key_'+ms.id">
<i :class="ms.icon"></i>
<span>{{ms.text}}</span>
</el-menu-item>
</el-submenu>
效果展示:
2.4.动态路由实现
我们点击下方的子菜单肯定会显示右侧白框里面的内容,所以我们需要实现动态路由
①实现路由跳转及当前项的设置
<el-menu router :default-active="$route.path">
<el-menu-item index="/company/userManager">用户管理</el-menu-item>
</el-menu>
注意事项:
①要实现路由跳转,先要在
el-menu
标签上添加router属性,然后只要在每个el-menu-item
标签内的index属性设置一下url即可实现点击el-menu-item
实现路由跳转。②导航当前项,在
el-menu
标签中绑定 :default-active="$route.path",注意是绑定属性,不要忘了加“:”,当$route.path等于el-menu-item
标签中的index属性值时则该item为当前项。③el-submenu标签中的url属性不能为空,且不能相同,否则会导致多个节点收缩/折叠效果相同的问题。
②生成相对应的Vue文件
根据我们点击子菜单所显示的层级关系进行Vue组件的编写,下面以书本管理下面的新增书本为例
AddBook.Vue
<template>
<h1>新增书本</h1>
</template>
<script>
</script>
<style>
</style>
③配置路由与路由路径的关系
index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import AppMain from '@/components/AppMain'
import LeftNav from '@/components/LeftNav'
import TopNav from '@/components/TopNav'
import Login from '@/views/Login'
import Registered from '@/views/Registered'
import AddBook from '@/views/book/AddBook'
import BookList from '@/views/book/BookList'
Vue.use(Router)
export default new Router({
routes: [{
path: '/',
name: 'Login',
component: Login
}, {
path: '/Registered',
name: 'Registered',
component: Registered
}, {
path: '/AppMain',
name: 'AppMain',
component: AppMain,
children: [{
path: '/LeftNav',
name: 'LeftNav',
component: LeftNav
}, {
path: '/TopNav',
name: 'TopNav',
component: TopNav
}, {
path: '/book/AddBook',
name: 'AddBook',
component: AddBook
}, {
path: '/book/BookList',
name: 'BookList',
component: BookList
}]
}]
})
④将组件渲染到页面上
在AppMain.js中显示组件就需要加上<router-view></router-view>
<template>
<el-container class="main-container">
<el-aside v-bind:class="asideClass">
<LeftNav></LeftNav>
</el-aside>
<el-container>
<el-header class="main-header">
<TopNav></TopNav>
</el-header>
<el-main class="main-center">
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
// 导入组件
import TopNav from '@/components/TopNav.vue'
import LeftNav from '@/components/LeftNav.vue'
// 导出模块
export default {
components: {
TopNav,LeftNav
},data() {
return {
asideClass: "main-aside"
}
},
created(){
this.$root.Bus.$on('aaa',r=>{
this.asideClass=r ? 'main-aside-collapsed':'main-aside';
});
}
};
</script>
<style scoped>
.main-container {
height: 100%;
width: 100%;
box-sizing: border-box;
}
.main-aside-collapsed {
/* 在CSS中,通过对某一样式声明! important ,可以更改默认的CSS样式优先级规则,使该条样式属性声明具有最高优先级 */
width: 64px !important;
height: 100%;
background-color: #334157;
margin: 0px;
}
.main-aside {
width: 240px !important;
height: 100%;
background-color: #334157;
margin: 0px;
}
.main-header,
.main-center {
padding: 0px;
border-left: 2px solid #333;
}
</style>
效果演示:
三、右侧内容数据表格
3.1.根据文档搭建页面
首先我们分析一下,我们右侧有那些内容?然后去到我们ELementUI官网查找相对应的案例代码,我们首先需要一个form表单提供我们输入书籍名称进行模糊查询,还需要数据表格展示数据,其次就是底部的分页条来完成分页效果,知道了需求我们直接去找案例代码即可。
AddBook.js
<template>
<div>
<!--搜索栏-->
<el-form :inline="true" class="form-search" style="padding: 30px;">
<el-form-item label="书本名称">
<el-input v-model="bookname" placeholder="请输入书本名称"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="query(1)">查询</el-button>
</el-form-item>
</el-form>
<!-- 数据表格-->
<el-table :data="tableData" style="width: 100%" :row-class-name="tableRowClassName">
<el-table-column prop="id" label="编号" width="180">
</el-table-column>
<el-table-column prop="bookname" label="书籍名称" width="180">
</el-table-column>
<el-table-column prop="price" label="书籍价格" width="180">
</el-table-column>
<el-table-column prop="booktype" label="书籍类别" width="180">
</el-table-column>
</el-table>
<!-- 分页栏-->
<div class="block">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage4"
:page-sizes="[100, 200, 300, 400]" :page-size="100" layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
data() {
return {
bookname: "",
tableData: []
}
},
methods: {
}
}
</script>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>
这样我们的基本内容就搭建完成了
3.2.实现模糊查询
和前面一样我们先去后端将接口定义好
package com.zking.ssm.controller;
import com.zking.ssm.model.Book;
import com.zking.ssm.service.IBookService;
import com.zking.ssm.util.JsonResponseBody;
import com.zking.ssm.util.PageBean;
import com.zking.ssm.vo.BookFileVo;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private IBookService bookService;
@RequestMapping("/addBook")
@ResponseBody
public JsonResponseBody<?> addBook(Book book){
try {
bookService.insert(book);
return new JsonResponseBody<>("新增书本成功",true,0,null);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("新增书本失败",false,0,null);
}
}
@RequestMapping("/editBook")
@ResponseBody
public JsonResponseBody<?> editBook(Book book){
try {
bookService.updateByPrimaryKey(book);
return new JsonResponseBody<>("编辑书本成功",true,0,null);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("编辑书本失败",false,0,null);
}
}
@RequestMapping("/delBook")
@ResponseBody
public JsonResponseBody<?> delBook(Book book){
try {
bookService.deleteByPrimaryKey(book.getId());
return new JsonResponseBody<>("删除书本成功",true,0,null);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("删除书本失败",false,0,null);
}
}
@RequestMapping("/queryBookPager")
@ResponseBody
public JsonResponseBody<List<Book>> queryBookPager(Book book, HttpServletRequest req){
try {
PageBean pageBean=new PageBean();
pageBean.setRequest(req);
List<Book> books = bookService.queryBookPager(book, pageBean);
return new JsonResponseBody<>("OK",true,pageBean.getTotal(),books);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("分页查询书本失败",false,0,null);
}
}
@RequestMapping("/queryBookCharts")
@ResponseBody
public JsonResponseBody<?> queryBookCharts(){
try{
Map<String, Object> charts = bookService.queryBookCharts();
return new JsonResponseBody<>("OK",true,0,charts);
}catch (Exception e){
e.printStackTrace();
return new JsonResponseBody<>("查询统计分析数据失败",false,0,null);
}
}
@RequestMapping("/upload")
@ResponseBody
public JsonResponseBody<?> upload(BookFileVo bookFileVo){
try {
MultipartFile bookFile = bookFileVo.getBookFile();
System.out.println(bookFileVo);
System.out.println(bookFile.getContentType());
System.out.println(bookFile.getOriginalFilename());
return new JsonResponseBody<>("上传成功",true,0,null);
} catch (Exception e) {
e.printStackTrace();
return new JsonResponseBody<>("上传失败",false,0,null);
}
}
@RequestMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response){
try {
String relativePath = "uploads/1.jpg";
String absolutePath = request.getRealPath(relativePath);
InputStream is = new FileInputStream(new File(absolutePath));
OutputStream out = response.getOutputStream();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("1.jpg", "UTF-8"));
byte[] by = new byte[1024];
int len = -1;
while (-1 != (len = is.read(by))) {
out.write(by);
}
is.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("/downloadUrl")
public void downloadUrl(HttpServletRequest request, HttpServletResponse response){
String relativePath = "uploads/1.jpg";
String absolutePath = request.getRealPath(relativePath);
InputStream is = null;
OutputStream out = null;
try {
is = new FileInputStream(new File(absolutePath));
// 设置Content-Disposition
response.setHeader("Content-Disposition",
"attachment;filename=" + URLEncoder.encode("1.jpg", "UTF-8"));
out = response.getOutputStream();
IOUtils.copy(is, out);
response.flushBuffer();
System.out.println("完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(out);
}
}
}
由此我们可知后端查询书籍的接口为:http://localhost:8080/ssm/book/queryBookPager
action.js文件添加下列接口
'BOOK_LIST': '/book/queryBookPager', //书籍查询
在AddBook.vue中的钩子函数内编写方法去到后端拿取数据赋予变量
created() {
//加载页面先去后端拿数据
let params={
bookname:this.bookname
}
let url = this.axios.urls.BOOK_LIST;
this.axios.get(url, {params:params}).then(r => {
console.log(r)
this.tableData = r.data.rows
}).catch(e => {
})
}
由于不止我们初始页面需要用到这个方法模糊查询也要所以我们将该代码进行封装让它有复用性
methods: {
//封装查询方法
list(params) {
let url = this.axios.urls.BOOK_LIST;
this.axios.get(url, {
params: params
}).then(r => {
console.log(r)
this.tableData = r.data.rows
}).catch(e => {
})
},
//模糊查询方法
query() {
let params = {
bookname: this.bookname
}
this.list(params)
}
},
created() {
//加载页面先去后端拿数据
let params = {
bookname: this.bookname
}
this.list()
}
效果展示:
四、分页实现
更改我们的分页栏代码并定义变量,编写分页栏中自带的两个方法,一个是页码发生变化会触发一个是页数发生改变会触发。
<!-- 分页栏-->
<div class="block">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="page"
:page-sizes="[10, 20, 30, 40]" :page-size="rows" layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<script>
export default {
data() {
return {
bookname: "",
tableData: [],
rows: 10,
page: 1,
total: 0,
}
},
methods: {
//封装查询方法
list(params) {
let url = this.axios.urls.BOOK_LIST;
this.axios.get(url, {
params: params
}).then(r => {
console.log(r)
this.tableData = r.data.rows
this.total = r.data.total
}).catch(e => {
})
},
//模糊查询方法
query() {
let params = {
bookname: this.bookname
}
this.list(params)
},
//当页发生变化会触发
handleSizeChange(r) {
let params = {
bookname: this.bookname,
rows: this.rows,
rows: r
}
this.list(params)
},
//当前页数发生变化会触发
handleCurrentChange(p) {
let params = {
bookname: this.bookname,
rows: this.rows,
page: p
}
this.list(params)
}
},
created() {
//加载页面先去后端拿数据
let params = {
bookname: this.bookname
}
this.list()
}
}
</script>
效果展示:
到这里我的分享就结束了,欢迎到评论区探讨交流!!
💖如果觉得有用的话还请点个赞吧 💖