Gck 1 year ago
parent
commit
64399b7bed
31 changed files with 5353 additions and 0 deletions
  1. 5 0
      pom.xml
  2. 43 0
      src/main/java/com/example/xiaoshiweixinback/business/exception/BusinessException.java
  3. 62 0
      src/main/java/com/example/xiaoshiweixinback/business/exception/BusinessExceptionErrorEnum.java
  4. 31 0
      src/main/java/com/example/xiaoshiweixinback/business/exception/GlobalExceptionHandler.java
  5. 123 0
      src/main/java/com/example/xiaoshiweixinback/business/jwt/JwtTokenUtil.java
  6. 34 0
      src/main/java/com/example/xiaoshiweixinback/business/jwt/JwtUserInfo.java
  7. 81 0
      src/main/java/com/example/xiaoshiweixinback/business/jwt/properties/JwtProperties.java
  8. 46 0
      src/main/java/com/example/xiaoshiweixinback/business/redis/CacheTTLEnum.java
  9. 553 0
      src/main/java/com/example/xiaoshiweixinback/business/redis/RedisService.java
  10. 80 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/BeanUtil.java
  11. 798 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/CollectionKit.java
  12. 399 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/DateUtil.java
  13. 42 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/JSONUtil.java
  14. 233 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/LogHelper.java
  15. 93 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/MD5Util.java
  16. 73 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/PageKit.java
  17. 12 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/RandomUtil.java
  18. 44 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/RegexUtil.java
  19. 1370 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/StrKit.java
  20. 537 0
      src/main/java/com/example/xiaoshiweixinback/business/utils/ToolUtil.java
  21. 33 0
      src/main/java/com/example/xiaoshiweixinback/controller/LoginController.java
  22. 26 0
      src/main/java/com/example/xiaoshiweixinback/entity/dto/LoginDTO.java
  23. 49 0
      src/main/java/com/example/xiaoshiweixinback/entity/dto/WXLoginDTO.java
  24. 32 0
      src/main/java/com/example/xiaoshiweixinback/entity/vo/Jscode2SessionWo.java
  25. 12 0
      src/main/java/com/example/xiaoshiweixinback/entity/vo/LoginVO.java
  26. 20 0
      src/main/java/com/example/xiaoshiweixinback/entity/vo/SendCodeVO.java
  27. 39 0
      src/main/java/com/example/xiaoshiweixinback/entity/vo/WXLoginVO.java
  28. 20 0
      src/main/java/com/example/xiaoshiweixinback/okhttp/RequestCallBack.java
  29. 179 0
      src/main/java/com/example/xiaoshiweixinback/okhttp/RequestManager.java
  30. 109 0
      src/main/java/com/example/xiaoshiweixinback/okhttp/ResponseManager.java
  31. 175 0
      src/main/java/com/example/xiaoshiweixinback/service/LoginService.java

+ 5 - 0
pom.xml

@@ -135,6 +135,11 @@
             <artifactId>commons-pool2</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.6</version>
+        </dependency>
+        <dependency>
             <groupId>com.mysql</groupId>
             <artifactId>mysql-connector-j</artifactId>
             <scope>runtime</scope>

+ 43 - 0
src/main/java/com/example/xiaoshiweixinback/business/exception/BusinessException.java

@@ -0,0 +1,43 @@
+package com.example.xiaoshiweixinback.business.exception;
+
+
+import com.bjbz.core.exception.BaseBusinessException;
+import com.bjbz.core.log.tools.LogHelper;
+
+
+public class BusinessException extends BaseBusinessException {
+
+
+	private static final long serialVersionUID = 465630095603311090L;
+
+	public BusinessException(Throwable throwable, BusinessExceptionErrorEnum e) {
+		LogHelper.log(BusinessException.class, throwable);
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+	}
+
+	public BusinessException(Throwable throwable, BusinessExceptionErrorEnum e, String errorMessage) {
+		LogHelper.log(BusinessException.class, throwable);
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+		this.extraMessage = errorMessage;
+	}
+
+	public BusinessException(BusinessExceptionErrorEnum e) {
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+	}
+
+	public BusinessException(BusinessExceptionErrorEnum e, String errorMessage) {
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+		this.extraMessage = errorMessage;
+	}
+
+	public BusinessException(BusinessExceptionErrorEnum e, Object extraMessage) {
+		this.errorMessage = e.getMessage();
+		this.extraMessage = extraMessage;
+		this.errorCode = e.getCode();
+	}
+
+}

+ 62 - 0
src/main/java/com/example/xiaoshiweixinback/business/exception/BusinessExceptionErrorEnum.java

@@ -0,0 +1,62 @@
+package com.example.xiaoshiweixinback.business.exception;
+
+public enum BusinessExceptionErrorEnum {
+	//1000 系统异常
+	TOKEN_EXPIRED(1001,"TOKE过期!"),
+	TOKEN_PARSE_ERROR(1002,"TOKE解析错误!"),
+	TOKEN_SECRET_ERROR(1003,"没有访问权限!"),
+	LOGIN_USER_PASSWORD_ERROR(1004,"用户名密码错误!"),
+	LOGIN_USER_FORBIDDEN(1005,"用户被停用!"),
+	LOGIN_USER_DELETE(1006,"用户被删除!"),
+	API_AUTHORITY_ERROR(1007,"API调用权限异常!"),
+	UPLOAD_IMAGE_TYPE_ERROR(1010,"上传图片格式错误!"),
+	FILE_TOO_BIG(1011,"上传文件大小不能超过100M"),
+	FILE_NO_HAVE_NAME(1012,"未传文件名或文件名为空"),
+	NO_DATA_AUTH(1013,"暂无数据权限,请联系管理员"),
+	SIGNIN_ACCOUNT_HAVE_ALREADY_REGISTER(1014,"登录账号已存在"),
+	OLD_PASSWORD_ERROR(1015,"原密码错误"),
+	EXCEL_READ_ERROR(1016,"excel有错误,请先处理"),
+	PARAM_ERROR(1017,"参数错误"),
+	NO_AUTH_ROLE(1018,"暂无操作权限"),
+	NO_ATTACHMENT(1019,"无附件信息"),
+	REMOTE_FILE_READ_ERROR(1020,"远程文件读取失败"),
+	DOWNLOAD_ERROR(1021,"文件下载失败"),
+	INTERFACE_IS_STOP(1022,"接口已停用"),
+	CALL_API_ERROR(1023,"接口调用失败"),
+    TEMPLATE_EXCEL_DOWNLOAD_ERROR(1024,"模板下载失败"),
+	REQUEST_ERROR(1025,"请求错误"),
+	IMAGE_SIZE_ERROR(1026, "图片格式错误"),
+	IMAGE_SEIZE_ERROR(1027, "图片大小不能超过4M"),
+	IDCARD_NOT_FOUND_ERROR(1028,"身份证无法识别"),
+	SYSTEM_BUSY(1029,"系统繁忙,请稍后重试"),
+	RECOGNIZE_ERROR(1030, "识别错误"),
+	NO_DATA_EXPORT(1031,"暂无可导出数据"),
+	UPLOAD_ERROR(1032,"上传失败"),
+
+	THE_COMPANY_NAME_HAS_EXIST(110001, "企业名称已存在"),
+	THE_COMPANY_STATUS_NOT_APPROVE_PASS(110002,"该企业审核未通过,不可发布职位需求"),
+	THE_ACCOUNT_HAS_EXISTS(110003, "账号已存在"),
+	THE_PHONE_HAS_EXISTS(110005, "手机号已存在"),
+	THE_FEEDBACK_CONTENT_IS_NOT_EMPTY(110004, "反馈内容不得为空"),
+
+	;
+
+	private int code;
+	private String message;
+	private BusinessExceptionErrorEnum(int code, String desc) {
+		this.setCode(code);
+		this.setMessage(desc);
+	}
+	public String getMessage() {
+		return message;
+	}
+	public void setMessage(String message) {
+		this.message = message;
+	}
+	public int getCode() {
+		return code;
+	}
+	public void setCode(int code) {
+		this.code = code;
+	}
+}

+ 31 - 0
src/main/java/com/example/xiaoshiweixinback/business/exception/GlobalExceptionHandler.java

@@ -0,0 +1,31 @@
+/*
+package com.example.xiaoshiweixinback.business.exception;
+
+
+import com.example.xiaoshiweixinback.business.utils.ToolUtil;
+
+@ControllerAdvice
+public class GlobalExceptionHandler extends BaseGlobalExceptionHandler{
+    @SuppressWarnings("deprecation")
+    @ExceptionHandler(BusinessException.class)
+    @ResponseStatus(HttpStatus.OK)
+    @ResponseBody //在返回自定义相应类的情况下必须有,这是@ControllerAdvice注解的规定
+    public ResponseData<Object> exceptionHandler(BusinessException e, HttpServletResponse response) {
+        ResponseData<Object> rd;
+        try {
+            rd = new ResponseData<Object>();
+        } catch (BusinessException e1) {
+            return new ResponseData<Object>(e.getErrorCode(), e.getErrorMessage());
+        }
+        rd.setCode(e.getErrorCode());
+        rd.setMessage(e.getErrorMessage()+""+ (ToolUtil.isNotEmpty(e.getExtraMessage())?":"+e.getExtraMessage():""));
+        if (e.getExtraMessage() != null) {
+            rd.setData(e.getExtraMessage());
+        }
+//        LogHelper.log(GlobalExceptionHandler.class, e);
+        LogHelper.warnLog(e);
+        return rd;
+    }
+
+}
+*/

+ 123 - 0
src/main/java/com/example/xiaoshiweixinback/business/jwt/JwtTokenUtil.java

