Springboot应用开发:工具类整理

目录

一、编写目的

二、映射工具类

2.1 依赖

2.2 代码

三、日期格式

3.1 依赖

3.2 代码

四、加密

4.1 代码

五、Http请求

5.1 依赖

5.2 代码

六、金额

6.1 代码

七、二维码

7.1 依赖

7.2 代码

八、坐标转换

8.1 代码

九、树结构

9.1 代码

9.1.1 节点

 9.1.2 工具类

十、结语


Welcome to Code Block's blog

本篇文章主要介绍了

[Springboot应用开发:工具类整理]
❤博主广交技术好友,喜欢文章的可以关注一下❤

一、编写目的

        在实际的Springboot应用开发中,有很多类可作为工具类,这些类将实际开发中可能用到的重复性代码进行提取,方便在后续的开发中使用,在这里我对在开发中经常用到的工具类进行整理,方便自己之后查找,同时希望可以帮助到有实现相关功能的朋友。

二、映射工具类

        映射工具类主要用于在不同实体类结构之间的转换,经常用于DTO->BO的转换.例:在Controller中接收的Body(DTO)与要存储到数据库中的字段(BO)经常是不同的.这时可以使用该工具类进行转换,使用sourceToTarget对单个实体类或列表进行转换.具体代码如下:

2.1 依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>

2.2 代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 转换工具类
 */
public class ConvertUtils {
    private static Logger logger = LoggerFactory.getLogger(ConvertUtils.class);

    /**
     *
     * @param source 原始类实体
     * @param target 目标类
     * @return 目标类实体
     * @param <T> 泛型
     */
    public static <T> T sourceToTarget(Object source, Class<T> target){
        if(source == null){
            return null;
        }
        T targetObject = null;
        try {
            targetObject = target.newInstance();
            BeanUtils.copyProperties(source, targetObject);
        } catch (Exception e) {
            logger.error("convert error ", e);
        }

        return targetObject;
    }

    /**
     *
     * @param sourceList 原始类实体列表
     * @param target 目标类
     * @return 目标类实体列表
     * @param <T> 泛型
     */
    public static <T> List<T> sourceToTarget(Collection<?> sourceList, Class<T> target){
        if(sourceList == null){
            return null;
        }

        List targetList = new ArrayList<>(sourceList.size());
        try {
            for(Object source : sourceList){
                T targetObject = target.newInstance();
                BeanUtils.copyProperties(source, targetObject);
                targetList.add(targetObject);
            }
        }catch (Exception e){
            logger.error("convert error ", e);
        }

        return targetList;
    }
}

三、日期格式

        日期格式工具类主要用于日期格式的转换和日期的计算,例如:从yyyy-MM-dd HH:mm:ss转换为yyyy-MM-dd格式或者从字符串转换为日期格式.具体代码如下:

3.1 依赖

		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
			<version>2.9.9</version>
		</dependency>
        <dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.9</version><!--$NO-MVN-MAN-VER$ -->
		</dependency>

3.2 代码

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 日期处理
 * @author seaua
 */
public class DateUtils {
	/** 时间格式(yyyy-MM-dd) */
	public final static String DATE_PATTERN = "yyyy-MM-dd";
	/** 时间格式(yyyy-MM-dd HH:mm:ss) */
	public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";


	public static Date parse(String date) {
	    if(StringUtils.isEmpty(date)){
	        return null;
        }
        SimpleDateFormat df = new SimpleDateFormat(DATE_TIME_PATTERN);
        try {
            return df.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 日期格式化 日期格式为:yyyy-MM-dd
     * @param date  日期
     * @return  返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }

    /**
     * 日期格式化 日期格式为:yyyy-MM-dd
     * @param date  日期
     * @param pattern  格式,如:DateUtils.DATE_TIME_PATTERN
     * @return  返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if(date != null){
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }

    /**
     * 日期解析
     * @param date  日期
     * @param pattern  格式,如:DateUtils.DATE_TIME_PATTERN
     * @return  返回Date
     */
    public static Date parse(String date, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串转换成日期
     * @param strDate 日期字符串
     * @param pattern 日期的格式,如:DateUtils.DATE_TIME_PATTERN
     */
    public static Date stringToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate)){
            return null;
        }

        DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
        return fmt.parseLocalDateTime(strDate).toDate();
    }

    /**
     * 根据周数,获取开始日期、结束日期
     * @param week  周期  0本周,-1上周,-2上上周,1下周,2下下周
     * @return  返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date 日期
     * @param seconds 秒数,负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date 日期
     * @param minutes 分钟数,负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date 日期
     * @param hours 小时数,负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数,负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }

    /**
     * 对日期的【周】进行加/减
     *
     * @param date 日期
     * @param weeks 周数,负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date 日期
     * @param months 月数,负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date 日期
     * @param years 年数,负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }
}

四、加密

        加密工具类用于对数据进行加密,这里是使用HmacSHA256加密算法进行加密,具体代码如下:

4.1 代码

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class HMACSHA256 {

    public static String HMACSHA256(String key, String data) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(signingKey);
            return byte2hex(mac.doFinal(data.getBytes()));
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1) {
                hs.append('0');
            }
            hs.append(stmp);
        }
        return hs.toString().toUpperCase();
    }
}

五、Http请求

        Http请求工具类用于从request获取相关请求参数,如获取参数列表(ParameterMap)或者请求的Language参数.具体代码如下:

5.1 依赖

        <dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.9</version><!--$NO-MVN-MAN-VER$ -->
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

5.2 代码

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Http
 */
public class HttpContextUtils {
	/**
	 * 获取http请求
	 * @return request
	 */
	public static HttpServletRequest getHttpServletRequest() {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (requestAttributes == null) {
			return null;
		}

		return ((ServletRequestAttributes) requestAttributes).getRequest();
	}

	/**
	 * 获取http请求的请求参数列表
	 * @param request http请求
	 * @return 请求参数列表
	 */
	public static Map<String, String> getParameterMap(HttpServletRequest request) {
		Enumeration<String> parameters = request.getParameterNames();

		Map<String, String> params = new HashMap<>();
		while (parameters.hasMoreElements()) {
			String parameter = parameters.nextElement();
			String value = request.getParameter(parameter);
			if (StringUtils.isNotBlank(value)) {
				params.put(parameter, value);
			}
		}

		return params;
	}

	/**
	 * 获取域名 Domain
	 * @return Domain
	 */
	public static String getDomain() {
		HttpServletRequest request = getHttpServletRequest();
		StringBuffer url = request.getRequestURL();
		return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
	}

	/**
	 * 获取请求地址
	 * @return origin
	 */
	public static String getOrigin() {
		HttpServletRequest request = getHttpServletRequest();
		return request.getHeader(HttpHeaders.ORIGIN);
	}

	/**
	 * 获取语言,默认返回 "zh-CN"
	 * @return language
	 */
	public static String getLanguage() {
		// 默认语言
		String defaultLanguage = "zh-CN";
		// request
		HttpServletRequest request = getHttpServletRequest();
		if (request == null) {
			return defaultLanguage;
		}

		// 请求语言
		defaultLanguage = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);

