Springboot应用开发:工具类整理

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,182元/月
可观测监控 Prometheus 版,每月50GB免费额度
简介: 在实际的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>

image.gif

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;
    }
}

image.gif

三、日期格式

       日期格式工具类主要用于日期格式的转换和日期的计算,例如:从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>

image.gif

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();
    }
}

image.gif

四、加密

       加密工具类用于对数据进行加密,这里是使用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();
    }
}

image.gif

五、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>

image.gif

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();
  }
  
}

image.gif

六、金额

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

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);
  }
}

image.gif

七、二维码

       二维码工具类在实际开发中用于二维码的生成,在本工具类中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>

image.gif

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);
  }
}

image.gif

八、坐标转换

       坐标转换用于不同地理坐标数据之间的转换,这在地理应用开发中经常用到,在本篇文章中的代码中实现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;
    }
}

image.gif

九、树结构

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

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;
    }
}

image.gif

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;
    }
}

image.gif

十、结语

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

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

感谢关注和收藏!

image.gif 编辑

目录
相关文章
|
NoSQL Java Redis
小白版的springboot中集成mqtt服务(超级无敌详细),实现不了掐我头!!!
小白版的springboot中集成mqtt服务(超级无敌详细),实现不了掐我头!!!
|
2月前
|
算法 关系型数据库 Java
Springboot集成PostGIS完成路径规划
因为公司里需要做关于林区防火方面的项目,需要完成着火后山区路径的导航,但.....某德的功能似乎只能到达山区的边上,后边的路就需要自己完成导航了。搞了一个周终于有所效果了,也遇见了很多的坑,在此记录一下,希望以后不要踩坑。需要上述的环境才能进行路径导航,环境的搭建可以参阅
82 5
|
2月前
|
缓存 前端开发 Java
SpringBoot 实现动态菜单功能完整指南
本文介绍了一个动态菜单系统的实现方案,涵盖数据库设计、SpringBoot后端实现、Vue前端展示及权限控制等内容,适用于中后台系统的权限管理。
212 1
|
2月前
|
IDE Java 开发工具
IntelliJ IDEA 使用技巧与插件推荐
IntelliJ IDEA 是一个功能强大、扩展性丰富的开发工具。通过掌握常用的快捷键和技巧,结合合适的插件,可以大幅提升你的开发效率。
115 1
|
2月前
|
监控 Java 开发工具
Springboot秒集成-视频推拉流
在工作中需要用到视频的推拉流服务,刚开始准备使用netty服务自己实现RTSP推拉流服务,但在RTSP解包时卡住,自己实现难度确实有点大,后来在网上找到了Zlm4j库,它是基于ZLMediaKit服务实现的Jna版本,可以很容易的集成到Springboot中,在此也。希望本篇博客可以帮助到想快速实现视频推拉流服务的朋友。
248 10
|
2月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
221 3
|
2月前
|
传感器 定位技术 数据格式
常用通信协议及数据格式
常用通信协议和格式总结
230 2
|
6月前
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestBody
`@RequestBody` 是 Spring 框架中的注解,用于将 HTTP 请求体中的 JSON 数据自动映射为 Java 对象。例如,前端通过 POST 请求发送包含 `username` 和 `password` 的 JSON 数据,后端可通过带有 `@RequestBody` 注解的方法参数接收并处理。此注解适用于传递复杂对象的场景,简化了数据解析过程。与表单提交不同,它主要用于接收 JSON 格式的实体数据。
476 0
|
Java 测试技术 开发工具
Spring Boot中的开发工具与插件推荐
Spring Boot中的开发工具与插件推荐

热门文章

最新文章