spring-boot-ztree-async-caffeine

ztree异步加载树形菜单,demo结构如下:

图片.png

springboot打成war包后(不含jsp), 后台启动, 并不输出nohup.out日志的方法:

  nohup java -jar hello.war > /dev/null &

1.pom文件:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zy</groupId>
    <artifactId>spring-boot-ztree-async-ajax-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>spring-boot-ztree-async-ajax-demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.17.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </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-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <!--<scope>test</scope>-->
        </dependency>
        <!--用于解析jsp,不能与HTML的支持包同时存在-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.46</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.6.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.jsp

2.1index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<jsp:forward page="/files/getFatherFileUrls"/>

2.2fileUrl.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<HTML>
<HEAD>
    <TITLE> ZTREE DEMO - Async</TITLE>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="${pageContext.request.contextPath }/css/demo.css" type="text/css">
    <link rel="stylesheet" href="${pageContext.request.contextPath }/css/zTreeStyle/zTreeStyle.css" type="text/css">
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-3.3.1.js"></script>
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.ztree.core.js"></script>
    <SCRIPT type="text/javascript">
        <!--
        let setting = {
            async: {
                enable: true,
                url:"/files/getSonFileUrls", // 这里是controller层RequestingMapping对应的值
                autoParam:["id"], // 这里的id是传递到后台的参数,controller中可以接收到
                //otherParam:{"otherParam":"zTreeAsyncTest"}, // 本案例中,这里可以不写
                dataFilter: filter
            },
            data: {
                simpleData: {
                    enable: true
                }
            }
        };

        function filter(treeId, parentNode, childNodes) {
            if (!childNodes) return null;
            for (var i=0, l=childNodes.length; i<l; i++) {
                childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
            }
            return childNodes;
        }

        $(document).ready(function(){
            $.fn.zTree.init($("#treeDemo"), setting, ${fatherFileUrls}); // 此处的$中的值,是初始化顶级父节点
        });
        //-->
    </SCRIPT>
</HEAD>

<BODY>
<h1>异步加载节点数据的树</h1>
<h6>[ 文件路径: core/async.html ]</h6>
<div class="content_wrap">
    <div class="zTreeDemoBackground left">
        <ul id="treeDemo" class="ztree"></ul>
    </div>
</div>
</BODY>
</HTML>

3.css与js(均参考ztree官网)

图片.png

4.controller层

package com.zy.controller;

import com.alibaba.fastjson.JSON;
import com.zy.service.FileUrlServiceI;
import com.zy.utils.ZtreeUtils;
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;
import java.util.Map;

@Controller
@RequestMapping("/files/")
public class FileUrlController {

    @Autowired
    private FileUrlServiceI fileUrlService;

    @RequestMapping("getFatherFileUrls")
    public String getFatherFileUrls(Map map){
        List<ZtreeUtils> list = fileUrlService.getFatherFileUrls();
        Object json = JSON.toJSON(list);
        map.put("fatherFileUrls", json);
        return "fileUrl";
    }

    @RequestMapping("getSonFileUrls")
    @ResponseBody
    public Object getSonFileUrls(String id){
        List<ZtreeUtils> list = fileUrlService.getSonFileUrls(id);
        Object json = JSON.toJSON(list);
        return json;
    }
}

5.service层实现类

package com.zy.service.impl;

import com.zy.mapper.FileUrlMapper;
import com.zy.service.FileUrlServiceI;
import com.zy.utils.StringTools;
import com.zy.utils.ZtreeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
@Service("fileUrlService")
public class FileUrlServiceImpl implements FileUrlServiceI {

    @Autowired
    private FileUrlMapper fileUrlMapper;

    // 此处加载两级节点
    @Override
    @Cacheable(value = "fileUrls")
    public List<ZtreeUtils> getFatherFileUrls() {
        List<String> list = fileUrlMapper.getFatherFileUrls();
        List<ZtreeUtils> ztree = new ArrayList<>();
        list.forEach(fileUrl -> {
            ztree.add(new ZtreeUtils(fileUrl + "/", "0", fileUrl + "/", true, true));
            getSecondFileUrls(ztree, fileUrl + "/");
        });
        return ztree;
    }

    @Override
    @Cacheable(value = "fileUrls")
    public List<ZtreeUtils> getSonFileUrls(String filePath) {
        Integer generationNum = StringTools.getCharCount(filePath, 47) + 1;
        List<String> list = fileUrlMapper.getSonFileUrls(generationNum, filePath);
        List<ZtreeUtils> ztree = new ArrayList<>();
        // 这里并未对最后一级子节点进行处理(最后一级子节点不需要加"/"
        list.forEach(fileUrl -> {
            String[] split = fileUrl.split("/");
            ztree.add(new ZtreeUtils(fileUrl + "/", filePath, split[split.length - 1], false, true));
        });
        return ztree;
    }

    // 加载二级子节点
    private void getSecondFileUrls(List<ZtreeUtils> ztree, String filePath) {
        List<String> list = fileUrlMapper.getSonFileUrls(2, filePath);
        // 这里并未对最后一级子节点进行处理(最后一级子节点不需要加"/"
        list.forEach(fileUrl -> {
            String[] split = fileUrl.split("/");
            ztree.add(new ZtreeUtils(fileUrl + "/", filePath, split[split.length - 1], false, true));
        });
    }
}

6.mapper层

package com.zy.mapper;

import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface FileUrlMapper {

    List<String> getFatherFileUrls();

    List<String> getSonFileUrls(@Param("generationNum") Integer generationNum,
                                @Param("filePath") String filePath);
}

7.工具类

7.1ztree工具类