		return defaultLanguage;
	}

	/**
	 * 获取请求消息头中的数据
	 */
	public static String getRequestReader(HttpServletRequest request) {
		String line;
		StringBuilder sb = new StringBuilder();
		try {
			while ((line = request.getReader().readLine()) != null) {
				sb.append(line);
			}
			request.getReader().close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	
}

六、金额

        金额用于对金额数据进行转换,即带有格式的字符串数据,将其转换为方便存储和计算的数据,本工具类中将元转换为分.具体代码如下:

6.1 代码

/**
 * @author seaua
 */
public class MoneyUtil {
	
	/**
	 * 获取金额,转换单位,元转换成分
	 */
	public static String getMoney(String amount) {
		if (amount == null) {
			return "0";
		}
		String currency = amount.replaceAll("[$¥,]", ""); // 处理包含, ¥
		// 或者$的金额
		int index = currency.indexOf(".");
		int length = currency.length();
		long amLong;
		if (index == -1) {
			amLong = Long.parseLong(currency + "00");
		} else if (length - index >= 3) {
			amLong = Long.parseLong((currency.substring(0, index + 3)).replace(".", ""));
		} else if (length - index == 2) {
			amLong = Long.parseLong((currency.substring(0, index + 2)).replace(".", "") + 0);
		} else {
			amLong = Long.parseLong((currency.substring(0, index + 1)).replace(".", "") + "00");
		}
		return Long.toString(amLong);
	}
}

七、二维码

        二维码工具类在实际开发中用于二维码的生成,在本工具类中createImageToLocal将生成的二维码存储到本地,createImage用于生成二维码并转换为base64字符串,用于在网络中传输.具体代码如下:

7.1 依赖

		<dependency>
			<groupId>com.alipay.sdk</groupId>
			<artifactId>alipay-sdk-java</artifactId>
			<version>4.10.70.ALL</version>
		</dependency>
		<dependency>
			<groupId>com.google.zxing</groupId>
			<artifactId>core</artifactId>
			<version>3.3.3</version>
		</dependency>
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.7.3</version>
		</dependency>

7.2 代码

import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.alipay.api.internal.util.file.ByteArrayOutputStream;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import cn.hutool.core.codec.Base64Encoder;

public class QRCodeUtil {

	// 二维码尺寸
	public static final int QRCODE_SIZE = 300;
	// 存放二维码的路径
	public static final String PAY_PATH = "c://pay";

	/**
	 * 生成二维码存到本地
	 * 
	 * @param content      源内容
	 * @param outputStream 输出流
	 * @throws Exception
	 */
	public static void createImageToLocal(String content, OutputStream outputStream) throws Exception {
		Hashtable hints = new Hashtable();
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		hints.put(EncodeHintType.MARGIN, 1);
		BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
				hints);
		int width = bitMatrix.getWidth();
		int height = bitMatrix.getHeight();
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
			}
		}
		// 存到磁盘
		ImageIO.write(image, "jpg", outputStream);
	}

	/**
	 * 生成二维码
	 * 
	 * @param content 源内容
	 * @return
	 * @throws Exception
	 */
	public static String createImage(String content) throws Exception {
		Hashtable hints = new Hashtable();
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		hints.put(EncodeHintType.MARGIN, 1);
		BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
				hints);
		int width = bitMatrix.getWidth();
		int height = bitMatrix.getHeight();
		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
			}
		}
		// 创建储存图片二进制流的输出流
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ImageIO.write(image, "jpg", baos);
		// 转成Base64格式
		byte[] b = baos.toByteArray();
		Base64Encoder encoder = new Base64Encoder();
		return encoder.encode(b);
	}

}

八、坐标转换

        坐标转换用于不同地理坐标数据之间的转换,这在地理应用开发中经常用到,在本篇文章中的代码中实现gps84ToXY(wgs84到大地2000),GCJ02ToWGS84:火星坐标系(GCJ02)转地球坐标系(WGS84)具体代码如下:

8.1 代码

public class RtkUtils {
    /**
     * 将WGS84经纬度转为大地2000坐标
     *
     * @param B      纬度
     * @param L      经度
     * @param degree //
     * @return
     */
    public static double[] gps84ToXY(double B, double L, double degree) {
        double[] xy = {0, 0};
        double a = 6378137;//椭球长半轴
        double b = 6356752.3142451795;//椭球短半轴
        double e = 0.081819190842621;//第一偏心率
        double eC = 0.0820944379496957;//第二偏心率
        double L0 = 0;//中央子午线经度
        int n = 0;//带号
        if (degree == 6) {
            //6度
            n = (int) (Math.round((L + degree / 2) / degree));
            L0 = degree * n - degree / 2;
        } else {
            //3度
            n = (int) Math.round(L / degree);
            L0 = degree * n;
        }
        //开始计算
        double radB = B * Math.PI / 180;//纬度(弧度)
        double radL = L * Math.PI / 180;//经度(弧度)
        double deltaL = (L - L0) * Math.PI / 180;//经度差(弧度)
        double N = a * a / b / Math.sqrt(1 + eC * eC * Math.cos(radB) * Math.cos(radB));
        double C1 = 1.0 + 3.0 / 4 * e * e + 45.0 / 64 * Math.pow(e, 4) + 175.0 / 256 * Math.pow(e, 6) + 11025.0 / 16384 * Math.pow(e, 8);
        double C2 = 3.0 / 4 * e * e + 15.0 / 16 * Math.pow(e, 4) + 525.0 / 512 * Math.pow(e, 6) + 2205.0 / 2048 * Math.pow(e, 8);
        double C3 = 15.0 / 64 * Math.pow(e, 4) + 105.0 / 256 * Math.pow(e, 6) + 2205.0 / 4096 * Math.pow(e, 8);
        double C4 = 35.0 / 512 * Math.pow(e, 6) + 315.0 / 2048 * Math.pow(e, 8);
        double C5 = 315.0 / 131072 * Math.pow(e, 8);
        double t = Math.tan(radB);
        double eta = eC * Math.cos(radB);
        double X = a * (1 - e * e) * (C1 * radB - C2 * Math.sin(2 * radB) / 2 + C3 * Math.sin(4 * radB) / 4 - C4 * Math.sin(6 * radB) / 6 + C5 * Math.sin(8 * radB));
        xy[0] = X + N * Math.sin(radB) * Math.cos(radB) * Math.pow(deltaL, 2) * (1 + Math.pow(deltaL * Math.cos(radB), 2) * (5 - t * t + 9 * eta * eta + 4 * Math.pow(eta, 4)) / 12 + Math.pow(deltaL * Math.cos(radB), 4) * (61 - 58 * t * t + Math.pow(t, 4)) / 360) / 2;
        xy[1] = N * deltaL * Math.cos(radB) * (1 + Math.pow(deltaL * Math.cos(radB), 2) * (1 - t * t + eta * eta) / 6 + Math.pow(deltaL * Math.cos(radB), 4) * (5 - 18 * t * t + Math.pow(t, 4) - 14 * eta * eta - 58 * eta * eta * t * t) / 120) + 500000;// +n * 1000000;
        return xy;
    }

