目录
一、时间处理
1、获取过去7天内的日期数组
/**
* 获取过去7天内的日期数组
*
* @return 日期数组
* @Auth YFL
*/
public static ArrayList<String> pastDay(String time, int day) {
ArrayList<String> pastDaysList = new ArrayList<>();
try {
//我这里传来的时间是个string类型的,所以要先转为date类型的。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(time);
for (int i = day; i >= 0; i--) {
pastDaysList.add(getPastDate(i, date));
}
} catch (ParseException e) {
e.printStackTrace();
}
return pastDaysList;
}
2、获取过去第几天的日期
/**
* 获取过去第几天的日期
*
* @param past 过去第几天
* @return 返回日期字符串
* @Auth YFL
*/
public static String getPastDate(int past, Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - past);
Date today = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(today);
}
3、将分钟转换为时分秒格式 00:00:00
/**
* 将分钟转换为时分秒格式 00:00:00
*
* @param min 过去多少天
* @return 返回字符串时间
* @Auth YFL
*/
public static String minConvertHourMinSecond(Long min) {
String result = "";
if (min != null) {
long m = min;
String format;
Object[] array;
long days = m / (60 * 24);
long hours = m / (60) - days * 24;
long minutes;
long second;
if (days > 0) {
hours += days * 24;
minutes = m - hours * 60;
} else {
minutes = m - hours * 60 - days * 24 * 60;
}
second = (m - minutes - hours * 60) / 60;
String hoursStr;
String minutesStr;
String secondStr;
if (hours < 10) {
hoursStr = "0" + hours;
} else {
hoursStr = hours + "";
}
if (minutes < 10) {
minutesStr = "0" + minutes;
} else {
minutesStr = minutes + "";
}
if (second < 10) {
secondStr = "0" + second;
} else {
secondStr = second + "";
}
format = "%1$s:%2$s:%3$s";
array = new Object[]{hoursStr, minutesStr, secondStr};
result = String.format(format, array);
}
return result;
}
4、获取当前的日期
/**
* 获取当前的日期
*
* @return 现在的日期时间 格式为yyyy-MM-dd
* @Auth YFL
*/
public static String getNowDateStr() {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
5、输入年份和月份判断当年当月一个共有多少天
/**
* 输入年份和月份判断当年当月一个共有多少天
*
* @param year 年份
* @param month 月份
* @return 返回天数
* @Auth YFL
*/
public static int getYearOfDays(int year, int month) {
switch (month) {
//1,3,5,7,8,10,12都是31天
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
//4,6,9,11都是30天
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
//判断闰年
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
return 29;
} else {
return 28;
}
}
return 0;
}
6、根据开始日期和结束日期获取本周时间list
/**
* 根据开始日期和结束日期获取本周时间list
* @param dBegin 开始日期
* @param dEnd 结束日期
* @Auth YFL
**/
public static List<Date> findDates(Date dBegin, Date dEnd) {
List<Date> lDate = new ArrayList<Date>();
lDate.add(dBegin);
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime())) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
lDate.add(calBegin.getTime());
}
return lDate;
}
7、时间格式转换(String to Date)
/**
* 时间格式转换(String to Date)
* @param strDate
* @param format
* @Auth YFL
*/
public static Date stringToDate(String strDate, String format) {
SimpleDateFormat formatter = new SimpleDateFormat(format);
ParsePosition pos = new ParsePosition(0);
Date strtodate = formatter.parse(strDate, pos);
return strtodate;
}
8、计算两个时间差
/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟";
}
9、计算年龄
/**
* 计算年龄
**/
public static int getAge(Date birthDay) {
Calendar cal = Calendar.getInstance();
if (cal.before(birthDay)) { // 出生日期晚于当前时间,无法计算
return 0;
}
int yearNow = cal.get(Calendar.YEAR); // 当前年份
int monthNow = cal.get(Calendar.MONTH); // 当前月份
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); // 当前日期
cal.setTime(birthDay);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
int age = yearNow - yearBirth; // 计算整岁数
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
if (dayOfMonthNow < dayOfMonthBirth) {
age--;// 当前日期在生日之前,年龄减一
}
} else {
age--;// 当前月份在生日之前,年龄减一
}
}
return age;
}
10、日期转星期
/**
* 日期转星期
*
* @param datetime
* @return
*/
public static String dateToWeek(String datetime) {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
Calendar cal = Calendar.getInstance(); // 获得一个日历
Date datet = null;
try {
datet = f.parse(datetime);
cal.setTime(datet);
} catch (ParseException e) {
e.printStackTrace();
}
int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
if (w < 0) {
w = 0;
}
return weekDays[w];
}
11、计算两个日期相隔的天数
/**
* 计算两个日期相隔的天数
*/
public static int nDaysBetweenTwoDate(String firstString, String secondString) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date firstDate = null;
Date secondDate = null;
try {
firstDate = df.parse(firstString);
secondDate = df.parse(secondString);
} catch (Exception e) {
// 日期型字符串格式错误
e.printStackTrace();
}
int nDay = (int) ((secondDate.getTime() - firstDate.getTime()) / (24 * 60 * 60 * 1000));
return nDay;
}
12、获取两个日期之间的所有日期
public static List<String> getBetweenDays(String startTime, String endTime) {
// 返回的日期集合
List<String> days = new ArrayList<String>();
DateFormat dateFormat = new SimpleDateFormat(YYYY_MM_DD);
try {
Date start = dateFormat.parse(startTime);
Date end = dateFormat.parse(endTime);
Calendar tempStart = Calendar.getInstance();
tempStart.setTime(start);
Calendar tempEnd = Calendar.getInstance();
tempEnd.setTime(end);
tempEnd.add(Calendar.DATE, +1);// 日期加1(包含结束)
while (tempStart.before(tempEnd)) {
days.add(dateFormat.format(tempStart.getTime()));
tempStart.add(Calendar.DAY_OF_YEAR, 1);
}
} catch (ParseException e) {
e.printStackTrace();
}
return days;
}
二、集合处理
1、根据集合中某一元素作为条件去重
// 例句:使用自己的对象 ——>
private static List<UserCar> removeDuplicates2(List<UserCar> cars) {
return cars.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<UserCar>(Comparator.comparing(UserCar::getCarNo))), ArrayList::new)
);
}
2、统计List集合中每个元素出现的次数
/**
* 统计List集合中每个元素出现的次数
* 例如list(["111","111","222","333"])
* ->
* 则返回Map {111=2, 222=1, 333=1}
* @AUTH : yfl
* @DATE : 2022年12月27日 上午11:35:22
* @param falcons
* @return Map<String, Integer>
*/
public static Map<String, Long> frequencyOfListQ(List<String> falcons) {
if (falcons.isEmpty()) {
return new HashMap<>();
}
return falcons.stream().collect(Collectors.groupingBy(k -> k, Collectors.counting()));
}
3、求Map<K,V>中Value(值)的最大值 返回记录数据
/**
* @param map 入参
* @TODO : 求Map<K,V>中Value(值)的最大值 返回记录数据
* @AUTH : yfl
* @DATE : 2022年12月27日 上午11:35:22
* @return_type : Map<String,Long>
*/
public static Map<String, Long> getMaxValue(Map<String, Long> map) {
if (map == null) {
return new HashMap<>();
}
Map<String, Long> maxMap = new HashMap<>();
int length = map.size();
Collection<Long> c = map.values();
Object[] obj = c.toArray();
Arrays.sort(obj);
for (Map.Entry<String, Long> entry : map.entrySet()) {
if (entry.getValue() == obj[length - 1]) {
maxMap.put(entry.getKey(), entry.getValue());
}
}
return maxMap;
}
4、找出两个集合中不同的元素
/**
* 找出两个集合中不同的元素
* @param t1 集合1
* @param t2 集合2
* @param <T> 泛型
*/
public static <T> List<T> compare(List<T> t1, List<T> t2) {
//用来保存最后结果的集合
List<T> list3 = new ArrayList<>();
for (T t : t2) {
if (!t1.contains(t)) {
list3.add(t);
}
}
for (T t : t1) {
if (!t2.contains(t)) {
list3.add(t);
}
}
return list3;
}
5、对集合中某对象中的元素进行排序
// 选择对象元素时推荐使用int类型,默认是降序 limit是取集合前几位 limit(n)
List<ExerciseRankingVo> exerciseRankingVos = collect.stream().sorted(Comparator.comparing(ExerciseRankingVo::getCount).reversed()).limit(20).collect(Collectors.toList());
6、判断集合中是否存在某个元素
// 获取集合中需要判断的字段,转换成数组
String[] string = exerciseRankingVos.stream().map(ExerciseRankingVo::getPhone).toArray(String[]::new);
// 当返回下标为负数表示需要查询的元素不在集合中,正数则在数组当中(index从0开始)
// binarySearch 二分查找法
int index = Arrays.binarySearch(string, phone);
7、对Map进行排序
// 将map使用流的方式放入LinkedHashMap中进行排序 (对key进行排序)
Map<String, Object> result = new LinkedHashMap<>();
map.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
8、求集合A(aList)和集合B(bList)的交集
// 循环aList, 过滤出id在bList里的对象,2个stream代替2个for循环,filter是过滤,anyMatch是有任意匹配
aList.stream().filter(p1 -> bList.stream().anyMatch(p2 -> p1.getId().equals(p2.getId())))
9、求aList独有的,不在bList中的
// 循环aList, 过滤出id不在bList里的对象,noneMatch是没有任何匹配,与anyMatch刚好相反
aList.stream().filter(p1 -> bList.stream().noneMatch(p2 -> p1.getId().equals(p2.getId())))
10、求bList独有的,不在aList中的
// 循环bList, 过滤出id不在aList里的对象
bList.stream().filter(p1 -> aList.stream().noneMatch(p2 -> p1.getId().equals(p2.getId())))
11、将集合以逗号分割为字符串
List<Integer> collect = bySportItemList.stream().map(ArenaSportItem::getSportItemId).collect(Collectors.toList());
String ids = collect.stream().map(Objects::toString).collect(Collectors.joining(","));
三、基于concurrentHash的本地缓存工具
package com.example.demoproject.demo;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
/**
* <pre>
* 基于concurrentHash的本地缓存工具类
* 缓存删除基于timer定时器
* <pre>
*/
public class CacheUtil {
//默认大小
private static final int DEFAULT_CAPACITY = 1024;
// 最大缓存大小
private static final int MAX_CAPACITY = 10000;
//默认缓存过期时间
private static final long DEFAULT_TIMEOUT = 3600;
//1000毫秒
private static final long SECOND_TIME = 1000;
//存储缓存的Map
private static final ConcurrentHashMap<String, Object> map;
private static final Timer timer;
static {
map = new ConcurrentHashMap<>(DEFAULT_CAPACITY);
timer = new Timer();
}
//私有化构造方法
private CacheUtil() {
}
/**
* <pre>
* 缓存任务清除类
* <pre>
*/
static class ClearTask extends TimerTask {
private String key;
public ClearTask(String key) {
this.key = key;
}
@Override
public void run() {
CacheUtil.remove(key);
}
}
//==================缓存的增删改查==================//
/**
* <pre>
* 添加缓存
* <pre>
*/
public static boolean put(String key, Object object) {
if (checkCapacity()) {
map.put(key, object);
//默认缓存时间
timer.schedule(new ClearTask(key), DEFAULT_TIMEOUT);
return true;
}
return false;
}
/**
* <pre>
* 添加缓存
* <pre>
*/
public static boolean put(String key, Object object, int time_out) {
if (checkCapacity()) {
map.put(key, object);
//默认缓存时间
timer.schedule(new ClearTask(key), time_out * SECOND_TIME);
}
return false;
}
/**
* <pre>
* 判断容量大小
* <pre>
*/
public static boolean checkCapacity() {
return map.size() < MAX_CAPACITY;
}
/**
* <pre>
* 批量增加缓存
* <pre>
*/
public static boolean put(Map<String, Object> m, int time_out) {
if (map.size() + m.size() <= MAX_CAPACITY) {
map.putAll(map);
for (String key : m.keySet()) {
timer.schedule(new ClearTask(key), time_out * SECOND_TIME);
}
return true;
}
return false;
}
/**
* <pre>
* 删除缓存
* <pre>
*/
public static void remove(String key) {
map.remove(key);
}
/**
* <pre>
* 清除所有缓存
* <pre>
*/
public void clearAll() {
if (map.size() > 0) {
map.clear();
}
timer.cancel();
}
/**
* <pre>
* 获取缓存
* <pre>
*/
public static Object get(String key) {
return map.get(key);
}
/**
* <pre>
* 是否包含某个缓存
* <pre>
*/
public static boolean isContain(String key) {
return map.contains(key);
}
}
四、信息脱敏
1、自定义脱敏工具类:SensitivityUtil
public class SensitivityUtil {
/**
* 【中文姓名】只显示第一个汉字,其他隐藏为星号,比如:才**
*/
public static String hideChineseName(String chineseName) {
if (chineseName == null) {
return null;
}
return desValue(chineseName, 1, 0, "*");
}
/**
* 隐藏邮箱
*/
public static String hideEmail(String email) {
return email.replaceAll("(\\w?)(\\w+)(\\w)(@\\w+\\.[a-z]+(\\.[a-z]+)?)", "$1****$3$4");
}
/**
* 隐藏手机号中间四位
*/
public static String hidePhone(String phone) {
return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
}
/**
* 隐藏身份证
*/
public static String hideIDCard(String idCard) {
return idCard.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1*****$2");
}
/**
* 对字符串进行脱敏操作
* @param origin 原始字符串
* @param prefixNoMaskLen 左侧需要保留几位明文字段
* @param suffixNoMaskLen 右侧需要保留几位明文字段
* @param maskStr 用于遮罩的字符串, 如'*'
* @return 脱敏后结果
*/
public static String desValue(String origin, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) {
if (origin == null) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0, n = origin.length(); i < n; i++) {
if (i < prefixNoMaskLen) {
sb.append(origin.charAt(i));
continue;
}
if (i > (n - suffixNoMaskLen - 1)) {
sb.append(origin.charAt(i));
continue;
}
sb.append(maskStr);
}
return sb.toString();
}
2、自定义脱敏注解 @SensitivityEncrypt
(1)脱敏类型枚举
import lombok.Getter;
/**
* 脱敏类型枚举
*/
@Getter
public enum SensitivityTypeEnum {
/**
* 姓名
*/
NAME,
/**
* 身份证号
*/
ID_CARD,
/**
* 邮箱
*/
EMAIL,
/**
* 手机号
*/
PHONE,
/**
* 自定义(此项需设置脱敏的前置后置长度)
*/
CUSTOMER
}
(2)脱敏注解: SensitivityEncrypt
/**
* 自定义数据脱敏注解
*/
// 作用在字段上
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitivitySerializer.class) // 该注解使用序列化的方式
public @interface SensitivityEncrypt {
/**
* 脱敏数据类型(必须指定类型)
*/
SensitivityTypeEnum type();
/**
* 前面有多少不需要脱敏的长度
*/
int prefixNoMaskLen() default 1;
/**
* 后面有多少不需要脱敏的长度
*/
int suffixNoMaskLen() default 1;
/**
* 用什么符号进行打码
*/
String symbol() default "*";
}
(3)引入jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.6.1</version>
</dependency>
(4)自定义脱敏序列化:SensitivitySerializer
@NoArgsConstructor
@AllArgsConstructor
public class SensitivitySerializer extends JsonSerializer<String> implements ContextualSerializer {
// 脱敏类型
private SensitivityTypeEnum sensitivityTypeEnum;
// 前几位不脱敏
private Integer prefixNoMaskLen;
// 最后几位不脱敏
private Integer suffixNoMaskLen;
// 用什么打码
private String symbol;
/**
* 序列化 数据处理
*/
@Override
public void serialize(final String origin, final JsonGenerator jsonGenerator,
final SerializerProvider serializerProvider) throws IOException {
//判断是否为空脱敏类型
if (StringUtils.isNotBlank(origin) && null != sensitivityTypeEnum) {
//判断脱敏类型,进入对应类型的数据处理
switch (sensitivityTypeEnum) {
case CUSTOMER:
jsonGenerator.writeString(SensitivityUtil.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, symbol));
break;
case NAME:
jsonGenerator.writeString(SensitivityUtil.hideChineseName(origin));
break;
case ID_CARD:
jsonGenerator.writeString(SensitivityUtil.hideIDCard(origin));
break;
case PHONE:
jsonGenerator.writeString(SensitivityUtil.hidePhone(origin));
break;
case EMAIL:
jsonGenerator.writeString(SensitivityUtil.hideEmail(origin));
break;
default:
throw new IllegalArgumentException("unknown privacy type enum " + sensitivityTypeEnum);
}
} else {
//如果脱敏类型为空则赋值空,要不然会导致序列化错误
jsonGenerator.writeString("");
}
}
/**
* 读取自定义注解SensitivityEncrypt 创建上下文所需
*/
@Override
public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider,
final BeanProperty beanProperty) throws JsonMappingException {
if (beanProperty != null) {
if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
SensitivityEncrypt sensitivityEncrypt = beanProperty.getAnnotation(SensitivityEncrypt.class);
if (sensitivityEncrypt == null) {
sensitivityEncrypt = beanProperty.getContextAnnotation(SensitivityEncrypt.class);
}
if (sensitivityEncrypt != null) {
return new SensitivitySerializer(sensitivityEncrypt.type(), sensitivityEncrypt.prefixNoMaskLen(),
sensitivityEncrypt.suffixNoMaskLen(), sensitivityEncrypt.symbol());
}
}
return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
}
return serializerProvider.findNullValueSerializer(null);
}
}
3、简易脱敏工具类
/**
* @author yfl
* @date 2023/02/02
*/
public class EncryptionUtils {
/**
* 手机号码前三后四脱敏
* 脱敏规则:保留前三后四
*/
public static String mobileEncrypt(String mobile) {
if (StringUtils.isEmpty(mobile) || (mobile.length() != 11)) {
return mobile;
}
return mobile.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2");
}
/**
* 功能描述:姓名脱敏
* 脱敏规则:只显示第一个汉字
*/
public static String nameEncrypt(String fullName) {
if (StringUtils.isNotBlank(fullName)) {
String name = StringUtils.left(fullName, 1);
return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
}
return fullName;
}
/**
* 功能描述:身份证号脱敏
* 脱敏规则:保留前六后三
*/
public static String idNumberEncrypt(String idNumber) {
if (StringUtils.isNotBlank(idNumber)) {
return StringUtils.left(idNumber, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(idNumber, 3), StringUtils.length(idNumber), "*"), "******"));
}
return idNumber;
}
/**
* 功能描述:地址脱敏
* 脱敏规则:从第四位开始隐藏,隐藏至最后两位
*/
public static String addressEncrypt(String address) {
if (StringUtils.isNotBlank(address)) {
return StringUtils.left(address, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(address, address.length() - 11), StringUtils.length(address), "*"), "***"));
}
return address;
}
}