文章目录
前言
使用工具:IDEA
使用技术栈:spring boot , mysql
建表sql:
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键递增',
`name` varchar(255) DEFAULT NULL COMMENT '分类名称',
`parent_id` int(11) DEFAULT NULL COMMENT '父节点id',
`url` varchar(255) DEFAULT NULL COMMENT '分类链接',
`icon` varchar(255) DEFAULT NULL COMMENT '分类图标',
`t_order` int(11) DEFAULT NULL COMMENT '分类排序权重',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;
INSERT INTO `menu` VALUES ('1', '新闻', '0', '/www/xinwen', 'xxx', '1');
INSERT INTO `menu` VALUES ('2', '每日日报', '1', '/www/meiriribao', 'xxx', '2');
INSERT INTO `menu` VALUES ('3', '每日晚报', '1', '/www/zaobao', 'xxx', '1');
INSERT INTO `menu` VALUES ('4', '河南日报', '2', '/www/henan', 'xxx', '2');
INSERT INTO `menu` VALUES ('5', '上海日报', '2', '/www/shanghai', 'xxx', '1');
INSERT INTO `menu` VALUES ('6', '南京日报', '2', '/www/nanjing', 'xxx', '3');
INSERT INTO `menu` VALUES ('7', '开封日报', '4', '/www/zhoukou', 'xxx', '2');
INSERT INTO `menu` VALUES ('8', '郑州日报', '4', '/www/zhenghzou', 'xxx', '3');
使用的maven依赖
<?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.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.threeBody</groupId>
<artifactId>threeBody</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>threeBody</name>
<description>三级分类</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</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>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置:application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/testjson
spring.datasource.username=
spring.datasource.password=
#控制台打印日志
logging.level.com.threebody.dao=debug
启动类
package com.threebody;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.threebody.dao")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
项目结构
如下图所示:
代码部分
实体类: entity
package com.threebody.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* (Menu)实体类
*
* @author makejava
* @since 2022-02-02 15:15:18
*/
@Data
public class Menu implements Comparable<Menu>, Serializable {
private static final long serialVersionUID = -30738037318430454L;
/**
* 主键递增
*/
private Integer id;
/**
* 分类名称
*/
private String name;
/**
* 父节点id
*/
private Integer parentId;
/**
* 分类链接
*/
private String url;
/**
* 分类图标
*/
private String icon;
/**
* 分类排序权重
*/
private Integer tOrder;
//子菜单列表
private List<Menu> children;
@Override
public int compareTo(Menu o) {
if(this.tOrder != o.tOrder){
return this.tOrder - o.tOrder;
}
return 0;
}
}
dao层 :dao
package com.threebody.dao;
import com.threebody.entity.Menu;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* (Menu)表数据库访问层
*
* @author makejava
* @since 2022-02-02 15:15:19
*/
public interface MenuDao {
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
Menu queryById(Integer id);
/**
* 查询全部数据
* @param offset 查询起始位置
* @param limit 查询条数
* @return
*/
List<Menu> queryAllByLimit(Integer offset, Integer limit);
/**
* 三级分类
* @return
*/
List<Menu> threeBody();
}
mapper层
<?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.threebody.dao.MenuDao">
<resultMap id="BaseResultMap" type="com.threebody.entity.Menu">
<!--@Table menu-->
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="parentId" column="parent_id" jdbcType="INTEGER"/>
<result property="url" column="url" jdbcType="VARCHAR"/>
<result property="icon" column="icon" jdbcType="VARCHAR"/>
<result property="tOrder" column="t_order" jdbcType="INTEGER"/>
</resultMap>
<!--查询单个-->
<select id="queryById" resultMap="BaseResultMap">
select
id, name, parent_id, url, icon, t_order
from testjson.menu
where id = #{id}
</select>
<!--查询全部数据-->
<select id="queryAllByLimit" resultMap="BaseResultMap">
select
*
from testjson.menu
</select>
<!--三级分类-->
<select id="threeBody" resultMap="BaseResultMap">
select
*
from testjson.menu
</select>
</mapper>
业务层:service
package com.threebody.service;
import com.threebody.entity.Menu;
import java.util.List;
/**
* (Menu)表服务接口
*
* @author makejava
* @since 2022-02-02 15:15:19
*/
public interface MenuService {
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
Menu queryById(Integer id);
/**
* 查询全部数据
* @param offset 查询起始位置
* @param limit 查询条数
* @return
*/
List<Menu> queryAllByLimit(Integer offset, Integer limit);
/**
* 三级分类
* @param menu
* @return
*/
List<Menu> threeBody(Menu menu);
}
业务实现类: serviceImpl
package com.threebody.service.impl;
import com.threebody.entity.Menu;
import com.threebody.dao.MenuDao;
import com.threebody.service.MenuService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* (Menu)表服务实现类
*
* @author makejava
* @since 2022-02-02 15:15:20
*/
@Service("menuService")
public class MenuServiceImpl implements MenuService {
@Resource
private MenuDao menuDao;
/**
* 通过ID查询单条数据
*
* @param id 主键
* @return 实例对象
*/
@Override
public Menu queryById(Integer id) {
return this.menuDao.queryById(id);
}
/**
* queryAllByLimit
* @param offset 查询起始位置
* @param limit 查询条数
* @return
*/
@Override
public List<Menu> queryAllByLimit(Integer offset, Integer limit) {
return menuDao.queryAllByLimit(offset,limit);
}
/**
* 三级分类
* @param menu
* @return
*/
@Override
public List<Menu> threeBody(Menu menu) {
try {
//查询出所有的菜单
List<Menu> allMenu = menuDao.threeBody();
//根节点存储
List<Menu> rootMenu = new ArrayList<>();
//根据传递的参数设置根节点
if(menu != null && menu.getId()!= null){
//父节点为传递的id为根节点
for (Menu nav : allMenu) {
if(nav.getParentId().equals(menu.getId())){
rootMenu.add(nav);
}
}
}else {
//父节点是0的,为根节点
for (Menu nav : allMenu) {
if(nav.getParentId().equals(0)){
rootMenu.add(nav);
}
}
}
// 根据Menu类的order排序
Collections.sort(rootMenu);
//为根节点设置子菜单,getChild是递归调用
for (Menu nv : rootMenu) {
//获取根节点下的所有子节点,使用getChild方法
List<Menu> childList = getChild(nv.getId(),allMenu);
//给根节点设置子节点
nv.setChildren(childList);
}
return rootMenu;
} catch (Exception e) {
e.printStackTrace();
return new ArrayList<>();
}
}
private List<Menu> getChild(Integer id, List<Menu> allMenu) {
//子菜单
List<Menu> childList = new ArrayList<>();
for (Menu nav : allMenu) {
//遍历所有节点,将所有菜单的父id与传过来的根节点的id比较
//相等说明:为该根节点的子节点
if(nav.getParentId().equals(id)){
childList.add(nav);
}
}
//递归设置子节点
for (Menu nav : childList) {
nav.setChildren(getChild(nav.getId(),allMenu));
}
//排序
Collections.sort(childList);
//如果节点下没有子节点,返回一个空List(递归退出)
if(childList.size() == 0){
return new ArrayList<Menu>();
}
return childList;
}
}
控制层:controller
package com.threebody.controller;
import com.threebody.entity.Menu;
import com.threebody.service.MenuService;
import com.threebody.utils.R;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* (Menu)表控制层
*
* @author makejava
* @since 2022-02-02 15:15:20
*/
@RestController
@RequestMapping("menu")
public class MenuController {
/**
* 服务对象
*/
@Resource
private MenuService menuService;
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@GetMapping("selectOne")
public R selectOne(Integer id) {
Menu queryById = menuService.queryById(id);
return R.ok().put("data",queryById);
}
/**
* 查询全部数据
* @param offset 查询起始位置
* @param limit 查询条数
* @return
*/
@GetMapping("queryAllByLimit")
public R queryAllByLimit(Integer offset, Integer limit){
List<Menu> queryAllByLimit = menuService.queryAllByLimit(offset, limit);
return R.ok().put("data",queryAllByLimit);
}
/**
* 三级分类
* @param menu
* @return
*/
@GetMapping("threeBody")
public R threeBody(Menu menu){
List<Menu> threeBody = menuService.threeBody(menu);
return R.ok().put("data",threeBody);
}
}
组件
package com.threebody.utils;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author Mark sunlightcs@gmail.com
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
public Integer getCode() {
return (Integer) this.get("code");
}
}
最后效果图:
localhost:8080/menu/selectOne?id=1
localhost:8080/menu/queryAllByLimit?offset=0&limit=2
localhost:8080/menu/threeBody
{
"msg": "success",
"code": 0,
"data": [{
"id": 1,
"name": "新闻",
"parentId": 0,
"url": "/www/xinwen",
"icon": "xxx",
"children": [{
"id": 3,
"name": "每日晚报",
"parentId": 1,
"url": "/www/zaobao",
"icon": "xxx",
"children": [],
"torder": 1
},
{
"id": 2,
"name": "每日日报",
"parentId": 1,
"url": "/www/meiriribao",
"icon": "xxx",
"children": [{
"id": 5,
"name": "上海日报",
"parentId": 2,
"url": "/www/shanghai",
"icon": "xxx",
"children": [],
"torder": 1
},
{
"id": 4,
"name": "河南日报",
"parentId": 2,
"url": "/www/henan",
"icon": "xxx",
"children": [{
"id": 7,
"name": "开封日报",
"parentId": 4,
"url": "/www/zhoukou",
"icon": "xxx",
"children": [],
"torder": 2
},
{
"id": 8,
"name": "郑州日报",
"parentId": 4,
"url": "/www/zhenghzou",
"icon": "xxx",
"children": [],
"torder": 3
}
],
"torder": 2
},
{
"id": 6,
"name": "南京日报",
"parentId": 2,
"url": "/www/nanjing",
"icon": "xxx",
"children": [],
"torder": 3
}
],
"torder": 2
}
],
"torder": 1
}]
}