    private static final double PI = 3.1415926535897932384626;
    // 卫星椭球坐标投影到平面地图坐标系的投影因子。  地球长半径
    private static final double EARTH_MAJOR_RADIUS = 6378245.0;
    // 椭球的偏心率。
    private static final double ECCENTRICITY_RATIO = 0.00669342162296594323;

    /**
     * 火星坐标系(GCJ02)转地球坐标系(WGS84)
     *
     * @param gcjLat 火星坐标纬度
     * @param gcjLng 火星坐标经度
     */
    public static Double[] GCJ02ToWGS84(Double gcjLng, Double gcjLat) {
        double dlat = transformlat(gcjLng - 105.0, gcjLat - 35.0);
        double dlng = transformlng(gcjLng - 105.0, gcjLat - 35.0);
        double radlat = gcjLat / 180.0 * PI;
        double magic = Math.sin(radlat);
        magic = 1 - ECCENTRICITY_RATIO * magic * magic;
        double sqrtmagic = Math.sqrt(magic);
        dlat = (dlat * 180.0) / ((EARTH_MAJOR_RADIUS * (1 - ECCENTRICITY_RATIO)) / (magic * sqrtmagic) * PI);
        dlng = (dlng * 180.0) / (EARTH_MAJOR_RADIUS / sqrtmagic * Math.cos(radlat) * PI);
        double mglat = gcjLat + dlat;
        double mglng = gcjLng + dlng;
        return new Double[]{gcjLng * 2 - mglng, gcjLat * 2 - mglat};
    }

    private static Double transformlat(double lng, double lat) {
        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }
    private static Double transformlng(double lng, double lat) {
        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }

}

九、树结构

        树结构工具类在实际开发中用于处理树状结构,如菜单部门数据的展示等,具体代码如下:

9.1 代码

9.1.1 节点

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 树节点,所有需要实现树节点的,都需要继承该类
 * @author seaua
 */
public class TreeNode<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    private Long id;
    /**
     * 上级ID
     */
    private Long pid;
    /**
     * 子节点列表
     */
    private List<T> children = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getPid() {
        return pid;
    }

    public void setPid(Long pid) {
        this.pid = pid;
    }

    public List<T> getChildren() {
        return children;
    }

    public void setChildren(List<T> children) {
        this.children = children;
    }
}

 9.1.2 工具类

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 树形结构工具类,如:菜单、部门等
 */
public class TreeUtils {

    /**
     * 根据pid,构建树节点
     */
    public static <T extends TreeNode> List<T> build(List<T> treeNodes, Long pid) {
        //pid不能为空
        AssertUtils.isNull(pid, "pid");

        List<T> treeList = new ArrayList<>();
        for(T treeNode : treeNodes) {
            if (pid.equals(treeNode.getPid())) {
                treeList.add(findChildren(treeNodes, treeNode));
            }
        }

        return treeList;
    }

