Browse Source

Merge branch 'develop-v3.0.0' of http://39.106.8.246:3003/FM-dev/fm-basics into develop-v3.0.0

lijie 3 years ago
parent
commit
794c0fba69
21 changed files with 1623 additions and 23 deletions
  1. 0 5
      fm-common/src/main/java/com/persagy/fm/common/config/FeignExceptionHandler.java
  2. 24 16
      fm-common/src/main/java/com/persagy/fm/common/constant/RegexConstants.java
  3. 615 0
      fm-common/src/main/java/com/persagy/fm/common/lang/PsDate.java
  4. 326 0
      fm-common/src/main/java/com/persagy/fm/common/lang/PsDateTime.java
  5. 271 0
      fm-common/src/main/java/com/persagy/fm/common/lang/PsTime.java
  6. 14 0
      fm-common/src/main/java/com/persagy/fm/common/model/vo/DuplicateVO.java
  7. 2 0
      fm-common/src/main/java/com/persagy/fm/common/model/vo/EnumVO.java
  8. 6 0
      fm-common/src/main/java/com/persagy/fm/common/model/vo/SimpleObjVO.java
  9. 23 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateDeserializer.java
  10. 22 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateSerializer.java
  11. 23 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateTimeDeserializer.java
  12. 22 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateTimeSerializer.java
  13. 24 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsTimeDeserializer.java
  14. 22 0
      fm-common/src/main/java/com/persagy/fm/common/serializer/PsTimeSerializer.java
  15. 74 0
      fm-common/src/main/java/com/persagy/fm/common/utils/ListUtil.java
  16. 10 0
      fm-common/src/main/java/com/persagy/fm/common/utils/ResultHelper.java
  17. 7 0
      fm-mybatis/README.md
  18. 46 0
      fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsDateTimeTypeHandler.java
  19. 46 0
      fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsDateTypeHandler.java
  20. 46 0
      fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsTimeTypeHandler.java
  21. 0 2
      fm-server/src/main/java/com/persagy/ServerApplication.java

+ 0 - 5
fm-common/src/main/java/com/persagy/fm/common/config/FeignExceptionHandler.java

@@ -51,9 +51,4 @@ public class FeignExceptionHandler {
             throw new RpcException(resultMsg);
         }
     }
-
-    @Before("pointCutMethod()")
-    public void test() {
-        System.out.println("test test test");
-    }
 }

+ 24 - 16
fm-common/src/main/java/com/persagy/fm/common/constant/RegexConstants.java

