目录
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; } }
十、结语
上述为本人在实际开发中经常用到的工具类,您可以直接使用这些工具类代码,当然也可以优化这些类并扩展自己的相关功能。
如果你对区块链感兴趣,可以看一下我的区块链专栏.
感谢关注和收藏!
编辑