🍊日常编码小技巧
SpringBoot
消息转换器
忽略属性为null的字段
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Configuration public class GlobalConfig extends WebMvcConfigurationSupport { @Override protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { super.configureMessageConverters(converters); converters.add(mappingJackson2HttpMessageConverter()); } /** * 自定义mappingJackson2HttpMessageConverter * 目前实现:空值忽略,空字段可返回 */ private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return new MappingJackson2HttpMessageConverter(objectMapper); } }
Maven
Maven打包相关小命令记录
编译多模块项目中的其中一个模块:
-pl
是 Maven 命令中的一个参数,用于指定要构建的模块。在这个例子中,-pl
后面跟的是要构建的模块的 ID,即 1-basic/dubbo-samples-spring-boot
。
这个参数的作用是只构建指定的模块,而不是整个项目的所有模块。这对于只编译和运行特定的模块非常有用,可以节省时间和资源。
mvn clean install -pl 1-basic/dubbo-samples-spring-boot
编译和运行指定模块:
-
mvn clean compile exec:java
:这是 Maven 的编译和执行命令。clean
命令会清理编译输出目录,compile
命令会编译模块中的源代码。exec:java
命令会运行模块中的主类。 -
-pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider
:这是-pl
参数,用于指定要构建和执行的模块。在这个例子中,指定的模块是1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider
。 -
-Dexec.mainClass="org.apache.dubbo.springboot.demo.provider.ProviderApplication"
:这是-D
参数,用于指定要运行的主类。在这个例子中,要运行的主类是org.apache.dubbo.springboot.demo.provider.ProviderApplication
。
总之,这个命令的作用是编译并运行 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider
模块中的 org.apache.dubbo.springboot.demo.provider.ProviderApplication
类。
mvn clean compile exec:java -pl 1-basic/dubbo-samples-spring-boot/dubbo-samples-spring-boot-provider -Dexec.mainClass="org.apache.dubbo.springboot.demo.provider.ProviderApplication"
Java基础:
统计每个字符出现的次数,并排序
class Springboot04ServiceConsumerApplicationTests { public static void main(String[] args) { String str = "dadqwgDADADdbuqdiewhdfqccndcfDHFUWMIwuiwqfrwrfi"; System.out.println(sortStrToOne(str)); System.out.println(sortStrToTwo(str)); System.out.println(sortStrToThree(str)); System.out.println(sortStrToFour(str)); } public static Map<Character, Integer> sortStrToOne(String str) { Map<Character, Integer> characterIntegerMap = new HashMap<>(); // 1、将数据添加到map中 for (char c : str.toCharArray()) { characterIntegerMap.compute(c, (k, v) -> Objects.nonNull(v) ? v + 1 : 1); } // 2、将数据放到list集合进行排序 List<Map.Entry<Character, Integer>> entryList = new ArrayList<>(characterIntegerMap.entrySet()); // 如果value相同,则按照key排序 entryList.sort(Map.Entry.comparingByKey()); // 按照value排序 entryList.sort(Map.Entry.comparingByValue()); // 3、遍历集合,放到Map中 Map<Character, Integer> result = new LinkedHashMap<>(); for (Map.Entry<Character, Integer> entry : entryList) { result.put(entry.getKey(), entry.getValue()); } return result; } public static Map<Character, Integer> sortStrToTwo(String str) { Map<Character, Integer> characterIntegerMap = new HashMap<>(); // 1、将数据添加到map中 for (char c : str.toCharArray()) { characterIntegerMap.compute(c, (k, v) -> Objects.nonNull(v) ? v + 1 : 1); } // 2、通过TreeMap排序 TreeMap<Character, Integer> sortedMap = new TreeMap<>((o1, o2) -> { int result = characterIntegerMap.get(o1).compareTo(characterIntegerMap.get(o2)); if (result == 0) { result = o1.compareTo(o2); } return result; }); // 3、进行排序 sortedMap.putAll(characterIntegerMap); return sortedMap; } public static Map<Character, Integer> sortStrToThree(String str) { Map<Character, Integer> characterIntegerMap = new HashMap<>(); // 1、将数据添加到map中 for (char c : str.toCharArray()) { characterIntegerMap.compute(c, (k, v) -> Objects.nonNull(v) ? v + 1 : 1); } LinkedHashMap<Character, Integer> sortedMap = new LinkedHashMap<>(); // 2、Stream进行排序,并将数据放到map中 characterIntegerMap.entrySet().stream() .sorted(Map.Entry.<Character, Integer>comparingByValue() .thenComparing(Map.Entry.comparingByKey())) .forEachOrdered(entry -> sortedMap.put(entry.getKey(), entry.getValue())); // 3、返回结果 return sortedMap; } public static Map<Character, Integer> sortStrToFour(String str) { // 1、将数据添加到map中 HashMap<Character, Integer> map = new HashMap<>(); for (char c : str.toCharArray()) map.compute(c, (k, v) -> Objects.nonNull(v) ? v + 1 : 1); // 2、通过TreeSet进行排序 TreeSet<Map.Entry<Character, Integer>> treeSet = new TreeSet<>( Comparator.comparing(Map.Entry<Character, Integer>::getValue) .thenComparing(Map.Entry::getKey) ); // 3、执行排序 treeSet.addAll(map.entrySet()); // 4、将TreeSet转为Map返回 return treeSetToMap(treeSet); } public static <K, V> Map<K, V> treeSetToMap(TreeSet<Map.Entry<K, V>> treeSet) { Map<K, V> map = new LinkedHashMap<>(); for (Map.Entry<K, V> entry : treeSet) { map.put(entry.getKey(), entry.getValue()); } return map; } }
Java实现数据分组:
public static void main(String[] args) { List<User> userList = new ArrayList<>(); userList.add(new User("张三", 23, 1)); userList.add(new User("李四", 25, 0)); userList.add(new User("王五", 20, 0)); userList.add(new User("赵六", 23, 1)); userList.add(new User("田七", 21, 1)); System.out.println("=============对性别进行分组================"); Map<Integer, List<User>> collect = userList.stream().collect(Collectors.groupingBy(User::getSex)); collect.forEach((k, v) -> { System.out.println(k + ":" + v); }); System.out.println("=============按照年龄段进行分组================"); Map<String, List<User>> collectUserAge = userList.stream().collect(Collectors.groupingBy(u -> { Integer userAge = u.getUserAge(); if (userAge >= 18 && userAge <= 20) { return "18-20"; } else if (userAge >= 21 && userAge <= 23) { return "21-23"; } else if (userAge >= 24 && userAge <= 26) { return "24-26"; } else { return "其他"; } })); collectUserAge.forEach((k, v) -> { System.out.println(k + ":" + v); }); System.out.println("=============统计分组的人数================"); Map<Integer, Long> integerLongMap = userList.stream().collect(Collectors.groupingBy(User::getSex, Collectors.counting())); integerLongMap.forEach((k, v) -> { System.out.println(k + ":" + v); }); }
对Map集合按照key进行排序:
public static void main(String[] args) { Map<Integer, Object> map = new HashMap<>(); map.put(1, "张三"); map.put(3, "李四"); map.put(2, "王五"); List<Map.Entry<Integer, Object>> collect = map.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList()); collect.forEach(System.out::println); }
List转Map集合(1):k,v均为list
/** * 将List转为Map * * @param list 原数据 * @param keyExtractor Key的抽取规则 * @param <K> Key * @param <V> Value * @return */ public static <K, V> Map<K, V> listToMap(List<V> list, Function<V, K> keyExtractor) { /*等于空就直接返回空的map*/ if (list == null || list.isEmpty()) { return new HashMap<>(); } Map<K, V> map = new HashMap<>(list.size()); for (V element : list) { /*设置map的K为list的值*/ K key = keyExtractor.apply(element); if (key == null) { continue; } /*设置map的V为list的值*/ map.put(key, element); } return map; }
使用:
1 public static void main(String[] args) { 2 // 1.创建List集合 3 List<? extends Serializable> list = new ArrayList<>(Arrays.asList(1, 2, 42, "23")); 4 // 2.调用方法将list集合转map集合 5 Map<? extends Serializable, ? extends Serializable> map = listToMap(list, Function.identity()); 6 // 3.遍历map集合 7 Set<? extends Map.Entry<? extends Serializable, ? extends Serializable>> entries = map.entrySet(); 8 entries.forEach(System.out::println); 9 }
输出:
List转Map集合(2):自定义k
List<User> list = new ArrayList<>(); Map<String, User> collect = list.stream().collect(Collectors.toMap(User::getId, Function.identity(), (e1, e2) -> e1));
使用
@Data @NoArgsConstructor @AllArgsConstructor class User { private Long id; private String name; private String sex; public static void main(String[] args) { List<User> list = new ArrayList<>(); list.add(new User(1L, "张三", "男")); list.add(new User(2L, "李四", "女")); Map<Long, User> collect = list.stream().collect(Collectors.toMap(User::getId, Function.identity(), (e1, e2) -> e1)); collect.forEach((k, v) -> { System.out.println(k + ":" + v); }); } }
输出:
1:User(id=1, name=张三, sex=男) 2:User(id=2, name=李四, sex=女)
解释:
list的 ArrayList 对象,然后使用add方法向其中添加了两个 User 对象。 之后,代码使用了Java 8的Stream API和Collectors类的toMap方法,将 list 中的元素转换为一个Map对象 collect。 toMap 方法接受三个参数: 第一个参数为函数,它将 list 中的每一个元素转换为一个键,在这个例子中使用 User::getId 方法获取每个用户的名字作为键。 第二个参数是函数,用于将 list 中的每一个元素转换为一个值。在这个例子中使用了 Function.identity() 方法,表示该方法的输入和输出是同一个对象,即这里的键值对是由User对象本身构成。 第三个参数是一个BinaryOperator函数,用于在发现重复键时进行处理。在这个例子中使用的是(e1, e2) -> e1,表示如果出现重复键,则只保留第一个键。 最后调用 forEach 方法遍历 map 并打印出来 综上,这段代码用于将一个包含两个用户对象的列表转化为一个用用户名为键,用户对象为值的Map对象并遍历这个map, 每个键值对都会被打印出来。
封装好的日期时间类
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; /** * @ClassName DateFormatUtil * @Author zhangzhixi * @Description * @Date 2022-5-2 19:11 * @Version 1.0 */ public class DateFormatUtil { public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * 格式化结束日期,并加一天 * * @param endtime * @return */ public static String formatEndDate(String endtime) { Date endDate = DateUtil.parseDate(endtime, "yyyy-MM-dd"); Calendar c = Calendar.getInstance(); c.setTime(endDate); c.add(Calendar.DAY_OF_MONTH, 1);// 今天+1天 String endDateStr = DateUtil.format(c.getTime(), "yyyy-MM-dd"); return endDateStr; } /** * 格式化结束日期 不做任何处理 * * @param endtime * @return */ public static String formatEndDateNow(String endtime) { Date endDate = DateUtil.parseDate(endtime, "yyyy-MM-dd"); Calendar c = Calendar.getInstance(); c.setTime(endDate); //c.add(Calendar.DAY_OF_MONTH, 1);// 今天+1天 String endDateStr = DateUtil.format(c.getTime(), "yyyy-MM-dd"); return endDateStr; } /** * 日期加/减**天 * * @param date * @param day * @return */ public static String formateDateHandleDay(String date, int day) { Date endDate = DateUtil.parseDate(date, "yyyy-MM-dd"); Calendar c = Calendar.getInstance(); c.setTime(endDate); c.add(Calendar.DAY_OF_MONTH, day); String endDateStr = DateUtil.format(c.getTime(), "yyyy-MM-dd"); return endDateStr; } /** * 日期加/减**月 * * @param date * @param month * @return */ public static String formateDateHandleMonth(String date, int month, String formate) { Date endDate = DateUtil.parseDate(date, "yyyy-MM-dd"); Calendar c = Calendar.getInstance(); c.setTime(endDate); c.add(Calendar.MONTH, month); String endDateStr = DateUtil.format(c.getTime(), "yyyy-MM-dd"); return endDateStr; } /** * 日期加/减**年 * * @param date * @param year * @return */ public static String formateDateHandleYear(String date, int year) { Date endDate = DateUtil.parseDate(date, "yyyy-MM-dd"); Calendar c = Calendar.getInstance(); c.setTime(endDate); c.add(Calendar.YEAR, year); String endDateStr = DateUtil.format(c.getTime(), "yyyy-MM-dd"); return endDateStr; } /** * 获取当前月的第一天 * * @return */ public static String formateDateFirstDay() { Calendar cale; String firstday; //获取前月的第一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 0); cale.set(Calendar.DAY_OF_MONTH, 1); //将小时至0 cale.set(Calendar.HOUR_OF_DAY, 0); //将分钟至0 cale.set(Calendar.MINUTE, 0); //将秒至0 cale.set(Calendar.SECOND, 0); //将毫秒至0 cale.set(Calendar.MILLISECOND, 0); firstday = sdf.format(cale.getTime()); return firstday; } /** * 获取当前月的最后一天 * * @return */ public static String formateDateLastDay() { Calendar cale = Calendar.getInstance(); String lastday; //获取前月的最后一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 1); cale.set(Calendar.DAY_OF_MONTH, 0); //将小时至23 cale.set(Calendar.HOUR_OF_DAY, 23); //将分钟至59 cale.set(Calendar.MINUTE, 59); //将秒至59 cale.set(Calendar.SECOND, 59); //将毫秒至59 cale.set(Calendar.MILLISECOND, 59); lastday = sdf.format(cale.getTime()); return lastday; } //获取当前月的天数 public static int getDayOfMonth() { Calendar aCalendar = Calendar.getInstance(Locale.CHINA); int day = aCalendar.getActualMaximum(Calendar.DATE); return day; } //获取当天凌晨0点0分0秒Date public Date getZeroOfDay() { Calendar calendar = Calendar.getInstance(); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); Date beginOfDate = calendar.getTime(); return beginOfDate; } //获取当天23点59分59秒Date public static Date getLastOfDay() { Calendar calendar = Calendar.getInstance(); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59); Date endOfDate = calendar.getTime(); return endOfDate; } /** * 获取当前时间的前一天同一时间 */ private String getBeforeDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 - 1); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59); String beforeDay = sdf.format(calendar.getTime()); return beforeDay; } /** * 获取当前时间的后一天同一时间 */ private String getAfterDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 + 1); String afterDay = sdf.format(calendar.getTime()); return afterDay; } /** * 获取当前时间的前一天0点0分0秒 */ public String getZeroOfBeforeDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 - 1); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); String beforeDay = sdf.format(calendar.getTime()); return beforeDay; } /** * 获取当前时间的前一天23点59分59秒 */ public String getLastOfBeforeDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 - 1); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59); String beforeDay = sdf.format(calendar.getTime()); return beforeDay; } /** * 获取当前时间后一天0点0分0秒 */ private String getZeroOfAfterDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 + 1); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0); String afterDay = sdf.format(calendar.getTime()); return afterDay; } /** * 获取当前时间后一天23点59分59秒 */ private String getLastOfAfterDay() { Calendar calendar = Calendar.getInstance(); int dd2 = calendar.get(Calendar.DATE); calendar.set(Calendar.DATE, dd2 + 1); calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59); String afterDay = sdf.format(calendar.getTime()); return afterDay; } /** * 获取当前月的第count天0分0秒0分 * * @return */ public String getZeroOfDays(int count) { Calendar cale = Calendar.getInstance(); //获取前月的第一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 0); cale.set(Calendar.DAY_OF_MONTH, 1); int dd2 = cale.get(Calendar.DATE); cale.set(Calendar.DATE, dd2 + count); cale.set(cale.get(Calendar.YEAR), cale.get(Calendar.MONTH), cale.get(Calendar.DAY_OF_MONTH), 0, 0, 0); String day = sdf.format(cale.getTime()); return day; } /** * 获取当前月的第count天23分59秒59分 * * @return */ public String getLastOfDays(int count) { Calendar cale = Calendar.getInstance(); //获取前月的第一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 0); cale.set(Calendar.DAY_OF_MONTH, 1); int dd2 = cale.get(Calendar.DATE); cale.set(Calendar.DATE, dd2 + count); cale.set(cale.get(Calendar.YEAR), cale.get(Calendar.MONTH), cale.get(Calendar.DAY_OF_MONTH), 23, 59, 59); String day = sdf.format(cale.getTime()); return day; } /** * 获取当前月的第count天 * * @return */ public static Date getDays(int count) { Calendar cale = Calendar.getInstance(); //获取前月的第一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 0); cale.set(Calendar.DAY_OF_MONTH, 1); int dd2 = cale.get(Calendar.DATE); cale.set(Calendar.DATE, dd2 + count); Date date = cale.getTime(); return date; } /** * 获取当前时间的前一月同一时间 */ public static String getBeforeMonth(Date date) { Calendar calendar = Calendar.getInstance(); //过去一月 calendar.setTime(date); calendar.add(Calendar.MONTH, -1); Date m = calendar.getTime(); String mon = sdf.format(m); return mon; } /** * 获取上个月的第一天 * * @return */ public static String getBeforeMonthFirstDay() { Calendar cale = Calendar.getInstance(); String firstday; //获取上个月的第一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, -1); cale.set(Calendar.DAY_OF_MONTH, 1); //将小时至0 cale.set(Calendar.HOUR_OF_DAY, 0); //将分钟至0 cale.set(Calendar.MINUTE, 0); //将秒至0 cale.set(Calendar.SECOND, 0); //将毫秒至0 cale.set(Calendar.MILLISECOND, 0); firstday = sdf.format(cale.getTime()); return firstday; } /** * 获取下个月的最后一天 * * @return */ public static String getBeforeMonthLastDay() { Calendar cale = Calendar.getInstance(); String lastday; //获取下个月的最后一天 cale = Calendar.getInstance(); cale.add(Calendar.MONTH, 0); cale.set(Calendar.DAY_OF_MONTH, 0); //将小时至23 cale.set(Calendar.HOUR_OF_DAY, 23); //将分钟至59 cale.set(Calendar.MINUTE, 59); //将秒至59 cale.set(Calendar.SECOND, 59); //将毫秒至59 cale.set(Calendar.MILLISECOND, 59); return sdf.format(cale.getTime()); } } class DateUtil { public static String FORMAT_YEAR = "yyyy"; public static String FORMAT_MONTH = "MM"; public static String FORMAT_DAY = "dd"; public static String FORMAT_HOUR = "HH"; public static String FORMAT_MI = "mm"; public static String FORMAT_SEC = "ss"; public static String FORMAT_DATETIME = "yyyy-MM-dd HH:mm:ss"; public static String FORMAT_SDATETIME = "yyyy-MM-dd HH:mm"; public static String FORMAT_DATE = "yyyy-MM-dd"; public static String FORMAT_STIME = "HH:mm"; public static String FORMAT_TIME = "HH:mm:ss"; public DateUtil() { } public static String formatDate(Date date, String format) { if (date == null) { date = new Date(System.currentTimeMillis()); } if (format == null) { format = FORMAT_DATE; } SimpleDateFormat df = new SimpleDateFormat(format); return df.format(date); } public static String format(Date date, String format) { if (date == null) { return ""; } else { if (format == null) { format = FORMAT_DATE; } SimpleDateFormat df = new SimpleDateFormat(format); return df.format(date); } } public static Date parseDate(String datestr, String format) { SimpleDateFormat df = new SimpleDateFormat(format); try { return df.parse(datestr); } catch (ParseException var4) { var4.printStackTrace(); return null; } } private static GregorianCalendar getGregorianCalendar(Date date) { GregorianCalendar calendar = new GregorianCalendar(); calendar.setFirstDayOfWeek(2); calendar.setTime(date); return calendar; } public static Date getWeekFirstDate(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.set(7, 2); return calendar.getTime(); } public static Date getWeekLastDate(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.set(7, 1); return calendar.getTime(); } public static Date getMonthFirstDate(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.set(5, 1); return calendar.getTime(); } public static Date getMonthLastDate(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(2, 1); calendar.set(5, 1); calendar.add(5, -1); return calendar.getTime(); } public static int getWeekNumber(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); return calendar.get(3); } public static int getWeek(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); return calendar.get(7); } public static int getMonth(Date date) { GregorianCalendar calendar = getGregorianCalendar(date); return calendar.get(2); } public static Date addDateDay(Date date, int count) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(5, count); Date newdate = calendar.getTime(); return newdate; } public static Date addDatetimeHour(Date date, int count) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(10, count); Date newdate = calendar.getTime(); return newdate; } public static Date addDatetimeMinute(Date date, int count) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(12, count); Date newdate = calendar.getTime(); return newdate; } public static Date addDateMonth(Date date, int count) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(2, count); Date newdate = calendar.getTime(); return newdate; } public static Date addDateYear(Date date, int count) { GregorianCalendar calendar = getGregorianCalendar(date); calendar.add(1, count); Date newdate = calendar.getTime(); return newdate; } public static long getDateDay(Date startDate, Date endDate) { Date startDay = parseDate(format(startDate, (String) null), FORMAT_DATE); Date endDay = parseDate(format(endDate, (String) null), FORMAT_DATE); long day = (startDay.getTime() - endDay.getTime()) / 86400000L; return day; } public static float getIntervalHour(Date startDate, Date endDate) { return (float) (endDate.getTime() - startDate.getTime()) / 3600000.0F; } }
格式化日期:Mon Jan 16 15:56:56 CST 2023
此格式是美国的时间使用格式,转换为中国方式需要进行格式化
/** * 格式化CST时间 * * @param time 要格式化的时间 * @return 格式化后的时间 */ public static String formatCSTTime(String time) { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); Date date = null; try { date = sdf.parse(time); } catch (ParseException e) { e.printStackTrace(); } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); }
正确停止一个线程:
终止一个线程可以调用线程的stop方法,但是stop这个方法会强行终止,没有保存的数据将会丢失,实际开发中一般会采用boolean标记的方式进行终止:
public class FileDemo { static boolean flag = false; public static void setFlag(boolean flag) { FileDemo.flag = flag; } public static void main(String[] args) throws InterruptedException { final Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i++) { if (flag) { return; } System.out.println(Thread.currentThread().getName() + "==》" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "t1"); t1.start(); Thread.sleep(5000); /*5S后终止线程*/ setFlag(true); } }
正则匹配IP的合法性
/** * 判断IP地址的合法性,这里采用了正则表达式的方法来判断 * return true,合法 */ public static boolean ipCheck(String text) { if (text != null && !text.isEmpty()) { // 定义正则表达式 String regex = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"; // 判断ip地址是否与正则表达式匹配 if (text.matches(regex)) { // 返回判断信息 return true; } else { // 返回判断信息 return false; } } return false; }
随机生成数字/字母的四位验证码:
//定义可选择的字符 public static final char[] CHARS = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; static Random random = new Random(); private String getRandomString() { StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 4; i++) { //生成四个字符 if (random.nextBoolean()) { /*如果随机生成的Boolean值是true,如果生成了字母字符,就让字符转为小写*/ buffer.append(String.valueOf(CHARS[random.nextInt(CHARS.length)]).toLowerCase()); } else { buffer.append(CHARS[random.nextInt(CHARS.length)]); } } return buffer.toString(); }
日期格式转换:
Demo1:Wed Feb 22 18:01:08 CST 2023
/** * 格式化CST时间 * @param time 要格式化的时间 * @return 格式化后的时间 */ public static String formatCSTTime(String time) { SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US); Date date = null; try { date = sdf.parse(time); } catch (ParseException e) { e.printStackTrace(); } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); }
Demo2:Wt paz 16 00:00:00 -0500 2013
/** * 标准化时间显示 * EEE MMM dd HH:mm:ss 'CST' yyyy * 到 * yyyy-MM-dd HH:mm:ss * * @param dateStr 要进行格式化的时间字符串 * @return 格式化后的时间字符串 */ public static String formatDateStr(String dateStr) { String dateResult = dateStr; try { dateResult = sfEnd.format(sfStart.parse(dateStr)); } catch (Exception e) { e.printStackTrace(); } return dateResult; }
快速遍历文件夹
/** * @ClassName TraverseFiles * @Author zhangzhixi * @Description * @Date 2022-12-11 11:28 * @Version 1.0 */ @SuppressWarnings("all") public class TraverseFiles { public static void main(String[] args) throws IOException { // 1、需求:打印文件夹内所有的文件名称(含子级) // 方法1 : printFileNames(Paths.get("src").toFile()); // 方法2: //Files.walk(Paths.get("src")).forEach(System.out::println); System.out.println("*******************************************"); // 2、注意:(1)try-with-resources (2)遍历结果不要包含文件夹 try (Stream<Path> pathStream = Files.walk(Paths.get("src"))) { // 可以简化成:Files::isRegularFile pathStream.filter(f -> Files.isRegularFile(f)).forEach(f -> System.out.println(f.getFileName())); } System.out.println("*******************************************"); // 3、需求:在文件夹的所有Java文件中寻找单词File findWorkToFile("src","file",".java"); } /** * 在指定目录下查找单词 * @param path 指定目录 * @param word 指定单词 * @param endWith 什么类型的文件 * @throws IOException 异常 */ private static void findWorkToFile(String path,String word,String endWith) throws IOException { Files.walkFileTree(Paths.get(path), new FileVisitor<Path>() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toString().endsWith(endWith)) { File toFile = file.toFile(); BufferedReader bufferedReader = new BufferedReader(new FileReader(toFile)); String line; while ((line = bufferedReader.readLine()) != null) { if (line.contains(word)) { System.out.println("Found 'File' in file " + toFile.getName()); break; } } } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } // 打印文件夹中的文件名称,包括子级文件夹中的文件 public static void printFileNames(File folder) { // 获取文件夹中的文件列表 File[] files = folder.listFiles(); // 对于每个文件,判断它是否是文件夹 assert files != null; for (File file : files) { if (file.isDirectory()) { // 如果是文件夹,递归调用函数来打印文件名称 printFileNames(file); } else { // 如果不是文件夹,直接打印文件名称 System.out.println(file.getName()); } } } }
时间转换:秒-->天:时:分:秒,天:时:分:秒-->秒
/** * 秒--->天时分秒 */ @Test void contextLoads() { String str = "6000"; int seconds = Integer.parseInt(str); int temp = 0; StringBuilder videoLength = new StringBuilder(); // 天 temp = seconds / 86400; videoLength.append((temp < 10) ? "0" + temp + ":" : "" + temp + ":"); // 时 temp = (seconds % 86400) / 3600; videoLength.append((temp < 10) ? "0" + temp + ":" : "" + temp + ":"); // 分 temp = seconds % 3600 / 60; videoLength.append((temp < 10) ? "0" + temp + ":" : "" + temp + ":"); // 秒 temp = seconds % 3600 % 60; videoLength.append((temp < 10) ? "0" + temp : "" + temp); System.out.println(videoLength.toString()); } /** * 将时间格式为"天:时:分:秒"的时间转换为总秒数 */ @Test public void convertTimeToSeconds() { String time = "00:01:40:00"; String[] parts = time.split(":"); int days = Integer.parseInt(parts[0]); int hours = Integer.parseInt(parts[1]); int minutes = Integer.parseInt(parts[2]); int seconds = Integer.parseInt(parts[3]); System.out.println(days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 + seconds); }
图形验证码工具类
import javax.imageio.ImageIO; import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.util.Random; /** * @创建人 cx * @创建时间 2018/11/27 17:36 * @描述 验证码生成 */ public class VerifyCodeUtils { //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; private static final Random random = new Random(); /** * 使用系统默认字符源生成验证码 * * @param verifySize 验证码长度 * @return */ public static String generateVerifyCode(int verifySize) { return generateVerifyCode(verifySize, VERIFY_CODES); } /** * 使用指定源生成验证码 * * @param verifySize 验证码长度 * @param sources 验证码字符源 * @return */ public static String generateVerifyCode(int verifySize, String sources) { if (sources == null || sources.length() == 0) { sources = VERIFY_CODES; } int codesLen = sources.length(); Random rand = new Random(System.currentTimeMillis()); StringBuilder verifyCode = new StringBuilder(verifySize); for (int i = 0; i < verifySize; i++) { verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1))); } return verifyCode.toString(); } /** * 生成随机验证码文件,并返回验证码值 * * @param w * @param h * @param outputFile * @param verifySize * @return * @throws IOException */ public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException { String verifyCode = generateVerifyCode(verifySize); outputImage(w, h, outputFile, verifyCode); return verifyCode; } /** * 输出随机验证码图片流,并返回验证码值 * * @param w * @param h * @param os * @param verifySize * @return * @throws IOException */ public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException { String verifyCode = generateVerifyCode(verifySize); outputImage(w, h, os, verifyCode); return verifyCode; } /** * 生成指定验证码图像文件 * * @param w * @param h * @param outputFile * @param code * @throws IOException */ public static void outputImage(int w, int h, File outputFile, String code) throws IOException { if (outputFile == null) { return; } File dir = outputFile.getParentFile(); if (!dir.exists()) { dir.mkdirs(); } try { outputFile.createNewFile(); FileOutputStream fos = new FileOutputStream(outputFile); outputImage(w, h, fos, code); fos.close(); } catch (IOException e) { throw e; } } /** * 输出指定验证码图片流 * * @param w * @param h * @param os * @param code * @throws IOException */ public static void outputImage(int w, int h, OutputStream os, String code) throws IOException { int verifySize = code.length(); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Random rand = new Random(); Graphics2D g2 = image.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Color[] colors = new Color[5]; Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW}; float[] fractions = new float[colors.length]; for (int i = 0; i < colors.length; i++) { colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; fractions[i] = rand.nextFloat(); } Arrays.sort(fractions); g2.setColor(Color.GRAY);// 设置边框色 g2.fillRect(0, 0, w, h); Color c = getRandColor(200, 250); g2.setColor(c);// 设置背景色 g2.fillRect(0, 2, w, h - 4); //绘制干扰线 Random random = new Random(); g2.setColor(getRandColor(160, 200));// 设置线条的颜色 for (int i = 0; i < 20; i++) { int x = random.nextInt(w - 1); int y = random.nextInt(h - 1); int xl = random.nextInt(6) + 1; int yl = random.nextInt(12) + 1; g2.drawLine(x, y, x + xl + 40, y + yl + 20); } // 添加噪点 float yawpRate = 0.05f;// 噪声率 int area = (int) (yawpRate * w * h); for (int i = 0; i < area; i++) { int x = random.nextInt(w); int y = random.nextInt(h); int rgb = getRandomIntColor(); image.setRGB(x, y, rgb); } shear(g2, w, h, c);// 使图片扭曲 g2.setColor(getRandColor(100, 160)); int fontSize = h - 4; Font font = new Font("Algerian", Font.ITALIC, fontSize); g2.setFont(font); char[] chars = code.toCharArray(); for (int i = 0; i < verifySize; i++) { AffineTransform affine = new AffineTransform(); affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2); g2.setTransform(affine); g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10); } g2.dispose(); ImageIO.write(image, "jpg", os); } private static Color getRandColor(int fc, int bc) { if (fc > 255) fc = 255; if (bc > 255) bc = 255; int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } private static int getRandomIntColor() { int[] rgb = getRandomRgb(); int color = 0; for (int c : rgb) { color = color << 8; color = color | c; } return color; } private static int[] getRandomRgb() { int[] rgb = new int[3]; for (int i = 0; i < 3; i++) { rgb[i] = random.nextInt(255); } return rgb; } private static void shear(Graphics g, int w1, int h1, Color color) { shearX(g, w1, h1, color); shearY(g, w1, h1, color); } private static void shearX(Graphics g, int w1, int h1, Color color) { int period = random.nextInt(2); boolean borderGap = true; int frames = 1; int phase = random.nextInt(2); for (int i = 0; i < h1; i++) { double d = (double) (0) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); g.copyArea(0, i, w1, 1, (int) d, 0); g.setColor(color); g.drawLine((int) d, i, 0, i); g.drawLine((int) d + w1, i, w1, i); } } private static void shearY(Graphics g, int w1, int h1, Color color) { int period = random.nextInt(40) + 10; // 50; boolean borderGap = true; int frames = 20; int phase = 7; for (int i = 0; i < w1; i++) { double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames); g.copyArea(i, 0, 1, h1, 0, (int) d); g.setColor(color); g.drawLine(i, (int) d, i, 0); g.drawLine(i, (int) d + h1, i, h1); } } }
SpringBoot获取Bean工具类
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author zhixi */ @Component public class ApplicationContextUtils implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } /** * 根据bean名字获取工厂中指定bean 对象 * * @param beanName bean名称 * @return bean对象 */ public static Object getBean(String beanName) { return context.getBean(beanName); } }
防范输入XSS攻击(全局过滤器)
1、引入工具包
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.3</version> </dependency>
2、编写过滤器类
import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @ClassName XssFilter * @Author zhangzhixi * @Description 过滤所有请求,将参数中的特殊字符过滤掉 * @Date 2022/8/18 12:56 * @Version 1.0 */ @WebFilter(urlPatterns = "/*") @Component public class XssFilter implements Filter { @Override public void init(FilterConfig config) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); chain.doFilter(xssRequest, response); } @Override public void destroy() { } }
3、使用装饰器模式,对参数进行处理
package com.zhixi.config.xss; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; import cn.hutool.json.JSONUtil; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; /** * @ClassName XssHttpServletRequestWrapper * @Author zhangzhixi * @Description 装饰器模式-Xss过滤处理 * @Date 2022/8/18 12:51 * @Version 1.0 */ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { /** * 构造函数:接收一个request对象 */ public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } /** * 重写getHeader方法,对头部信息进行过滤 */ @Override public String getParameter(String name) { String value = super.getParameter(name); if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } return value; } /** * 重写getHeader方法,对头部信息进行过滤 */ @Override public String[] getParameterValues(String name) { String[] values = super.getParameterValues(name); if (values != null) { for (int i = 0; i < values.length; i++) { String value = values[i]; if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } values[i] = value; } } return values; } /** * 重写getHeader方法,对头部信息进行过滤 */ @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> parameters = super.getParameterMap(); Map<String, String[]> map = new LinkedHashMap<>(); if (parameters != null) { for (String key : parameters.keySet()) { String[] values = parameters.get(key); for (int i = 0; i < values.length; i++) { String value = values[i]; if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } values[i] = value; } map.put(key, values); } } return map; } /** * 重写getHeader方法,对头部信息进行过滤 */ @Override public String getHeader(String name) { String value = super.getHeader(name); if (!StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); } return value; } /** * 重写getInputStream方法,先读取整个请求流,然后对流中的每个键值对进行过滤,然后返回新的InputStream */ @Override public ServletInputStream getInputStream() throws IOException { InputStream in = super.getInputStream(); StringBuilder body = new StringBuilder(); InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8); BufferedReader buffer = new BufferedReader(reader); String line = buffer.readLine(); while (line != null) { body.append(line); line = buffer.readLine(); } buffer.close(); reader.close(); in.close(); Map<String, Object> map = JSONUtil.parseObj(body.toString()); Map<String, Object> resultMap = new HashMap<>(map.size()); for (String key : map.keySet()) { Object val = map.get(key); if (map.get(key) instanceof String) { resultMap.put(key, HtmlUtil.filter(val.toString())); } else { resultMap.put(key, val); } } String str = JSONUtil.toJsonStr(resultMap); final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes()); return new ServletInputStream() { @Override public int read() throws IOException { return bain.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } }; } }
防范输入XSS攻击(工具类)
/** * 去掉请求中的js、html、style、等字符,防止xss攻击 * * @Author zhixi */ public class DeleteJS { /** * 定义script的正则表达式 */ private static final Pattern SCRIPT_PATTERN = Pattern.compile("<script[^>]*?>[\\s\\S]*?<\\/script>", Pattern.CASE_INSENSITIVE); /** * 定义style的正则表达式 */ private static final Pattern STYLE_PATTERN = Pattern.compile("<style[^>]*?>[\\s\\S]*?<\\/style>", Pattern.CASE_INSENSITIVE); /** * 定义HTML标签的正则表达式 */ private static final Pattern HTML_PATTERN = Pattern.compile("<[^>]+>", Pattern.CASE_INSENSITIVE); /** * 定义空格回车换行符 */ private static final Pattern SPACE_PATTERN = Pattern.compile("\\s*|\t|\r|\n", Pattern.CASE_INSENSITIVE); /** * 定义非法字符: * "[^a-zA-Z0-9_\\u4e00-\\u9fa5]":除了中文、英文、数字、下划线 * "[^a-zA-Z0-9_\\u4e00-\\u9fa5\\s\\r\\n]":除了中文、英文、数字、下划线、空格、回车、换行 */ private static final Pattern SPECIAL_PATTERN = Pattern.compile("[^a-zA-Z0-9_\\u4e00-\\u9fa5]", Pattern.CASE_INSENSITIVE); /** * 去掉所有的html标签 * * @param htmlStr url * @return 处理后的url数据 */ public static String getTextFromHtml(String htmlStr) { if (StringUtils.isBlank(htmlStr)) { return null; } return delHtmlTag(htmlStr).replaceAll(" ", ""); } /** * 删除Html标签 * * @param htmlStr url * @return 处理后的url数据 */ private static String delHtmlTag(String htmlStr) { htmlStr = SCRIPT_PATTERN.matcher(htmlStr).replaceAll(""); htmlStr = STYLE_PATTERN.matcher(htmlStr).replaceAll(""); htmlStr = HTML_PATTERN.matcher(htmlStr).replaceAll(""); htmlStr = SPACE_PATTERN.matcher(htmlStr).replaceAll(""); htmlStr = SPECIAL_PATTERN.matcher(htmlStr).replaceAll(""); return sanitizeUrl(htmlStr.trim()); } /** * 对url进行编码解码处理 * * @param url 网址 * @return 处理后的网址 */ private static String sanitizeUrl(String url) { String decodedUrl = decodeUrl(url); return encodeHtmlEntities(decodedUrl); } /** * 解码网址 * * @param url 网址 * @return 解码后的网址 */ private static String decodeUrl(String url) { try { return URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("解码网址时出错", e); } } /** * 编码HTML实体 * * @param input 输入 * @return 编码后的HTML实体 */ private static String encodeHtmlEntities(String input) { StringBuilder encodedOutput = new StringBuilder(); for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); switch (c) { case '<': encodedOutput.append("<"); break; case '>': encodedOutput.append(">"); break; case '\"': encodedOutput.append("""); break; case '\'': encodedOutput.append("'"); break; case '&': encodedOutput.append("&"); break; default: encodedOutput.append(c); } } return encodedOutput.toString(); } }
Java操作Word
需求:因为要每天写巡检文档,而且我比较懒,通常是一个月写一次,文档内容几乎都是一样的,只是文档中的日期有变化,如果一个个的复制,修改名称,修改文件日期比较繁琐,可以使用poi工具来实现:
添加pom
<dependencies> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.8</version> </dependency> </dependencies>
代码
public static void main(String[] args) { // 需要保证有原始文件存在 // 获取当前月份 Calendar calendar = Calendar.getInstance(); int month = calendar.get(Calendar.MONTH) + 1; String monthStr; if (month < 10) { monthStr = "0" + month; } else { monthStr = "" + month; } // 获取当月的天数 int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); System.out.println(monthStr + "月份的天数为:" + day); // 1、拷贝文件,生成每月的数据 String fileName = "F:\\BeijingCreativeSky\\说明书\\每日巡检\\2023-" + monthStr + "\\2023-" + monthStr + "-01.docx"; for (int i = 2; i <= day; i++) { String newFileOutput; // 拷贝文件 if (i < 10) { newFileOutput = "F:\\BeijingCreativeSky\\说明书\\每日巡检\\2023-" + monthStr + "\\2023-" + monthStr + "-0" + i + ".docx"; } else { newFileOutput = "F:\\BeijingCreativeSky\\说明书\\每日巡检\\2023-" + monthStr + "\\2023-" + monthStr + "-" + i + ".docx"; } try { Files.copy(Paths.get(fileName), Paths.get(newFileOutput), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { throw new RuntimeException(e); } } // 2、读取文件,替换日期 for (int i = 2; i <= day; i++) { String newFileOutput; String newDate; // 拷贝文件 if (i < 10) { newFileOutput = "F:\\BeijingCreativeSky\\说明书\\每日巡检\\2023-" + monthStr + "\\2023-" + monthStr + "-0" + i + ".docx"; newDate = "0" + i; } else { newFileOutput = "F:\\BeijingCreativeSky\\说明书\\每日巡检\\2023-" + monthStr + "\\2023-" + monthStr + "-" + i + ".docx"; newDate = "" + i; } replaceDateInWordFile(newFileOutput, newFileOutput, newDate); } } /** * 替换word中的日期 * * @param inputFile 读取的文件 * @param outputFile 输出的文件 * @param newDate 替换的日期 */ private static void replaceDateInWordFile(String inputFile, String outputFile, String newDate) { try (FileInputStream fis = new FileInputStream(inputFile)) { XWPFDocument document = new XWPFDocument(fis); for (XWPFParagraph paragraph : document.getParagraphs()) { List<XWPFRun> runs = paragraph.getRuns(); if (runs != null) { for (XWPFRun run : runs) { String text = run.getText(0); if (text != null && text.contains("01")) { text = text.replace("01", newDate); run.setText(text, 0); } } } } try (FileOutputStream fos = new FileOutputStream(outputFile)) { // 写入 document.write(fos); } } catch (IOException e) { e.printStackTrace(); } }
反射获取类的所有属性
/** * 反射获取类的所有属性,包括当前类及父类所有属性(private、public) * <p> * getFields():获取类的所有公共属性,包括父类 * getDeclaredFields():获取当前类的所有属性(private,public),不包括父类 * getSuperclass():获取父类 * <p> * * @param clazz 类 * @return 属性列表 */ public static List<Field> getAllFields(Class<?> clazz) { List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())); Class<?> superClass = clazz.getSuperclass(); if (superClass != null) { fields.addAll(getAllFields(superClass)); } return fields; }
判断判断Bean是否为空对象(包含空字符串)
代码业务中有个需求需要用到判断Bean中所有属性是否为null或者为"",使用hutoo的BeanUtil工具类,发现只有判断为null的逻辑,下面是对工具类做了一些修改:
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.19</version> </dependency>
public static void main(String[] args) { BidSection bidSection1 = new BidSection(); bidSection1.setF_org_id(""); bidSection1.setF_project_type(null); BidSection bidSection2 = new BidSection(); bidSection2.setF_org_id(null); bidSection2.setF_project_type(null); BidSection bidSection3 = new BidSection(); bidSection3.setF_org_id("111"); bidSection3.setF_project_type(null); boolean empty1 = isEmpty(bidSection1); // true,所有属性都为null或者"" boolean empty2 = isEmpty(bidSection2);// true,所有属性都为null或者"" boolean empty3 = isEmpty(bidSection3);// false,有一个属性不为null或者"",所以不为空 System.out.println(empty1); System.out.println(empty2); System.out.println(empty3); } /** * 判断Bean是否为空对象,空对象表示本身为null/"" 或者只要属性都未属性为null/"" 此方法不判断static属性 * * @param bean Bean对象 * @param ignoreFieldNames 不需要判断的属性列表 * @return 是否为空,true表示为空 */ public static boolean isEmpty(Object bean, String... ignoreFieldNames) { if (null != bean) { for (Field field : ReflectUtil.getFields(bean.getClass())) { if (ModifierUtil.isStatic(field)) { continue; } if ((!ArrayUtil.contains(ignoreFieldNames, field.getName())) && null != getFieldValue(bean, field)) { return false; } } } return true; } /** * 获取字段值 * * @param obj 对象,static字段则此字段为null * @param field 字段 * @return 字段值 * @throws UtilException 包装IllegalAccessException异常 */ public static Object getFieldValue(Object obj, Field field) throws UtilException { Object result; try { setAccessible(field); // 此处用来限制是否为空字符串的逻辑 if ("".equals(field.get(obj)) || null == field.get(obj)) { return null; } // 静态字段获取时对象为null if (obj instanceof Class) { obj = null; } result = field.get(obj); } catch (IllegalAccessException e) { throw new UtilException(e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName()); } return result; } /** * 设置方法为可访问(私有方法可以被外部调用) * * @param <T> AccessibleObject的子类,比如Class、Method、Field等 * @param accessibleObject 可设置访问权限的对象,比如Class、Method、Field等 * @since 4.6.8 */ public static <T extends AccessibleObject> void setAccessible(T accessibleObject) { if (null != accessibleObject && !accessibleObject.isAccessible()) { accessibleObject.setAccessible(true); } }
Stream计算BigDecimal
BigDecimal reduce = supplyPlanMatList.stream().map(SupplyPlanMat::getF_purch_num).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
年份周数转换工具类
/** * @author zhangzhixi * @version 1.0 * @description 年份周数转换工具类 * @date 2023-12-23 21:11 */ public class YearWeekUtil { /** * 获取当前周,例2023-W51 * * @return 当前日期的周 */ public static String getYearWeek() { LocalDate localDate = LocalDate.now(); int weekOfYear = localDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); int year = localDate.getYear(); return year + "-W" + weekOfYear; } /** * 获取当前周,例:2023 第 52 周 * * @return 当前日期的周 */ public static String getYearWeek2() { LocalDate localDate = LocalDate.now(); int weekOfYear = localDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); int year = localDate.getYear(); return year + " 第 " + weekOfYear + " 周"; } /** * 检查周份数据格式是否正确 */ public static void checkYearWeek(String yearWeek) { if (!yearWeek.matches("\\d{4}-W\\d{1,2}")) throw new SupplyException("周份数据格式错误"); } /** * 通过日期获取周 * * @param dateStr 日期字符串 * @return 周 */ public static String getYearWeekByDate(String dateStr) { LocalDate localDate = LocalDate.parse(dateStr); int weekOfYear = localDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); int year = localDate.getYear(); return year + "-W" + weekOfYear; } /** * 获取格式化后的周信息 * * @param yearWeek 周信息,例如:2023-W51 * @return 格式化后的周信息,例如:2023年12月第3周 */ public static String formatWeekDate(String yearWeek) { checkYearWeek(yearWeek); String[] split = yearWeek.split("-"); int year = Integer.parseInt(split[0]); int week = Integer.parseInt(split[1].substring(1)); LocalDate startDate = getWeekStartDate(year, week); return getFormattedWeekInfo(startDate); } /** * 根据年份和周数获取周的开始日期 * * @param year 年份 * @param weekOfYear 周数 * @return 周的开始日期 */ private static LocalDate getWeekStartDate(int year, int weekOfYear) { return LocalDate.ofYearDay(year, (weekOfYear - 1) * 7 + 1) .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); } /** * 根据日期获取格式化的周信息 * * @param startDate 日期 * @return 格式化的周信息 */ private static String getFormattedWeekInfo(LocalDate startDate) { int weekOfMonth = startDate.get(WeekFields.of(Locale.getDefault()).weekOfMonth()); return String.format("%s年%s月第%d周", startDate.getYear(), startDate.getMonth().getValue(), weekOfMonth); } }
AOP打印方法入参及返回值
@Component @Aspect @Slf4j public class AspectConfig { @Around("@within(org.springframework.web.bind.annotation.RestController)" + "||@within(org.springframework.stereotype.Controller)") public Object after(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = requestAttributes.getRequest(); log.info("请求地址:{}", request.getRequestURI()); log.info("请求方式:{}", request.getMethod()); log.info("请求类方法:{}", joinPoint.getSignature()); log.info("请求类方法参数:{}", JSONUtil.toJsonStr(filterArgs(joinPoint.getArgs()))); long start = System.currentTimeMillis(); Object result = joinPoint.proceed(joinPoint.getArgs()); log.info("请求响应参数:{}", JSONUtil.toJsonStr(result)); long end = System.currentTimeMillis(); log.info("执行耗时:{}", end - start + "ms"); log.info(""); return result; } private List<Object> filterArgs(Object[] objects) { return Arrays.stream(objects).filter(obj -> !(obj instanceof MultipartFile) && !(obj instanceof HttpServletResponse) && !(obj instanceof HttpServletRequest)).collect(Collectors.toList()); } }
消除Jackson使用抛出的异常
import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.boot.json.JsonParseException; import java.util.concurrent.Callable; /** * @author zhangzhixi * @version 1.0 * @description Jackson工具类:https://www.zhihu.com/question/501897937/answer/3374600944 * @date 2024-01-25 9:16 */ class JacksonUtil { private JacksonUtil() { } /** * Jackson ObjectMapper */ private static final ObjectMapper OBJECT_MAPPER; static { OBJECT_MAPPER = new ObjectMapper(); } public static <T> T tryParse(Callable<T> parser) { return tryParse(parser, JacksonException.class); } public static <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) { try { return parser.call(); } catch (Exception ex) { if (check.isAssignableFrom(ex.getClass())) { throw new JsonParseException(ex); } throw new IllegalStateException(ex); } } /** * 将对象转换为JSON字符串 * * @param obj 对象 * @return JSON字符串 */ public static String writeValueAsString(Object obj) { return tryParse(() -> OBJECT_MAPPER.writeValueAsString(obj)); } }
使用Stream流对数组进行判断名称是否重复
public static List<String> checkFileNamesUsingStream(MultipartFile[] uploadFiles) { if (uploadFiles == null || uploadFiles.length == 0) { return Collections.emptyList(); } Map<String, Long> fileNameCounts = Arrays.stream(uploadFiles) .map(MultipartFile::getOriginalFilename) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); return fileNameCounts.entrySet().stream() .filter(entry -> entry.getValue() > 1) .map(Map.Entry::getKey) .toList(); } public static void main(String[] args) { List<String> checkFileNamesUsingStream = checkFileNamesUsingStream(new MultipartFile[0]); if (checkFileNamesUsingStream != null && !checkFileNamesUsingStream.isEmpty()) { System.out.println("文件名重复:" + checkFileNamesUsingStream); } }