@@ -0,0 +1,123 @@
+package com.example.xiaoshiweixinback.business.jwt;
+
+import com.bjbz.common.jwt.properties.JwtProperties;
+import com.bjbz.common.util.ToolUtil;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class JwtTokenUtil {
+
+    @Autowired
+    private JwtProperties jwtProperties;
+
+    /**
+     * 获取用户名从token中
+     */
+    public String getUsernameFromToken(String token) {
+        return getClaimFromToken(token).getSubject();
+    }
+
+    /**
+     * 获取jwt发布时间
+     */
+    public Date getIssuedAtDateFromToken(String token) {
+        return getClaimFromToken(token).getIssuedAt();
+    }
+
+    /**
+     * 获取jwt失效时间
+     */
+    public Date getExpirationDateFromToken(String token) {
+        return getClaimFromToken(token).getExpiration();
+    }
+
+    /**
+     * 获取jwt接收者
+     */
+    public String getAudienceFromToken(String token) {
+        return getClaimFromToken(token).getAudience();
+    }
+
+    /**
+     * 获取私有的jwt claim
+     */
+    public String getPrivateClaimFromToken(String token, String key) {
+        return getClaimFromToken(token).get(key).toString();
+    }
+
+    /**
+     * 获取md5 key从token中
+     */
+    public String getMd5KeyFromToken(String token) {
+        return getPrivateClaimFromToken(token, jwtProperties.getMd5Key());
+    }
+
+    /**
+     * 获取jwt的payload部分
+     */
+    public Claims getClaimFromToken(String token) {
+        return Jwts.parser()
+                .setSigningKey(jwtProperties.getSecret())
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    /**
+     * 解析token是否正确,不正确会报异常<br>
+     */
+    public void parseToken(String token) throws JwtException {
+        Jwts.parser().setSigningKey(jwtProperties.getSecret()).parseClaimsJws(token).getBody();
+    }
+
+    /**
+     * <pre>
+     *  验证token是否失效
+     *  true:过期   false:没过期
+     * </pre>
+     */
+    public Boolean isTokenExpired(String token) {
+        final Date expiration = getExpirationDateFromToken(token);
+        return expiration.before(new Date());
+    }
+
+    /**
+     * 生成token(通过用户信息JSON格式和签名时候用的随机数)
+     */
+    public String generateToken(String userInfo, String randomKey) {
+        Map<String, Object> claims = new HashMap<>();
+        claims.put(jwtProperties.getMd5Key(), randomKey);
+        return doGenerateToken(claims, userInfo);
+    }
+
+    /**
+     * 生成token
+     */
+    private String doGenerateToken(Map<String, Object> claims, String subject) {
+        final Date createdDate = new Date();
+        final Date expirationDate = new Date(createdDate.getTime() + jwtProperties.getExpiration() * 1000);
+
+        return Jwts.builder()
+                .setClaims(claims)
+                .setSubject(subject)
+                .setIssuedAt(createdDate)
+                .setExpiration(expirationDate)
+                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
+                .compact();
+    }
+
+    /**
+     * 获取混淆MD5签名用的随机字符串
+     */
+    public String getRandomKey() {
+        return ToolUtil.getRandomString(6);
+    }
+}

+ 34 - 0
src/main/java/com/example/xiaoshiweixinback/business/jwt/JwtUserInfo.java

@@ -0,0 +1,34 @@
+package com.bjbz.common.jwt;
+
+
+public class JwtUserInfo {
+    private String token;
+
+
+    /**
+     * @Title: toJsonString
+     * @Description: 返回json字符串
+     * @param @return    参数
+     * @return String    返回类型
+     * @throws
+     * @author Orange
+     * @date 2018年1月28日
+     */
+    public String toJsonString() {
+        return JSONUtil.toJSONString(this);
+    }
+
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+
+
+
+
+}

+ 81 - 0
src/main/java/com/example/xiaoshiweixinback/business/jwt/properties/JwtProperties.java

@@ -0,0 +1,81 @@
+package com.example.xiaoshiweixinback.business.jwt.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties(prefix = JwtProperties.JWT_PREFIX)
+public class JwtProperties {
+
+    public static final String JWT_PREFIX = "jwt";
+
+    private String header = "Authorization";
+
+    private String secret = "defaultSecret";
+
+    private String distributeToken = "DistributeToken";
+
+    private Long expiration = 60*60*24L;
+
+//    private String authPath = "demo/auth";
+
+    private String md5Key = "randomKey";
+
+    public static String getJwtPrefix() {
+        return JWT_PREFIX;
+    }
+
+
+
+    public String getDistributeToken() {
+        return distributeToken;
+    }
+
+
+
+    public void setDistributeToken(String distributeToken) {
+        this.distributeToken = distributeToken;
+    }
+
+
+
+    public String getHeader() {
+        return header;
+    }
+
+    public void setHeader(String header) {
+        this.header = header;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public Long getExpiration() {
+        return expiration;
+    }
+
+    public void setExpiration(Long expiration) {
+        this.expiration = expiration;
+    }
+
+//    public String getAuthPath() {
+//        return authPath;
+//    }
+//
+//    public void setAuthPath(String authPath) {
+//        this.authPath = authPath;
+//    }
+
+    public String getMd5Key() {
+        return md5Key;
+    }
+
+    public void setMd5Key(String md5Key) {
+        this.md5Key = md5Key;
+    }
+}

+ 46 - 0
src/main/java/com/example/xiaoshiweixinback/business/redis/CacheTTLEnum.java

@@ -0,0 +1,46 @@
+package com.example.xiaoshiweixinback.business.redis;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @ClassName
+ * @Description TODO
+ * @Author 陈凯裕
+ * @Date 2022/7/15 18:08
+ * @Version TODO
+ **/
+public class CacheTTLEnum {
+
+    public static final CacheTTLEnum ONE_MINUTE = new CacheTTLEnum(1L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum TEN_MINUTE = new CacheTTLEnum(10L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum FIFTEEN_MINUTE = new CacheTTLEnum(15L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum THIRTY_MINUTE = new CacheTTLEnum(30L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum ONE_HOUR = new CacheTTLEnum(1L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum TWELVE_HOUR = new CacheTTLEnum(12L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum ONE_DAY = new CacheTTLEnum(1L,TimeUnit.DAYS);
+    public static final CacheTTLEnum TWO_HOUR = new CacheTTLEnum(2L,TimeUnit.HOURS);
+
+
+    private Long time;
+
+    private TimeUnit unit;
+
+    protected CacheTTLEnum(Long time, TimeUnit unit) {
+        this.time = time;
+        this.unit = unit;
+    }
+
+    public Long getTime() {
+        return time;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+}

+ 553 - 0
src/main/java/com/example/xiaoshiweixinback/business/redis/RedisService.java

@@ -0,0 +1,553 @@
+/*
+package com.example.xiaoshiweixinback.business.redis;
+
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+*/
+/**
+ * @ClassName
+ * @Description TODO
+ * @Author 陈凯裕
+ * @Date 2022/7/15 14:02
+ * @Version TODO
+ **//*
+
+@Component
+public class RedisService {
+
+    @Resource
+    RedisTemplate redisTemplate;
+
+    */
+/** -------------------key相关操作--------------------- *//*
+
+
+
+    */
+/**
+     * 删除key
+     *//*
+
+    public void delete(String key) {
+        redisTemplate.delete(key);
+    }
+
+    */
+/**
+     * 批量删除key
+     *//*
+
+    public void delete(Collection<String> keys) {
+        redisTemplate.delete(keys);
+    }
+
+
+    */
+/**
+     * 是否存在key
+     *//*
+
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    */
+/**
+     * 设置过期时间
+     *//*
+
+    public Boolean expire(String key, CacheTTLEnum ttlEnum) {
+        return redisTemplate.expire(key, ttlEnum.getTime(), ttlEnum.getUnit());
+    }
+
+
+    */
+/**
+     * 移除 key 的过期时间,key 将持久保持
+     *//*
+
+    public Boolean persist(String key) {
+        return redisTemplate.persist(key);
+    }
+
+
+    */
+/**
+     * 返回 key 的剩余的过期时间
+     *//*
+
+    public Long getExpire(String key, TimeUnit unit) {
+        return redisTemplate.getExpire(key, unit);
+    }
+
+    */
+/**
+     * 修改 key 的名称
+     *//*
+
+    public void rename(String oldKey, String newKey) {
+        redisTemplate.rename(oldKey, newKey);
+    }
+
+    */
+/** -------------------string相关操作--------------------- *//*
+
+
+    */
+/**
+     * 设置指定 key 的值
+     *//*
+
+    public void set(String key, Object value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    */
+/**
+     * 获取指定 key 的值
+     *//*
+
+    public Object get(String key) {
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    public <T> T get(String key,Class<T> clazz){
+        return (T)get(key);
+    }
+
+
+    */
+/**
+     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
+     *//*
+
+    public Object getAndSet(String key, Object value) {
+        return redisTemplate.opsForValue().getAndSet(key, value);
+    }
+
+    public <T> T getAndSet(String key,Object value,Class<T> clazz){
+        return (T)getAndSet(key,value);
+    }
+
+
+    */
+/**
+     * 批量获取
+     *//*
+
+    public List<Object> multiGet(Collection<String> keys) {
+        return redisTemplate.opsForValue().multiGet(keys);
+    }
+
+
+    */
+/**
+     * 只有在 key 不存在时设置 key 的值
+     *//*
+
+    public boolean setIfAbsent(String key, Object value) {
+        return redisTemplate.opsForValue().setIfAbsent(key, value);
+    }
+
+
+    */
+/**
+     * 设置一个key,值为自增的LONG类型,每调用一次+1并且返回值自增后的值
+     *//*
+
+    public Long incrBy(String key) {
+        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key,redisTemplate.getConnectionFactory());
+        return redisAtomicLong.incrementAndGet();
+    }
+
+
+    */
+/** -------------------hash相关操作------------------------- *//*
+
+
+    */
+/**
+     * 获取存储在hash表中指定字段的值
+     *//*
+
+    public Object hGet(String key, String field) {
+        return redisTemplate.opsForHash().get(key, field);
+    }
+
+    */
+/*
+     * 存储指定键值对至hash表中
+     * *//*
+
+    public void hPut(String key, String hashKey, Object value) {
+        redisTemplate.opsForHash().put(key, hashKey, value);
+    }
+
+    */
+/**
+     * 获取hash表中所有的键值对
+     *//*
+
+    public Map<String, Object> hGetAll(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    */
+/**
+     * 获取hash表中所有给定字段的值
+     *//*
+
+    public List<Object> hMultiGet(String key, Collection<String> fields) {
+        return redisTemplate.opsForHash().multiGet(key, fields);
+    }
+
+    */
+/*
+    * 批量插入到hash表中
+    * *//*
+
+    public void hPutAll(String key, Map<String, Object> maps) {
+        redisTemplate.opsForHash().putAll(key, maps);
+    }
+
+
+    */
+/**
+     * 删除一个或多个hash表字段
+     *//*
+
+    public Long hDelete(String key, String... fields) {
+        return redisTemplate.opsForHash().delete(key, fields);
+    }
+
+    */
+/**
+     * 查看hash表 key 中,指定的字段是否存在
+     *//*
+
+    public boolean hExists(String key, String field) {
+        return redisTemplate.opsForHash().hasKey(key, field);
+    }
+
+
+    */
+/**
+     * 获取所有hash表中的字段
+     *//*
+
+    public Set<String> hKeys(String key) {
+        return redisTemplate.opsForHash().keys(key);
+    }
+
+    */
+/**
+     * 获取hash表中字段的数量
+     *//*
+
+    public Long hSize(String key) {
+        return redisTemplate.opsForHash().size(key);
+    }
+
+
+    */
+/** ------------------------list相关操作---------------------------- *//*
+
+
+    */
+/**
+     * 通过索引获取列表中的元素
+     *//*
+
+    public Object lIndex(String key, long index) {
+        return redisTemplate.opsForList().index(key, index);
+    }
+
+    */
+/**
+     * 通过索引设置列表元素的值
+     *//*
+
+    public void lSet(String key, long index, String value) {
+        redisTemplate.opsForList().set(key, index, value);
+    }
+
+    */
+/**
+     * 获取列表指定范围内的元素
+     *//*
+
+    public List<JpCityPO> lRange(String key, long start, long end) {
+        return redisTemplate.opsForList().range(key, start, end);
+    }
+
+    */
+/**
+     * 列表队列左push
+     *//*
+
+    public Long lLeftPush(String key, Object value) {
+        return redisTemplate.opsForList().leftPush(key, value);
+    }
+
+    */
+/**
+     * 列表队列批量左push
+     *//*
+
+    public Long lLeftPushAll(String key, Object... value) {
+        if(value.length==0)
+            return 0L;
+        return redisTemplate.opsForList().leftPushAll(key, value);
+    }
+
+
+    */
+/**
+     * 列表队列右push
+     *//*
+
+    public Long lRightPush(String key, Object value) {
+        return redisTemplate.opsForList().rightPush(key, value);
+    }
+
+    */
+/**
+     * 列表队列批量右push
+     *//*
+
+    public Long lRightPushAll(String key, Object... value) {
+        if(value.length==0)
+            return 0L;
+        return redisTemplate.opsForList().rightPushAll(key, value);
+    }
+
+    */
+/**
+     * 弹出列表左侧的第一个元素
+     *//*
+
+    public Object lLeftPop(String key) {
+        return redisTemplate.opsForList().leftPop(key);
+    }
+
+
+    */
+/**
+     * 弹出列表右侧的第一个元素
+     *
+     * @param key
+     * @return 删除的元素
+     *//*
+
+    public Object lRightPop(String key) {
+        return redisTemplate.opsForList().rightPop(key);
+    }
+
+    */
+/**
+     * 获取列表长度
+     *//*
+
+    public Long lLen(String key) {
+        return redisTemplate.opsForList().size(key);
+    }
+
+    */
+/** --------------------set相关操作-------------------------- *//*
+
+
+    */
+/**
+     * set添加元素
+     *//*
+
+    public Long sAdd(String key, Object... values) {
+        return redisTemplate.opsForSet().add(key, values);
+    }
+
+    */
+/**
+     * set移除元素
+     *//*
+
+    public Long sRemove(String key, Object... values) {
+        return redisTemplate.opsForSet().remove(key, values);
+    }
+
+    */
+/**
+     * 获取集合的大小
+     *
+     * @param key
+     * @return
+     *//*
+
+    public Long sSize(String key) {
+        return redisTemplate.opsForSet().size(key);
+    }
+
+    */
+/**
+     * 获取集合所有元素
+     *//*
+
+    public Set<String> sGetMembers(String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    */
+/**
+     * 判断集合是否包含元素
+     *//*
+
+    public boolean sContains(String key,Object value){
+        return redisTemplate.opsForSet().isMember(key,value);
+    }
+
+    */
+/**------------------zSet相关操作--------------------------------*//*
+
+
+    */
+/**
+     * 添加元素,有序集合是按照元素的score值由小到大排列
+     *//*
+
+    public Boolean zAdd(String key, Object value, double score) {
+        return redisTemplate.opsForZSet().add(key, value, score);
+    }
+
+
+    */
+/**
+     * 移除指定value的值
+     *//*
+
+    public Long zRemove(String key, Object... values) {
+        return redisTemplate.opsForZSet().remove(key, values);
+    }
+
+    */
+/**
+     * 增加元素的score值,并返回增加后的值
+     *//*
+
+    public Double zIncrementScore(String key, Object value, double delta) {
+        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
+    }
+
+    */
+/**
+     * 返回元素在集合的排名,按Score升序排名
+     *//*
+
+    public Long zRank(String key, Object value) {
+        return redisTemplate.opsForZSet().rank(key, value);
+    }
+
+    */
+/**
+     * 返回元素在集合的排名,按Score倒序排名
+     *//*
+
+    public Long zReverseRank(String key, Object value) {
+        return redisTemplate.opsForZSet().reverseRank(key, value);
+    }
+
+    */
+/**
+     * 获取集合的元素, 升序
+     *//*
+
+    public Set<String> zRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().range(key, start, end);
+    }
+
+
+    */
+/**
+     * 获取集合的元素, 倒序
+     *//*
+
+    public Set<String> zReverseRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().reverseRange(key, start, end);
+    }
+
+    */
+/**
+     * 根据Score值查询集合元素,升序
+     *//*
+
+    public Set<String> zRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
+    }
+
+    */
+/**
+     * 根据Score值查询集合元素, 倒序
+     *//*
+
+    public Set<Object> zReverseRangeByScore(String key, double min,
+                                            double max) {
+        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
+    }
+
+    */
+/**
+     * 根据score值获取集合元素数量
+     *//*
+
+    public Long zCount(String key, double min, double max) {
+        return redisTemplate.opsForZSet().count(key, min, max);
+    }
+
+    */
+/**
+     * 获取集合大小
+     *
+     * @param key
+     * @return
+     *//*
+
+    public Long zSize(String key) {
+        return redisTemplate.opsForZSet().size(key);
+    }
+
+    */
+/**
+     * 获取集合中value元素的score值
+     *//*
+
+    public Double zScore(String key, Object value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
+    */
+/**
+     * 移除指定索引位置的成员
+     *//*
+
+    public Long zRemoveRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().removeRange(key, start, end);
+    }
+
+    */
+/**
+     * 根据指定的score值的范围来移除成员
+     *//*
+
+    public Long zRemoveRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
+    }
+
+
+}
+
+
+*/

+ 80 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/BeanUtil.java

@@ -0,0 +1,80 @@
+//package com.example.xiaoshiweixinback.business.utils;
+
+//public  class BeanUtil {
+//
+//
+//	/**
+//	* @Title: copy
+//	* @Description: 类属性复制
+//	* @param @param source
+//	* @param @param target    参数
+//	* @return void    返回类型
+//	* @throws
+//	* @author Orange
+//	* @date 2019年4月3日
+//	*/
+//	public static void copy(Object source,Object target){
+//		org.springframework.beans.BeanUtils.copyProperties(source, target);
+//	}
+//
+//	/**
+//	 * @name: 克隆source为新对象
+//	 * @author Peach
+//	 * @date:2018/9/4
+//	 */
+//	public static <T> T cloneNewObject(Object source,Class<T> clazz){
+//		T t = null;
+//		try {
+//			t = clazz.newInstance();
+//		} catch (Exception e) {
+//			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+//			throw new BaseBusinessException(BaseExceptionErrorEnum.INIT_GENERICITY_BEAN_ERROR);
+//		}
+//		BeanUtil.copy(source,t);
+//		return t;
+//	}
+//
+//
+//	/**
+//	 * @Title: newTclass
+//	 * @Description: 实例化泛型类
+//	 * @param @param
+//	 *            clazz
+//	 * @param @return
+//	 * @param @throws
+//	 *            InstantiationException
+//	 * @param @throws
+//	 *            IllegalAccessException 参数
+//	 * @return T 返回类型
+//	 * @throws @author
+//	 *             Orange
+//	 * @date 2018年1月16日
+//	 */
+//	public static <T> T newTclass(Class<T> clazz) {
+//		T a = null;
+//		try {
+//			a = clazz.newInstance();
+//		} catch (Exception e) {
+//			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+//			throw new BaseBusinessException(BaseExceptionErrorEnum.INIT_GENERICITY_BEAN_ERROR);
+//		}
+//		return a;
+//	}
+//
+//	public static Object[] getEntities(Object target, Class<?>[] objs) {
+//		Object[] entities = new Object[objs.length];
+//		int count = 0;
+//		for (Class<?> o : objs) {
+//			Object entity = null;
+//			try {
+//				entity = o.newInstance();
+//			} catch (Exception e) {
+//				continue;
+//			}
+//			if (target != null)
+//				copy(target, entity);
+//			entities[count ++] = entity;
+//		}
+//		return entities;
+//	}
+//}

+ 798 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/CollectionKit.java

@@ -0,0 +1,798 @@
+package com.example.xiaoshiweixinback.business.utils;
+
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * 集合相关工具类,包括数组
+ * 
+ * @author xiaoleilu
+ * 
+ */
+public class CollectionKit {
+	
+	private CollectionKit() {
+		// 静态类不可实例化
+	}
+	
+	/**
+	 * 以 conjunction 为分隔符将集合转换为字符串
+	 * 
+	 * @param <T> 被处理的集合
+	 * @param collection 集合
+	 * @param conjunction 分隔符
+	 * @return 连接后的字符串
+	 */
+	public static <T> String join(Iterable<T> collection, String conjunction) {
+		StringBuilder sb = new StringBuilder();
+		boolean isFirst = true;
+		for (T item : collection) {
+			if (isFirst) {
+				isFirst = false;
+			} else {
+				sb.append(conjunction);
+			}
+			sb.append(item);
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 以 conjunction 为分隔符将数组转换为字符串
+	 * 
+	 * @param <T> 被处理的集合
+	 * @param array 数组
+	 * @param conjunction 分隔符
+	 * @return 连接后的字符串
+	 */
+	public static <T> String join(T[] array, String conjunction) {
+		StringBuilder sb = new StringBuilder();
+		boolean isFirst = true;
+		for (T item : array) {
+			if (isFirst) {
+				isFirst = false;
+			} else {
+				sb.append(conjunction);
+			}
+			sb.append(item);
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 将多个集合排序并显示不同的段落(分页)
+	 * @param pageNo 页码
+	 * @param numPerPage 每页的条目数
+	 * @param comparator 比较器
+	 * @param colls 集合数组
+	 * @return 分页后的段落内容
+	 */
+	@SafeVarargs
+	public static <T> List<T> sortPageAll(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {
+		final List<T> result = new ArrayList<T>();
+		for (Collection<T> coll : colls) {
+			result.addAll(coll);
+		}
+		
+		Collections.sort(result, comparator);
+		
+		//第一页且数目少于第一页显示的数目
+		if(pageNo <=1 && result.size() <= numPerPage) {
+			return result;
+		}
+		
+		final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);
+		return result.subList(startEnd[0], startEnd[1]);
+	}
+
+	/**
+	 * 将多个集合排序并显示不同的段落(分页)
+	 * @param pageNo 页码
+	 * @param numPerPage 每页的条目数
+	 * @param comparator 比较器
+	 * @param colls 集合数组
+	 * @return 分业后的段落内容
+	 */
+//	@SafeVarargs
+//	public static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {
+//		BoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage);
+//		for (Collection<T> coll : colls) {
+//			queue.addAll(coll);
+//		}
+//
+//		//第一页且数目少于第一页显示的数目
+//		if(pageNo <=1 && queue.size() <= numPerPage) {
+//			return queue.toList();
+//		}
+//
+//		final int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);
+//		return queue.toList().subList(startEnd[0], startEnd[1]);
+//	}
+
+	/**
+	 * 将Set排序(根据Entry的值)
+	 *
+	 * @param set 被排序的Set
+	 * @return 排序后的Set
+	 */
+	public static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) {
+		List<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set);
+		Collections.sort(list, new Comparator<Entry<Long, Long>>(){
+
+			@Override
+			public int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) {
+				if (o1.getValue() > o2.getValue()){
+					return 1;
+				}
+				if (o1.getValue() < o2.getValue()){
+					return -1;
+				}
+				return 0;
+			}
+		});
+		return list;
+	}
+
+	/**
+	 * 切取部分数据
+	 *
+	 * @param <T> 集合元素类型
+	 * @param surplusAlaDatas 原数据
+	 * @param partSize 每部分数据的长度
+	 * @return 切取出的数据或null
+	 */
+	public static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) {
+		if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){
+			return null;
+		}
+
+		final List<T> currentAlaDatas = new ArrayList<T>();
+		int size = surplusAlaDatas.size();
+		// 切割
+		if (size > partSize) {
+			for (int i = 0; i < partSize; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		} else {
+			for (int i = 0; i < size; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		}
+		return currentAlaDatas;
+	}
+
+	/**
+	 * 切取部分数据
+	 *
+	 * @param <T> 集合元素类型
+	 * @param surplusAlaDatas 原数据
+	 * @param partSize 每部分数据的长度
+	 * @return 切取出的数据或null
+	 */
+	public static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) {
+		if (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){
+			return null;
+		}
+
+		final List<T> currentAlaDatas = new ArrayList<T>();
+		int size = surplusAlaDatas.size();
+		// 切割
+		if (size > partSize) {
+			for (int i = 0; i < partSize; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		} else {
+			for (int i = 0; i < size; i++) {
+				currentAlaDatas.add(surplusAlaDatas.pop());
+			}
+		}
+		return currentAlaDatas;
+	}
+
+	/**
+	 * 新建一个HashMap
+	 *
+	 * @return HashMap对象
+	 */
+	public static <T, K> HashMap<T, K> newHashMap() {
+		return new HashMap<T, K>();
+	}
+
+	/**
+	 * 新建一个HashMap
+	 * @param size 初始大小,由于默认负载因子0.75,传入的size会实际初始大小为size / 0.75
+	 * @return HashMap对象
+	 */
+	public static <T, K> HashMap<T, K> newHashMap(int size) {
+		return new HashMap<T, K>((int)(size / 0.75));
+	}
+
+	/**
+	 * 新建一个HashSet
+	 *
+	 * @return HashSet对象
+	 */
+	public static <T> HashSet<T> newHashSet() {
+		return new HashSet<T>();
+	}
+
+	/**
+	 * 新建一个HashSet
+	 *
+	 * @return HashSet对象
+	 */
+	@SafeVarargs
+	public static <T> HashSet<T> newHashSet(T... ts) {
+		HashSet<T> set = new HashSet<T>();
+		for (T t : ts) {
+			set.add(t);
+		}
+		return set;
+	}
+
+	/**
+	 * 新建一个ArrayList
+	 *
+	 * @return ArrayList对象
+	 */
+	public static <T> ArrayList<T> newArrayList() {
+		return new ArrayList<T>();
+	}
+
+	/**
+	 * 新建一个ArrayList
+	 *
+	 * @return ArrayList对象
+	 */
+	@SafeVarargs
+	public static <T> ArrayList<T> newArrayList(T... values) {
+		return new ArrayList<T>(Arrays.asList(values));
+	}
+
+	/**
+	 * 将新元素添加到已有数组中<br/>
+	 * 添加新元素会生成一个新的数组,不影响原数组
+	 *
+	 * @param buffer 已有数组
+	 * @param newElement 新元素
+	 * @return 新数组
+	 */
+	public static <T> T[] append(T[] buffer, T newElement) {
+		T[] t = resize(buffer, buffer.length + 1, newElement.getClass());
+		t[buffer.length] = newElement;
+		return t;
+	}
+
+	/**
+	 * 生成一个新的重新设置大小的数组
+	 *
+	 * @param buffer 原数组
+	 * @param newSize 新的数组大小
+	 * @param componentType 数组元素类型
+	 * @return 调整后的新数组
+	 */
+	public static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {
+		T[] newArray = newArray(componentType, newSize);
+		System.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length);
+		return newArray;
+	}
+
+	/**
+	 * 新建一个空数组
+	 * @param componentType 元素类型
+	 * @param newSize 大小
+	 * @return 空数组
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T[] newArray(Class<?> componentType, int newSize) {
+		return (T[]) Array.newInstance(componentType, newSize);
+	}
+
+	/**
+	 * 生成一个新的重新设置大小的数组<br/>
+	 * 新数组的类型为原数组的类型
+	 *
+	 * @param buffer 原数组
+	 * @param newSize 新的数组大小
+	 * @return 调整后的新数组
+	 */
+	public static <T> T[] resize(T[] buffer, int newSize) {
+		return resize(buffer, newSize, buffer.getClass().getComponentType());
+	}
+
+	/**
+	 * 将多个数组合并在一起<br>
+	 * 忽略null的数组
+	 *
+	 * @param arrays 数组集合
+	 * @return 合并后的数组
+	 */
+	@SafeVarargs
+	public static <T> T[] addAll(T[]... arrays) {
+		if (arrays.length == 1) {
+			return arrays[0];
+		}
+
+		int length = 0;
+		for (T[] array : arrays) {
+			if(array == null) {
+				continue;
+			}
+			length += array.length;
+		}
+		T[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length);
+
+		length = 0;
+		for (T[] array : arrays) {
+			if(array == null) {
+				continue;
+			}
+			System.arraycopy(array, 0, result, length, array.length);
+			length += array.length;
+		}
+		return result;
+	}
+
+	/**
+	 * 克隆数组
+	 * @param array 被克隆的数组
+	 * @return 新数组
+	 */
+	public static <T> T[] clone(T[] array) {
+		if (array == null) {
+			return null;
+		}
+		return array.clone();
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @return 数字列表
+	 */
+	public static int[] range(int excludedEnd) {
+		return range(0, excludedEnd, 1);
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param includedStart 开始的数字(包含)
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @return 数字列表
+	 */
+	public static int[] range(int includedStart, int excludedEnd) {
+		return range(includedStart, excludedEnd, 1);
+	}
+
+	/**
+	 * 生成一个数字列表<br>
+	 * 自动判定正序反序
+	 * @param includedStart 开始的数字(包含)
+	 * @param excludedEnd 结束的数字(不包含)
+	 * @param step 步进
+	 * @return 数字列表
+	 */
+	public static int[] range(int includedStart, int excludedEnd, int step) {
+		if(includedStart > excludedEnd) {
+			int tmp = includedStart;
+			includedStart = excludedEnd;
+			excludedEnd = tmp;
+		}
+
+		if(step <=0) {
+			step = 1;
+		}
+
+		int deviation = excludedEnd - includedStart;
+		int length = deviation / step;
+		if(deviation % step != 0) {
+			length += 1;
+		}
+		int[] range = new int[length];
+		for(int i = 0; i < length; i++) {
+			range[i] = includedStart;
+			includedStart += step;
+		}
+		return range;
+	}
+
+	/**
+	 * 截取数组的部分
+	 * @param list 被截取的数组
+	 * @param start 开始位置(包含)
+	 * @param end 结束位置(不包含)
+	 * @return 截取后的数组,当开始位置超过最大时,返回null
+	 */
+	public static <T> List<T> sub(List<T> list, int start, int end) {
+		if(list == null || list.isEmpty()) {
+			return null;
+		}
+
+		if(start < 0) {
+			start = 0;
+		}
+		if(end < 0) {
+			end = 0;
+		}
+
+		if(start > end) {
+			int tmp = start;
+			start = end;
+			end = tmp;
+		}
+
+		final int size = list.size();
+		if(end > size) {
+			if(start >= size) {
+				return null;
+			}
+			end = size;
+		}
+
+		return list.subList(start, end);
+	}
+
+	/**
+	 * 截取集合的部分
+	 * @param list 被截取的数组
+	 * @param start 开始位置(包含)
+	 * @param end 结束位置(不包含)
+	 * @return 截取后的数组,当开始位置超过最大时,返回null
+	 */
+	public static <T> List<T> sub(Collection<T> list, int start, int end) {
+		if(list == null || list.isEmpty()) {
+			return null;
+		}
+
+		return sub(new ArrayList<T>(list), start, end);
+	}
+
+	/**
+	 * 数组是否为空
+	 * @param array 数组
+	 * @return 是否为空
+	 */
+	public static <T> boolean isEmpty(T[] array) {
+		return array == null || array.length == 0;
+	}
+
+	/**
+	 * 数组是否为非空
+	 * @param array 数组
+	 * @return 是否为非空
+	 */
+	public static <T> boolean isNotEmpty(T[] array) {
+		return false == isEmpty(array);
+	}
+
+	/**
+	 * 集合是否为空
+	 * @param collection 集合
+	 * @return 是否为空
+	 */
+	public static boolean isEmpty(Collection<?> collection) {
+		return collection == null || collection.isEmpty();
+	}
+
+	/**
+	 * 集合是否为非空
+	 * @param collection 集合
+	 * @return 是否为非空
+	 */
+	public static boolean isNotEmpty(Collection<?> collection) {
+		return false == isEmpty(collection);
+	}
+
+	/**
+	 * Map是否为空
+	 * @param map 集合
+	 * @return 是否为空
+	 */
+	public static boolean isEmpty(Map<?, ?> map) {
+		return map == null || map.isEmpty();
+	}
+
+	/**
+	 * Map是否为非空
+	 * @param map 集合
+	 * @return 是否为非空
+	 */
+	public static <T> boolean isNotEmpty(Map<?, ?> map) {
+		return false == isEmpty(map);
+	}
+
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    [a,b,c,d]<br>
+	 *		values = [1,2,3,4]<br>
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static <T, K> Map<T, K> zip(T[] keys, K[] values) {
+		if(isEmpty(keys) || isEmpty(values)) {
+			return null;
+		}
+
+		final int size = Math.min(keys.length, values.length);
+		final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));
+		for(int i = 0; i < size; i++) {
+			map.put(keys[i], values[i]);
+		}
+
+		return map;
+	}
+
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    a,b,c,d<br>
+	 *		values = 1,2,3,4<br>
+	 *		delimiter = ,
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static Map<String, String> zip(String keys, String values, String delimiter) {
+		return zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter));
+	}
+	
+	/**
+	 * 映射键值(参考Python的zip()函数)<br>
+	 * 例如:<br>
+	 * 		keys =    [a,b,c,d]<br>
+	 *		values = [1,2,3,4]<br>
+	 * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>
+	 * 如果两个数组长度不同,则只对应最短部分
+	 * @param keys 键列表
+	 * @param values 值列表
+	 * @return Map
+	 */
+	public static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) {
+		if(isEmpty(keys) || isEmpty(values)) {
+			return null;
+		}
+		
+		final List<T> keyList = new ArrayList<T>(keys);
+		final List<K> valueList = new ArrayList<K>(values);
+		
+		final int size = Math.min(keys.size(), values.size());
+		final Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));
+		for(int i = 0; i < size; i++) {
+			map.put(keyList.get(i), valueList.get(i));
+		}
+		
+		return map;
+	}
+	
+	/**
+	 * 数组中是否包含元素
+	 * @param array 数组
+	 * @param value 被检查的元素
+	 * @return 是否包含
+	 */
+	public static <T> boolean contains(T[] array, T value) {
+		final Class<?> componetType = array.getClass().getComponentType();
+		boolean isPrimitive = false;
+		if(null != componetType) {
+			isPrimitive = componetType.isPrimitive();
+		}
+		for (T t : array) {
+			if(t == value) {
+				return true;
+			}else if(false == isPrimitive && null != value && value.equals(t)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/**
+	 * 将Entry集合转换为HashMap
+	 * @param entryCollection entry集合
+	 * @return Map
+	 */
+	public static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) {
+		HashMap<T,K> map = new HashMap<T, K>();
+		for (Entry<T, K> entry : entryCollection) {
+			map.put(entry.getKey(), entry.getValue());
+		}
+		return map;
+	}
+	
+	/**
+	 * 将集合转换为排序后的TreeSet
+	 * @param collection 集合
+	 * @param comparator 比较器
+	 * @return treeSet
+	 */
+	public static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){
+		final TreeSet<T> treeSet = new TreeSet<T>(comparator);
+		for (T t : collection) {
+			treeSet.add(t);
+		}
+		return treeSet;
+	}
+	
+	/**
+	 * 排序集合
+	 * @param collection 集合
+	 * @param comparator 比较器
+	 * @return treeSet
+	 */
+	public static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){
+		List<T> list = new ArrayList<T>(collection);
+		Collections.sort(list, comparator);
+		return list;
+	}
+	
+	//------------------------------------------------------------------- 基本类型的数组转换为包装类型数组
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Integer[] wrap(int... values){
+		final int length = values.length;
+		Integer[] array = new Integer[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Long[] wrap(long... values){
+		final int length = values.length;
+		Long[] array = new Long[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Character[] wrap(char... values){
+		final int length = values.length;
+		Character[] array = new Character[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Byte[] wrap(byte... values){
+		final int length = values.length;
+		Byte[] array = new Byte[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Short[] wrap(short... values){
+		final int length = values.length;
+		Short[] array = new Short[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Float[] wrap(float... values){
+		final int length = values.length;
+		Float[] array = new Float[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Double[] wrap(double... values){
+		final int length = values.length;
+		Double[] array = new Double[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 将基本类型数组包装为包装类型
+	 * @param values 基本类型数组
+	 * @return 包装类型数组
+	 */
+	public static Boolean[] wrap(boolean... values){
+		final int length = values.length;
+		Boolean[] array = new Boolean[length];
+		for(int i = 0; i < length; i++){
+			array[i] = values[i];
+		}
+		return array;
+	}
+	
+	/**
+	 * 判定给定对象是否为数组类型
+	 * @param obj 对象
+	 * @return 是否为数组类型
+	 */
+	public static boolean isArray(Object obj){
+		return obj.getClass().isArray();
+	}
+	
+	/**
+	 * 数组或集合转String
+	 * 
+	 * @param obj 集合或数组对象
+	 * @return 数组字符串,与集合转字符串格式相同
+	 */
+	public static String toString(Object obj) {
+		if (null == obj) {
+			return null;
+		}
+		if (isArray(obj)) {
+			try {
+				return Arrays.deepToString((Object[]) obj);
+			} catch (Exception e) {
+				final String className = obj.getClass().getComponentType().getName();
+				switch (className) {
+					case "long":
+						return Arrays.toString((long[]) obj);
+					case "int":
+						return Arrays.toString((int[]) obj);
+					case "short":
+						return Arrays.toString((short[]) obj);
+					case "char":
+						return Arrays.toString((char[]) obj);
+					case "byte":
+						return Arrays.toString((byte[]) obj);
+					case "boolean":
+						return Arrays.toString((boolean[]) obj);
+					case "float":
+						return Arrays.toString((float[]) obj);
+					case "double":
+						return Arrays.toString((double[]) obj);
+					default:
+						return null;
+				}
+			}
+		}
+		return obj.toString();
+	}
+}

+ 399 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/DateUtil.java

@@ -0,0 +1,399 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+
+package com.example.xiaoshiweixinback.business.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+import org.apache.commons.lang3.time.DateUtils;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DateUtil {
+
+
+	*/
+/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getYear() {
+		return formatDate(new Date(), "yyyy");
+	}
+
+	*/
+/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getYear(Date date) {
+		return formatDate(date, "yyyy");
+	}
+
+	public static String getCurrentServerDate(String format) {
+		return formatDate(new Date(), format);
+	}
+	
+	*/
+/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getDay() {
+		return formatDate(new Date(), "yyyy-MM-dd");
+	}
+
+	*/
+/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getDay(Date date) {
+		return formatDate(date, "yyyy-MM-dd");
+	}
+
+	*/
+/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getDays() {
+		return formatDate(new Date(), "yyyyMMdd");
+	}
+
+	*/
+/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getDays(Date date) {
+		return formatDate(date, "yyyyMMdd");
+	}
+
+	*/
+/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+	}
+
+	*/
+/**
+	 * 获取YYYY-MM-DD HH:mm:ss.SSS格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getMsTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
+	}
+
+	*/
+/**
+	 * 获取YYYYMMDDHHmmss格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getAllTime() {
+		return formatDate(new Date(), "yyyyMMddHHmmss");
+	}
+
+	*/
+/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 *//*
+
+	public static String getTime(Date date) {
+		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	public static String formatDate(Date date, String pattern) {
+		String formatDate = null;
+		if (StringUtils.isNotBlank(pattern)) {
+			formatDate = DateFormatUtils.format(date, pattern);
+		} else {
+			formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+		}
+		return formatDate;
+	}
+
+	*/
+/**
+	 * @Title: compareDate
+	 * @Description:(日期比较,如果s>=e 返回true 否则返回false)
+	 * @param s
+	 * @param e
+	 * @return boolean
+	 * @throws
+	 * @author luguosui
+	 *//*
+
+	public static boolean compareDate(String s, String e) {
+		if (parseDate(s) == null || parseDate(e) == null) {
+			return false;
+		}
+		return parseDate(s).getTime() >= parseDate(e).getTime();
+	}
+
+	*/
+/**
+	 * 格式化日期
+	 *
+	 * @return
+	 *//*
+
+	public static Date parseDate(String date) {
+		return parse(date,"yyyy-MM-dd");
+	}
+
+	*/
+/**
+	 * 格式化日期
+	 *
+	 * @return
+	 *//*
+
+	public static Date parseTime(String date) {
+		return parse(date,"yyyy-MM-dd HH:mm:ss");
+	}
+
+	*/
+/**
+	 * 格式化日期
+	 *
+	 * @return
+	 *//*
+
+	public static Date parse(String date, String pattern) {
+		try {
+			return DateUtils.parseDate(date,pattern);
+		} catch (ParseException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	*/
+/**
+	 * 格式化日期
+	 *
+	 * @return
+	 *//*
+
+	public static String format(Date date, String pattern) {
+		return DateFormatUtils.format(date, pattern);
+	}
+
+	*/
+/**
+	 * 把日期转换为Timestamp
+	 *
+	 * @param date
+	 * @return
+	 *//*
+
+	public static Timestamp format(Date date) {
+		return new Timestamp(date.getTime());
+	}
+
+	*/
+/**
+	 * 校验日期是否合法
+	 *
+	 * @return
+	 *//*
+
+	public static boolean isValidDate(String s) {
+		return parse(s, "yyyy-MM-dd HH:mm:ss") != null;
+	}
+
+	*/
+/**
+	 * 校验日期是否合法
+	 *
+	 * @return
+	 *//*
+
+	public static boolean isValidDate(String s, String pattern) {
+        return parse(s, pattern) != null;
+	}
+
+	public static int getDiffYear(String startTime, String endTime) {
+		DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+		try {
+			int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(
+					startTime).getTime()) / (1000 * 60 * 60 * 24)) / 365);
+			return years;
+		} catch (Exception e) {
+			// 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
+			return 0;
+		}
+	}
+
+	*/
+/**
+	 * <li>功能描述:时间相减得到天数
+	 *
+	 * @param beginDateStr
+	 * @param endDateStr
+	 * @return long
+	 * @author Administrator
+	 *//*
+
+	public static long getDaySub(String beginDateStr, String endDateStr) {
+		long day = 0;
+		SimpleDateFormat format = new SimpleDateFormat(
+				"yyyy-MM-dd");
+		Date beginDate = null;
+		Date endDate = null;
+
+		try {
+			beginDate = format.parse(beginDateStr);
+			endDate = format.parse(endDateStr);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
+		// System.out.println("相隔的天数="+day);
+
+		return day;
+	}
+
+	*/
+/**
+	 * 得到n天之后的日期
+	 *
+	 * @param days
+	 * @return
+	 *//*
+
+	public static String getAfterDayDate(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		String dateStr = sdfd.format(date);
+
+		return dateStr;
+	}
+
+	*/
+/**
+	 * 得到n天之后是周几
+	 *
+	 * @param days
+	 * @return
+	 *//*
+
+	public static String getAfterDayWeek(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdf = new SimpleDateFormat("E");
+		String dateStr = sdf.format(date);
+
+		return dateStr;
+	}
+
+	*/
+/**
+	 * 格式化Oracle Date
+	 * @param value
+	 * @return
+	 *//*
+
+//	public static String buildDateValue(Object value){
+//		if(Func.isOracle()){
+//			return "to_date('"+ value +"','yyyy-mm-dd HH24:MI:SS')";
+//		}else{
+//			return Func.toStr(value);
+//		}
+//	}
+	*/
+/**
+	 * @Description: 获取当前时间的周一及周日
+	 * @Param: Date
+	 * @Author: LHX
+	 * @Date: 9:59 2018/11/19
+	 * @return: java.util.Map<java.lang.String,java.lang.String>
+
+	 *//*
+
+	public static Map<String,String> getWeekDate(Date date) {
+		Map<String,String> map = new HashMap();
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		// 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
+		cal.setFirstDayOfWeek(Calendar.MONDAY);
+		// 获得当前日期是一个星期的第几天
+		int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
+		if(dayWeek==1){
+			dayWeek = 8;
+		}
+		// 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
+		cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);
+		Date mondayDate = cal.getTime();
+		String weekBegin = sdf.format(mondayDate);
+		//获取星期日
+		cal.add(Calendar.DATE, 4 +cal.getFirstDayOfWeek());
+		Date sundayDate = cal.getTime();
+		String weekEnd = sdf.format(sundayDate);
+		map.put("mondayDate", weekBegin);
+		map.put("sundayDate", weekEnd);
+		return map;
+	}
+
+	public static void main(String[] args) {
+		System.out.println(getTime(new Date()));
+		System.out.println(getAfterDayWeek("3"));
+	}
+
+}
+*/

+ 42 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/JSONUtil.java

@@ -0,0 +1,42 @@
+//package com.example.xiaoshiweixinback.business.utils;
+//
+//import com.alibaba.fastjson.JSON;
+//
+//
+///**
+//* @Description: JSON工具
+//* @author Orange
+//* @date 2018年1月28日
+//*
+//*/
+//public class JSONUtil {
+//
+//    /**
+//    * @Title: toJSONString
+//    * @Description: 转JSON字符串
+//    * @param @param obj
+//    * @param @return    参数
+//    * @return String    返回类型
+//    * @throws
+//    * @author Orange
+//    * @date 2018年1月28日
+//    */
+//    public static String toJSONString(Object obj){
+//        return JSON.toJSONString(obj);
+//    }
+//
+//    /**
+//    * @Title: parseObject
+//    * @Description: JSON字符串转实体
+//    * @param @param json
+//    * @param @param t
+//    * @param @return    参数
+//    * @return T    返回类型
+//    * @throws
+//    * @author Orange
+//    * @date 2018年1月28日
+//    */
+//    public static <T> T parseObject(String json,Class<T> t){
+//        return JSON.parseObject(json,t);
+//    }
+//}

+ 233 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/LogHelper.java

@@ -0,0 +1,233 @@
+/*
+package com.example.xiaoshiweixinback.business.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+*/
+/**
+ * 日志工具类
+ * @author Peach
+ *
+ *//*
+
+public class LogHelper {
+	
+	private static Logger logger = null;
+
+	//------------------------------------------系统日志记录-------------------------
+	*/
+/**
+	 * @param info
+	 *//*
+
+	public static void log(Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("info={}",info);
+	}
+	
+	public static void log(Throwable e,Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("exception={} info={}",throwable2String(e),info);
+	}
+	
+	*/
+/**
+	 * @param clazz
+	 * @param info
+	 *//*
+
+	public static void log(Class clazz, String info) {
+		logger = LoggerFactory.getLogger(clazz);
+		logger.info(info);
+	}
+	
+	*/
+/**
+	 * @param clazz
+	 * @param e
+	 *//*
+
+	public static void log(Class clazz, Throwable e) {
+		log(clazz,throwable2String(e));
+	}
+	
+	*/
+/**
+	 * @param name
+	 * @param info
+	 *//*
+
+	@Deprecated
+	public static void log(String name, String info) {
+		logger = LoggerFactory.getLogger(name);
+		logger.info(name+"-"+info);
+	}
+	
+	*/
+/**
+	 * @param name
+	 * @param e
+	 *//*
+
+	@Deprecated
+	public static void log(String name, Throwable e) {
+		log(name,throwable2String(e));
+	}
+	
+	
+	*/
+/**
+	 * @param name
+	 * @param info
+	 * @param e
+	 *//*
+
+	@Deprecated
+	public static void log(String name, String info,Throwable e) {
+		log(name,info+"-"+throwable2String(e));
+	}
+	
+	
+	*/
+/**
+	 * @param clazz
+	 * @param info
+	 * @param e
+	 *//*
+
+	public static void log(Class clazz, String info,Throwable e) {
+		log(clazz,info+"-"+throwable2String(e));
+	}
+	
+	*/
+/**
+	 * 将异常信息转为string
+	 * @param e
+	 * @return
+	 *//*
+
+	private static String throwable2String(Throwable e){
+		if(checkBaseBusinessException(e)) {
+			BaseBusinessException bbe = (BaseBusinessException)e;
+			return "----->"+bbe.getErrorMessage()+(bbe.getExtraMessage()==null?"":bbe.getExtraMessage());
+		}
+		PrintWriter pw = null;
+		StringWriter sw = null;
+		try{
+			sw = new StringWriter();
+			pw = new PrintWriter(sw);
+			e.printStackTrace(pw);
+			pw.flush();
+			sw.flush();
+		}catch (Exception e1) {
+			logger.info(e.getMessage());
+		}finally{
+			if(sw!=null){
+				try{
+					sw.close();
+				}catch (Exception e2) {
+					e2.printStackTrace();
+					return "";
+				}
+			}else{
+				return "";
+			}
+			if(pw!=null){
+				pw.close();
+			}
+			return sw.toString();
+		}
+		
+	}
+	
+	
+	*/
+/**
+	* @Title: checkBaseBusinessException
+	* @Description: 判断异常是否为系统异常
+	* @param @param e
+	* @param @return    参数
+	* @return boolean    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月23日
+	*//*
+
+	private static boolean checkBaseBusinessException(Throwable e) {
+		return BaseBusinessException.class.isInstance(e);
+	}
+	
+	
+	//------------------------------------------多业务日志记录-------------------------
+	
+	*/
+/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*//*
+
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum,Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, info={}", businessLogTypeEnum.getType(), info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	*/
+/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*//*
+
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum,Throwable e,Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, exception={} ,info={}", businessLogTypeEnum.getType(), throwable2String(e),info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	*/
+/**
+	* @Title: warnLog
+	* @Description: 警告日志
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月26日
+	*//*
+
+	public static void warnLog(Throwable e,Object...info) {
+		//系统级别日志不打印
+		if(checkBaseBusinessException(e)) {
+			log(e,info);
+		}else {
+			Logger logger = LoggerFactory.getLogger("error_log");
+			logger.warn("[System Exception] exception={} ,info={}", throwable2String(e),info);
+		}
+	}
+}
+*/

+ 93 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/MD5Util.java

@@ -0,0 +1,93 @@
+package com.example.xiaoshiweixinback.business.utils;
+
+import java.security.MessageDigest;
+import java.util.Random;
+
+
+/**
+ * 标准MD5加密方法,使用java类库的security包的MessageDigest类处理 <BR>
+ * 也可变为非标准MD5,请修改下面的移位算法
+ *
+ *
+ */
+public class MD5Util {
+
+    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
+
+    public static String MD5(String s) {
+        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+        try {
+            byte[] btInput = s.getBytes();
+            // 获得MD5摘要算法的 MessageDigest 对象
+            MessageDigest mdInst = MessageDigest.getInstance("MD5");
+            // 使用指定的字节更新摘要
+            mdInst.update(btInput);
+            // 获得密文
+            byte[] md = mdInst.digest();
+            // 把密文转换成十六进制的字符串形式
+            int j = md.length;
+            char str[] = new char[j * 2];
+            int k = 0;
+            for (int i = 0; i < j; i++) {
+                byte byte0 = md[i];
+                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
+                str[k++] = hexDigits[byte0 & 0xf];
+            }
+            return new String(str);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /**
+     * 加盐MD5,随机盐
+     */
+    public static String saltMD5(String password) {
+        String salt = genSalt();
+        password = MD5(password + salt);
+        char[] cs = new char[48];
+        for (int i = 0; i < 48; i += 3) {
+            cs[i] = password.charAt(i / 3 * 2);
+            char c = salt.charAt(i / 3);
+            cs[i + 1] = c;
+            cs[i + 2] = password.charAt(i / 3 * 2 + 1);
+        }
+        return new String(cs);
+    }
+
+
+    /**
+     * @return 动态盐
+     */
+    private static String genSalt() {
+        Random r = new Random();
+        StringBuilder sb = new StringBuilder(16);
+        sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
+        int len = sb.length();
+        if (len < 16) {
+            for (int i = 0; i < 16 - len; i++) {
+                sb.append("0");
+            }
+        }
+        String salt = sb.toString();
+        return salt;
+    }
+
+    /**
+     * 校验
+     */
+    public static boolean saltMD5Verify(String password, String md5) {
+        char[] cs1 = new char[32];
+        char[] cs2 = new char[16];
+        for (int i = 0; i < 48; i += 3) {
+            cs1[i / 3 * 2] = md5.charAt(i);
+            cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
+            cs2[i / 3] = md5.charAt(i + 1);
+        }
+        String salt = new String(cs2);
+        return MD5(password + salt).equals(new String(cs1));
+    }
+
+}

+ 73 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/PageKit.java

@@ -0,0 +1,73 @@
+package com.example.xiaoshiweixinback.business.utils;
+
+
+import java.util.List;
+
+/**
+ * 分页工具类
+ * 
+ * @author xiaoleilu
+ * 
+ */
+public class PageKit {
+
+	/**
+	 * 将页数和每页条目数转换为开始位置和结束位置<br>
+	 * 此方法用于不包括结束位置的分页方法<br>
+	 * 例如:<br>
+	 * 页码:1,每页10 -> [0, 10]<br>
+	 * 页码:2,每页10 -> [10, 20]<br>
+	 * 。。。<br>
+	 * 
+	 * @param pageNo
+	 *            页码(从1计数)
+	 * @param countPerPage
+	 *            每页条目数
+	 * @return 第一个数为开始位置,第二个数为结束位置
+	 */
+	public static int[] transToStartEnd(int pageNo, int countPerPage) {
+		if (pageNo < 1) {
+			pageNo = 1;
+		}
+
+		if (countPerPage < 1) {
+			countPerPage = 0;
+//			LogKit.warn("Count per page  [" + countPerPage + "] is not valid!");
+		}
+
+		int start = (pageNo - 1) * countPerPage;
+		int end = start + countPerPage;
+
+		return new int[] { start, end };
+	}
+
+	/**
+	 * 根据总数计算总页数
+	 * 
+	 * @param totalCount
+	 *            总数
+	 * @param numPerPage
+	 *            每页数
+	 * @return 总页数
+	 */
+	public static int totalPage(int totalCount, int numPerPage) {
+		if (numPerPage == 0) {
+			return 0;
+		}
+		return totalCount % numPerPage == 0 ? (totalCount / numPerPage)
+				: (totalCount / numPerPage + 1);
+	}
+
+/*	public static <T> Page<T> paged(List<T> list) {
+		int current = 1;
+		int size = 10;
+		Page<T> page = new Page<>(current, size);
+		int count = list.size();
+		page.setSize(size);
+		page.setCurrent(current);
+		page.setTotal(count);
+		page.setPages(count % 10 == 0 ? count / 10 : count /10 + 1);
+		page.setRecords(list);
+		return page;
+	}*/
+}

+ 12 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/RandomUtil.java

@@ -0,0 +1,12 @@
+package com.example.xiaoshiweixinback.business.utils;
+
+public class RandomUtil {
+
+    /**
+     * 随机验证码
+     * @return
+     */
+    public static String getSixRandom(){
+        return String.valueOf((int) ((Math.random() * 9 + 1) * Math.pow(10, 5)));
+    }
+}

+ 44 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/RegexUtil.java

@@ -0,0 +1,44 @@
+package com.example.xiaoshiweixinback.business.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+  * 正则工具类
+ */
+public class RegexUtil {
+
+    /**
+     * 大陆号码或香港号码均可
+     */
+    public static boolean isPhoneLegal(String str) throws PatternSyntaxException {
+        return isChinaPhoneLegal(str) || isHKPhoneLegal(str);
+    }
+
+    /**
+     * 手机号验证,1开头,后面10位随机0-9数字
+     */
+    public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^[1][0-9]{10}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    /**
+     * 香港手机号码8位数,5|6|8|9开头+7位任意数
+     */
+    public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^(5|6|8|9)\\d{7}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+}

File diff suppressed because it is too large
+ 1370 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/StrKit.java


+ 537 - 0
src/main/java/com/example/xiaoshiweixinback/business/utils/ToolUtil.java

@@ -0,0 +1,537 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.example.xiaoshiweixinback.business.utils;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * 高频方法集合类
+ */
+public class ToolUtil {
+
+    
+    /**
+    * @Title: getRandomString
+    * @Description: 生成随机字符串
+    * @param @param length
+    * @param @return    参数
+    * @return String    返回类型
+    * @throws
+    * @author Orange
+    * @date 2018年10月18日
+    */
+    public static String getRandomString(int length) {
+        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+        Random random = new Random();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            int number = random.nextInt(base.length());
+            sb.append(base.charAt(number));
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * 判断一个对象是否是时间类型
+     * 
+     * @author stylefeng
+     * @Date 2017/4/18 12:55
+     */
+    public static String dateType(Object o){
+        if(o instanceof Date){
+            return DateUtil.getDay((Date) o);
+        }else{
+            return o.toString();
+        }
+    }
+
+    /**
+     * 获取异常的具体信息
+     *
+     * @author fengshuonan
+     * @Date 2017/3/30 9:21
+     * @version 2.0
+     */
+    public static String getExceptionMsg(Exception e) {
+        StringWriter sw = new StringWriter();
+        try{
+            e.printStackTrace(new PrintWriter(sw));
+        }finally {
+            try {
+                sw.close();
+            } catch (IOException e1) {
+                e1.printStackTrace();
+            }
+        }
+        return sw.getBuffer().toString().replaceAll("\\$","T");
+    }
+
+    /**
+     * 比较两个对象是否相等。<br>
+     * 相同的条件有两个,满足其一即可:<br>
+     * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2)
+     *
+     * @param obj1 对象1
+     * @param obj2 对象2
+     * @return 是否相等
+     */
+    public static boolean equals(Object obj1, Object obj2) {
+        return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);
+    }
+
+    /**
+     * 计算对象长度,如果是字符串调用其length函数,集合类调用其size函数,数组调用其length属性,其他可遍历对象遍历计算长度
+     *
+     * @param obj 被计算长度的对象
+     * @return 长度
+     */
+    public static int length(Object obj) {
+        if (obj == null) {
+            return 0;
+        }
+        if (obj instanceof CharSequence) {
+            return ((CharSequence) obj).length();
+        }
+        if (obj instanceof Collection) {
+            return ((Collection<?>) obj).size();
+        }
+        if (obj instanceof Map) {
+            return ((Map<?, ?>) obj).size();
+        }
+
+        int count;
+        if (obj instanceof Iterator) {
+            Iterator<?> iter = (Iterator<?>) obj;
+            count = 0;
+            while (iter.hasNext()) {
+                count++;
+                iter.next();
+            }
+            return count;
+        }
+        if (obj instanceof Enumeration) {
+            Enumeration<?> enumeration = (Enumeration<?>) obj;
+            count = 0;
+            while (enumeration.hasMoreElements()) {
+                count++;
+                enumeration.nextElement();
+            }
+            return count;
+        }
+        if (obj.getClass().isArray() == true) {
+            return Array.getLength(obj);
+        }
+        return -1;
+    }
+
+    /**
+     * 对象中是否包含元素
+     *
+     * @param obj     对象
+     * @param element 元素
+     * @return 是否包含
+     */
+    public static boolean contains(Object obj, Object element) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj instanceof String) {
+            if (element == null) {
+                return false;
+            }
+            return ((String) obj).contains(element.toString());
+        }
+        if (obj instanceof Collection) {
+            return ((Collection<?>) obj).contains(element);
+        }
+        if (obj instanceof Map) {
+            return ((Map<?, ?>) obj).values().contains(element);
+        }
+
+        if (obj instanceof Iterator) {
+            Iterator<?> iter = (Iterator<?>) obj;
+            while (iter.hasNext()) {
+                Object o = iter.next();
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (obj instanceof Enumeration) {
+            Enumeration<?> enumeration = (Enumeration<?>) obj;
+            while (enumeration.hasMoreElements()) {
+                Object o = enumeration.nextElement();
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (obj.getClass().isArray() == true) {
+            int len = Array.getLength(obj);
+            for (int i = 0; i < len; i++) {
+                Object o = Array.get(obj, i);
+                if (equals(o, element)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象是否不为空(新增)
+     *
+     * @param o String,List,Map,Object[],int[],long[]
+     * @return
+     */
+    public static boolean isNotEmpty(Object o) {
+        return !isEmpty(o);
+    }
+
+    /**
+     * 对象是否为空
+     *
+     * @param o String,List,Map,Object[],int[],long[]
+     * @return
+     */
+    @SuppressWarnings("rawtypes")
+    public static boolean isEmpty(Object o) {
+        if (o == null) {
+            return true;
+        }
+        if (o instanceof String) {
+            if (o.toString().trim().equals("")) {
+                return true;
+            }
+        } else if (o instanceof List) {
+            if (((List) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Map) {
+            if (((Map) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Set) {
+            if (((Set) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Object[]) {
+            if (((Object[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof int[]) {
+            if (((int[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof long[]) {
+            if (((long[]) o).length == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象组中是否存在 Empty Object
+     *
+     * @param os 对象组
+     * @return
+     */
+    public static boolean isOneEmpty(Object... os) {
+        for (Object o : os) {
+            if (isEmpty(o)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 对象组中是否全是 Empty Object
+     *
+     * @param os
+     * @return
+     */
+    public static boolean isAllEmpty(Object... os) {
+        for (Object o : os) {
+            if (!isEmpty(o)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 是否为数字
+     *
+     * @param obj
+     * @return
+     */
+    public static boolean isNum(Object obj) {
+        try {
+            Integer.parseInt(obj.toString());
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 如果为空, 则调用默认值
+     *
+     * @param str
+     * @return
+     */
+    public static Object getValue(Object str, Object defaultValue) {
+        if (isEmpty(str)) {
+            return defaultValue;
+        }
+        return str;
+    }
+
+    /**
+     * 格式化文本
+     *
+     * @param template 文本模板,被替换的部分用 {} 表示
+     * @param values   参数值
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Object... values) {
+        return StrKit.format(template, values);
+    }
+
+    /**
+     * 格式化文本
+     *
+     * @param template 文本模板,被替换的部分用 {key} 表示
+     * @param map      参数值对
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Map<?, ?> map) {
+        return StrKit.format(template, map);
+    }
+
+    /**
+     * 强转->string,并去掉多余空格
+     *
+     * @param str
+     * @return
+     */
+    public static String toStr(Object str) {
+        return toStr(str, "");
+    }
+
+    /**
+     * 强转->string,并去掉多余空格
+     *
+     * @param str
+     * @param defaultValue
+     * @return
+     */
+    public static String toStr(Object str, String defaultValue) {
+        if (null == str) {
+            return defaultValue;
+        }
+        return str.toString().trim();
+    }
+
+    /**
+     * 强转->int
+     *
+     * @param obj
+     * @return
+     */
+//	public static int toInt(Object value) {
+//		return toInt(value, -1);
+//	}
+
+    /**
+     * 强转->int
+     *
+     * @param obj
+     * @param defaultValue
+     * @return
+     */
+//	public static int toInt(Object value, int defaultValue) {
+//		return Convert.toInt(value, defaultValue);
+//	}
+
+    /**
+     * 强转->long
+     *
+     * @param obj
+     * @return
+     */
+//	public static long toLong(Object value) {
+//		return toLong(value, -1);
+//	}
+
+    /**
+     * 强转->long
+     *
+     * @param obj
+     * @param defaultValue
+     * @return
+     */
+//	public static long toLong(Object value, long defaultValue) {
+//		return Convert.toLong(value, defaultValue);
+//	}
+//
+//	public static String encodeUrl(String url) {
+//		return URLKit.encode(url, CharsetKit.UTF_8);
+//	}
+//
+//	public static String decodeUrl(String url) {
+//		return URLKit.decode(url, CharsetKit.UTF_8);
+//	}
+
+    /**
+     * map的key转为小写
+     *
+     * @param map
+     * @return Map<String,Object>
+     */
+    public static Map<String, Object> caseInsensitiveMap(Map<String, Object> map) {
+        Map<String, Object> tempMap = new HashMap<>();
+        for (String key : map.keySet()) {
+            tempMap.put(key.toLowerCase(), map.get(key));
+        }
+        return tempMap;
+    }
+
+    /**
+     * 获取map中第一个数据值
+     *
+     * @param <K> Key的类型
+     * @param <V> Value的类型
+     * @param map 数据源
+     * @return 返回的值
+     */
+    public static <K, V> V getFirstOrNull(Map<K, V> map) {
+        V obj = null;
+        for (Entry<K, V> entry : map.entrySet()) {
+            obj = entry.getValue();
+            if (obj != null) {
+                break;
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * 创建StringBuilder对象
+     *
+     * @return StringBuilder对象
+     */
+    public static StringBuilder builder(String... strs) {
+        final StringBuilder sb = new StringBuilder();
+        for (String str : strs) {
+            sb.append(str);
+        }
+        return sb;
+    }
+
+    /**
+     * 创建StringBuilder对象
+     *
+     * @return StringBuilder对象
+     */
+    public static void builder(StringBuilder sb, String... strs) {
+        for (String str : strs) {
+            sb.append(str);
+        }
+    }
+
+    /**
+     * 去掉指定后缀
+     *
+     * @param str    字符串
+     * @param suffix 后缀
+     * @return 切掉后的字符串,若后缀不是 suffix, 返回原字符串
+     */
+    public static String removeSuffix(String str, String suffix) {
+        if (isEmpty(str) || isEmpty(suffix)) {
+            return str;
+        }
+
+        if (str.endsWith(suffix)) {
+            return str.substring(0, str.length() - suffix.length());
+        }
+        return str;
+    }
+
+    /**
+     * 当前时间
+     *
+     * @author stylefeng
+     * @Date 2017/5/7 21:56
+     */
+    public static String currentTime(){
+        return DateUtil.getTime();
+    }
+
+    /**
+     * 首字母大写
+     *
+     * @author stylefeng
+     * @Date 2017/5/7 22:01
+     */
+    public static String firstLetterToUpper(String val){
+        return StrKit.firstCharToUpperCase(val);
+    }
+
+    /**
+     * 首字母小写
+     *
+     * @author stylefeng
+     * @Date 2017/5/7 22:02
+     */
+    public static String firstLetterToLower(String val){
+        return StrKit.firstCharToLowerCase(val);
+    }
+
+    /**
+     * 判断是否是windows操作系统
+     *
+     * @author stylefeng
+     * @Date 2017/5/24 22:34
+     */
+    public static Boolean isWinOs(){
+        String os = System.getProperty("os.name");
+        if(os.toLowerCase().startsWith("win")){
+            return true;
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 获取临时目录
+     *
+     * @author stylefeng
+     * @Date 2017/5/24 22:35
+     */
+    public static String getTempPath(){
+        return System.getProperty("java.io.tmpdir");
+    }
+}

+ 33 - 0
src/main/java/com/example/xiaoshiweixinback/controller/LoginController.java

@@ -0,0 +1,33 @@
+package com.example.xiaoshiweixinback.controller;
+
+
+import com.example.xiaoshiweixinback.entity.dto.LoginDTO;
+import com.example.xiaoshiweixinback.entity.vo.LoginVO;
+
+/**
+ * 登录相关接口
+ * @author: 高昌奎
+ */
+@RestController
+@RequestMapping("/login")
+public class LoginController {
+
+    @Autowired
+    private LoginService loginService;
+
+    @PostMapping(value = "/login")
+    public LoginVO login(@Valid @RequestBody LoginDTO vo) {
+        return loginService.login(vo);
+    }
+
+    @PostMapping(value = "/loginByWeChat")
+    public WXLoginDTO loginByWeChat(@Valid @RequestBody WXLoginVO vo) throws Exception {
+        return loginService.loginByWeChat(vo);
+    }
+
+    //发送验证码
+    @PostMapping("/sendCode")
+    public boolean sendCode(@RequestBody @Valid SendCodeVO vo, HttpServletRequest request) {
+        return appLoginService.sendCode(vo,request);
+    }
+}

+ 26 - 0
src/main/java/com/example/xiaoshiweixinback/entity/dto/LoginDTO.java

@@ -0,0 +1,26 @@
+package com.example.xiaoshiweixinback.entity.dto;
+
+
+@Data
+public class LoginDTO {
+
+    private String userName;
+
+    private String password;
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 49 - 0
src/main/java/com/example/xiaoshiweixinback/entity/dto/WXLoginDTO.java

@@ -0,0 +1,49 @@
+package com.example.xiaoshiweixinback.entity.dto;
+
+public class WXLoginDTO {
+
+    //微信openid
+    private String openId;
+
+    private String token;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public Integer getIdentityType() {
+        return identityType;
+    }
+
+    public void setIdentityType(Integer identityType) {
+        this.identityType = identityType;
+    }
+
+    public Integer getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Integer companyId) {
+        this.companyId = companyId;
+    }
+
+    public Integer getTalentId() {
+        return talentId;
+    }
+
+    public void setTalentId(Integer talentId) {
+        this.talentId = talentId;
+    }
+}

+ 32 - 0
src/main/java/com/example/xiaoshiweixinback/entity/vo/Jscode2SessionWo.java

@@ -0,0 +1,32 @@
+package com.example.xiaoshiweixinback.entity.vo;
+
+/**
+ * @Description: code置换openid返回的实体<br>微信返回例子:{"session_key":"GdbSHJQi8B+odx5R8umU1w==","expires_in":7200,"openid":"oCwYd0dN-NO8Sxvf_iIwN6c4S4Rs"}
+ * @author Orange
+ * @date 2017年7月24日
+ *
+ */
+public class Jscode2SessionWo {
+    private String session_key;
+    private String expires_in;
+    private String openid;
+
+    public String getSession_key() {
+        return session_key;
+    }
+    public void setSession_key(String session_key) {
+        this.session_key = session_key;
+    }
+    public String getExpires_in() {
+        return expires_in;
+    }
+    public void setExpires_in(String expires_in) {
+        this.expires_in = expires_in;
+    }
+    public String getOpenid() {
+        return openid;
+    }
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+}

+ 12 - 0
src/main/java/com/example/xiaoshiweixinback/entity/vo/LoginVO.java

@@ -0,0 +1,12 @@
+package com.example.xiaoshiweixinback.entity.vo;
+
+@Data
+public class LoginVO {
+
+    private String userName;
+
+    private String phone;
+
+    private String token;
+
+}

+ 20 - 0
src/main/java/com/example/xiaoshiweixinback/entity/vo/SendCodeVO.java

@@ -0,0 +1,20 @@
+package com.example.xiaoshiweixinback.entity.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotBlank;
+
+public class SendCodeVO {
+
+    @NotBlank
+    @ApiModelProperty(example="",required=false,value="手机号")
+    private String phoneNo;
+
+    public String getPhoneNo() {
+        return phoneNo;
+    }
+
+    public void setPhoneNo(String phoneNo) {
+        this.phoneNo = phoneNo;
+    }
+}

+ 39 - 0
src/main/java/com/example/xiaoshiweixinback/entity/vo/WXLoginVO.java

@@ -0,0 +1,39 @@
+package com.example.xiaoshiweixinback.entity.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+
+public class WXLoginVO {
+
+    @ApiModelProperty(example="",required=false,value="code")
+    private String code;
+
+    @ApiModelProperty(example="",required=false,value="包括敏感数据在内的完整用户信息的加密数据")
+    private String encryptedData;
+
+    @ApiModelProperty(example="",required=false,value="加密算法的初始向量")
+    private String iv;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getEncryptedData() {
+        return encryptedData;
+    }
+
+    public void setEncryptedData(String encryptedData) {
+        this.encryptedData = encryptedData;
+    }
+
+    public String getIv() {
+        return iv;
+    }
+
+    public void setIv(String iv) {
+        this.iv = iv;
+    }
+}

+ 20 - 0
src/main/java/com/example/xiaoshiweixinback/okhttp/RequestCallBack.java

@@ -0,0 +1,20 @@
+package com.example.xiaoshiweixinback.okhttp;
+
+
+
+/**
+ * @author Peach
+ *
+ * @param <T>
+ */
+public interface RequestCallBack<T> {
+    /**
+     * 响应成功
+     */
+    void onRequestSuccess(T result);
+
+    /**
+     * 响应失败
+     */
+    void onRequestFailed(String errorMsg);
+}

+ 179 - 0
src/main/java/com/example/xiaoshiweixinback/okhttp/RequestManager.java

@@ -0,0 +1,179 @@
+package com.example.xiaoshiweixinback.okhttp;
+
+import com.bjbz.common.exception.BusinessException;
+import com.bjbz.common.exception.BusinessExceptionErrorEnum;
+import com.bjbz.common.filter.AuthFilter;
+import com.bjbz.common.util.JSONUtil;
+import com.bjbz.core.log.tools.LogHelper;
+import okhttp3.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by Peach on 2016-12-13.
+ */
+
+public class RequestManager {
+	private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");// mdiatype
+
+
+
+	private static volatile RequestManager mInstance;// 单例引用
+	private OkHttpClient mOkHttpClient;// okHttpClient 实例
+
+
+	/**
+	 * 初始化RequestManager
+	 */
+	private RequestManager() {
+		// 初始化OkHttpClient
+		mOkHttpClient = new OkHttpClient().newBuilder().connectTimeout(600, TimeUnit.SECONDS)// 设置超时时间
+				.readTimeout(600, TimeUnit.SECONDS)// 设置读取超时时间
+				.writeTimeout(600, TimeUnit.SECONDS)// 设置写入超时时间
+				.build();
+	}
+
+	/**
+	 * 获取单例引用
+	 *
+	 * @return
+	 */
+	public static RequestManager getInstance() {
+		RequestManager inst = mInstance;
+		if (inst == null) {
+			synchronized (RequestManager.class) {
+				inst = mInstance;
+				if (inst == null) {
+					inst = new RequestManager();
+					mInstance = inst;
+				}
+			}
+		}
+		return inst;
+	}
+
+
+	/**
+     * 向内部应用发送JSON请求通过token
+	 * @param url
+     * @param object
+     * @param token
+     * @return
+     */
+	public String postJsonInnerAppByToken(String url, Object object, String token) {
+		RequestBody body = RequestBody.create(MEDIA_TYPE_JSON,JSONUtil.toJSONString(object));
+		Request request = new Request.Builder()
+				.url(url)
+				.post(body)
+				.addHeader(AuthFilter.HEADER, token)
+				.build();
+		String result=null;
+		try {
+			LogHelper.log(RequestManager.class,url+":调用请求->"+JSONUtil.toJSONString(object));
+			Response response = mOkHttpClient.newCall(request).execute();
+			if (response.isSuccessful()) {
+				result = response.body().string();
+				LogHelper.log(RequestManager.class,url+":调用成功->"+result);
+			}else{
+				LogHelper.log(RequestManager.class,url+":调用失败->"+response.message());
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			LogHelper.log(e,url+":调用异常");
+			throw new BusinessException(BusinessExceptionErrorEnum.SYSTEM_HTTP_ERROR);
+		}
+		return result;
+	}
+
+	/**
+	 * 向内部应用发送JSON请求通过token
+	 * @param url
+	 * @param object
+	 * @param token
+	 * @return
+	 */
+	public String postNormalInnerAppByToken(String url, Map<String,String> params) {
+		RequestBody body = new FormBody.Builder()
+				.add("mobile", params.get("mobile"))
+				.add("msgfmt",  params.get("msgfmt"))
+				.add("timespan",  params.get("timespan"))
+				.add("pwd",  params.get("pwd"))
+				.add("userid",  params.get("userid"))
+				.add("content",  params.get("content"))
+				.build();
+		Request request = new Request.Builder()
+				.url(url)
+				.post(body)
+				.build();
+		String result=null;
+		try {
+			LogHelper.log(RequestManager.class,url+":调用请求->"+JSONUtil.toJSONString(params));
+			Response response = mOkHttpClient.newCall(request).execute();
+			if (response.isSuccessful()) {
+				result = response.body().string();
+				LogHelper.log(RequestManager.class,url+":调用成功->"+result);
+			}else{
+				LogHelper.log(RequestManager.class,url+":调用失败->"+response.message());
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+			LogHelper.log(e,url+":调用异常");
+			throw new BusinessException(BusinessExceptionErrorEnum.SYSTEM_HTTP_ERROR);
+		}
+		return result;
+	}
+
+	/**
+	 * okHttp post同步请求表单提交
+	 *
+	 * @param actionUrl
+	 *            接口地址
+	 * @param paramsMap
+	 *            请求参数
+	 */
+	public String requestPostBySynWithForm(String actionUrl, HashMap<String, String> paramsMap)throws Exception {
+		String result = "";
+		// 创建一个FormBody.Builder
+		FormBody.Builder builder = new FormBody.Builder();
+		for (String key : paramsMap.keySet()) {
+			// 追加表单信息
+			builder.add(key, paramsMap.get(key));
+		}
+		// 生成表单实体对象
+		RequestBody formBody = builder.build();
+		// 补全请求地址
+		String requestUrl = String.format("%s", actionUrl);
+		// 创建一个请求
+		final Request request = addHeaders().url(requestUrl).post(formBody).build();
+		// 创建一个Call
+		final Call call = mOkHttpClient.newCall(request);
+		// 执行请求
+		Response response = call.execute();
+		if (response.isSuccessful()) {
+			result = response.body().string();
+			LogHelper.log("response ----->" + result);
+		}
+		else {
+			throw new BusinessException(BusinessExceptionErrorEnum.REQUEST_ERROR,response.code());
+		}
+		return result;
+	}
+
+	/**
+	 * 统一为请求添加头信息
+	 *
+	 * @return
+	 */
+	private Request.Builder addHeaders() {
+		Request.Builder builder = new Request.Builder();
+		// .addHeader("Connection", "keep-alive")
+		// .addHeader("platform", "2")
+		// .addHeader("phoneModel", Build.MODEL)
+		// .addHeader("systemVersion", Build.VERSION.RELEASE)
+		// .addHeader("appVersion", "1.0.0");
+		return builder;
+	}
+
+}

+ 109 - 0
src/main/java/com/example/xiaoshiweixinback/okhttp/ResponseManager.java

@@ -0,0 +1,109 @@
+package com.example.xiaoshiweixinback.okhttp;
+
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.List;
+
+
+public class ResponseManager {
+    /**
+    * @Title: parseObject
+    * @Description: 将json字符串转化为对象
+    * @param @param jsonStr
+    * @param @param clazz
+    * @param @return    参数
+    * @return T    返回类型
+    * @throws
+    * @author Peach
+    * @date 2017年4月17日
+    */
+    public  static  <T> T parseObject(String jsonStr, Class clazz){
+        T t=null;
+        try {
+            t = (T) JSON.parseObject(jsonStr, clazz);
+        }catch (Exception e){
+        	e.printStackTrace();
+        }
+        return t;
+    }
+    
+    /**
+    * @Title: parseArray
+    * @Description: 把json 转化成类对象列表
+    * @param @param json
+    * @param @param t
+    * @param @return    参数
+    * @return List<T>    返回类型
+    * @throws
+    * @author Peach
+    * @date 2017年4月17日
+    */
+    public static <T> List<T> parseArray(String json, Class<T> t) {
+        try {
+            if (json != null && !"".equals(json.trim())) {
+                List<T> res = JSONArray.parseArray(json.trim(), t);
+                return res;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+    
+    /**
+    * @Title: toJSON
+    * @Description: 将对象转化为JSON字符串
+    * @param @param obj
+    * @param @return    参数
+    * @return String    返回类型
+    * @throws
+    * @author Peach
+    * @date 2017年4月17日
+    */
+    public static String toJSON(Object obj) {
+        try {
+            return JSONObject.toJSONString(obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    /**
+     * 校验htttp调用是否成功
+     * @param json
+     * @return
+     */
+    public static boolean checkHTTPOK(String json){
+        JSONObject obj = JSONObject.parseObject(json);
+        if(obj.containsKey("code")){
+            if(obj.getInteger("code").equals(0)){
+                return true;
+            }else{
+                return false;
+            }
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 返回内部应用message
+     * @param json
+     * @return
+     */
+    public static String getResponseMessage(String json) {
+        JSONObject obj = JSONObject.parseObject(json);
+        if(obj.containsKey("message")){
+            return obj.getString("message").toString();
+        }else{
+            return null;
+        }
+
+    }
+}
+

+ 175 - 0
src/main/java/com/example/xiaoshiweixinback/service/LoginService.java

@@ -0,0 +1,175 @@
+package com.example.xiaoshiweixinback.service;
+
+
+import com.example.xiaoshiweixinback.business.exception.BusinessException;
+import com.example.xiaoshiweixinback.business.exception.BusinessExceptionErrorEnum;
+import com.example.xiaoshiweixinback.business.jwt.JwtTokenUtil;
+import com.example.xiaoshiweixinback.business.utils.RandomUtil;
+import com.example.xiaoshiweixinback.business.utils.RegexUtil;
+import com.example.xiaoshiweixinback.business.utils.ToolUtil;
+import com.example.xiaoshiweixinback.entity.vo.Jscode2SessionWo;
+import com.example.xiaoshiweixinback.entity.vo.SendCodeVO;
+import com.example.xiaoshiweixinback.okhttp.RequestManager;
+import com.example.xiaoshiweixinback.okhttp.ResponseManager;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.*;
+
+@Service
+public class LoginService {
+
+    @Autowired
+    private Environment environment;
+
+    @Autowired
+    private JwtTokenUtil jwtTokenUtil;
+
+
+    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Throwable.class)
+    public LoginDTO login(LoginVO vo) {
+        LogHelper.log("登录开始");
+        LoginDTO loginDTO = new LoginDTO();
+        //查询用户
+        LogHelper.log("登陆结束");
+        return loginDTO;
+    }
+
+    /**
+     * 微信小程序登录
+     * @title: loginByWeChat
+     * @author
+     * @date: 2023/04/04
+     * @param vo
+     * @return: WXLoginDTO
+     * @throws Exception
+     */
+    public WXLoginDTO loginByWeChat(WXLoginVO vo) throws Exception {
+        String code = vo.getCode();
+        String encryptedData = vo.getEncryptedData();
+        String iv = vo.getIv();
+        //返回数据
+        WXLoginDTO wxLoginDTO = new WXLoginDTO();
+        String appId = environment.getProperty("weChat.appId");
+        String appSecret = environment.getProperty("weChat.appSecret");
+        //1.根据code 获取微信小程序的openid和session_key
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put("appid", appId);
+        map.put("secret", appSecret);
+        map.put("js_code", code);
+        map.put("grant_type", "authorization_code");
+        String result = RequestManager.getInstance().requestPostBySynWithForm("https://api.weixin.qq.com/sns/jscode2session", map);
+        Jscode2SessionWo jscode2SessionWo = ResponseManager.parseObject(result, Jscode2SessionWo.class);
+
+        if (ToolUtil.isNotEmpty(jscode2SessionWo)) {
+            //2.查询数据表
+            Person person = new Person();
+            if (ToolUtil.isNotEmpty(person)) {
+                wxLoginDTO.setOpenId();
+                wxLoginDTO.setToken(this.getToken());
+            } else {
+                // 3. 解密用户数据
+                String decryptedData = decrypt(encryptedData, jscode2SessionWo.getSession_key(), iv);
+
+                // 4. 获取用户手机号(需要用户授权)
+                String phoneNumber = "";
+                JSONObject userData = JSONObject.parseObject(decryptedData);
+                if (ToolUtil.isNotEmpty(userData) && userData.containsKey("purePhoneNumber")) {
+                    phoneNumber = userData.getString("purePhoneNumber");
+                }
+
+                if (jscode2SessionWo.getOpenid() != null) {
+                    //添加用户表中
+                    wxLoginDTO.setOpenId(jscode2SessionWo.getOpenid());
+                    wxLoginDTO.setToken(this.getToken(user));
+                } else {
+                    throw new BusinessException(BusinessExceptionErrorEnum.SYSTEM_ERROR);
+                }
+            }
+        }
+
+        if (ToolUtil.isNotEmpty(wxLoginDTO.getOpenId())) {
+
+        }
+        return wxLoginDTO;
+    }
+
+    public boolean sendCode(SendCodeVO vo, HttpServletRequest request) {
+        if (!RegexUtil.isPhoneLegal(vo.getPhoneNo())) {
+            throw new BusinessException(ExceptionEnum.PHONE_FORMAT_ERROR);
+        }
+        //生成验证码
+        String random = RandomUtil.getSixRandom();
+
+        //手机号和验证码放进缓存 设置过期时间15m
+        redisService.set(vo.getPhoneNo(), random);
+        redisService.expire(vo.getPhoneNo(), CacheTTLEnum.FIFTEEN_MINUTE);
+        //发送短信
+//        smsService.sendMessage(vo.getPhoneNo(), random);
+        return true;
+    }
+
+    public String getToken() {
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        com.bjbz.common.jwt.JwtUserInfo jwtUserInfo = new com.bjbz.common.jwt.JwtUserInfo();
+        jwtUserInfo.setToken(uuid);
+        String token = jwtTokenUtil.generateToken(jwtUserInfo.toJsonString(), jwtTokenUtil.getRandomKey());
+        return token;
+    }
+
+    /**
+     * 解密用户数据
+     *
+     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
+     * @param sessionKey    会话密钥
+     * @param iv            加密算法的初始向量
+     * @return 解密后的用户数据
+     */
+    private static String decrypt(String encryptedData, String sessionKey, String iv) {
+        byte[] encryptedDataByte = Base64.decodeBase64(encryptedData);
+        byte[] sessionKeyByte = Base64.decodeBase64(sessionKey);
+        byte[] ivByte = Base64.decodeBase64(iv);
+
+        try {
+            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+            SecretKeySpec secretKeySpec = new SecretKeySpec(sessionKeyByte, "AES");
+            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivByte);
+            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+
+            byte[] decryptedDataByte = cipher.doFinal(encryptedDataByte);
+            return new String(decryptedDataByte);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /*public String getAccessToken() {
+        String appId = environment.getProperty("wx.appId");
+        String appSecret = environment.getProperty("wx.appSecret");
+        if (lock.tryLock()) {
+            try {
+                HashMap<String, String> map = new HashMap<>();
+                map.put("appid", appId);
+                map.put("secret", appSecret);
+                map.put("grant_type", "client_credential");
+
+                String result = RequestManager.getInstance().requestGetBySyn("https://api.weixin.qq.com/cgi-bin/token", map);
+                LogHelper.log(MiniAppService.class, "申请Token结果:" + result);
+                ApplyAccessWo applyAccessWo = ResponseManager.parseObject(result, ApplyAccessWo.class);
+                if (StringUtils.hasLength(applyAccessWo.getAccess_token())) {//成功得到access_token
+                    return applyAccessWo.getAccess_token();
+                } else {//获取access_token失败
+                    throw new BusinessException(ExceptionEnum.WX_APPLY_ACCESS_TOKEN_ERROR);
+                }
+            } catch (Exception e) {
+                throw new BusinessException(ExceptionEnum.WX_APPLY_ACCESS_TOKEN_ERROR);
+            } finally {
+                lock.unlock();
+            }
+        }
+        return null;
+    }*/
+}