    /**
     * 查找子节点
     */
    private static <T extends TreeNode> T findChildren(List<T> treeNodes, T rootNode) {
        for(T treeNode : treeNodes) {
            if(rootNode.getId().equals(treeNode.getPid())) {
                rootNode.getChildren().add(findChildren(treeNodes, treeNode));
            }
        }
        return rootNode;
    }

    /**
     * 构建树节点
     */
    public static <T extends TreeNode> List<T> build(List<T> treeNodes) {
        List<T> result = new ArrayList<>();

        //list转map
        Map<Long, T> nodeMap = new LinkedHashMap<>(treeNodes.size());
        for(T treeNode : treeNodes){
            nodeMap.put(treeNode.getId(), treeNode);
        }

        for(T node : nodeMap.values()) {
            T parent = nodeMap.get(node.getPid());
            if(parent != null && !(node.getId().equals(parent.getId()))){
                parent.getChildren().add(node);
                continue;
            }

            result.add(node);
        }

        return result;
    }

}

十、结语

        上述为本人在实际开发中经常用到的工具类,您可以直接使用这些工具类代码,当然也可以优化这些类并扩展自己的相关功能。

如果你对区块链感兴趣,可以看一下我的区块链专栏.

感谢关注和收藏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938991.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【第一节】Git的简介和安装

目录 一、git的介绍 二、git 的安装 2.1 Linux 平台安装 2.2 源码安装 2.3 Windows 平台安装 2.4 Mac 平台安装 2.5 Git 配置 2.5.1 配置文件 2.5.2 用户信息配置 2.5.3 文本编辑器配置 2.5.4 差异分析工具配置 2.5.5 查看配置信息 一、git的介绍 Git 是一种开源的…

数据库和SQL的基本概念

目录 定义数据分类非结构化数据&#xff1a;半结构化数据 :​ 结构化数据 : SQL(Structured Query Language)概念分类 关系模型常用的概念数据库管理概念理解 定义 数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库。 数据库是长期储存在…

oneflow深度学习框架使用问题总结(Windows/Linux)

目录 1.简述 2.在Windows下使用Oneflow深度学习框架&#xff08;错误记录&#xff0c;谨慎&#xff0c;官方不支持&#xff0c;需要WSL&#xff09; 2.1安装Anaconda 2.1创建虚拟环境 2.2安装Pytorch 2.3安装Pycharm 2.4 安装Oneflow 3.在Linux下使用Oneflow深度学习框…

TypeScript 变量与常量

文章目录 一、变量声明(一)let 关键字(块级作用域)(二)var 关键字(函数级作用域,与 let 的区别)二、常量声明(一)const 关键字(不可重新赋值)一、变量声明 (一)let 关键字(块级作用域) 在 TypeScript 中,let 关键字用于声明变量,它所声明的变量具有块级作用…

【Go】-倒排索引的简单实现

目录 什么是倒排索引 定义 基本结构和原理 分词在倒排索引中的重要性 简单倒排索引的实现 接口定义 简单数据库的实现 倒排索引 正排索引 测试 总结 什么是倒排索引 定义 倒排索引&#xff08;Inverted Index&#xff09;是一种索引数据结构&#xff0c;它是文档检…

使用 Wireshark 和 Lua 脚本解析通讯报文

在复杂的网络环境中&#xff0c;Wireshark 凭借其强大的捕获和显示功能&#xff0c;成为协议分析不可或缺的工具。然而&#xff0c;面对众多未被内置支持的协议或需要扩展解析的场景&#xff0c;Lua 脚本的引入为Wireshark 提供了极大的灵活性和可扩展性。本文将详细介绍如何使…

黑马Java面试教程_P7_常见集合_P4_HashMap

系列博客目录 文章目录 系列博客目录4. HashMap相关面试题4.4 面试题-HashMap的put方法的具体流程 频54.4.1 hashMap常见属性4.4.2 源码分析 HashMap的构造函数面试文稿&#xff1a; 4.5 讲一讲HashMap的扩容机制 难3频4面试文稿&#xff1a; 4.6 面试题-hashMap的寻址算法 难4…

Netcat:网络中的瑞士军刀

免责声明&#xff1a;使用本教程或工具&#xff0c;用户必须遵守所有适用的法律和法规&#xff0c;并且用户应自行承担所有风险和责任。 文章目录 一、引言二、简述三、Netcat功能&#xff1f;四、参数选项五、Netcat 的常见功能六、高级用法多连接处理创建简单的代理 七、Netc…