package com.zy.utils;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ZtreeUtils {

    private String id;

    private String pId;

    private String name;

    private Boolean open;

    private Boolean isParent;
}

7.2stringtools工具类

package com.zy.utils;

import org.apache.commons.lang3.StringUtils;

public class StringTools {

    public static int getCharCount(String str, int c){
        if (StringUtils.isEmpty(str)){
            return -1;
        }
        int count = 0;
        for (int i = 0; i < str.length(); i ++){
            if (str.charAt(i) == c){
                count ++;
            }
        }
        return count;
    }
}

8.config包下配置类

8.1静态资源配置类

package com.zy.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class StaticResourceMapping extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 配置静态资源
        registry.addResourceHandler("/js/**").addResourceLocations("WEB-INF/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("WEB-INF/css/");
        super.addResourceHandlers(registry);
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 配置默认访问页:需要在浏览器中输入ip+端口号
        registry.addViewController("/").setViewName("forward:/index.jsp");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
        super.addViewControllers(registry);
    }
}

8.2配置caffine缓存的map类

package com.zy.config;

import com.github.benmanes.caffeine.cache.CacheLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CaffineCacheRefresh {

    /**
     * 必须要指定这个Bean,refreshAfterWrite=1800s这个配置属性才生效
     *
     * @return
     */
    @Bean
    public CacheLoader<Object, Object> cacheLoader() {

        CacheLoader<Object, Object> cacheLoader = new CacheLoader<Object, Object>() {

            @Override
            public Object load(Object key) throws Exception {
                return null;
            }

            // 重写这个方法将oldValue值返回回去,进而刷新缓存
            @Override
            public Object reload(Object key, Object oldValue) throws Exception {
                return oldValue;
            }
        };

        return cacheLoader;
    }
}

8.3配置项目启动时加载数据的类

package com.zy.config;

import com.zy.mapper.FileUrlMapper;
import com.zy.service.FileUrlServiceI;
import com.zy.utils.ZtreeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 项目启动时加载数据的类
 */
@Component
public class InitData implements CommandLineRunner {

    @Autowired
    private FileUrlServiceI fileUrlService;

    @Override
    public void run(String... strings) throws Exception {
        getFatherFileUrls();
    }

    @CachePut(value = "fileUrls")
    public List<ZtreeUtils> getFatherFileUrls(){
        return fileUrlService.getFatherFileUrls();
    }
}

9.启动类

package com.zy;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@MapperScan("com.zy.mapper")
@EnableCaching
public class SpringBootZtreeAsyncAjaxDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootZtreeAsyncAjaxDemoApplication.class, args);
    }
}

10.application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring_boot_ztree
    username: root
    password: 123456
      # 配置jsp的解析
  mvc:
    view:
      prefix: /WEB-INF/jsp/
      suffix: .jsp
  cache:
    cache-names: fileUrls
    caffeine:
      spec: initialCapacity=50,maximumSize=500,expireAfterWrite=10s,refreshAfterWrite=5s
#  Caffeine配置说明:
#
#initialCapacity=[integer]: 初始的缓存空间大小
#maximumSize=[long]: 缓存的最大条数
#maximumWeight=[long]: 缓存的最大权重
#expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
#expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
#refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
#weakKeys: 打开key的弱引用
#  weakValues:打开value的弱引用
#  softValues:打开value的软引用
#  recordStats:开发统计功能
#
#  注意:
#
#  expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。
#  maximumSize和maximumWeight不可以同时使用
#  weakValues和softValues不可以同时使用

# mybatis中,静态资源不发布:此处指的是resources文件夹下的文件
mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml
  config-location: classpath:mybatis/sqlMappingConfig.xml

11.mybatis配置文件

11.1全局配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--设置全局配置环境-->
    <settings>
<!--        &lt;!&ndash;开启全局缓存&ndash;&gt;
        <setting name="cacheEnabled" value="true"/>
        &lt;!&ndash;开启懒加载&ndash;&gt;
        <setting name="lazyLoadingEnabled" value="true"/>
        &lt;!&ndash;关闭延迟加载&ndash;&gt;
        <setting name="aggressiveLazyLoading" value="false"/>-->
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <!--配置分页插件pageHelper的拦截器:5.0版本之后的配置-->
    <!--<plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>-->
</configuration>

11.2分配置文件

<?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.zy.mapper.FileUrlMapper">
    <!-- 查询顶级父目录 -->
    <select id="getFatherFileUrls" resultType="string">
        SELECT DISTINCT SUBSTRING_INDEX(fileUrl,'/',1)
        FROM tb_fileurl
    </select>

    <!-- 查询子目录 -->
    <select id="getSonFileUrls" resultType="string">
        SELECT DISTINCT SUBSTRING_INDEX(fileUrl,'/',#{generationNum})
        FROM tb_fileurl
        where fileUrl like concat(#{filePath},'%')
    </select>
</mapper>

12.表中内容

图片.png

13.结果图示

图片.png
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,410评论 6赞 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 137,268评论 19赞 139
  • 很久都不知道我自己是啥样的一个人了,就很迷茫,找不到自己,不知道自己是个啥样的人,不知道自己喜欢啥样的人,也不知道...
    俊橙迪尼奥阅读 354评论 0赞 1
  • 搬家后,坐车的地点也发生改变。一段地铁一段公交,带我看市井中的那些事。
    阿猪宝阅读 155评论 0赞 0
  • 前段时间流行一个段子,说的是:“有一个北京人,1984年为了圆出国梦,卖了鼓楼大街一个四合院,凑了30万,背到意大...
    绿色牧羊人阅读 703评论 0赞 0

友情链接更多精彩内容