@@ -8,32 +8,35 @@ package com.persagy.fm.common.constant;
  **/
 public class RegexConstants {
     /**
+     * 空字符串正则表达式
+     */
+    private static final String BLANK_REGEX = "^$";
+    /**
      * 中文正则表达式
      */
-    public static final String CH_REGEX = "[\u4e00-\u9fa5]";
+    private static final String CH_REGEX = "[\u4e00-\u9fa5]";
     /**
      * 小写字母正则表达式
      */
-    public static final String LOWERCASE_REGEX = "[a-z]";
+    private static final String LOWERCASE_REGEX = "[a-z]";
     /**
      * 大写字母正则表达式
      */
-    public static final String UPPERCASE_REGEX = "[A-Z]";
-
+    private static final String UPPERCASE_REGEX = "[A-Z]";
     /**
      * 数字正则表达式
      */
-    public static final String NUM_REGEX = "[0-9]";
+    private static final String NUM_REGEX = "[0-9]";
     /**
-     * 允许的字符正则表达式
+     * 允许的特殊字符正则表达式
      */
-    public static final String CHAR_REGEX = "['._#~]";
+    private static final String CHAR_REGEX = "['._#~]";
 
-    public static final String EN_REGEX_EXPRESSION = LOWERCASE_REGEX + "|" + UPPERCASE_REGEX;
-    public static final String EN_NUM_REGEX_EXPRESSION = EN_REGEX_EXPRESSION + "|" + NUM_REGEX;
-    public static final String EN_NUM_CHAR_REGEX_EXPRESSION = EN_NUM_REGEX_EXPRESSION + "|" + CHAR_REGEX;
-    public static final String NAME_REGEX_EXPRESSION = EN_NUM_CHAR_REGEX_EXPRESSION + "|" + CH_REGEX;
-    public static final String TEXT_REGEX_EXPRESSION = CH_REGEX + "|" + EN_REGEX_EXPRESSION;
+    private static final String EN_REGEX_EXPRESSION = LOWERCASE_REGEX + "|" + UPPERCASE_REGEX;
+    private static final String EN_NUM_REGEX_EXPRESSION = EN_REGEX_EXPRESSION + "|" + NUM_REGEX;
+    private static final String EN_NUM_CHAR_REGEX_EXPRESSION = EN_NUM_REGEX_EXPRESSION + "|" + CHAR_REGEX;
+    private static final String NAME_REGEX_EXPRESSION = EN_NUM_CHAR_REGEX_EXPRESSION + "|" + CH_REGEX;
+    private static final String TEXT_REGEX_EXPRESSION = CH_REGEX + "|" + EN_REGEX_EXPRESSION;
 
     /**
      * 允许的字符正则表达式报警信息
@@ -68,7 +71,12 @@ public class RegexConstants {
      * 支持数字和字母
      */
     public static final String EN_NUM_REGEX = "(" + EN_NUM_REGEX_EXPRESSION + ")+";
-    ;
+
+    /**
+     * 英文或空字符串正则表达式
+     * 支持数字和字母和空字符串
+     */
+    public static final String EN_NUM_BLANK_REGEX = "(" + BLANK_REGEX + "|" + EN_NUM_REGEX_EXPRESSION + ")+";
     /**
      * 英文正则表达式报警信息
      */
@@ -92,9 +100,8 @@ public class RegexConstants {
     /**
      * 身份证正则表达式
      */
-    public static final String ID_CARD_REGEX = "( ^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|" +
-            "(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
-            "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{2}$)";
+    public static final String ID_CARD_REGEX = "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)";
+    public static final String ID_CARD_OR_BLANK_REGEX = "(" +BLANK_REGEX + "|" + ID_CARD_REGEX + ")";
 
     /**
      * 身份证非法提示
@@ -105,6 +112,7 @@ public class RegexConstants {
      * 手机号正则表达式
      */
     public static final String PHONE_REGEX = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\\d{8}$";
+    public static final String PHONE_OR_BLANK_REGEX = "(" +BLANK_REGEX + "|" + PHONE_REGEX + ")";
 
     /**
      * 手机号非法提示

+ 615 - 0
fm-common/src/main/java/com/persagy/fm/common/lang/PsDate.java

@@ -0,0 +1,615 @@
+package com.persagy.fm.common.lang;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * 自定日期类,用于转化表示日期串,日期对象等
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+public class PsDate implements Serializable, Comparable<PsDate>, Cloneable {
+
+    /** 序列id */
+    private static final long serialVersionUID = 5668159214884319312L;
+
+    /** 默认的日期格式化对象 */
+    public static DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+    /** 默认时区 */
+    public static ZoneId DEFAULT_ZONE_ID = ZoneId.of(ZoneId.SHORT_IDS.get("CTT"));
+
+    /*日期时间常量*/
+    /** 一天毫秒数 */
+    public static final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
+    /** 一小时毫秒数 */
+    public static final int MILLIS_PER_HOUR = 60 * 60 * 1000;
+    /** 一分钟毫秒数 */
+    public static final int MILLIS_PER_MINUTE = 60 * 1000;
+    /** 一秒毫秒数 */
+    public static final int MILLIS_PER_SECOND = 1000;
+
+    /** 保存时间的日期对象 */
+    protected Calendar calendar = null;
+
+    /**
+     * 自定义日期无参构造方法。
+     */
+    public PsDate() {
+        calendar = Calendar.getInstance();
+        init();
+    }
+
+    /**
+     * 通过毫秒数来构造自定义日期对象
+     * (以从1970年1月1日0时0分0秒到现在的毫秒数来构造日期)
+     * @param millis 毫秒数
+     */
+    public PsDate(long millis) {
+        this();
+        setMillis(millis);
+    }
+
+    /**
+     * 通过日期对象构造自定义日期对象
+     * @param date 日期对象
+     */
+    public PsDate(Date date) {
+        this();
+        setDate(date);
+    }
+
+    /**
+     * 通过默认形式日期串构造自定义日期对象
+     * @param date 默认格式日期串
+     */
+    public PsDate(String date) {
+        this(date, DEFAULT_FORMAT);
+    }
+
+    /**
+     * 通过默认形式日期串构造自定义日期对象
+     * @param date   默认格式日期串
+     * @param format 格式化串
+     */
+    public PsDate(String date, String format) {
+        this();
+        DateTimeFormatter dateFormat = null;
+        if (format != null) {
+            dateFormat = DateTimeFormatter.ofPattern(format);
+        }
+        parse(date, dateFormat);
+    }
+
+    /**
+     * 通过日期串和指定的格式化对象构造自定义日期对象
+     * @param date       符合格式化对象的日期时间对象
+     * @param dateFormat 格式化对象
+     */
+    public PsDate(String date, DateTimeFormatter dateFormat) {
+        this();
+        parse(date, dateFormat);
+    }
+
+    /**
+     * 按指定日期形式解析日期字符串
+     * @param date       日期字符串
+     * @param dateFormat 日期形式
+     */
+    protected void parse(String date, DateTimeFormatter dateFormat) {
+        if (StringUtils.isEmpty(date)) {
+            return;
+        }
+        if (dateFormat == null) {
+            dateFormat = DEFAULT_FORMAT;
+        }
+        LocalDate localDate = LocalDate.parse(date, dateFormat);
+        setDate(Date.from(localDate.atStartOfDay().toInstant(ZoneOffset.UTC)));
+    }
+
+    /**
+     * 设置指定时间属性的值
+     * @param field 时间属性
+     * @param value 时间属性的值
+     */
+    public void set(int field, int value) {
+        calendar.set(field, value);
+    }
+
+    /**
+     * 取得定时间属性的值
+     * @param field 时间属性
+     * @return 定时间属性的值
+     */
+    public int get(int field) {
+        return calendar.get(field);
+    }
+
+    /**
+     * 初始方法
+     */
+    protected void init() {
+        set(Calendar.HOUR_OF_DAY, 0);
+        set(Calendar.MINUTE, 0);
+        set(Calendar.SECOND, 0);
+        set(Calendar.MILLISECOND, 0);
+    }
+
+    /**
+     * 根据对象构建自定义日期对象
+     * @param obj 对象
+     * @return 自定义日期对象
+     */
+    public static PsDate parsePsDate(Object obj) {
+        if (obj == null || "".equals(obj.toString().trim())) {
+            return null;
+        }
+        if (obj instanceof PsDate) {
+            return new PsDate(((PsDate) obj).getMillis());
+        }
+
+        if (obj instanceof Date) {
+            return new PsDate((Date) obj);
+        }
+        if (obj instanceof Integer) {
+            return new PsDate(((Number) obj).longValue() * 1000);
+        }
+        if (obj instanceof Number) {
+            return new PsDate(((Number) obj).longValue());
+        }
+        // 目前存储的格式,都是数字,兼容时间戳会误判,暂不这样处理了
+//        if (NumberUtils.isCreatable(obj.toString())) {
+//            return new PsDate(NumberUtils.toLong(obj.toString()));
+//        }
+        return new PsDate(obj.toString());
+
+    }
+
+    /**
+     * 设置日期对象的时间
+     * @param date 日期对象
+     */
+    public void setDate(Date date) {
+        calendar.setTime(date);
+        init();
+    }
+
+    /**
+     * 取得当前日期所表示的java日期对象
+     * @return java日期对象
+     */
+    public Date getDate() {
+        return calendar.getTime();
+    }
+
+    /**
+     * 设置日期对象的时间
+     * @param millis 日期对象
+     */
+    public void setMillis(long millis) {
+        calendar.setTimeInMillis(millis);
+        init();
+    }
+
+    /**
+     * 取得日期对象的毫秒数
+     * @return 毫秒数
+     */
+    public long getMillis() {
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * 比较日期先后,对象日期在参数日期之后为true
+     * @param when 比较的日期的对象
+     * @return 布尔值
+     */
+    public boolean after(PsDate when) {
+        return compareTo(when) > 0;
+    }
+
+    /**
+     * 比较日期先后,对象日期在参数日期之前为true
+     * @param when 比较的日期的对象
+     * @return 布尔值
+     */
+    public boolean before(PsDate when) {
+        return compareTo(when) < 0;
+    }
+
+    /**
+     * 返回指定天数之后的自定义日期对象
+     * @param days 指定的天数
+     * @return 自定义日期对象
+     */
+    public PsDate getDateAfter(int days) {
+        long millis = getMillis() + MILLIS_PER_DAY * days;
+        return new PsDate(millis);
+    }
+
+    /**
+     * 返回指定天数之前的自定义日期对象
+     * @param days 指定的天数
+     * @return 自定义日期对象
+     */
+    public PsDate getDateBefore(int days) {
+        return getDateAfter(-days);
+    }
+
+    /**
+     * 取得当前日期对象在指定的日期对象之后多少天
+     * @param when 要比较的自定义对象
+     * @return 在比较的自定义对象之后多少天
+     */
+    public int getDaysAfter(PsDate when) {
+        return getDaysBetween(when, this);
+    }
+
+    /**
+     * 取得开始日期到结束日期直接相差多少天
+     * @param begin 开始日期
+     * @param end   结束日期
+     * @return 相差天数
+     */
+    public static int getDaysBetween(PsDate begin, PsDate end) {
+        int days = 0;
+        if (begin != null && end != null) {
+            PsDate e = new PsDate(end.getMillis());
+            PsDate b = new PsDate(begin.getMillis());
+            days = (int) (e.getMillis() / MILLIS_PER_DAY - b.getMillis() / MILLIS_PER_DAY);
+        }
+        return days;
+    }
+
+    /**
+     * 格式化时间数字串为两位
+     * @param number 数字
+     * @return 数字串
+     */
+    public String formatNumber(int number) {
+        return number < 10 ? "0" + number : Integer.toString(number);
+    }
+
+    /**
+     * 取得日期对象中的日
+     * @return 天数
+     */
+    public int getDay() {
+        return get(Calendar.DATE);
+    }
+
+    /**
+     * 取得日期对象中的日串
+     * @return 天数串(两位)
+     */
+    public String getDAY() {
+        return formatNumber(getDay());
+    }
+
+    /**
+     * 取得日期对象的月份
+     * @return
+     */
+    public int getMonth() {
+        return get(Calendar.MONTH);
+    }
+
+    /**
+     * 取得日期对象的月份串(两位)
+     * @return 月份串(两位)
+     */
+    public String getMONTH() {
+        return formatNumber(getMonth() + 1);
+    }
+
+    /**
+     * 取得当前日期对象所在月的英文写法
+     * @return 月的英文串
+     */
+    public String getEnMonth() {
+        switch (getMonth()) {
+            case 1:
+                return "Jan";
+            case 2:
+                return "Feb";
+            case 3:
+                return "Mar";
+            case 4:
+                return "Apr";
+            case 5:
+                return "May";
+            case 6:
+                return "Jun";
+            case 7:
+                return "Jul";
+            case 8:
+                return "Aug";
+            case 9:
+                return "Sep";
+            case 10:
+                return "Oct";
+            case 11:
+                return "Nov";
+            case 12:
+                return "Dec";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 取得日期对象的年份
+     * @return 年份串
+     */
+    public int getYear() {
+        return get(Calendar.YEAR);
+    }
+
+    /**
+     * 取得年字符串
+     * @return 年字符串
+     */
+    public String getYEAR() {
+        return Integer.toString(getYear());
+    }
+
+
+    /**
+     * 取得当前日期对象的星期表示
+     * @return 星期表示
+     */
+    public int getWeek() {
+        return get(Calendar.DAY_OF_WEEK);
+    }
+
+    /**
+     * 取得当前日期对象的星期中文简单表示
+     * @return 星期中文简单表示
+     */
+    public String getSimpleZhWeek() {
+        switch (getWeek()) {
+            case 1:
+                return "日";
+            case 2:
+                return "一";
+            case 3:
+                return "二";
+            case 4:
+                return "三";
+            case 5:
+                return "四";
+            case 6:
+                return "五";
+            case 7:
+                return "六";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 取得当前日期对象的星期英文表示
+     * @return 星期英文表示
+     */
+    public String getZhWeek() {
+        switch (getWeek()) {
+            case 1:
+                return "星期日";
+            case 2:
+                return "星期一";
+            case 3:
+                return "星期二";
+            case 4:
+                return "星期三";
+            case 5:
+                return "星期四";
+            case 6:
+                return "星期五";
+            case 7:
+                return "星期六";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 取得当前日期对象的星期英文表示
+     * @return 星期英文表示
+     */
+    public String getEnWeek() {
+        switch (getWeek()) {
+            case 1:
+                return "Sunday";
+            case 2:
+                return "Monday";
+            case 3:
+                return "Tuesday";
+            case 4:
+                return "Wednesday";
+            case 5:
+                return "Thursday";
+            case 6:
+                return "Friday";
+            case 7:
+                return "Saturday";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * 取得当前日期对象的星期英文简单表示
+     * @return 星期英文简单表示
+     */
+    public String getSimpleEnWeek() {
+        switch (getWeek()) {
+            case 1:
+                return "Sun";
+            case 2:
+                return "Mon";
+            case 3:
+                return "Tue";
+            case 4:
+                return "Wed";
+            case 5:
+                return "Thu";
+            case 6:
+                return "Fri";
+            case 7:
+                return "Sat";
+            default:
+                return null;
+        }
+    }
+
+
+    /**
+     * 判断当前日期所在是否是闰年
+     * @return 布尔值
+     */
+    public boolean isLeapYear() {
+        return isLeapYear(getYear());
+    }
+
+    /**
+     * 判断指定年是否是闰年
+     * @param year  指定的年
+     * @return 布尔值
+     */
+    public static boolean isLeapYear(int year) {
+        return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
+    }
+
+    /**
+     * 取得当前日期对象所在月有多少天
+     * @return 天数
+     */
+    public int getDaysInMonth() {
+        return getDaysMonth(getYear(), getMonth());
+    }
+
+    /**
+     * 取得指定的年月里一个月有多少天
+     * @param year  指定的年
+     * @param month 指定的月
+     * @return 天数
+     */
+    public static int getDaysMonth(int year, int month) {
+        switch (month) {
+            case 1:
+            case 3:
+            case 5:
+            case 7:
+            case 8:
+            case 10:
+            case 12:
+                return 31;
+            case 2:
+                if (isLeapYear(year)) {
+                    return 29;
+                } else {
+                    return 28;
+                }
+            default:
+                return 30;
+        }
+    }
+
+    /**
+     * 取得当前日期所在年包含的周数
+     * @return 年包含的周数
+     */
+    public int getWeekOfYear() {
+        return get(Calendar.WEEK_OF_YEAR);
+    }
+
+    /**
+     * 用默认的格式化串转化日期
+     * @see Object#toString()
+     */
+    @Override
+    public String toString() {
+        return toString(DEFAULT_FORMAT);
+    }
+
+    /**
+     * 用指定的格式化串,格式化日期对象为日期串
+     * @param format 格式化串
+     * @return 格式化后的日期串
+     */
+    public String toString(String format) {
+        if (format == null) {
+            return toString();
+        }
+        DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(format);
+        return toString(dateFormat);
+    }
+
+    /**
+     * 用指定的格式化对象,格式化日期对象为日期串
+     * @param dateFormat 指定的格式化对象
+     * @return 格式化后的日期串
+     */
+    public String toString(DateTimeFormatter dateFormat) {
+        if (dateFormat == null) {
+            return toString();
+        }
+        return dateFormat.format(getDate().toInstant().atZone(PsDate.DEFAULT_ZONE_ID).toLocalDate());
+    }
+
+    /**
+     * 实现比较接口方法
+     * @see Comparable#compareTo(Object)
+     */
+    @Override
+    public int compareTo(PsDate psDate) {
+        return calendar.compareTo(psDate.calendar);
+    }
+
+    /**
+     * 比较日期是否相等
+     * @param o 比较的对象
+     * @return 布尔值
+     */
+    @Override
+    public boolean equals(Object o) {
+        if ((o != null) && (o instanceof PsDate)) {
+            return this.getMillis() == ((PsDate) o).getMillis();
+        }
+        return false;
+    }
+
+    /**
+     * 克隆日期对象。
+     * @see Object#clone()
+     */
+    @Override
+    public Object clone() {
+        PsDate psDate;
+        try {
+            psDate = (PsDate) super.clone();
+        } catch (CloneNotSupportedException e) {
+            return new PsDate(getMillis());
+        }
+        psDate.calendar = (Calendar) calendar.clone();
+        return psDate;
+    }
+
+    /**
+     * 取得对象的hashCode
+     * @see Date#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return calendar.hashCode();
+    }
+
+}

+ 326 - 0
fm-common/src/main/java/com/persagy/fm/common/lang/PsDateTime.java

@@ -0,0 +1,326 @@
+package com.persagy.fm.common.lang;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * 自定日期时间类,用于转化表示日期时间串等
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+public class PsDateTime extends PsDate implements Comparable<PsDate> {
+    /** 序列化id */
+    private static final long serialVersionUID = 7280791980952901691L;
+
+    /** 日期格式化对象 */
+    public static DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+    /** 自定义日期时间无参构造方法。 */
+    public PsDateTime() {
+        super();
+    }
+
+    /**
+     * 通过毫秒数构造自定义日期时间对象
+     * (以从1970年1月1日0时0分0秒到现在的毫秒数来构造日期)
+     * @param millis 毫秒数
+     */
+    public PsDateTime(long millis) {
+        super(millis);
+    }
+
+    /**
+     * 通过日期对象构造自定义日期时间对象
+     * @param date 日期对象
+     */
+    public PsDateTime(Date date) {
+        super(date);
+    }
+
+    /**
+     * 通过自定义日期对象构造自定义日期时间对象
+     * @param date 日期对象
+     */
+    public PsDateTime(PsDate date) {
+        super(date.getMillis());
+    }
+
+    /**
+     * 通过自定义日期对象和时间对象构造自定义日期时间对象
+     * @param date 日期对象
+     */
+    public PsDateTime(PsDate date, PsTime time) {
+        super(date.getMillis() + time.getMillis());
+    }
+
+    /**
+     * 通过默认形式日期串构造自定义日期对象
+     * @param date 默认格式日期串
+     */
+    public PsDateTime(String date) {
+        super(date, DEFAULT_FORMAT);
+    }
+
+    /**
+     * 通过日期串和指定的格式化串构造自定义日期时间对象
+     * @param date   符合格式串的日期时间对象
+     * @param format 日期格式化串
+     */
+    public PsDateTime(String date, String format) {
+        super(date, format);
+    }
+
+    /**
+     * 通过日期串和指定的格式化对象构造自定义日期时间对象
+     * @param date       符合格式化对象的日期时间对象
+     * @param dateFormat 格式化对象
+     */
+    public PsDateTime(String date, DateTimeFormatter dateFormat) {
+        super(date, dateFormat);
+    }
+
+
+    /**
+     * 用日期对象初始化对象
+     */
+    @Override
+    protected void init() {
+        set(Calendar.MILLISECOND, 0);
+    }
+
+    @Override
+    protected void parse(String date, DateTimeFormatter dateFormat) {
+        if (StringUtils.isEmpty(date)) {
+            return;
+        }
+        if (dateFormat == null) {
+            dateFormat = DEFAULT_FORMAT;
+        }
+        LocalDateTime localDate = LocalDateTime.parse(date, dateFormat);
+        ZonedDateTime zdt = localDate.atZone(PsDate.DEFAULT_ZONE_ID);
+        setDate(Date.from(zdt.toInstant()));
+    }
+
+    /**
+     * 根据对象构建自定义日期时间对象
+     * @param obj 对象
+     * @return 自定义日期时间对象
+     */
+    public static PsDateTime parsePsDateTime(Object obj) {
+        if (obj == null || "".equals(obj.toString())) {
+            return null;
+        }
+        if (obj instanceof PsDate) {
+            return new PsDateTime(((PsDate) obj).getMillis());
+        }
+
+        if (obj instanceof Date) {
+            return new PsDateTime((Date) obj);
+        }
+        if (obj instanceof Integer) {
+            return new PsDateTime(((Integer) obj).longValue() * 1000);
+        }
+        if (obj instanceof Number) {
+            return new PsDateTime(((Number) obj).longValue());
+        }
+//        if (NumberUtils.isCreatable(obj.toString())) {
+//            return new PsDateTime(NumberUtils.toLong(obj.toString()));
+//        }
+        return new PsDateTime(obj.toString());
+
+    }
+
+    /**
+     * 取得自定义日期时间对象中的自定义日期对象
+     * @return 自定义日期对象
+     */
+    public PsDate getDDate() {
+        return new PsDate(getMillis());
+    }
+
+    /**
+     * 取得自定义日期时间对象中的自定义时间对象
+     * @return 自定义时间对象
+     */
+    public PsTime getDTime() {
+        return new PsTime(getMillis());
+    }
+
+    /**
+     * 返回指定天数之后的自定义日期时间对象
+     */
+    @Override
+    public PsDateTime getDateAfter(int days) {
+        return new PsDateTime(getMillis() + MILLIS_PER_DAY * days);
+    }
+
+    /**
+     * 返回指定天数之前的自定义日期时间对象
+     */
+    @Override
+    public PsDateTime getDateBefore(int days) {
+        return getDateAfter(-days);
+    }
+
+    /**
+     * 取得两个日期时间对象相差的小时数
+     * @param begin 开始日期时间
+     * @param end   结束日期时间
+     * @return 小时数
+     */
+    public static int getHoursBetween(PsDateTime begin, PsDateTime end) {
+        return (int) (end.getMillis() / PsDate.MILLIS_PER_HOUR - begin.getMillis() / PsDate.MILLIS_PER_HOUR);
+    }
+
+    /**
+     * 取得两个日期时间对象相差的分钟数
+     * @param begin 开始日期时间
+     * @param end   结束日期时间
+     * @return 分钟数
+     */
+    public static int getMinutesBetween(PsDateTime begin, PsDateTime end) {
+        return (int) (end.getMillis() / PsDate.MILLIS_PER_MINUTE - begin.getMillis() / PsDate.MILLIS_PER_MINUTE);
+    }
+
+    /**
+     * 取得两个日期时间对象相差的秒数
+     * @param begin 开始日期时间
+     * @param end   结束日期时间
+     * @return 秒数
+     */
+    public static int getSecondsBetween(PsDateTime begin, PsDateTime end) {
+        return (int) (end.getMillis() / PsDate.MILLIS_PER_SECOND - begin.getMillis() / PsDate.MILLIS_PER_SECOND);
+    }
+
+    /**
+     * 取得两个日期时间对象相差的毫秒数
+     * @param begin 开始日期时间
+     * @param end   结束日期时间
+     * @return 毫秒数
+     */
+    private static long getMillisBetween(PsDateTime begin, PsDateTime end) {
+        if (begin == null || end == null) {
+            return 0;
+        }
+        return end.getMillis() - begin.getMillis();
+    }
+
+    /**
+     * 取得当前日期时间对象在指定的日期时间对象之后多少毫秒
+     * @param dateTime 要比较的自定义日期时间
+     * @return 当前时间在给定日期时间
+     */
+    public long getMillisAfter(PsDateTime dateTime) {
+        return getMillisBetween(dateTime, this);
+    }
+
+    /**
+     * 取得小时数
+     * @return 小时数
+     */
+    public int getHour() {
+        return get(Calendar.HOUR_OF_DAY);
+    }
+
+    /**
+     * 取得小时数字符串
+     * @return 小时数字符串
+     */
+    public String getHOUR() {
+        return formatNumber(getHour());
+    }
+
+    /**
+     * 取得分钟数
+     * @return 分钟数
+     */
+    public int getMinute() {
+        return get(Calendar.MINUTE);
+    }
+
+    /**
+     * 取得分钟数字符串
+     * @return 分钟数字符串
+     */
+    public String getMINUTE() {
+        return formatNumber(getMinute());
+    }
+
+    /**
+     * 取得秒数
+     * @return 秒数
+     */
+    public int getSecond() {
+        return get(Calendar.SECOND);
+    }
+
+    /**
+     * 取得秒数字符串
+     * @return 秒数字符串
+     */
+    public String getSECOND() {
+        return formatNumber(getSecond());
+    }
+
+    /**
+     * 取得毫秒数
+     * @return 毫秒数
+     */
+    public int getMilliSecond() {
+        return get(Calendar.MILLISECOND);
+    }
+
+    /**
+     * 取得毫秒数串
+     * @return 毫秒数串
+     */
+    public String getMILLISECOND() {
+        int ms = getMilliSecond();
+        return Integer.toString(ms + 1000).substring(1);
+    }
+
+    /**
+     * 实现比较接口方法
+     * @see Comparable#compareTo(Object)
+     */
+    @Override
+    public int compareTo(PsDate psDate) {
+        return calendar.compareTo(psDate.calendar);
+    }
+
+    /**
+     * 比较日期是否相等
+     * @param o 比较的对象
+     * @return 布尔值
+     */
+    @Override
+    public boolean equals(Object o) {
+        if ((o != null) && (o instanceof PsDate)) {
+            return this.getMillis() == ((PsDate) o).getMillis();
+        }
+        return false;
+    }
+
+    /**
+     * 用默认的格式化串转化日期时间
+     * @see Object#toString()
+     */
+    @Override
+    public String toString() {
+        return toString(DEFAULT_FORMAT);
+    }
+
+    @Override
+    public String toString(DateTimeFormatter dateFormat) {
+        if (dateFormat == null) {
+            return toString();
+        }
+        return dateFormat.format(getDate().toInstant().atZone(PsDate.DEFAULT_ZONE_ID));
+    }
+}

+ 271 - 0
fm-common/src/main/java/com/persagy/fm/common/lang/PsTime.java

@@ -0,0 +1,271 @@
+package com.persagy.fm.common.lang;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * 自定时间类,用于转化表示时间串等
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+public class PsTime extends PsDate {
+    /** 序列化id */
+    private static final long serialVersionUID = 733417362967334525L;
+
+    /** 时间格式化对象 */
+    public static DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("HHmmss");
+
+    /**
+     * 自定义时间无参构造方法。
+     */
+    public PsTime() {
+        super();
+    }
+
+    /**
+     * 通过毫秒数构造自定义时间对象
+     * (以从1970年1月1日0时0分0秒到现在的毫秒数来构造日期)
+     * @param millis 毫秒数
+     */
+    public PsTime(long millis) {
+        super(millis);
+    }
+
+    /**
+     * 通过日期对象构造自定义时间对象
+     *
+     * @param date 日期对象
+     */
+    public PsTime(Date date) {
+        super(date);
+    }
+
+    /**
+     * 通过默认形式时间串构造自定义时间对象
+     *
+     * @param time 默认格式日期串
+     */
+    public PsTime(String time) {
+        super(time, DEFAULT_FORMAT);
+    }
+
+    /**
+     * 通过时间串和指定的格式化串构造自定义时间对象
+     *
+     * @param time   符合格式串的时间对象
+     * @param format 时间格式化串
+     */
+    public PsTime(String time, String format) {
+        super(time, format);
+    }
+
+    /**
+     * 通过时间串和指定的格式化对象构造自定义时间对象
+     *
+     * @param time       符合格式化对象的时间对象
+     * @param timeFormat 格式化对象
+     */
+    public PsTime(String time, DateTimeFormatter timeFormat) {
+        super(time, timeFormat);
+    }
+
+    /**
+     * 根据对象构建自定义时间对象
+     * @param obj 对象
+     * @return 自定义时间对象
+     */
+    public static PsTime parsePsTime(Object obj) {
+        if (obj == null || "".equals(obj.toString().trim())) {
+            return null;
+        }
+        if (obj instanceof PsDate) {
+            return new PsTime(((PsDate) obj).getMillis());
+        }
+
+        if (obj instanceof Date) {
+            return new PsTime((Date) obj);
+        }
+        if (obj instanceof Integer) {
+            return new PsTime(((Integer) obj).longValue() * 1000);
+        }
+        if (obj instanceof Number) {
+            return new PsTime(((Number) obj).longValue());
+        }
+//        if (NumberUtils.isCreatable(obj.toString())) {
+//            return new PsTime(NumberUtils.toLong(obj.toString()));
+//        }
+        return new PsTime(obj.toString());
+    }
+
+    /**
+     * 用时间对象初始化对象
+     */
+    @Override
+    protected void init() {
+        set(Calendar.YEAR, 1970);
+        set(Calendar.MONTH, 1);
+        set(Calendar.DATE, 1);
+    }
+
+    @Override
+    protected void parse(String date, DateTimeFormatter dateFormat) {
+        if (StringUtils.isEmpty(date)) {
+            return;
+        }
+        if (dateFormat == null) {
+            dateFormat = DEFAULT_FORMAT;
+        }
+        LocalTime localDate = LocalTime.parse(date, dateFormat);
+        ZonedDateTime zdt = localDate.atDate(LocalDate.now()).atZone(PsDate.DEFAULT_ZONE_ID);
+        setDate(Date.from(zdt.toInstant()));
+    }
+
+    /**
+     * 比较时间先后,对象时间在参数时间之后为true
+     * @param when 比较的时间对象
+     * @return 布尔值
+     */
+    public boolean after(PsTime when) {
+        return compareTo(when) > 0;
+    }
+
+    /**
+     * 比较时间先后,对象时间在参数时间之前为true
+     * @param when 比较的时间对象
+     * @return 布尔值
+     */
+    public boolean before(PsTime when) {
+        return compareTo(when) < 0;
+    }
+
+    /**
+     * 比较日期先后,对象日期在参数日期之后为true
+     * @param when 比较的日期的对象
+     * @return 布尔值
+     * @deprecated
+     */
+    @Override
+    public boolean after(PsDate when) {
+        return getMillis() > 0;
+    }
+
+    /**
+     * 比较日期先后,对象日期在参数日期之前为true
+     * @param when 比较的日期的对象
+     * @return 布尔值
+     * @deprecated
+     */
+    @Override
+    public boolean before(PsDate when) {
+        return getMillis() < 0;
+    }
+
+    /**
+     * 返回指定天数之后的自定义日期对象
+     * @param days 指定的天数
+     * @return 自定义日期对象
+     * @deprecated
+     */
+    @Override
+    public PsDate getDateAfter(int days) {
+        return null;
+    }
+
+    /**
+     * 返回指定天数之前的自定义日期对象
+     * @param days 指定的天数
+     * @return 自定义日期对象
+     * @deprecated
+     */
+    @Override
+    public PsDate getDateBefore(int days) {
+        return getDateAfter(-days);
+    }
+
+    /**
+     * 取得当前日期对象在指定的日期对象之后多少天
+     * @param when 要比较的自定义对象
+     * @return 在比较的自定义对象之后多少天
+     * @deprecated
+     */
+    @Override
+    public int getDaysAfter(PsDate when) {
+        return 0;
+    }
+
+    /**
+     * 取得两个时间对象相差的小时数
+     * @param begin 开始时间
+     * @param end   结束时间
+     * @return 相差的小时整数
+     */
+    public static int getHoursBetween(PsTime begin, PsTime end) {
+        return (int) (getMilisBetween(begin, end) / MILLIS_PER_HOUR);
+    }
+
+    /**
+     * 取得两个时间对象相差的分钟数
+     * @param begin 开始时间
+     * @param end   结束时间
+     * @return 相差的分钟整数
+     */
+    public static int getMinutesBetween(PsTime begin, PsTime end) {
+        return (int) (getMilisBetween(begin, end) / MILLIS_PER_MINUTE);
+    }
+
+    /**
+     * 取得两个时间对象相差的秒数
+     * @param begin 开始时间
+     * @param end   结束时间
+     * @return 相差的秒整数
+     */
+    public static int getSecondsBetween(PsTime begin, PsTime end) {
+        return (int) (getMilisBetween(begin, end) / MILLIS_PER_SECOND);
+    }
+
+    /**
+     * 取得两个时间对象相差的毫秒数
+     * @param begin 开始时间
+     * @param end   结束时间
+     * @return 相差的毫秒整数
+     */
+    public static long getMilisBetween(PsTime begin, PsTime end) {
+        if (begin == null || end == null) {
+            return 0;
+        }
+        return end.getMillis() - begin.getMillis();
+    }
+
+    /**
+     * 取得当前时间对象在指定的时间对象之后多少毫秒
+     * @param time 要比较的自定义时间
+     * @return 当前时间在给定时间
+     */
+    public long getMillisAfter(PsTime time) {
+        return getMilisBetween(time, this);
+    }
+
+    /**
+     * 用默认的格式化串转化日期
+     * @see Object#toString()
+     */
+    @Override
+    public String toString() {
+        return toString(DEFAULT_FORMAT);
+    }
+
+    @Override
+    public String toString(DateTimeFormatter dateFormat) {
+        if (dateFormat == null) {
+            return toString();
+        }
+        return dateFormat.format(getDate().toInstant().atZone(PsDate.DEFAULT_ZONE_ID).toLocalTime());
+    }
+}

+ 14 - 0
fm-common/src/main/java/com/persagy/fm/common/model/vo/DuplicateVO.java

@@ -0,0 +1,14 @@
+package com.persagy.fm.common.model.vo;
+
+import lombok.Data;
+
+/**
+ * 校验是否重复vo
+ *
+ * @author lixing
+ * @version V1.0 2021/4/7 7:36 下午
+ **/
+@Data
+public class DuplicateVO {
+    private Boolean duplicate;
+}

+ 2 - 0
fm-common/src/main/java/com/persagy/fm/common/model/vo/EnumVO.java

@@ -1,5 +1,6 @@
 package com.persagy.fm.common.model.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import lombok.Data;
 import org.checkerframework.checker.units.qual.K;
 
@@ -10,6 +11,7 @@ import org.checkerframework.checker.units.qual.K;
  * @version V1.0 2021/3/12 6:24 下午
  **/
 @Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class EnumVO {
     private String key;
     private String value;

+ 6 - 0
fm-common/src/main/java/com/persagy/fm/common/model/vo/SimpleObjVO.java

@@ -1,6 +1,9 @@
 package com.persagy.fm.common.model.vo;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 /**
  * 简单对象vo类
@@ -9,6 +12,9 @@ import lombok.Data;
  * @version V1.0 2021/3/27 5:18 下午
  **/
 @Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class SimpleObjVO {
     private String id;
     private String name;

+ 23 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateDeserializer.java

@@ -0,0 +1,23 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.persagy.fm.common.lang.PsDate;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 日期反序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsDateDeserializer extends JsonDeserializer<PsDate> {
+    @Override
+    public PsDate deserialize(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
+        return PsDate.parsePsDate(p.getLongValue());
+    }
+}

+ 22 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateSerializer.java

@@ -0,0 +1,22 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.persagy.fm.common.lang.PsDate;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 日期序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsDateSerializer extends JsonSerializer<PsDate> {
+    @Override
+    public void serialize(PsDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeNumber(value.getMillis());
+    }
+}

+ 23 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateTimeDeserializer.java

@@ -0,0 +1,23 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.persagy.fm.common.lang.PsDateTime;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 时间反序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsDateTimeDeserializer extends JsonDeserializer<PsDateTime> {
+    @Override
+    public PsDateTime deserialize(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
+        return PsDateTime.parsePsDateTime(p.getLongValue());
+    }
+}

+ 22 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsDateTimeSerializer.java

@@ -0,0 +1,22 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.persagy.fm.common.lang.PsDateTime;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 时间序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsDateTimeSerializer extends JsonSerializer<PsDateTime> {
+    @Override
+    public void serialize(PsDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeNumber(value.getMillis());
+    }
+}

+ 24 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsTimeDeserializer.java

@@ -0,0 +1,24 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.persagy.fm.common.lang.PsTime;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 时间反序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsTimeDeserializer extends JsonDeserializer<PsTime> {
+
+    @Override
+    public PsTime deserialize(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
+        return PsTime.parsePsTime(p.getLongValue());
+    }
+}

+ 22 - 0
fm-common/src/main/java/com/persagy/fm/common/serializer/PsTimeSerializer.java

@@ -0,0 +1,22 @@
+package com.persagy.fm.common.serializer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.persagy.fm.common.lang.PsTime;
+import org.springframework.boot.jackson.JsonComponent;
+
+import java.io.IOException;
+
+/**
+ * @Description 时间序列化
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@JsonComponent
+public class PsTimeSerializer extends JsonSerializer<PsTime> {
+    @Override
+    public void serialize(PsTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+        gen.writeNumber(value.getMillis());
+    }
+}

+ 74 - 0
fm-common/src/main/java/com/persagy/fm/common/utils/ListUtil.java

@@ -0,0 +1,74 @@
+package com.persagy.fm.common.utils;
+
+import org.apache.poi.ss.formula.functions.T;
+import org.assertj.core.util.Lists;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * list工具类
+ *
+ * @author lixing
+ * @version V1.0 2021/4/6 10:52 上午
+ **/
+public class ListUtil {
+    /**
+     * 获取listAfter对比listBefore新增的元素
+     * 使用遍历进行对比,性能有待提升,不适合大数据量对比
+     *
+     * @param listBefore listBefore
+     * @param listAfter listAfter
+     * @return 新增的元素
+     * @author lixing
+     * @version V1.0 2021/4/6 10:58 上午
+     */
+    public static <T> List<T> getAddedList(List<T> listBefore, List<T> listAfter) {
+        if (CollectionUtils.isEmpty(listAfter)) {
+            return null;
+        }
+        if (CollectionUtils.isEmpty(listBefore)) {
+            return listAfter;
+        }
+
+        List<T> result = Lists.newArrayList();
+        listAfter.forEach(t -> {
+            // 如果listAfter中的元素不在listBefore中,认为是新增的元素
+            if (!listBefore.contains(t)) {
+                result.add(t);
+            }
+        });
+        return result;
+    }
+
+    /**
+     * 获取listAfter对比listBefore删除的元素
+     * 使用遍历进行对比,性能有待提升,不适合大数据量对比
+     *
+     * @param listBefore listBefore
+     * @param listAfter listAfter
+     * @return 删除的元素
+     * @author lixing
+     * @version V1.0 2021/4/6 10:58 上午
+     */
+    public static <T> List<T> getDeletedList(List<T> listBefore, List<T> listAfter) {
+        return getAddedList(listAfter, listBefore);
+    }
+
+    public static <T> Boolean listChanged(List<T> listBefore, List<T> listAfter) {
+        if (listBefore == null) {
+            return listAfter == null;
+        }
+        if (listAfter == null) {
+            return true;
+        }
+        return listBefore.retainAll(listAfter) || listAfter.retainAll(listBefore);
+    }
+
+//    public static void main(String[] args) {
+//        ArrayList<String> list1 = Lists.newArrayList("1", "2", "3");
+//        ArrayList<String> list2 = Lists.newArrayList("1", "2", "3");
+//        System.out.println(listChanged(list1, list2));
+//    }
+}

+ 10 - 0
fm-common/src/main/java/com/persagy/fm/common/utils/ResultHelper.java

@@ -52,6 +52,16 @@ public class ResultHelper {
     }
 
     /**
+     * 单个数据
+     * @param content
+     * @param <T>
+     * @return
+     */
+    public static <T> CommonResult<T> single(T content, String desc) {
+        return new CommonResult(ResponseCode.A00000.getCode(), desc, content);
+    }
+
+    /**
      * 多个数据 - 列表
      * @param records
      * @param <T>

+ 7 - 0
fm-mybatis/README.md

@@ -164,6 +164,13 @@ spring:
 树型内部码工具
 * 可对实现ITreeEntity的model自动生成innerCode内部码。
 	
+自定义日期类型转换
+* 全局处理日期类型转换char,需要增加配置
+  ```
+  mybatis-plus:
+    typeHandlersPackage: com.persagy.fm.mybatis.type
+  ```
+
 最新变化
 ---------------
 

+ 46 - 0
fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsDateTimeTypeHandler.java

@@ -0,0 +1,46 @@
+package com.persagy.fm.mybatis.type;
+
+import com.persagy.fm.common.lang.PsDateTime;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Mybatis日期时间全局处理
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@MappedJdbcTypes(JdbcType.CHAR)
+@MappedTypes(PsDateTime.class)
+public class PsDateTimeTypeHandler extends BaseTypeHandler<PsDateTime> {
+
+    @Override
+    public void setNonNullParameter(PreparedStatement preparedStatement, int i, PsDateTime psDateTime, JdbcType jdbcType) throws SQLException {
+        preparedStatement.setString(i, psDateTime.toString());
+    }
+
+    @Override
+    public PsDateTime getNullableResult(ResultSet resultSet, String s) throws SQLException {
+        String date = resultSet.getString(s);
+        return StringUtils.isBlank(date)? null:PsDateTime.parsePsDateTime(date);
+    }
+
+    @Override
+    public PsDateTime getNullableResult(ResultSet resultSet, int i) throws SQLException {
+        String date = resultSet.getString(i);
+        return StringUtils.isBlank(date)? null:PsDateTime.parsePsDateTime(date);
+    }
+
+    @Override
+    public PsDateTime getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
+        String date = callableStatement.getString(i);
+        return StringUtils.isBlank(date)? null:PsDateTime.parsePsDateTime(date);
+    }
+}

+ 46 - 0
fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsDateTypeHandler.java

@@ -0,0 +1,46 @@
+package com.persagy.fm.mybatis.type;
+
+import com.persagy.fm.common.lang.PsDate;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Mybatis日期全局处理
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@MappedJdbcTypes(JdbcType.CHAR)
+@MappedTypes(PsDate.class)
+public class PsDateTypeHandler extends BaseTypeHandler<PsDate> {
+
+    @Override
+    public void setNonNullParameter(PreparedStatement preparedStatement, int i, PsDate psDate, JdbcType jdbcType) throws SQLException {
+        preparedStatement.setString(i, psDate.toString());
+    }
+
+    @Override
+    public PsDate getNullableResult(ResultSet resultSet, String s) throws SQLException {
+        String date = resultSet.getString(s);
+        return StringUtils.isBlank(date)? null:PsDate.parsePsDate(date);
+    }
+
+    @Override
+    public PsDate getNullableResult(ResultSet resultSet, int i) throws SQLException {
+        String date = resultSet.getString(i);
+        return StringUtils.isBlank(date)? null:PsDate.parsePsDate(date);
+    }
+
+    @Override
+    public PsDate getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
+        String date = callableStatement.getString(i);
+        return StringUtils.isBlank(date)? null:PsDate.parsePsDate(date);
+    }
+}

+ 46 - 0
fm-mybatis/src/main/java/com/persagy/fm/mybatis/type/PsTimeTypeHandler.java

@@ -0,0 +1,46 @@
+package com.persagy.fm.mybatis.type;
+
+import com.persagy.fm.common.lang.PsTime;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Mybatis时间全局处理
+ * @author Charlie Yu
+ * @version 1.0 2021-04-08
+ */
+@MappedJdbcTypes(JdbcType.CHAR)
+@MappedTypes(PsTime.class)
+public class PsTimeTypeHandler extends BaseTypeHandler<PsTime> {
+
+    @Override
+    public void setNonNullParameter(PreparedStatement preparedStatement, int i, PsTime psTime, JdbcType jdbcType) throws SQLException {
+        preparedStatement.setString(i, psTime.toString());
+    }
+
+    @Override
+    public PsTime getNullableResult(ResultSet resultSet, String s) throws SQLException {
+        String date = resultSet.getString(s);
+        return StringUtils.isBlank(date)? null:PsTime.parsePsTime(date);
+    }
+
+    @Override
+    public PsTime getNullableResult(ResultSet resultSet, int i) throws SQLException {
+        String date = resultSet.getString(i);
+        return StringUtils.isBlank(date)? null:PsTime.parsePsTime(date);
+    }
+
+    @Override
+    public PsTime getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
+        String date = callableStatement.getString(i);
+        return StringUtils.isBlank(date)? null:PsTime.parsePsTime(date);
+    }
+}

+ 0 - 2
fm-server/src/main/java/com/persagy/ServerApplication.java

@@ -33,8 +33,6 @@ public class ServerApplication {
     public static void main(String[] args) {
         SpringApplication application = new SpringApplication(ServerApplication.class);
         application.setBannerMode(Banner.Mode.OFF);
-//        application.addListeners((ApplicationListener<ApplicationStartedEvent>) event ->
-//                System.out.println("\033[1;93;44m>>>>>> " + event.getApplicationContext().getEnvironment().getProperty("spring.application.name") + " has started!!! \033[m"));
         application.run(args);
     }
 }