这是一个vue3 + scss的数字滚动效果

介绍: 当数字变化时&#xff0c;只改变变化的数字位&#xff0c;其余的不变&#xff0c;可以递增、递减、骤变、负数也可以&#xff0c;但是样式要根据具体的项目需求去改&#xff1b; 效果1、增加数字&#xff1a; 效果2、减少数字&#xff1a; 使用方法&#xff1a; <te…

Pytest-Bdd vs Behave:选择最适合的 Python BDD 框架

Pytest-Bdd vs Behave&#xff1a;选择最适合的 Python BDD 框架 Pytest BDD vs Behave&#xff1a;选择最适合的 Python BDD 框架BDD 介绍Python BDD 框架列表Python BehavePytest BDDPytest BDD vs Behave&#xff1a;关键区别Pytest BDD vs Behave&#xff1a;最佳应用场景结…

【Unity3D】无限循环列表(扩展版)

基础版&#xff1a;【Unity技术分享】UGUI之ScrollRect优化_ugui scrollrect 优化-CSDN博客 using UnityEngine; using UnityEngine.UI; using System.Collections.Generic;public delegate void OnBaseLoopListItemCallback(GameObject cell, int index); public class BaseLo…

【Elasticsearch】使用阿里云 infererence API 及 semantic text 进行向量搜索

原作者&#xff1a;Elastic布道师 刘晓国 在之前的文章 “Elasticsearch 开放推理 API 新增阿里云 AI 搜索支持”&#xff0c;它详细描述了如何使用 Elastic inference API 来针对阿里的密集向量模型&#xff0c;稀疏向量模型&#xff0c; 重新排名及 completion 进行展示。在…

景联文科技:精准语音标注,驱动语音技术新发展

在人工智能迅速发展的今天&#xff0c;语音技术的应用已经渗透到我们生活的方方面面。从智能音箱、语音助手到自动语音识别系统&#xff0c;高质量的语音数据是这些应用成功的关键。景联文科技作为领先的AI数据服务提供商&#xff0c;专注于为客户提供高精度、高效的语音标注服…

windows免登录linux

windows 生成秘钥文件 ssh-keygen -t rsa 将公钥传送到服务器 scp C:\Users\xx/.ssh/id_rsa.pub xxxx:/home/ruoyi/id_rsa.pub linux 使用ssh-copy-id -i ~/.ssh/id_rsa.pub userhost 如果禁用root登录&#xff0c;先开启 vim /etc/ssh/sshd_config PermitRootLogin yes …

基于容器的云原生,让业务更自由地翱翔云端

无论是要构建一个应用或开发一个更庞大的解决方案&#xff0c;在技术选型时&#xff0c;技术的开放性和可移植性已经成为很多企业优先考虑的问题之一。毕竟没人希望自己未来的发展方向和成长速度被自己若干年前选择使用的某项技术所限制或拖累。 那么当你的业务已经上云&#x…

Visual Studio 使用 GitHub Copilot 协助调试

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…

springboot限流注解

我们在工作中 有些接口访问量过大 为了保证服务的正常运行可以增加限流 第一步 引入aop和redis <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency…

MySQL多表查询时有哪些连接方式?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL多表查询时有哪些连接方式?】面试题。希望对大家有帮助&#xff1b; MySQL多表查询时有哪些连接方式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中进行多表查询时&#xff0c;常见的连接方式有以下…

Python | 虚拟环境01 - 什么是虚拟环境、它的由来

导言 python3真的不是安装了就完事&#xff0c;必须理解虚拟环境是什么才算是初步掌握python环境。 学习python3虚拟环境&#xff0c;建议参考B站教程。这位博主用了6个视频&#xff0c;每一个视频仅仅几分钟。居然把python3的虚拟环境讲明白了。 虚拟环境&#xff08;Virtual…

【已解决】在Visual Studio里将应用与Microsoft Store关联时提示网络异常

发布Windows应用时。在Visual Studio里点击"发布“&#xff0c;将应用与Microsoft Store关联时&#xff0c;一直提示网络错误。 查了一下论坛&#xff0c;发现之前也经常出现&#xff0c;但我是第一次遇到。 不能就这样一直被卡着呀&#xff0c;研究了一下&#xff0c;还…