标题idea从数据库创建一个springboot+bootstarp动态导航
一,标题idea新建一个项目
1,new一个项目
2,随便取一个项目名字
3. 选中lombok支持,写实体类的时候会用到,简化你的set,get方法的代码量
4. 选中web支持,可以打包成一个jar包直接运行
5. 选中MySql数据库支持driver
如果你是其他数据库环境,请选中其他支持库
6. 完成创建工程
二,导入strapbootcss和js
1,下载strapbootcss和js
1,从https://getbootstrap.com/的download页面下载,这里版本根据需要瞎子,我这里是最新的,下载的是编译过的,
如果需要源码,请下载Source files
2,直接导入cdn加速
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
这里我们采用第二方法导入CDN上的css,js文件
拷贝到cps项目里面
三.html从数据库读出数据并填入bootstrap格式的导航中
1,新建一个页面index.html在static目录下面
引入jquery支持,要用ajax获取数据.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<title>Title</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default right" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand active" href="#">固定导航</a>
</div>
<div>
<ul id='menu' class='nav navbar-nav '> </ul>
</div>
</div>
</nav>
<div class="main-content">
<div class="page-content " id="main"></div>
</div>
</div>
<script src="./js/index.js?v=6"></script>
</body>
</html>
2.新建index.js在static/js/目录下
/*普通json 转成树形json*/
function listToTree(list, pid) {
var ret = [];//一个存放结果的临时数组
for (var i in list) {
if (list[i].parent_id == pid) {//如果当前项的父id等于要查找的父id,进行递归
list[i].children = listToTree(list, list[i].id);
ret.push(list[i]);//把当前项保存到临时数组中
}
}
return ret;//递归结束后返回结果
}
var tree;
$(function () {
$.ajax({
type: "get", //请求方式
url: './nav/list', //加载本地json数据
dataType: "json", //请求类型
success: function (result) {
var menuData = eval(result);
tree = listToTree(menuData, 0);//调用函数,传入要转换的普通json和树中顶级元素的pid\
tree.sort()
var showMenu = $("#menu"); //获取ul(父节点)的位置
showTreeFirst(tree, showMenu);
showTree(tree);
}
})
})
/*根据处理过的树形json数据生成一级菜单*/
function showTreeFirst(data,parent) {
var dataLength = data.length;
if (dataLength < 7) {//最多生成五个菜单,其余隐藏
// console.log("dataLength < 6")
for (var i = 0; i < dataLength; i++) {
if (data[i].children.length) {//如果有子集
var html = ' <li class="dropdown"> ' +
'<a href="#" data-toggle="dropdown" id="' + data[i].id+ '" data-submenu="" > ' + data[i].nav_name + '<strong class="caret"></strong> </a>' +
' <ul class="dropdown-menu" id="submenu_' + data[i].id + '"></ul> </li> ';
console.log(data[i].nav_name);
parent.append(html);
} else {
var html = ' <li> <a href="#" data-toggle="dropdown" data-submenu="" id="' + data[i].id + '" > ' + data[i].nav_name + ' </a> </li> ';
parent.append(html);
}
}
} else {//最多生成五个菜单,其余隐藏
/* 先成前五个菜单*/
for (var i = 0; i < 5; i++) {
console.log("data[i].children.length"+data[i].children.length)
if (data[i].children.length) {//如果有子集
var html = ' <li class="dropdown">' +
' <a href="#" data-toggle="dropdown" id="' + data[i].id + '" data-submenu="" > ' + data[i].nav_name + ' </a> ' +
'<ul class="dropdown-menu" id="submenu_' + data[i].id + '"></ul> </li> ';
parent.append(html);
} else {
var html = ' <li> <a href="#" data-toggle="dropdown" data-submenu="" id="' + data[i].id +'" > ' + data[i].nav_name + ' </a> </li> ';
parent.append(html);
}
}
/* 生成“更多”按钮*/
var html = ' <li class="dropdown"> <a href="#" data-toggle="dropdown" data-submenu="" id="' + data[i].id
+ '" menunav_name="' + data[i].nav_name+'">更多<strong class="caret"></strong> </a> ' +
'<ul class="dropdown-menu" id="moreDropdownMenu"> </ul> </li>';
parent.append(html);
/* 生成“更多”按钮下的其他一级隐藏菜单*/
for (var i = 5; i < dataLength; i++) {
if (data[i].children.length) {//如果有子集
var html = ' <li class="dropdown-submenu"> <a id="'+ data[i].id +'" >' + data[i].nav_name + '</a> ' + '<ul class="dropdown-menu" id="submenu_' + data[i].id + '"> </ul>'
$("#moreDropdownMenu").append(html);
} else {
var html = '<li><a id="'+data[i].id+'" >' + data[i].nav_name + '</a> </li>'
$("#moreDropdownMenu").append(html);
}
}
}
}
/*根据处理过的树形json数据递归生成一级菜单以外的其他菜单*/
function showTree(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].children.length) {//如果有子集
/* 先判断父节点是否存在*/
if ($("#submenu_" + data[i].parent_id).size() == 0) {
showTree(data[i].children);//递归调用子集
} else {
var html = '<li class="dropdown-submenu">' +
' <a id="'+data[i].id+'" >' + data[i].nav_name + '</a>' +
'<ul class="dropdown-menu" id="submenu_'+data[i].id+'"> </ul>'
$("#submenu_"+data[i].parent_id).append(html);
showTree(data[i].children);//递归调用子集
}
} else {//没有子集直接显示
var html = '<li><a id="'+data[i].id+'">'+data[i].nav_name+'</a> </li>'
$("#submenu_" + data[i].parent_id).append(html);
}
}
}
四.从数据库读出数据.
1.修改pom.xml文件,插入支持库
为了防止大家漏掉某个包,我直接把现在的pom文件贴上来.
数据库连接使用了druid+mybatis
<?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.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.jean</groupId>
<artifactId>cps</artifactId>
<version>1.0</version>
<name>cps</name>
<packaging>jar</packaging>
<description>Company display</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-maven-plugin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<!-- 解决dto,do,vo转换问题 -->
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>alimaven</id>
<name>Maven Aliyun Mirror</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</build>
</project>
2.修改项目配置文件application.yml,如果没有,新建一个.
所在目录如下
server:
port: 80
spring:
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/templates/,classpath:/mapper/,file:static/
datasource:
name: mysql
type: com.alibaba.druid.pool.DruidDataSource
#druid相关配置
druid:
#监控统计拦截的filters
filters: stat
driver-class-name: com.mysql.jdbc.Driver
#基本属性
url: jdbc:mysql://192.168.1.5:3306/jinhong?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
#数据库账号
username: root
#数据库密码
password: 123
#配置初始化大小/最小/最大
initial-size: 1
min-idle: 1
max-active: 20
#获取连接等待超时时间
max-wait: 60000
#间隔多久进行一次检测,检测需要关闭的空闲连接
time-between-eviction-runs-millis: 60000
#一个连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
#打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
thymeleaf:
prefix: classpath:/templates/
check-template-location: true
suffix: .html
encoding: UTF-8
mode: LEGACYHTML5
cache: false
aop:
auto: true
proxy-target-class: true
servlet:
multipart:
max-file-size: 10MB
max-request-size: 100MB
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: cn.jean.model
#pagehelper
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
returnPageInfo: check
logging:
level:
cn.jean.dao : DEBUG
cn.jean.controller : DEBUG
swagger:
show: true
#工作模式
curvar:
dev: true
3.写程序的model,dao,server,controller层
NavDomain.java
package cn.jean.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NavDomain {
/**
* 主键
*/
private int id;
/**
* url
*/
private String module;
/**
* 导航名字
*/
private String nav_name;
/**
* 图标
*/
private String icon;
/**
* 序列
*/
private String guide;
/**
* 父目录
*/
private int parent_id;
/**
* 类别
*/
private String type;
/**
* 类型
*/
private int sort;
}
NavDao.java,这里有一个mybatis的mapper需要读入,在配置文件里面记得配置
mybatis:
mapper-locations: classpath:mapper/*.xml //配置文件,扫描mapper目录下的所有xml
type-aliases-package: cn.jean.model //类,扫描cn.jean.model下所有类
package cn.jean.dao;
import cn.jean.model.NavDomain;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface NavDao{
/**
* 添加一条导航记录
* @param nav
* @return
*/
int addNav(NavDomain nav);
/**
* 搜索-所有的
* @return
*/
List<NavDomain> getAllNav();
/**
* 搜索pid符合条件的
* @param parent_id
* @return
*/
List<NavDomain> getNavByPid(@Param("parent_id") Integer parent_id);
}
NavServer.java 这是个接口类,要写具体的实现impl
package cn.jean.service;
import cn.jean.dto.NavDto;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import java.util.List;
import cn.jean.model.NavDomain;
import org.apache.ibatis.annotations.Param;
public interface NavService {
/**
* 搜索-符合条件的
* @param nav
* @return
*/
void addNav(NavDomain nav);
/**
* 搜索-所有的
* @return
*/
List<NavDomain> getAllNav();
/**
* 搜索-符合条件的
* @param parent_id
* @return
*/
List<NavDomain> getNavByPid(@Param("parent_id") Integer parent_id);
/**
* 搜索-符合条件的
* @return
*/
JSONArray getAllJson();
}
NavServiceImpl.java
package cn.jean.impl;
import cn.jean.dto.NavDto;
import cn.jean.utils.DtoEntityUtil;
import cn.jean.dao.NavDao;
import cn.jean.model.NavDomain;
import cn.jean.service.NavService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import static java.util.Comparator.comparing;
@Service
public class NavServiceImpl implements NavService {
@Autowired
private NavDao navdao;
private DtoEntityUtil dtoEntity;
/**
* 添加一条导航记录
* @param nav
* @return
*/
@Override
public void addNav(NavDomain nav) {
navdao.addNav(nav);
}
/**
* 搜索-所有的
* @return
*/
@Override
public List<NavDomain> getAllNav() {
List<NavDomain> LNav = navdao.getAllNav();
return LNav;
}
/**
* 搜索pid符合条件的
* @param parent_id
* @return
*/
@Override
public List<NavDomain> getNavByPid(Integer parent_id) {
List<NavDomain> Nav = navdao.getNavByPid(parent_id);
return Nav;
}
@Override
// 获取树结构数据
public JSONArray getAllJson() {
JSONArray json = new JSONArray();
try {
// 从数据库里获取 List 数据,如果有条件,则根据相应条件获取,总之这里是一个树结构的 list
List<NavDomain> Navs = navdao.getAllNav();//取出所有数据
Navs.sort(comparing(NavDomain::getSort));
// ??? 为什么不是 NavDto 类型?这里 Nav 是 Entity,从数据库获取的数据当前是用 Entity 类型接收啦!
// 没关系的,可以转DTO
// 定义一个空数组,用来存放最终的树结构数据
List<NavDto> result = new ArrayList<>();
// 第一步遍历获取到的数据,将根节点数据存放 result 里
for (NavDomain nav: Navs) {
// 判断是否是根节点,就是 parentId,这里是从 0 开始,如果 parentId 为 0 ,则表示根节点
if (nav.getParent_id() == 0) {
// 这里可以将 entity 转为 DTO 存放
// 如果字段不多可以直接使用 set get 方法来存取,就像这样
NavDto navDto = new NavDto();
navDto = DtoEntityUtil.trans(nav,NavDto.class);
// 如果字段太多,超过5个以上,还是建议使用 mapper 方法来转哦,具体如何使用 mapper 将 Entity 转为 DTO 请移步下方链接
result.add(navDto);
}
}
// 根节点添加完就需要添加每个节点的子节点了,这里需要调用 递归方法 getChildren();
// 遍历根节点数据,为其设置子节点集合
for (NavDto Nav: result) {
// 获取子节点数据,传入 当前节点 id 和 所有 list
List<NavDto> childList = getChildren(Nav.getId(), Navs);
// 将获取到的子节点集合添加到根节点里
childList.sort(comparing(NavDto::getSort));
Nav.setChildren(childList);
}
// 将一层一层的树结构数据返回吧!
json.add(result);
} catch(Exception e) {
// 这里可以抛个异常
}
return json;
}
/**
* 获取子节点数据
* @param id 父节点 ID
* @param List<NavDomain> Navs 所有节点集合
* @return 返回子节点列表
*/
private List<NavDto> getChildren(Integer id, List<NavDomain> Navs) {
// 存在子节点数据
List<NavDto> childList = new ArrayList<>();
// 遍历所有节点数据
for (NavDomain nav : Navs) {
// 如果当前节点 ID 与父节点 ID 一致,表示当前数据是该节点的子节点
if (nav.getParent_id() == id) {
NavDto navDto = new NavDto();
navDto = DtoEntityUtil.trans(nav,NavDto.class);
// 如果字段太多,超过5个以上,还是建议使用 mapper 方法来转哦,具体如何使用 mapper 将 Entity 转为 DTO 请移步下方链接
childList.add(navDto);
}
}
// 重点来了,递归调用
for (NavDto item : childList) {
// 调用自身方法,依次添加子节点数据
item.setChildren(getChildren(item.getId(), Navs));
}
// 如果当前节点无子节点数据添加空数据,递归退出
if (childList.size() == 0) {
return new ArrayList<>();
}
// 返回最终的子节点数据
return childList;
}
}
NavController.java
package cn.jean.controller;
import cn.jean.service.NavService;
import cn.jean.model.NavDomain;
import com.alibaba.fastjson.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
@RequestMapping(value = "/nav")
public class NavController {
@Autowired
private NavService navService;
@GetMapping("list")
@ResponseBody
public List<NavDomain> getAllNav(){
List<NavDomain> l_nav = navService.getAllNav();
return l_nav;
}
@GetMapping("json")
@ResponseBody
public JSONArray getJson(){
JSONArray json = navService.getAllJson();
return json;
}
}
最后效果如图,全部代码和数据库文件,还有mapper文件都已上传到csdn
链接如下
https://download.youkuaiyun.com/download/brainjean/21110276
后续
后来发现在网页处理好慢,改为服务器端处理数据,前端只负责显示,项目地址
https://download.youkuaiyun.com/download/brainjean/21110748