Jelajahi Sumber

增加基础工具

hechunping 2 bulan lalu
induk
melakukan
6ce352ad5f
23 mengubah file dengan 2697 tambahan dan 6 penghapusan
  1. 18 5
      pom.xml
  2. 3 1
      src/main/java/com/xynet/marketing/AdminApplication.java
  3. 97 0
      src/main/java/com/xynet/marketing/utils/AESUtil.java
  4. 144 0
      src/main/java/com/xynet/marketing/utils/ArrayUtils.java
  5. 136 0
      src/main/java/com/xynet/marketing/utils/Base64Utils.java
  6. 452 0
      src/main/java/com/xynet/marketing/utils/DateUtil.java
  7. 186 0
      src/main/java/com/xynet/marketing/utils/Encrypt.java
  8. 45 0
      src/main/java/com/xynet/marketing/utils/FunctionUtils.java
  9. 104 0
      src/main/java/com/xynet/marketing/utils/HttpClientUtil.java
  10. 84 0
      src/main/java/com/xynet/marketing/utils/HttpServiceUtils.java
  11. 75 0
      src/main/java/com/xynet/marketing/utils/JsonUtils.java
  12. 70 0
      src/main/java/com/xynet/marketing/utils/MD5.java
  13. 106 0
      src/main/java/com/xynet/marketing/utils/MD5Encryption.java
  14. 197 0
      src/main/java/com/xynet/marketing/utils/MathUtil.java
  15. 6 0
      src/main/java/com/xynet/marketing/utils/RedisUtil.java
  16. 74 0
      src/main/java/com/xynet/marketing/utils/RetailSignUtils.java
  17. 82 0
      src/main/java/com/xynet/marketing/utils/SpringBeanUtils.java
  18. 29 0
      src/main/java/com/xynet/marketing/utils/redis/config/RedisConfig.java
  19. 38 0
      src/main/java/com/xynet/marketing/utils/redis/config/RedisConfiguration.java
  20. 59 0
      src/main/java/com/xynet/marketing/utils/redis/config/RedissonConfiguration.java
  21. 163 0
      src/main/java/com/xynet/marketing/utils/redis/utils/LockUtils2.java
  22. 231 0
      src/main/java/com/xynet/marketing/utils/redis/utils/RedisService.java
  23. 298 0
      src/main/java/com/xynet/marketing/utils/redis/utils/RedisServiceImpl.java

+ 18 - 5
pom.xml

@@ -86,10 +86,6 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
-        <dependency>
-            <groupId>redis.clients</groupId>
-            <artifactId>jedis</artifactId>
-        </dependency>
 
         <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
         <dependency>
@@ -150,6 +146,23 @@
             <version>2.2.3.RELEASE</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.9.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.17.6</version>
+        </dependency>
     </dependencies>
 
     <dependencyManagement>
@@ -174,7 +187,7 @@
 						<manifest>
 							<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
 							<addClasspath>true</addClasspath>
-							<mainClass>com.xynet.AdminApplication</mainClass>
+							<mainClass>com.xynet.marketing.AdminApplication</mainClass>
 							<classpathPrefix>dependency</classpathPrefix>
 							<useUniqueVersions>false</useUniqueVersions>
 						</manifest>

+ 3 - 1
src/main/java/com/xynet/AdminApplication.java → src/main/java/com/xynet/marketing/AdminApplication.java

@@ -1,5 +1,6 @@
-package com.xynet;
+package com.xynet.marketing;
 
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@@ -14,6 +15,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @EnableTransactionManagement
 @EnableFeignClients
 @EnableScheduling
+@MapperScan("com.xynet.marketing.mapper")
 public class AdminApplication {
 
     public static void main(String[] args) {

+ 97 - 0
src/main/java/com/xynet/marketing/utils/AESUtil.java

@@ -0,0 +1,97 @@
+package com.xynet.marketing.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Objects;
+
+public class AESUtil {
+    protected static final Logger logger = LoggerFactory.getLogger(AESUtil.class);
+    public static void main(String[] args) {
+        String data = "7udmY6IFu0:1589622062:1";
+        String key = "3152BCC2109A8E405BC1BE0A53D22350";
+        //String machineid = "888888";
+        String encrypt = Objects.requireNonNull(encrypt(data, key)).toLowerCase();
+        System.out.println("加密前:" + data);
+        System.out.println("加密后:" + encrypt);
+        //String[] cmds = {"curl", "-H", "Host: https://payapi.weixiao.qq.com/", "-H", "authorization: WxToken : " + machineid + encrypt, "-H", "Cache-Control: max-age=0", "--compressed", "https://payapi.weixiao.qq.com/config_v2"};
+        //execCurl(cmds);
+    }
+
+    public static String encrypt(String data, String key) {
+
+        String ivString = key.substring(0,16);
+        //偏移量
+        byte[] iv = ivString.getBytes();
+        try {
+            Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
+            int blockSize = cipher.getBlockSize();
+            byte[] dataBytes = data.getBytes();
+            int length = dataBytes.length;
+            //计算需填充长度
+
+            byte[] plaintext = new byte[length];
+            //填充
+            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
+            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
+            logger.info("key="+keySpec.toString());
+            //设置偏移量参数
+            IvParameterSpec ivSpec = new IvParameterSpec(iv);
+            logger.info("iv="+iv.toString());
+            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+            byte[] encryped = cipher.doFinal(plaintext);
+
+            return parseByte2HexStr(encryped);
+
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    public static String parseByte2HexStr(byte[] buf) {
+        StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < buf.length; ++i) {
+            String hex = Integer.toHexString(buf[i] & 255);
+            if (hex.length() == 1) {
+                hex = '0' + hex;
+            }
+            sb.append(hex.toUpperCase());
+        }
+
+        return sb.toString();
+    }
+
+
+
+    public static String execCurl(String[] cmds) {
+        ProcessBuilder process = new ProcessBuilder(cmds);
+        Process p;
+        try {
+            p = process.start();
+            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+            StringBuilder builder = new StringBuilder();
+            String line = null;
+            while ((line = reader.readLine()) != null) {
+                builder.append(line);
+                builder.append(System.getProperty("line.separator"));
+            }
+            return builder.toString();
+
+        } catch (IOException e) {
+            System.out.print("error");
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+}

+ 144 - 0
src/main/java/com/xynet/marketing/utils/ArrayUtils.java

@@ -0,0 +1,144 @@
+package com.xynet.marketing.utils;
+
+/**
+ * <p>Operations on arrays, primitive arrays (like {@code int[]}) and
+ * primitive wrapper arrays (like {@code Integer[]}).
+ *
+ * <p>This class tries to handle {@code null} input gracefully.
+ * An exception will not be thrown for a {@code null}
+ * array input. However, an Object array that contains a {@code null}
+ * element may throw an exception. Each method documents its behaviour.
+ *
+ * <p>#ThreadSafe#
+ * @since 2.0
+ */
+
+public class ArrayUtils {
+
+    /**
+     * An empty immutable {@code byte} array.
+     */
+    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>(byte)0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static byte[] copyOfRange(byte[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, from, copy, 0,
+                Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * <p>Produces a new {@code byte} array containing the elements
+     * between the start and end indices.
+     *
+     * <p>The start index is inclusive, the end index exclusive.
+     * Null array input produces null output.
+     *
+     * @param array  the array
+     * @param startIndexInclusive  the starting index. Undervalue (&lt;0)
+     *      is promoted to 0, overvalue (&gt;array.length) results
+     *      in an empty array.
+     * @param endIndexExclusive  elements up to endIndex-1 are present in the
+     *      returned subarray. Undervalue (&lt; startIndex) produces
+     *      empty array, overvalue (&gt;array.length) is demoted to
+     *      array length.
+     * @return a new array containing the elements between
+     *      the start and end indices.
+     * @since 2.1
+     */
+    public static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) {
+        if (array == null) {
+            return null;
+        }
+        if (startIndexInclusive < 0) {
+            startIndexInclusive = 0;
+        }
+        if (endIndexExclusive > array.length) {
+            endIndexExclusive = array.length;
+        }
+        final int newSize = endIndexExclusive - startIndexInclusive;
+        if (newSize <= 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+
+        final byte[] subarray = new byte[newSize];
+        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
+        return subarray;
+    }
+
+    /**
+     * <p>Adds all the elements of the given arrays into a new array.
+     * <p>The new array contains all of the element of {@code array1} followed
+     * by all of the elements {@code array2}. When an array is returned, it is always
+     * a new array.
+     *
+     * <pre>
+     * ArrayUtils.addAll(array1, null)   = cloned copy of array1
+     * ArrayUtils.addAll(null, array2)   = cloned copy of array2
+     * ArrayUtils.addAll([], [])         = []
+     * </pre>
+     *
+     * @param array1  the first array whose elements are added to the new array.
+     * @param array2  the second array whose elements are added to the new array.
+     * @return The new byte[] array.
+     * @since 2.1
+     */
+    public static byte[] addAll(final byte[] array1, final byte... array2) {
+        if (array1 == null) {
+            return clone(array2);
+        } else if (array2 == null) {
+            return clone(array1);
+        }
+        final byte[] joinedArray = new byte[array1.length + array2.length];
+        System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+        System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+        return joinedArray;
+    }
+
+    /**
+     * <p>Clones an array returning a typecast result and handling
+     * {@code null}.
+     *
+     * <p>This method returns {@code null} for a {@code null} input array.
+     *
+     * @param array  the array to clone, may be {@code null}
+     * @return the cloned array, {@code null} if {@code null} input
+     */
+    public static byte[] clone(final byte[] array) {
+        if (array == null) {
+            return null;
+        }
+        return array.clone();
+    }
+
+}

+ 136 - 0
src/main/java/com/xynet/marketing/utils/Base64Utils.java

@@ -0,0 +1,136 @@
+package com.xynet.marketing.utils;
+
+
+import sun.misc.BASE64Encoder;
+
+import java.io.*;
+
+
+/**
+ * BASE64编码解码工具包
+ *
+ * @author IceWee
+ * @date 2012-5-19
+ * @version 1.0
+ */
+public class Base64Utils {
+
+    /**
+     * 文件读取缓冲区大小
+     */
+    private static final int CACHE_SIZE = 1024;
+
+    /**
+     * <p>
+     * BASE64字符串解码为二进制数据
+     * </p>
+     *
+     * @param base64
+     * @return
+     * @throws Exception
+     */
+    public static byte[] decode(String base64) throws Exception {
+    	return new sun.misc.BASE64Decoder().decodeBuffer(base64) ; //Base64.decodeBase64(base64);
+    }
+
+    /**
+     * <p>
+     * 二进制数据编码为BASE64字符串
+     * </p>
+     *
+     * @param bytes
+     * @return
+     * @throws Exception
+     */
+    public static String encode(byte[] bytes) throws Exception {
+    	//return Base64.encodeBase64String(bytes);
+    	return new BASE64Encoder().encode(bytes);
+    }
+
+    /**
+     * <p>
+     * 将文件编码为BASE64字符串
+     * </p>
+     * <p>
+     * 大文件慎用,可能会导致内存溢出
+     * </p>
+     *
+     * @param filePath 文件绝对路径
+     * @return
+     * @throws Exception
+     */
+    public static String encodeFile(String filePath) throws Exception {
+        byte[] bytes = fileToByte(filePath);
+        return encode(bytes);
+    }
+
+    /**
+     * <p>
+     * BASE64字符串转回文件
+     * </p>
+     *
+     * @param filePath 文件绝对路径
+     * @param base64 编码字符串
+     * @throws Exception
+     */
+    public static void decodeToFile(String filePath, String base64) throws Exception {
+        byte[] bytes = decode(base64);
+        byteArrayToFile(bytes, filePath);
+    }
+
+    /**
+     * <p>
+     * 文件转换为二进制数组
+     * </p>
+     *
+     * @param filePath 文件路径
+     * @return
+     * @throws Exception
+     */
+    public static byte[] fileToByte(String filePath) throws Exception {
+        byte[] data = new byte[0];
+        File file = new File(filePath);
+        if (file.exists()) {
+            FileInputStream in = new FileInputStream(file);
+            ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
+            byte[] cache = new byte[CACHE_SIZE];
+            int nRead = 0;
+            while ((nRead = in.read(cache)) != -1) {
+                out.write(cache, 0, nRead);
+                out.flush();
+            }
+            out.close();
+            in.close();
+            data = out.toByteArray();
+        }
+        return data;
+    }
+
+    /**
+     * <p>
+     * 二进制数据写文件
+     * </p>
+     *
+     * @param bytes 二进制数据
+     * @param filePath 文件生成目录
+     */
+    public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
+        InputStream in = new ByteArrayInputStream(bytes);
+        File destFile = new File(filePath);
+        if (!destFile.getParentFile().exists()) {
+            destFile.getParentFile().mkdirs();
+        }
+        destFile.createNewFile();
+        OutputStream out = new FileOutputStream(destFile);
+        byte[] cache = new byte[CACHE_SIZE];
+        int nRead = 0;
+        while ((nRead = in.read(cache)) != -1) {
+            out.write(cache, 0, nRead);
+            out.flush();
+        }
+        out.close();
+        in.close();
+    }
+
+
+}

+ 452 - 0
src/main/java/com/xynet/marketing/utils/DateUtil.java

@@ -0,0 +1,452 @@
+package com.xynet.marketing.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * Copyright © 2018 xynet Tech Ltd. All rights reserved
+ * @author: sund
+ * @date: 2018年2月9日 下午3:21:58
+ * @remark:日期工具类
+ */
+public class DateUtil {
+	protected static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
+	static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+	static SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");//yyyyMMddHHmmss
+	static SimpleDateFormat ymdhms = new SimpleDateFormat("yyyyMMddHHmmss");
+	/**
+	 * 将Date类型转换为字符串
+	 * 
+	 * @param date
+	 *            日期类型
+	 * @return 日期字符串
+	 */
+	public static String format(Date date) {
+		return format(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/**
+	 * 将Date类型转换为字符串
+	 * 
+	 * @param date
+	 *            日期类型
+	 * @param pattern
+	 *            字符串格式
+	 * @return 日期字符串
+	 */
+	public static String format(Date date, String pattern) {
+		if (date == null) {
+			return "null";
+		}
+		if (pattern == null || pattern.equals("") || pattern.equals("null")) {
+			pattern = "yyyy-MM-dd HH:mm:ss";
+		}
+		return new SimpleDateFormat(pattern).format(date);
+	}
+
+	/**
+	 * 将字符串转换为Date类型
+	 *
+	 * @param date
+	 *            字符串类型
+	 * @return 日期类型(yyyy-MM-dd HH:mm:ss)
+	 */
+	public static Date format(String date) {
+		return format(date, null);
+	}
+
+	/**
+	 * 将字符串转换为Date类型
+	 *
+	 * @param date
+	 *            字符串类型
+	 * @param pattern
+	 *            格式
+	 * @return 日期类型
+	 */
+	public static Date format(String date, String pattern) {
+		if (pattern == null || pattern.equals("") || pattern.equals("null")) {
+			pattern = "yyyy-MM-dd HH:mm:ss";
+		}
+		if (date == null || date.equals("") || date.equals("null")) {
+			return new Date();
+		}
+		Date d = null;
+		try {
+			d = new SimpleDateFormat(pattern).parse(date);
+		} catch (ParseException pe) {
+		}
+		return d;
+	}
+
+	 // 两天之间的天数
+	public static int daysBetween(String startDate, String endDate)
+			throws ParseException {
+		 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+		 Date start = sdf.parse(startDate);
+		 Date end = sdf.parse(endDate);
+		 return  daysBetween(end,start);
+	}
+	
+	/*
+	 * 求两个日期之间的天数
+	 */
+	public static int daysBetween(Date startDate,Date endDate)
+	{
+		//一天24小时*60分钟*60秒*1000毫秒
+		return  (int) ((endDate.getTime() - 
+				startDate.getTime()-10) /(24*60*60*1000));
+	}
+	
+	/**
+	 * 求两个时间之间的时间
+	 * @param startDate 开始时间
+	 * @param endDate 结束时间
+	 * @param type 类型(1:秒 2:分 3:时 4:日)
+	 */
+	public static int daysBetweenV2(String startDate,String endDate,int type)
+			throws ParseException{
+		int h = 1;
+		int m = 1;
+		int s = 1;
+		if (type == 1) {
+			s = 1;
+		}
+		if (type == 2) {
+			s = 60;
+		}
+		if (type == 3) {
+			m = 60;
+			s = 60;
+		}
+		if (type == 4) {
+			m = 60;
+			s = 60;
+			h = 24;
+		}
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		Date start = sdf.parse(startDate);
+		Date end = sdf.parse(endDate);
+		//一天24小时*60分钟*60秒*1000毫秒
+		return  (int) ((end.getTime() - 
+				start.getTime()) /(h*m*s*1000));
+	}
+	
+	/*
+	 * 时间格式的转换
+	 */
+	public static Date formatUtc(String str)
+	{
+		String strTime = str.replace("Z", " UTC");
+		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
+		Date dateTime = null;
+		try {
+			dateTime = format.parse(strTime);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return  dateTime;
+	}
+	
+	/*
+	 * 求某一日期加N个小时后的时间
+	 */
+	public static String dateAddHours(Date startDate,int hours,String pattern)
+	{
+		//一天24小时*60分钟*60秒*1000毫秒
+		return format(new Date(startDate.getTime()+hours*60*60*1000),pattern);
+
+	}
+
+
+		/**
+		 * 判断是否在同一个月
+		 * @param startDate yyyy-MM-dd
+		 * @param endDate yyyy-MM-dd
+		 * @return false:不在同一个月内,true在同一个月内
+		 */
+		public static boolean isMonth(String startDate,String endDate){
+			if(margin(startDate, endDate)>31){
+				return false;
+			}
+			int startMonth = Integer.parseInt(startDate.substring(5, 7));
+			int endMonth = Integer.parseInt(endDate.substring(5, 7));
+			if(startMonth==endMonth){
+				return true;
+			}else{
+				return false;
+			}
+		}
+		/**
+		 * 计算开始日期和结束日期差
+		 * @param startDate yyyy-MM-dd
+		 * @param endDate yyyy-MM-dd
+		 * @return
+		 */
+		private static int margin(String startDate,String endDate){
+			ParsePosition pos = new ParsePosition(0);
+			ParsePosition pos2 = new ParsePosition(0);
+			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+			Date ds = sdf.parse(startDate, pos);
+			Date de = sdf.parse(endDate, pos2);
+			long l = de.getTime()-ds.getTime();
+			int margin = (int)(l/24*60*60*1000);
+			return margin;
+		}
+
+	/**
+	 * 判断时间跨度是否相差一个月
+	 * @param startTime  yyyyMMdd
+	 * @param endTime
+	 */
+    public static boolean  isDifference(String startTime,String endTime){
+        SimpleDateFormat f = new SimpleDateFormat("yyyyMMdd");
+        try {
+            Date d1 = f.parse(startTime);
+            Date d2 = f.parse(endTime);
+            //Date d2 = f.parse("20120101");
+            long day = (d2.getTime()-d1.getTime())/1000/60/60/24 + 1;
+            System.out.println("d1和d2相差" + day + "天。");
+            int month = isMaxMonth(startTime);
+            System.out.println(month);
+            if(day > month){
+                return false;
+            }else {
+                return  true;
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 判断这年的某月有多少天
+     * @param startTime 时间  yyyyMMdd
+     * @return
+     */
+    public static int isMaxMonth(String startTime) {
+        int year = 0;
+        int month = 0;
+        int days= 0 ;
+        year = Integer.parseInt(startTime.substring(0, 4));
+        month = Integer.parseInt(startTime.substring(4, 6));
+        switch(month){
+            case 2:
+                boolean flag=(year%4==0&&year%100!=100)||year%400==0;
+                if(flag){
+                    days=29;
+                }else{
+                    days=28;
+                }
+                break;
+            case 4:
+            case 6:
+            case 9:
+            case 11:
+                days=30;
+                break;
+            default:
+                days=31;
+                break;
+        }
+        return days;
+    }
+
+	/**
+	 * 返回序列化
+	 * @param date
+	 * @param index
+	 * @return
+	 */
+	public static int timexlh(Date date,int index) {
+		return (date.getHours()*60+date.getMinutes())/index;
+	}
+
+	/**
+	 *  获取昨天的yyyyMMdd
+
+	 * @param date
+	 * @return
+	 */
+	public static int yesterdayyyMMdd(Date date,int index) {
+		Date yesterday = new Date(date.getTime() - 86400000L*index);
+		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
+		String time = format.format(yesterday);
+		return Integer.parseInt(time);
+	}
+	/**
+	 *  获取前天的yyyyMMdd
+
+	 * @param date
+	 * @return
+	 */
+	public static int beforeYesterdayyyMMdd(Date date) {
+		Date yesterday = new Date(date.getTime() - 172800000l);
+		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
+		String time = format.format(yesterday);
+		return Integer.parseInt(time);
+	}
+
+	/**
+	 * 获取今天的yyyyMMdd
+	 * @param date
+	 * @return
+	 */
+	public static int todayyyMMdd(Date date) {
+		SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
+		String time = format.format(date);
+		return Integer.parseInt(time);
+	}
+
+	public static void main(String[] args){
+        String date = getMaxyesterdayDate();
+        System.out.println(date);
+    }
+
+    /**
+     * 时间字符串转intger
+     * @param str
+     * @return
+     */
+    public  static  Integer stringToInt(String str){
+	    try {
+	        //2019-08-08
+            StringBuffer sb = new StringBuffer();
+            String year = str.substring(0, 4);
+            String moth = str.substring(5, 7);
+            String day = str.substring(8, 10);
+            sb.append(year);
+            sb.append(moth);
+            sb.append(day);
+            return Integer.parseInt(sb.toString());
+        }catch (Exception e){
+	        return null;
+        }
+	}
+
+    /**
+     * 时间转字符串yyyyMMddHHmmss
+     * @param date
+     * @return
+     */
+	public static String dateToString(Date date){
+        String format = ymdhms.format(date);
+        return format;
+    }
+
+    public static Date stringToDate(String str) throws ParseException {
+        Date parse = ymdhms.parse(str);
+        return parse;
+    }
+
+	/**
+	 * 获取昨天最大 的时间
+	 * @return
+	 */
+	public static String getMaxyesterdayDate(){
+		Date date = new Date();
+		long time = date.getTime() - 1000*60*60;
+        String format = sdf.format(time);
+        System.out.println(format);
+        return format;
+    }
+
+	/**
+	 * 返回两个日期之间的所有日期
+	 * @param startTime
+	 * @param endTime
+	 * @return
+	 */
+	public static List<String> getDays(String startTime,String endTime){
+		List<String> days = new ArrayList<String>();
+		try {
+			Date start = ymd.parse(startTime);
+			Date end = ymd.parse(endTime);
+			
+			Calendar cldStart = Calendar.getInstance();
+			cldStart.setTime(start);
+			
+			Calendar cldEnd = Calendar.getInstance();
+			cldEnd.setTime(end);
+			cldEnd.add(Calendar.DATE, +1);
+			
+			while (cldStart.before(cldEnd)) {
+				days.add(ymd.format(cldStart.getTime()));
+				cldStart.add(Calendar.DAY_OF_YEAR, +1);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return days; 
+	}
+	
+	/**+
+	 * 获取从当前时间开始 加减后的时间(hep 用)
+	 * @param year int 年
+	 * @param month int 月
+	 * @param day int 天
+	 * @param hour int 时
+	 * @param minute int 分
+	 * @param type int 返回格式 1:"yyyy-MM-dd HH:mm:ss" 2:"yyyy-MM-dd" 3:"yyyyMMdd" 4:"yyyy-MM-dd HH:mm:00"
+	 * 	5:"yyyyMMddHHmmss" 6:"yyyy-MM"
+	 * @return
+	 */
+	public static String getUserDefinedTime(int year,int month, int day, int hour, int minute, int type, Date settime){
+		String format = "";
+		switch (type) {
+		case 1:
+			format = "yyyy-MM-dd HH:mm:ss";
+			break;
+		case 2:
+			format = "yyyy-MM-dd";
+			break;
+		case 3:
+			format = "yyyyMMdd";
+			break;
+		case 4:
+			format = "yyyy-MM-dd HH:mm:00";
+			break;
+		case 5:
+			format = "yyyyMMddHHmmss";
+			break;
+		case 6:
+			format = "yyyy-MM";
+			break;
+		default:
+			break;
+		}
+		Calendar cal=Calendar.getInstance();
+		if (settime != null) {
+			cal.setTime(settime);
+		}
+		if (year != 0) {
+			cal.add(Calendar.YEAR,+ year);
+		}
+		if (month != 0) {
+			cal.add(Calendar.MONTH, + month);
+		}
+		if (day != 0) {
+			cal.add(Calendar.DATE,+ day);
+		}
+	    if (hour != 0) {
+			cal.add(Calendar.HOUR,+ hour);
+		}
+	    if (minute != 0) {
+			cal.add(Calendar.MINUTE,+ minute);
+		}
+	    Date d=cal.getTime();
+	    SimpleDateFormat sdf = new SimpleDateFormat(format);
+	    String time = sdf.format(d);
+	    return time;
+	}
+}

+ 186 - 0
src/main/java/com/xynet/marketing/utils/Encrypt.java

@@ -0,0 +1,186 @@
+package com.xynet.marketing.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+
+/**
+ * 加密工具类
+ * 
+ * md5加密出来的长度是32位
+ * 
+ * sha加密出来的长度是40位
+ * 
+ * @author 孙旦
+ * 
+ */
+public class Encrypt {
+
+	/**
+	 * 测试
+	 * 
+	 * @param args
+	 */
+	/*public static void main(String[] args) {
+		// md5加密测试
+		
+		 * String md5_1 = md5("123456"); String md5_2 = md5("孙旦");
+		 * System.out.println(md5_1 + "\n" + md5_2); // sha加密测试 String sha_1 =
+		 * sha("123456"); String sha_2 = sha("孙旦"); System.out.println(sha_1 +
+		 * "\n" + sha_2);
+		 
+		
+		System.out.println("###############:"+e("15074944666123456"));
+	}*/
+
+	/**
+	 * 加密
+	 * 
+	 * @param inputText
+	 * @return
+	 */
+	public static String e(String inputText) {
+		return md5(inputText);
+	}
+
+	/**
+	 * 二次加密,应该破解不了了吧?
+	 * 
+	 * @param inputText
+	 * @return
+	 */
+	public static String md5AndSha(String inputText) {
+		return sha(md5(inputText));
+	}
+
+	/**
+	 * md5加密
+	 * 
+	 * @param inputText
+	 * @return
+	 */
+	public static String md5(String inputText) {
+		return encrypt(inputText, "md5");
+	}
+
+	/**
+	 * sha加密
+	 * 
+	 * @param inputText
+	 * @return
+	 */
+	public static String sha(String inputText) {
+		return encrypt(inputText, "sha-1");
+	}
+
+	/**
+	 * md5或者sha-1加密
+	 * 
+	 * @param inputText
+	 *            要加密的内容
+	 * @param algorithmName
+	 *            加密算法名称:md5或者sha-1,不区分大小写
+	 * @return
+	 */
+	private static String encrypt(String inputText, String algorithmName) {
+		if (inputText == null || "".equals(inputText.trim())) {
+			throw new IllegalArgumentException("请输入要加密的内容");
+		}
+		if (algorithmName == null || "".equals(algorithmName.trim())) {
+			algorithmName = "md5";
+		}
+		String encryptText = null;
+		try {
+			MessageDigest m = MessageDigest.getInstance(algorithmName);
+			m.update(inputText.getBytes("UTF8"));
+			byte s[] = m.digest();
+			// m.digest(inputText.getBytes("UTF8"));
+			return hex(s);
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		}
+		return encryptText;
+	}
+
+	/**
+	 * 返回十六进制字符串
+	 * 
+	 * @param arr
+	 * @return
+	 */
+	private static String hex(byte[] arr) {
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0; i < arr.length; ++i) {
+			sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1,
+					3));
+		}
+		return sb.toString();
+	}
+	
+
+	/**
+	 * 传入文本内容,返回 SHA-256 串
+	 * 
+	 * @param strText
+	 * @return
+	 */
+	public static String SHA256(final String strText) {
+		return SHA(strText, "SHA-256");
+	}
+
+	/**
+	 * 传入文本内容,返回 SHA-512 串
+	 * 
+	 * @param strText
+	 * @return
+	 */
+	public static String SHA512(final String strText) {
+		return SHA(strText, "SHA-512");
+	}
+
+	private static String SHA(final String strText, final String strType) {
+		// 返回值
+		String strResult = null;
+		// 是否是有效字符串
+		if (strText != null && strText.length() > 0) {
+			try {
+				// SHA 加密开始
+				// 创建加密对象 并傳入加密類型
+				MessageDigest messageDigest = MessageDigest
+						.getInstance(strType);
+				// 传入要加密的字符串
+				messageDigest.update(strText.getBytes());
+				// 得到 byte 類型结果
+				byte byteBuffer[] = messageDigest.digest();
+				// 將 byte 轉換爲 string
+				StringBuffer strHexString = new StringBuffer();
+				// 遍歷 byte buffer
+				for (int i = 0; i < byteBuffer.length; i++) {
+					String hex = Integer.toHexString(0xff & byteBuffer[i]);
+					if (hex.length() == 1) {
+						strHexString.append('0');
+					}
+					strHexString.append(hex);
+				}
+				// 得到返回結果
+				strResult = strHexString.toString();
+			} catch (NoSuchAlgorithmException e) {
+				e.printStackTrace();
+			}
+		}
+		return strResult;
+	}
+
+	/**
+	 * 传入文本内容,返回 SHA-256 串 小写
+	 *
+	 * @param strText
+	 * @return
+	 */
+	public static String SHA256LowerCase(final String strText) {
+		return SHA(strText, "SHA-256").toLowerCase();
+	}
+}

+ 45 - 0
src/main/java/com/xynet/marketing/utils/FunctionUtils.java

@@ -0,0 +1,45 @@
+package com.xynet.marketing.utils;
+
+/**
+ * 函数接口工具类
+ */
+public class FunctionUtils {
+
+    /**
+     * 有参有返回值
+     *
+     * @param <T>
+     */
+    @FunctionalInterface
+    public interface ParamsResult<T, R> {
+        R run(T params);
+    }
+
+    /**
+     * 无参有返回值
+     *
+     * @param <T>
+     */
+    @FunctionalInterface
+    public interface NoParamsResult<T> {
+        T run();
+    }
+
+    /**
+     * 有参无返回值
+     *
+     * @param <T>
+     */
+    @FunctionalInterface
+    public interface ParamsNoResult<T> {
+        void run(T params);
+    }
+
+    /**
+     * 无参无返回值
+     */
+    @FunctionalInterface
+    public interface NoParamsNoResult {
+        void run();
+    }
+}

+ 104 - 0
src/main/java/com/xynet/marketing/utils/HttpClientUtil.java

@@ -0,0 +1,104 @@
+package com.xynet.marketing.utils;
+
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.Consts;
+import org.apache.http.HttpEntity;
+import org.apache.http.StatusLine;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.http.impl.client.HttpClients.createDefault;
+
+/**
+ * 发送Http请求工具类, get post请求
+ */
+
+public class HttpClientUtil {
+
+  private static final Log logger = LogFactory.getLog(HttpClientUtil.class);
+  private static final int DEFAULT_TIMEOUT = 60000;
+
+  public static String senderPost(String url, Map<String, String> params,Long groupID,Long shopID,String traceID) throws IOException {
+
+    CloseableHttpClient httpClient = createDefault();
+    CloseableHttpResponse response = null;
+    String result = null;
+
+    try {
+      HttpPost httpPost = new HttpPost(url);
+      RequestConfig requestConfig = RequestConfig
+              .custom()
+              .setSocketTimeout(DEFAULT_TIMEOUT)
+              .setConnectTimeout(DEFAULT_TIMEOUT)
+              .build();//设置请求和传输超时时间
+
+      httpPost.setConfig(requestConfig);
+      httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
+      //将groupID与shopID放入header中传输,2.0接口header中参数不参与签名,traceID必传
+      httpPost.setHeader("groupID",groupID.toString());
+      httpPost.setHeader("shopID",shopID.toString());
+      httpPost.setHeader("traceID",traceID);
+
+      List<BasicNameValuePair> basicNameValuePairs = new ArrayList<BasicNameValuePair>();
+      for (Map.Entry<String, String> entity : params.entrySet()) {
+        basicNameValuePairs.add(new BasicNameValuePair(entity.getKey(), entity.getValue()));
+      }
+
+      UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(basicNameValuePairs, Consts.UTF_8);
+      httpPost.setEntity(urlEncodedFormEntity);
+      // 获取当前时间戳
+      Long now = System.currentTimeMillis();
+      response = httpClient.execute(httpPost);
+      StatusLine statusLine = response.getStatusLine();
+      Date date = new Date();
+      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+      String StartTime = sdf.format(date);
+      // 计算耗时
+      long time = System.currentTimeMillis() - now;
+      logger.info("调用三方平台耗时: "+time+"毫秒");
+      // 格式化请求参数
+      String requestParams = JSON.toJSONString(params);
+      int httpStatus = statusLine.getStatusCode();
+      logger.info(String.format("请求参数 url: %s, params: %s, response status: %s",
+              url,requestParams , httpStatus));
+
+      HttpEntity entity = response.getEntity();
+      result = EntityUtils.toString(entity, Consts.UTF_8);
+      logger.info(String.format("返回值 data: %s", result));
+      return result;
+    } catch (IOException e) {
+      throw e;
+    } finally {
+      try {
+        if (response != null) {
+          response.close();
+        }
+        if (httpClient != null) {
+          httpClient.close();
+        }
+      } catch (IOException e) {
+        logger.error("close http client failed", e);
+      }
+    }
+
+  }
+
+
+
+}
+

+ 84 - 0
src/main/java/com/xynet/marketing/utils/HttpServiceUtils.java

@@ -0,0 +1,84 @@
+package com.xynet.marketing.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Map;
+
+/**
+ * @author YanJ
+ * @date 2020/1/9-10:55
+ */
+public class HttpServiceUtils {
+
+    public static String sendPost(String urlParam, Map<String, String> params, String charset) {
+        StringBuffer resultBuffer = null;
+        // 构建请求参数
+        StringBuffer sbParams = new StringBuffer();
+        if (params != null && params.size() > 0) {
+            for (Map.Entry<String, String> e : params.entrySet()) {
+                sbParams.append(e.getKey());
+                sbParams.append("=");
+                sbParams.append(e.getValue());
+                sbParams.append("&");
+            }
+        }
+        URLConnection con = null;
+        OutputStreamWriter osw = null;
+        BufferedReader br = null;
+        try {
+            URL realUrl = new URL(urlParam);
+            // 打开和URL之间的连接
+            con = realUrl.openConnection();
+            // 设置通用的请求属性
+            con.setRequestProperty("accept", "*/*");
+            con.setRequestProperty("connection", "Keep-Alive");
+            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+            con.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            // 发送POST请求必须设置如下两行
+            con.setDoOutput(true);
+            con.setDoInput(true);
+            // 获取URLConnection对象对应的输出流
+            osw = new OutputStreamWriter(con.getOutputStream(), charset);
+            if (sbParams != null && sbParams.length() > 0) {
+                // 发送请求参数
+                osw.write(sbParams.substring(0, sbParams.length() - 1));
+                // flush输出流的缓冲
+                osw.flush();
+            }
+            // 定义BufferedReader输入流来读取URL的响应
+            resultBuffer = new StringBuffer();
+            int contentLength = Integer.parseInt(con.getHeaderField("Content-Length"));
+            if (contentLength > 0) {
+                br = new BufferedReader(new InputStreamReader(con.getInputStream(), charset));
+                String temp;
+                while ((temp = br.readLine()) != null) {
+                    resultBuffer.append(temp);
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (osw != null) {
+                try {
+                    osw.close();
+                } catch (IOException e) {
+                    osw = null;
+                    throw new RuntimeException(e);
+                }
+            }
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    br = null;
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return resultBuffer.toString();
+    }
+}

+ 75 - 0
src/main/java/com/xynet/marketing/utils/JsonUtils.java

@@ -0,0 +1,75 @@
+package com.xynet.marketing.utils;
+
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.List;
+
+/**
+ * json工具类
+ * 字符串对象相互转换
+ * @author YanJ
+ *
+ */
+public class JsonUtils {
+
+    // 定义jackson对象
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * 将对象转换成json字符串。
+     * <p>Title: pojoToJson</p>
+     * <p>Description: </p>
+     * @param data
+     * @return
+     */
+    public static String objectToJson(Object data) {
+    	try {
+			String string = MAPPER.writeValueAsString(data);
+			return string;
+		} catch (JsonProcessingException e) {
+			e.printStackTrace();
+		}
+    	return null;
+    }
+    
+    /**
+     * 将json结果集转化为对象
+     * 
+     * @param jsonData json数据
+     * @param clazz 对象中的object类型
+     * @return
+     */
+    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
+        try {
+            T t = MAPPER.readValue(jsonData, beanType);
+            return t;
+        } catch (Exception e) {
+        	e.printStackTrace();
+        }
+        return null;
+    }
+    
+    /**
+     * 将json数据转换成pojo对象list
+     * <p>Title: jsonToList</p>
+     * <p>Description: </p>
+     * @param jsonData
+     * @param beanType
+     * @return
+     */
+    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
+    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
+    	try {
+    		List<T> list = MAPPER.readValue(jsonData, javaType);
+    		return list;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+    	
+    	return null;
+    }
+    
+}

+ 70 - 0
src/main/java/com/xynet/marketing/utils/MD5.java

@@ -0,0 +1,70 @@
+package com.xynet.marketing.utils;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.SignatureException;
+
+/** 
+* 功能:MD5签名
+* 版本:3.3
+* 修改日期:2012-08-17
+* */
+public class MD5 {
+    public static void main(String[] args) {
+        String str = "appId=wx8632a91376b81e24&callback_url=http://u.shdplan.com/usr/details.html?paySuc=true&awaId=AID201508100946430003&money=1.99&nonceStr=1441076469693&package=prepay_id=wx2015090111010993f0dd52c80787614418&signType=MD5&status=0&timeStamp=1441076469693";
+        System.out.println(MD5.sign(str, "&key=8748fd966d0ffc47abd59e97", "utf-8"));
+        
+    }
+
+    /**
+     * 签名字符串
+     * @param text 需要签名的字符串
+     * @param key 密钥
+     * @param input_charset 编码格式
+     * @return 签名结果
+     */
+    public static String sign(String text, String key, String input_charset) {
+    	text = text + key;
+    	System.out.println(text);
+        return DigestUtils.md5Hex(getContentBytes(text, input_charset)).toUpperCase();
+    }
+    
+    /**
+     * 签名字符串
+     * @param text 需要签名的字符串
+     * @param sign 签名结果
+     * @param key 密钥
+     * @param input_charset 编码格式
+     * @return 签名结果
+     */
+    public static boolean verify(String text, String sign, String key, String input_charset) {
+    	text = text + key;
+    	String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
+    	if(mysign.equals(sign)) {
+    		return true;
+    	}
+    	else {
+    		return false;
+    	}
+    }
+
+    /**
+     * @param content
+     * @param charset
+     * @return
+     * @throws SignatureException
+     * @throws UnsupportedEncodingException 
+     */
+    private static byte[] getContentBytes(String content, String charset) {
+        if (charset == null || "".equals(charset)) {
+            return content.getBytes();
+        }
+        try {
+            return content.getBytes(charset);
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
+        }
+    }
+
+}

+ 106 - 0
src/main/java/com/xynet/marketing/utils/MD5Encryption.java

@@ -0,0 +1,106 @@
+package com.xynet.marketing.utils;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5加密(超级机器人对接用)
+ * @author hep
+ *
+ */
+public class MD5Encryption {
+    private final static String[] hexArray = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
+
+
+    /***
+     * 对指定的字符串进行MD5加密
+     */
+    public static String encrypByMD5(String originString) {
+        try {
+            //创建具有MD5算法的信息摘要
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            //使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
+            byte[] bytes = md.digest(originString.getBytes());
+            //将得到的字节数组变成字符串返回
+            String s = byteArrayToHex(bytes);
+            return s.toUpperCase();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
+     *
+     * @param encryptText 被签名的字符串
+     * @param encryptKey  密钥
+     * @return
+     * @throws Exception
+     */
+    public static String encrypByHMACSHA1(String encryptText, String encryptKey) {
+        try {
+            byte[] data = encryptKey.getBytes(StandardCharsets.UTF_8);
+            //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
+            SecretKey secretKey = new SecretKeySpec(data, "HmacSHA1");
+            //生成一个指定 Mac 算法 的 Mac 对象
+            Mac mac = Mac.getInstance("HmacSHA1");
+            //用给定密钥初始化 Mac 对象
+            mac.init(secretKey);
+            byte[] text = encryptText.getBytes(StandardCharsets.UTF_8);
+            //完成 Mac 操作
+            String s = byteArrayToHex(mac.doFinal(text));
+            return s;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /***
+     * 对指定的字符串进行MD5加密
+     */
+    public static String encrypBySHA1(String originString) {
+        try {
+            //创建具有MD5算法的信息摘要
+            MessageDigest md = MessageDigest.getInstance("SHA1");
+            //使用指定的字节数组对摘要进行最后更新,然后完成摘要计算
+            byte[] bytes = md.digest(originString.getBytes());
+            //将得到的字节数组变成字符串返回
+            String s = byteArrayToHex(bytes);
+            return s.toUpperCase();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将字节数组转换成十六进制,并以字符串的形式返回
+     * 128位是指二进制位。二进制太长,所以一般都改写成16进制,
+     * 每一位16进制数可以代替4位二进制数,所以128位二进制数写成16进制就变成了128/4=32位。
+     */
+    public static String byteArrayToHex(byte[] b) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < b.length; i++) {
+            sb.append(byteToHex(b[i]));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 将一个字节转换成十六进制,并以字符串的形式返回
+     */
+    public static String byteToHex(byte b) {
+        int n = b;
+        if (n < 0)
+            n = n + 256;
+        int d1 = n / 16;
+        int d2 = n % 16;
+        return hexArray[d1] + hexArray[d2];
+    }
+}

+ 197 - 0
src/main/java/com/xynet/marketing/utils/MathUtil.java

@@ -0,0 +1,197 @@
+package com.xynet.marketing.utils;
+
+import java.math.BigDecimal;
+import java.util.Random;
+
+/**
+ * 
+ * 数学运算工具类:主要包含加、减、乘、除、精度截取及比大小等功能<br>
+ * 此类采用BigDecimal进行基础运算,避免丢失精度以及灵活的控制四舍五入方式<br>
+ * 
+ *
+ */
+public class MathUtil {
+
+	/**
+	 * 
+	 * 加(结果默认舍入)
+	 * 
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @return 和
+	 *
+	 */
+	public static BigDecimal add(Number d1, Number d2,int scale) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.add(bd2).setScale(scale, BigDecimal.ROUND_HALF_UP);
+		
+	}
+	
+
+	/**
+	 * 
+	 * 加(含舍入判断)
+	 * 
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @param round 舍入方式(boolean值,true则入,false则舍)
+	 * @return 说明入参、返回、异常等
+	 */
+	public static BigDecimal add(Number d1, Number d2,int scale,boolean round) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.add(bd2).setScale(scale, round?BigDecimal.ROUND_HALF_UP:BigDecimal.ROUND_HALF_DOWN);		
+	}
+
+	/**
+	 * 
+	 * 减(结果默认舍入)
+	 * 
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @return 差
+	 *
+	 */
+	public static BigDecimal subtract(Number d1, Number d2,int scale) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.subtract(bd2).setScale(scale, BigDecimal.ROUND_HALF_UP);
+	}
+
+	/**
+	 * 
+	 * 减(含舍入判断)
+	 * 
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @param round 舍入方式(boolean值,true则入,false则舍)
+	 * @return 差
+	 *
+	 */
+	public static BigDecimal subtract(Number d1, Number d2,int scale,boolean round) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.subtract(bd2).setScale(scale, round?BigDecimal.ROUND_HALF_UP:BigDecimal.ROUND_HALF_DOWN);
+	}
+
+	/**
+	 * 除(结果默认舍入)
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @return 商
+	 */
+	public static BigDecimal divide(Number d1, Number d2, int scale) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.divide(bd2, scale, BigDecimal.ROUND_HALF_UP);
+	}
+	
+	/**
+	 * 除(含舍入判断)
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @param round 舍入方式(boolean值,true则入,false则舍)
+	 * @return 商
+	 */
+	public static BigDecimal divide(Number d1, Number d2, int scale,boolean round) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.divide(bd2, scale, round?BigDecimal.ROUND_HALF_UP:BigDecimal.ROUND_HALF_DOWN);
+	}
+	
+	/**
+	 * 乘(结果默认舍入)
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @return 积
+	 */
+	public static BigDecimal multiply(Number d1, Number d2, int scale) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.multiply(bd2).setScale(scale, BigDecimal.ROUND_HALF_UP);
+	}
+	
+	/**
+	 * 乘(含舍入判读)
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @param scale 小数位位数(四舍五入)
+	 * @param round 舍入方式(boolean值,true则入,false则舍)
+	 * @return 积
+	 */
+	public static BigDecimal multiply(Number d1, Number d2, int scale,boolean round) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		return bd1.multiply(bd2).setScale(scale, round?BigDecimal.ROUND_HALF_UP:BigDecimal.ROUND_HALF_DOWN);
+	}
+	
+	/**
+	 * 判断舍入与否后精确到指定位数
+	 * @param d1 数1
+	 * @param scale 小数位位数(四舍五入)
+	 * @param round 舍入方式(boolean值,true则入,false则舍)
+	 * @return 舍入数
+	 */
+	public static BigDecimal round(Number d1, int scale,boolean round) {
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		return bd1.setScale(scale, round?BigDecimal.ROUND_HALF_UP:BigDecimal.ROUND_HALF_DOWN);
+	}
+	
+	/**
+	 * 比较两数大小
+	 * @param d1 数1
+	 * @param d2 数2
+	 * @return 0相等,1则d1大,-1则d2大
+	 */
+	public static int checkBigger(Number d1,Number d2){
+		int result = -1;
+		BigDecimal bd1 = new BigDecimal(String.valueOf(d1));
+		BigDecimal bd2 = new BigDecimal(String.valueOf(d2));
+		if(bd1.compareTo(bd2)>0){
+			result = 1;
+		}else if(bd1.compareTo(bd2)==0){
+			result = 0;
+		}
+		return result;
+		
+	}
+	/**获取指定长度随机数*/
+	public static String getRandNum(int charCount) {
+        String charValue = "";
+        for (int i = 0; i < charCount; i++) {
+            char c = (char) (randomInt(0, 10) + '0');
+            charValue += String.valueOf(c);
+        }
+        return charValue;
+    }
+	/**获取指定范围随机数*/
+    public static int randomInt(int from, int to) {
+        Random r = new Random();
+        return from + r.nextInt(to - from);
+    }	
+    
+    /**获取随机字符串*/
+    public static String getRandStr(int charCount){
+    	StringBuffer randBf = new StringBuffer();
+        
+        char[] charAndnum = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+        Random random = new Random(); //用于产生随机数
+        for (int j = 0; j < charCount; j++) {
+        	randBf.append(charAndnum[random.nextInt(62)]);  
+        }
+        
+        return randBf.toString();
+    }
+    
+//	public static void main(String[] args){
+//	 System.out.println(getRandStr(8));		
+//	}
+}

+ 6 - 0
src/main/java/com/xynet/marketing/utils/RedisUtil.java

@@ -0,0 +1,6 @@
+package com.xynet.marketing.utils;
+
+public class RedisUtil {
+
+
+}

+ 74 - 0
src/main/java/com/xynet/marketing/utils/RetailSignUtils.java

@@ -0,0 +1,74 @@
+package com.xynet.marketing.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 签名加密(超级机器人对接)
+ * @author hep
+ *
+ */
+public class RetailSignUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(RetailSignUtils.class);
+
+    private static final String ALGORITHM = "HMAC-SHA1";
+
+    public static String getSignAuth(String host, String uri, String contentType, String methodType, 
+    		long timeMillis, String ak, String sk, String body, String queryString) {
+        log.info("host={}, uri={}, contentType={}, methodType={}, timeMillis={}, ak={}, sk={}, body={}, queryString={}", 
+        		host, uri, contentType, methodType, timeMillis, ak, sk, body, queryString);
+        String signedHeaders = getSignedHeaders(host, contentType, timeMillis);
+        log.info("signedHeaders = {}", signedHeaders);
+        
+        String payloadHex = getMD5Hex(body);
+        log.info("payloadHex = {}", payloadHex);
+        
+        String request = getRequest(methodType, uri, queryString, signedHeaders, payloadHex);
+        log.info("request = {}", request);
+        
+        String requextHex = getSHA1Hex(request);
+        log.info("requextHex = {}", requextHex);
+        
+        String stringToSign = getStringToSign(ALGORITHM, requextHex);
+        log.info("stringToSign = {}", stringToSign);
+        
+        String signature = getSignature(stringToSign, sk);
+        log.info("signature = {}", signature);
+        
+        String auth = MD5Encryption.encrypByHMACSHA1(stringToSign, sk);
+        log.info("auth = {}", auth);
+        return String.format("%s %s:%s", ALGORITHM, ak, signature);
+    }
+
+
+    private static String getSignedHeaders(String host, String contentType, long time) {
+        return host.toLowerCase() + ";" + contentType.toLowerCase() + ";" + String.valueOf(time).toLowerCase();
+    }
+
+    private static String getMD5Hex(String payload) {
+        String payloadUtf8 = new String(payload.getBytes(), StandardCharsets.UTF_8);
+        return MD5Encryption.encrypByMD5(payloadUtf8).toLowerCase();
+    }
+
+    private static String getSHA1Hex(String request) {
+        String requestUtf8 = new String(request.getBytes(), StandardCharsets.UTF_8);
+        return MD5Encryption.encrypBySHA1(requestUtf8).toLowerCase();
+    }
+
+    private static String getRequest(String httpRequestMethod, String uri, String queryString, String signHeaders, String hex) {
+        return httpRequestMethod + "\n" + uri + "\n" + queryString + "\n" + signHeaders + "\n" + hex;
+    }
+
+    private static String getStringToSign(String algorithm, String requextHex) {
+        return algorithm + "\n" + requextHex;
+    }
+
+    private static String getSignature(String stringToSign, String sk) {
+        return MD5Encryption.encrypByHMACSHA1(stringToSign, sk);
+    }
+
+
+}

+ 82 - 0
src/main/java/com/xynet/marketing/utils/SpringBeanUtils.java

@@ -0,0 +1,82 @@
+package com.xynet.marketing.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.stereotype.Component;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * spring bean工具
+ * 修改bean只需要获取到bean对象再set修改属性即可
+ */
+@Component
+public class SpringBeanUtils implements ApplicationContextAware {
+
+    private static ConfigurableApplicationContext configurableApplicationContext;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        SpringBeanUtils.applicationContext = applicationContext;
+        configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
+    }
+
+    /**
+     * 获取bean
+     */
+    public static <T> T getBean(Class<T> clazz) {
+        return applicationContext.getBean(clazz);
+    }
+
+    /**
+     * 获取bean
+     */
+    public static Object getBean(String beanName) {
+        return applicationContext.getBean(beanName);
+    }
+
+    /**
+     * 获取bean
+     */
+    public static <T> T getBean(String beanName, Class<T> clazz) {
+        return (T) applicationContext.getBean(beanName);
+    }
+
+
+
+
+
+    /**
+     * 是否存在bean
+     *
+     * @param name beanName
+     * @return
+     */
+    public static boolean existBean(String name) {
+        return configurableApplicationContext.containsBean(name);
+    }
+
+
+    /**
+     * 获取beanName
+     */
+    private static String getName(Class<?> clazz) {
+        String result;
+        String name = clazz.getName();
+        result = name.substring(name.lastIndexOf(".") + 1);
+        //首字母转小写
+        result = result.substring(0, 1).toLowerCase() + result.substring(1);
+        return result;
+    }
+}

+ 29 - 0
src/main/java/com/xynet/marketing/utils/redis/config/RedisConfig.java

@@ -0,0 +1,29 @@
+package com.xynet.marketing.utils.redis.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "spring.redis")
+public class RedisConfig {
+
+    private String host;
+
+    private Integer port;
+
+    private String password;
+
+    private cluster cluster;
+
+    @Data
+    public static class cluster {
+
+        private List<String> nodes;
+
+    }
+
+}

+ 38 - 0
src/main/java/com/xynet/marketing/utils/redis/config/RedisConfiguration.java

@@ -0,0 +1,38 @@
+package com.xynet.marketing.utils.redis.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.util.Objects;
+
+@Configuration
+public class RedisConfiguration {
+
+    @Bean
+    public RedisTemplate redisTemplateSerializer(RedisConnectionFactory factory) {
+        RedisTemplate redisTemplate = new RedisTemplate();
+        RedisSerializer stringSerializer = new StringRedisSerializer();
+        redisTemplate.setConnectionFactory(factory);
+        //设置key编码
+        redisTemplate.setKeySerializer(stringSerializer);
+        redisTemplate.setHashKeySerializer(stringSerializer);
+        //设置value编码
+        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        redisTemplate.setDefaultSerializer(serializer);
+        //序列化时添加对象信息
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
+        serializer.setObjectMapper(objectMapper);
+        return redisTemplate;
+    }
+}

+ 59 - 0
src/main/java/com/xynet/marketing/utils/redis/config/RedissonConfiguration.java

@@ -0,0 +1,59 @@
+package com.xynet.marketing.utils.redis.config;
+
+import cn.hutool.core.lang.Console;
+import lombok.AllArgsConstructor;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * redisson配置
+ */
+@Configuration
+@AllArgsConstructor
+public class RedissonConfiguration {
+
+    private RedisConfig redisConfig;
+
+    @Bean
+    public RedissonClient getRedisson() {
+        return redisConfig.getCluster() == null ? single() : cluster();
+    }
+
+    /**
+     * 单机
+     *
+     * @return
+     */
+    private RedissonClient single() {
+        Config config = new Config();
+        config.useSingleServer()
+                .setAddress("redis://" + redisConfig.getHost() + ":" + redisConfig.getPort())
+                .setPassword(redisConfig.getPassword());
+        return Redisson.create(config);
+    }
+
+    /**
+     * 集群
+     *
+     * @return
+     */
+    private RedissonClient cluster() {
+        RedisConfig.cluster cluster = redisConfig.getCluster();
+        List<String> nodes = cluster.getNodes();
+        List<String> clusterNodes = new ArrayList<>(nodes.size());
+        for (String node : nodes) {
+            clusterNodes.add("redis://" + node);
+        }
+        Config config = new Config();
+        config.useClusterServers()
+                .addNodeAddress(clusterNodes.toArray(new String[clusterNodes.size()]))
+                .setPassword(redisConfig.getPassword());
+        return Redisson.create(config);
+    }
+}

+ 163 - 0
src/main/java/com/xynet/marketing/utils/redis/utils/LockUtils2.java

@@ -0,0 +1,163 @@
+package com.xynet.marketing.utils.redis.utils;
+
+import com.xynet.marketing.utils.FunctionUtils;
+import com.xynet.marketing.utils.SpringBeanUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class LockUtils2 {
+
+    private String name;
+
+    private boolean tryLock = false;
+
+    private int timeout = 10;
+
+    private int timelose = 10;
+
+    private TimeUnit timeunit = TimeUnit.SECONDS;
+
+    private FunctionUtils.NoParamsNoResult fialFunction;
+
+    /**
+     * 锁名称
+     *
+     * @param name
+     * @return
+     */
+    public LockUtils2 name(String name) {
+        this.name = name;
+        return this;
+    }
+
+    /**
+     * 开启非公平锁
+     *
+     * @return
+     */
+    public LockUtils2 tryLock(FunctionUtils.NoParamsNoResult fialFunction) {
+        this.tryLock = true;
+        this.fialFunction = fialFunction;
+        return this;
+    }
+
+    /**
+     * 开启非公平锁
+     *
+     * @param timeout 等待时间
+     * @return
+     */
+    public LockUtils2 tryLock(int timeout, FunctionUtils.NoParamsNoResult fialFunction) {
+        this.tryLock = true;
+        this.timeout = timeout;
+        this.fialFunction = fialFunction;
+        return this;
+    }
+
+    /**
+     * 开启非公平锁
+     *
+     * @param timeout 等待时间
+     * @return
+     */
+    public LockUtils2 tryLock(int timeout) {
+        this.tryLock = true;
+        this.timeout = timeout;
+        return this;
+    }
+
+    /**
+     * 失效时间
+     *
+     * @param timelose
+     * @return
+     */
+    public LockUtils2 timelose(int timelose) {
+        this.timelose = timelose;
+        return this;
+    }
+
+    /**
+     * 时间单位
+     *
+     * @param timeunit
+     * @return
+     */
+    public LockUtils2 timeunit(TimeUnit timeunit) {
+        this.timeunit = timeunit;
+        return this;
+    }
+
+    /**
+     * 获取锁成功执行的函数
+     *
+     * @param successFunction
+     * @param <T>
+     * @return
+     */
+    public <T> T success(FunctionUtils.NoParamsResult<T> successFunction) {
+        RedissonClient redissonClient = SpringBeanUtils.getBean(RedissonClient.class);
+        RLock rlock = redissonClient.getLock(name);
+        try {
+            boolean fal;
+            if (!tryLock) {
+                rlock.lock(timelose, timeunit);
+                fal = true;
+            } else {
+                fal = rlock.tryLock(timeout, timelose, timeunit);
+            }
+            if (fal) {
+                return successFunction.run();
+            }
+            if (fialFunction != null) {
+                fialFunction.run();
+            }
+        } catch (Exception e) {
+            log.error("{}", e);
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            if (rlock.isLocked() && rlock.isHeldByCurrentThread()) {
+                rlock.unlock();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取锁成功执行的函数
+     *
+     * @param successFunction
+     * @return
+     */
+    public void success(FunctionUtils.NoParamsNoResult successFunction) {
+        RedissonClient redissonClient = SpringBeanUtils.getBean(RedissonClient.class);
+        RLock rlock = redissonClient.getLock(name);
+        try {
+            boolean fal;
+            if (!tryLock) {
+                rlock.lock(timelose, timeunit);
+                fal = true;
+            } else {
+                fal = rlock.tryLock(timeout, timelose, timeunit);
+            }
+            if (fal) {
+                successFunction.run();
+                return;
+            }
+            if (fialFunction != null) {
+                fialFunction.run();
+            }
+        } catch (Exception e) {
+            log.error("{}", e);
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            if (rlock.isLocked() && rlock.isHeldByCurrentThread()) {
+                rlock.unlock();
+            }
+        }
+    }
+}

+ 231 - 0
src/main/java/com/xynet/marketing/utils/redis/utils/RedisService.java

@@ -0,0 +1,231 @@
+package com.xynet.marketing.utils.redis.utils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 缓存接口
+ *
+ * @param <V>
+ * @author lijin
+ */
+public interface RedisService<V> {
+
+    /**
+     * 设置有效期
+     */
+    void timeout(String key, long timeout);
+
+    /**
+     * 设置有效期
+     */
+    void timeout(String key, long timeout, TimeUnit timeUnit);
+
+    /**
+     * 获取有效期
+     *
+     * @param key
+     * @return
+     */
+    long getTimeout(String key);
+
+    /**
+     * 获取有效期
+     *
+     * @param key
+     * @return
+     */
+    long getTimeout(String key, TimeUnit timeUnit);
+
+    /**
+     * 写入
+     */
+    void set(String key, V value);
+
+    /**
+     * 写入
+     */
+    void set(String key, V value, long timeout);
+
+    /**
+     * 写入
+     */
+    void set(Map<String, V> map);
+
+    /**
+     * 写入
+     */
+    void set(Map<String, V> map, long timeout);
+
+    /**
+     * 是否存在
+     */
+    boolean exists(String key);
+
+    /**
+     * 获取
+     */
+    V get(String key);
+
+    /**
+     * 获取
+     */
+    Map<String, V> get(List<String> keys);
+
+    /**
+     * 模糊获取
+     */
+    Map<String, V> like(String prex);
+
+    /**
+     * 删除
+     */
+    V remove(String key);
+
+    /**
+     * 删除
+     */
+    Map<String, V> remove(List<String> keys);
+
+    /**
+     * 模糊删除
+     */
+    Map<String, V> removeLike(String prex);
+
+    /**
+     * 写入集合
+     */
+    void setList(String key, V v);
+
+    /**
+     * 写入集合
+     */
+    void setList(String key, List<V> list);
+
+    /**
+     * 获取集合最前一个元素并移除
+     */
+    V getFirstListAndRemove(String key);
+
+    /**
+     * 获取集合最后一个元素并移除
+     */
+    V getLastListAndRemove(String key);
+
+    /**
+     * 获取集合
+     */
+    List<V> getList(String key);
+
+    /**
+     * 模糊获取集合
+     *
+     * @param key
+     * @return
+     */
+    List<V> getLikeList(String key);
+
+    /**
+     * 获取集合长度
+     */
+    int getListSize(String key);
+
+    /**
+     * 修改集合
+     */
+    void updateList(String key, int index, V value);
+
+    /**
+     * 删除集合
+     */
+    V removeList(String key, int index);
+
+    /**
+     * 删除集合
+     */
+    boolean removeList(String key, V v);
+
+    /**
+     * 删除集合
+     */
+    void removeList(String key);
+
+    List<V> removeLikeList(String key);
+
+    /**
+     * 写入map
+     */
+    void setMap(String key, String mk, V mv);
+
+    /**
+     * 写入map
+     */
+    void setMap(String key, Map<String, V> map);
+
+    /**
+     * 获取map
+     */
+    Map<String, V> getMap(String key);
+
+    /**
+     * 获取map
+     */
+    V getMap(String key, String mk);
+
+    /**
+     * 模糊查询map
+     */
+    Map<String, Map<String, V>> likeMap(String prex);
+
+    /**
+     * 获取map长度
+     *
+     * @param key
+     * @return
+     */
+    int getMapSize(String key);
+
+    /**
+     * 删除map
+     */
+    void removeMap(String key);
+
+    /**
+     * 删除map
+     */
+    void removeMap(String key, String mk);
+
+    /**
+     * 模糊删除map
+     *
+     * @param prex
+     */
+    void removeLikeMap(String prex);
+
+    /**
+     * 原子自增
+     */
+    long atomicIncrease(String key);
+
+    /**
+     * 原子自减
+     */
+    long atomicReduce(String key);
+
+    /**
+     * 设置原子值
+     */
+    long setAtomic(String key, long value);
+
+    /**
+     * 获取原子
+     */
+    long getAtomic(String key);
+
+    /**
+     * 原子变量0
+     */
+    void atomicEmpty(String key);
+
+}

+ 298 - 0
src/main/java/com/xynet/marketing/utils/redis/utils/RedisServiceImpl.java

@@ -0,0 +1,298 @@
+package com.xynet.marketing.utils.redis.utils;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.ListOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class RedisServiceImpl<V> implements RedisService<V> {
+
+    private RedisTemplate<String, V> redisTemplate;
+
+    public RedisServiceImpl(@Qualifier("redisTemplateSerializer") RedisTemplate redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+
+    private ValueOperations<String, V> getValueOperations() {
+        return redisTemplate.opsForValue();
+    }
+
+    private ListOperations<String, V> getListOperations() {
+        return redisTemplate.opsForList();
+    }
+
+    private HashOperations<String, String, V> getHashOperations() {
+        return redisTemplate.opsForHash();
+    }
+
+    @Override
+    public void timeout(String key, long timeout) {
+        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void timeout(String key, long timeout, TimeUnit timeUnit) {
+        redisTemplate.expire(key, timeout, timeUnit);
+    }
+
+    @Override
+    public long getTimeout(String key) {
+        return redisTemplate.getExpire(key);
+    }
+
+    @Override
+    public long getTimeout(String key, TimeUnit timeUnit) {
+        return redisTemplate.getExpire(key, timeUnit);
+    }
+
+    @Override
+    public void set(String key, V value) {
+        getValueOperations().set(key, value);
+    }
+
+    @Override
+    public void set(String key, V value, long timeout) {
+        set(key, value);
+        redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void set(Map<String, V> map) {
+        getValueOperations().multiSet(map);
+    }
+
+    @Override
+    public void set(Map<String, V> map, long timeout) {
+        set(map);
+        map.forEach((key, value) -> redisTemplate.expire(key, timeout, TimeUnit.SECONDS));
+    }
+
+    @Override
+    public boolean exists(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    @Override
+    public V get(String key) {
+        return getValueOperations().get(key);
+    }
+
+    @Override
+    public Map<String, V> get(List<String> keys) {
+        Map<String, V> map = new HashMap<>(keys.size());
+        keys.forEach(key -> {
+            V v = get(key);
+            if (v != null) {
+                map.put(key, v);
+            }
+        });
+        return map;
+    }
+
+    @Override
+    public Map<String, V> like(String prex) {
+        Set<String> keys = redisTemplate.keys("*" + prex + "*");
+        Map<String, V> map = new HashMap<>(keys.size());
+        if (CollectionUtils.isEmpty(keys)) {
+            return map;
+        }
+        keys.forEach(key -> {
+            V v = get(key);
+            map.put(key, v);
+        });
+        return map;
+    }
+
+    @Override
+    public V remove(String key) {
+        V v = get(key);
+        redisTemplate.delete(key);
+        return v;
+    }
+
+    @Override
+    public Map<String, V> remove(List<String> keys) {
+        Map<String, V> map = get(keys);
+        redisTemplate.delete(keys);
+        return map;
+    }
+
+    @Override
+    public Map<String, V> removeLike(String prex) {
+        Set<String> keys = redisTemplate.keys("*" + prex + "*");
+        Map<String, V> map = new HashMap<>(keys.size());
+        if (CollectionUtils.isEmpty(keys)) {
+            return map;
+        }
+        keys.forEach(key -> {
+            V v = remove(key);
+            map.put(key, v);
+        });
+        return map;
+    }
+
+    @Override
+    public void setList(String key, V v) {
+        getListOperations().rightPush(key, v);
+    }
+
+    @Override
+    public void setList(String key, List<V> list) {
+        getListOperations().rightPushAll(key, list);
+    }
+
+    @Override
+    public V getFirstListAndRemove(String key) {
+        return getListOperations().leftPop(key);
+    }
+
+    @Override
+    public V getLastListAndRemove(String key) {
+        return getListOperations().rightPop(key);
+    }
+
+    @Override
+    public List<V> getList(String key) {
+        ListOperations<String, V> listOperations = getListOperations();
+        List<V> list = listOperations.range(key, 0, listOperations.size(key));
+        return list;
+    }
+
+    @Override
+    public List<V> getLikeList(String key) {
+        Set<String> keys = redisTemplate.keys("*" + key + "*");
+        List<V> list = new ArrayList<>();
+        keys.forEach(s -> list.addAll(getList(s)));
+        return list;
+    }
+
+    @Override
+    public int getListSize(String key) {
+        long size = getListOperations().size(key);
+        return (int) size;
+    }
+
+    @Override
+    public void updateList(String key, int index, V value) {
+        getListOperations().set(key, index, value);
+    }
+
+    @Override
+    public V removeList(String key, int index) {
+        ListOperations<String, V> listOperations = getListOperations();
+        V v = listOperations.index(key, index);
+        listOperations.remove(key, 0, v);
+        return v;
+    }
+
+    @Override
+    public boolean removeList(String key, V v) {
+        Long remove = getListOperations().remove(key, 0, v);
+        return remove > 0 ? true : false;
+    }
+
+    @Override
+    public void removeList(String key) {
+        redisTemplate.delete(key);
+    }
+
+    @Override
+    public List<V> removeLikeList(String key) {
+        Set<String> keys = redisTemplate.keys("*" + key + "*");
+        List<V> list = new ArrayList<>();
+        keys.forEach(s -> {
+            list.addAll(getList(s));
+            redisTemplate.delete(s);
+        });
+        return list;
+    }
+
+    @Override
+    public void setMap(String key, String mk, V mv) {
+        getHashOperations().put(key, mk, mv);
+    }
+
+    @Override
+    public void setMap(String key, Map<String, V> map) {
+        getHashOperations().putAll(key, map);
+    }
+
+    @Override
+    public Map<String, V> getMap(String key) {
+        return getHashOperations().entries(key);
+    }
+
+    @Override
+    public V getMap(String key, String mk) {
+        return getHashOperations().get(key, mk);
+    }
+
+    @Override
+    public Map<String, Map<String, V>> likeMap(String prex) {
+        Set<String> keys = getHashOperations().getOperations().keys("*" + prex + "*");
+        Map<String, Map<String, V>> maps = new HashMap<>(keys.size());
+        if (CollectionUtils.isEmpty(keys)) {
+            return maps;
+        }
+        keys.forEach(key -> {
+            Map<String, V> map = getMap(key);
+            maps.put(key, map);
+        });
+        return maps;
+    }
+
+    @Override
+    public int getMapSize(String key) {
+        return Integer.valueOf(getHashOperations().size(key).toString());
+    }
+
+    @Override
+    public void removeMap(String key) {
+        redisTemplate.delete(key);
+    }
+
+    @Override
+    public void removeMap(String key, String mk) {
+        getHashOperations().delete(key, mk);
+    }
+
+    @Override
+    public void removeLikeMap(String prex) {
+        Set<String> keys = getHashOperations().getOperations().keys("*" + prex + "*");
+        keys.forEach(key -> removeMap(key));
+    }
+
+    @Override
+    public long atomicIncrease(String key) {
+        return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).getAndIncrement();
+    }
+
+    @Override
+    public long atomicReduce(String key) {
+        return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).getAndDecrement();
+    }
+
+    @Override
+    public long setAtomic(String key, long value) {
+        return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).getAndSet(value);
+    }
+
+    @Override
+    public long getAtomic(String key) {
+        return new RedisAtomicLong(key, redisTemplate.getConnectionFactory()).get();
+    }
+
+    @Override
+    public void atomicEmpty(String key) {
+        remove(key);
+    }
+
+}