Commit 31c793c3 authored by zuoadmin's avatar zuoadmin

Merge branch 'dev' into 'master'

Dev

See merge request !15
parents 6dc5c169 800406d4
package com.weface.code;
public class CommonResult<T> {
private long code;
private Integer code;
private String message;
private T data;
protected CommonResult() {
}
protected CommonResult(long code, String message) {
protected CommonResult(Integer code, String message) {
this.code = code;
this.message = message;
}
protected CommonResult(long code, String message, T data) {
protected CommonResult(Integer code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
......@@ -100,11 +100,11 @@ public class CommonResult<T> {
return new CommonResult<T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data);
}
public long getCode() {
public Integer getCode() {
return code;
}
public void setCode(long code) {
public void setCode(Integer code) {
this.code = code;
}
......
......@@ -5,7 +5,7 @@ package com.weface.code;
* Created by martin on 2019/7/16.
*/
public interface IErrorCode {
long getCode();
Integer getCode();
String getMessage();
}
package com.weface.code;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author : Administrator
* @date : 2022/4/19 14:35
*/
@Data
@Accessors(chain = true)
public class PushResultCode {
private int code;
private String result;
public static PushResultCode ok() {
return new PushResultCode().setCode(0).setResult("ok");
}
public static PushResultCode error() {
return new PushResultCode().setCode(1).setResult("error");
}
}
......@@ -5,16 +5,22 @@ public enum ResultCode implements IErrorCode {
FAILED(500, "操作失败"),
VALIDATE_FAILED(404, "参数检验失败"),
UNAUTHORIZED(401, "暂未登录或token已经过期"),
PARAMS_ERROR(40001, "参数错误不能为空"),
CONTENT_MORE_LENGTH(40002, "推送内容过长超过60字符"),
NOT_SIGN_ERROR(50003, "签名信息不可为空"),
REQUEST_EXPIRE_ERROR(50004, "请求已过期"),
CANNOT_ANALYSIS_PARAM_ERROR(50005, "无法解析的请求参数"),
SIGN_VALID_FAIL_ERROR(50006, "签名校验失败"),
FORBIDDEN(403, "没有相关权限");
private long code;
private String message;
private final Integer code;
private final String message;
private ResultCode(long code, String message) {
private ResultCode(Integer code, String message) {
this.code = code;
this.message = message;
}
public long getCode() {
public Integer getCode() {
return code;
}
......
package com.weface.common.utils;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
......@@ -88,4 +90,13 @@ public class Base64Util {
encodeStr = byte2Hex(instance.digest());
return encodeStr;
}
/**
* md5加密
*
* @param str 字符串
* @return 加密后结果
*/
public static String md5Encode(String str) {
return DigestUtils.md5Hex(str);
}
}
package com.weface.common.utils;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.locationtech.spatial4j.context.SpatialContext;
import org.locationtech.spatial4j.distance.DistanceUtils;
import org.locationtech.spatial4j.shape.Rectangle;
import org.springframework.util.AntPathMatcher;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
/**
* @author Administrator
*/
public class CommonUtil {
private static final SpatialContext SPATIAL_CONTEXT = SpatialContext.GEO;
/**
* 判断字符串是否Base64字符串
*/
public static boolean isBase64(String str) {
if (str == null || "".equals(str)) {
return false;
}
String reg = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
return Pattern.matches(reg, str);
}
/**
* 将一个集合平均分成n组
*/
public static <T> List<List<T>> averageAssign(List<T> source, int n) {
List<List<T>> result = new ArrayList<>();
//(先计算出余数)
int remainder = source.size() % n;
//然后是商
int number = source.size() / n;
//偏移量
int offset = 0;
for (int i = 0; i < n; i++) {
List<T> value;
if (remainder > 0) {
value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
remainder--;
offset++;
} else {
value = source.subList(i * number + offset, (i + 1) * number + offset);
}
result.add(value);
}
return result;
}
/**
* 将一个集合分成若干组,每组n个元素
*/
public static <T> List<List<T>> fixedGrouping(List<T> source, int n) {
if (null == source || source.size() == 0 || n <= 0) {
return null;
}
List<List<T>> result = new ArrayList<>();
int remainder = source.size() % n;
int size = (source.size() / n);
for (int i = 0; i < size; i++) {
List<T> subset;
subset = source.subList(i * n, (i + 1) * n);
result.add(subset);
}
if (remainder > 0) {
List<T> subset = source.subList(size * n, size * n + remainder);
result.add(subset);
}
return result;
}
/**
* 对实体类的某些字段进行加密
*
* @param t 实体类
* @param encryptFun 加密的方法
* @param fieldNames 要加密的字段数组
* @param <T> TT
* @return T
*/
public static <T> T encryptEntity(T t, Function<String, String> encryptFun, String[] fieldNames) {
for (String name : fieldNames) {
Class<?> clazz = t.getClass();
try {
Field field = clazz.getDeclaredField(name);
Class<?> fileType = field.getType();
//加密的字段,数据类型 必须是String
if (fileType == String.class) {
//设置字段为可操作
field.setAccessible(true);
String value = (String) field.get(t);
if (value == null) {
continue;
}
String encryptValue = encryptFun.apply(value);
//赋值为加密后的字段
field.set(t, encryptValue);
field.setAccessible(false);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
return t;
}
/**
* 对实体类的某些字段进行解码
*
* @param t 实体类对象
* @param decryptFun 解码的方法
* @param fieldNames 解码的字段数组
* @param <T> TT
* @return T
*/
public static <T> T decryptEntity(T t, Function<String, String> decryptFun, String[] fieldNames) {
for (String name : fieldNames) {
Class<?> clazz = t.getClass();
try {
Field field = clazz.getDeclaredField(name);
Class<?> fileType = field.getType();
//加密的字段,数据类型 必须是String
if (fileType == String.class) {
//设置字段为可操作
field.setAccessible(true);
String value = (String) field.get(t);
//如果是base64,(加密后的数据时base字符串),再进行解码
if (value != null && isBase64(value)) {
String decryptStr = decryptFun.apply(value);
//赋值为加密后的字段
field.set(t, decryptStr);
}
field.setAccessible(false);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
return t;
}
/**
* 签名的规则:sk + 所有非空参数值拼接 + sk
*
* @param param 所有请求参数
* @return sign 签名
*/
public static String apiParamSign(Map<String, Object> param, String sk) {
TreeMap<String, Object> map = new TreeMap<>(param);
StringBuilder builder = new StringBuilder();
builder.append(sk);
map.forEach((k, v) -> {
if (v != null && !"null".equals(v) && !"".equals(v)) {
builder.append(v);
}
});
builder.append(sk);
return SecureUtil.md5(builder.toString());
}
/**
* 调用百度接口,获取地址信息的经纬度
*
* @param address 地址信息
* @return double[] 0经度 1纬度
*/
public static double[] getAxisByAddress(String address) {
String url = "http://api.map.baidu.com/geocoding/v3/?address=%s&ret_coordtype=wgs84ll&output=json&ak=b9kvzxPGvOxvcPllM9P7s81C85bKQPgE";
String request = String.format(url, address);
JSONObject jsonObject = JSONUtil.parseObj(HttpUtil.get(request));
if (jsonObject.getInt(Constant.STATUS) == 0) {
JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
Double lng = location.getDouble("lng");
Double lat = location.getDouble("lat");
return new double[]{lng, lat};
}
return null;
}
/**
* 利用开源库计算外接正方形坐标
*
* @param distance 距离,单位千米
* @param userLng 当前经度
* @param userLat 当前纬度
* @return 返回正方形坐标
*/
public static Rectangle getRectangle(double distance, double userLng, double userLat) {
return SPATIAL_CONTEXT.getDistCalc()
.calcBoxByDistFromPt(SPATIAL_CONTEXT.getShapeFactory().pointXY(userLng, userLat),
distance * DistanceUtils.KM_TO_DEG, SPATIAL_CONTEXT, null);
}
/***
* 球面中,两点间的距离(第三方库方法)
*
* @param longitude 经度1
* @param latitude 纬度1
* @param userLng 经度2
* @param userLat 纬度2
* @return 返回距离,单位km
*/
public static double getDistance(Double longitude, Double latitude, double userLng, double userLat) {
return SPATIAL_CONTEXT.calcDistance(SPATIAL_CONTEXT.getShapeFactory().pointXY(userLng, userLat),
SPATIAL_CONTEXT.getShapeFactory().pointXY(longitude, latitude)) * DistanceUtils.DEG_TO_KM;
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll) {
return coll == null || coll.isEmpty();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return boolean 是否匹配
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
/**
* 获取真实ip地址,避免获取代理ip
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || Constant.UN_KNOW.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
* 加密ID和手机号
*
* @param uid uid
* @param tel 手机号
* @return 密文
*/
public static String encryptIdAndTel(String uid, String tel) {
//kkv+id+ 手机号码后五位+手机号码第六位+手机号码前五位
try {
String prefix = "kkv";
String sub1 = StrUtil.sub(tel, 0, 5);
String sub2 = StrUtil.sub(tel, 5, 6);
String sub3 = StrUtil.sub(tel, 6, 11);
return prefix + uid + sub3 + sub2 + sub1;
} catch (Exception e) {
return null;
}
}
/**
* 解析ID和手机号
*
* @param encryptStr 密文
* @return 明文
*/
public static String[] decryptIdAndTel(String encryptStr) {
//kkv+id+ 手机号码后五位+手机号码第六位+手机号码前五位
try {
String prefix = "kkv";
int length = encryptStr.length();
String hexTel = encryptStr.substring(length - 11, length);
String sub1 = StrUtil.sub(hexTel, 0, 5);
String sub2 = StrUtil.sub(hexTel, 5, 6);
String sub3 = StrUtil.sub(hexTel, 6, 11);
String tel = sub3 + sub2 + sub1;
String suffix = StrUtil.subAfter(encryptStr, prefix, true);
String uid = StrUtil.sub(suffix, 0, suffix.length() - 11);
String[] arr = new String[2];
arr[0] = uid;
arr[1] = tel;
return arr;
} catch (Exception e) {
return null;
}
}
}
package com.weface.common.utils;
/**
* 系统参数相关Key
*
* @author Mark sunlightcs@gmail.com
*/
public class ConfigConstant {
/**
* 云存储配置KEY
*/
public final static String CLOUD_STORAGE_CONFIG_KEY = "CLOUD_STORAGE_CONFIG_KEY";
}
......@@ -29,89 +29,48 @@ public class Constant {
*/
public static final String ASC = "asc";
/**
* 菜单类型
*
* @author chenshun
* @date 2016年11月15日 下午1:24:29
*/
public enum MenuType {
/**
* 目录
* DES密钥
*/
CATALOG(0),
public static final String DES_KEY = "Kkweface55389527";
/**
* 菜单
* 状态
*/
MENU(1),
/**
* 按钮
*/
BUTTON(2);
private int value;
MenuType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public static final String STATUS = "status";
/**
* 定时任务状态
*
* @author chenshun
* @date 2016年12月3日 上午12:07:22
*unknown
*/
public enum ScheduleStatus {
public static final String UN_KNOW = "unknown";
/**
* 正常
*时间戳
*/
NORMAL(0),
public static final String TIME_NAME = "timestamp";
/**
* 暂停
* redis缓存前缀
*/
PAUSE(1);
private int value;
ScheduleStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public static final String PUSH_TASK_INFO = "push_task_info";
/**
* 云服务商
*/
public enum CloudService {
/**
* 七牛云
* http 请求
*/
QINIU(1),
@SuppressWarnings("unused")
public enum MethodType {
/**
* 阿里云
* 请求类型
*/
ALIYUN(2),
/**
* 腾讯云
*/
QCLOUD(3);
GET("GET"),
POST("POST"),
PUT("PUT"),
DELETE("DELETE"),
PATCH("PATCH");
private int value;
private final String value;
CloudService(int value) {
MethodType(String value) {
this.value = value;
}
public int getValue() {
public String getValue() {
return value;
}
}
}
package com.weface.common.utils;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
/**
* @author Administrator
*/
public class DES {
private byte[] desKey;
public DES(String desKey) {
this.desKey = desKey.getBytes();
}
private static DES des;
private DES() {
}
public static DES getInstanceDes() {
if (ObjectUtil.isNull(des)) {
des = new DES(Constant.DES_KEY);
}
return des;
}
/**
* 加密
*
* @param plainText 原文
* @return 密文
* @throws Exception 异常
*/
public byte[] desEncrypt(byte[] plainText) throws Exception {
SecureRandom sr = new SecureRandom();
byte[] rawKeyData = desKey;
DESKeySpec dks = new DESKeySpec(rawKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
javax.crypto.SecretKey key = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(1, key, sr);
return cipher.doFinal(plainText);
}
/**
* 解密
*
* @param encryptText 密文
* @return 原文
* @throws Exception 异常
*/
public byte[] desDecrypt(byte[] encryptText) throws Exception {
SecureRandom sr = new SecureRandom();
byte[] rawKeyData = desKey;
DESKeySpec dks = new DESKeySpec(rawKeyData);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
javax.crypto.SecretKey key = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(2, key, sr);
return cipher.doFinal(encryptText);
}
/**
* 加密
*
* @param input 原文
* @return 加密后数据
* @throws Exception 异常
*/
public String encrypt(String input) throws Exception {
if (StringUtils.isEmpty(input)) {
return null;
}
return Base64.encode(desEncrypt(input.getBytes(StandardCharsets.UTF_8)));
}
/**
* 解密
*
* @param input 加密数据
* @return 原文
*/
public String decrypt(String input) {
if (StringUtils.isEmpty(input)) {
return null;
}
byte[] result = Base64.decode(input);
try {
if (CommonUtil.isBase64(input)) {
return new String(desDecrypt(result), StandardCharsets.UTF_8);
} else {
return input;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String encrypt2(String input) throws Exception {
return new String(desEncrypt(input.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
}
public String decrypt2(String input) throws Exception {
return new String(desDecrypt(input.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
}
public static void main(String[] args) {
DES des = new DES(Constant.DES_KEY);
String name = des.decrypt("mC8HL+gBKJs=");
String head = des.decrypt("JH2AUKTuP4k4065YeoNoDA==");
System.out.println(name);
System.out.println(head);
}
}
......@@ -5,9 +5,9 @@ import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
......@@ -82,4 +82,27 @@ public class HttpUtil {
}
return flag;
}
/**
* 从请求中拿到请求流数据
*
* @param request 请求
* @return 字节数组
* @throws IOException io异常
*/
public static byte[] getRequestInputStream(HttpServletRequest request) throws IOException {
ServletInputStream input = request.getInputStream();
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int position = 0;
while (true) {
position = input.read(buffer);
if (position == -1) {
break;
}
output.write(buffer, 0, position);
}
return output.toByteArray();
}
}
package com.weface.common.utils;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.weface.config.RedisExpireData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
......@@ -1053,6 +1055,50 @@ public class RedisUtil implements ApplicationContextAware {
log.info("hScan(...) => cursor -> {}", JSON.toJSONString(cursor));
return cursor;
}
/**
* @Description 获取redis hash 带过期时间的数据
* @Param [redisTemplate, redisKey, hashKey]
* @Return java.lang.String
*/
/**
* 获取redis hash 带过期时间的数据
*
* @param redisKey redisKey
* @param hashKey hashKey
* @return obj
*/
public static Object hGetEx(String redisKey, String hashKey) {
Object hashValue = hGet(redisKey, hashKey);
if (hashValue == null) {
return null;
}
RedisExpireData redisData = JSONUtil.toBean(hashValue.toString(), RedisExpireData.class);
if (redisData == null) {
return null;
} else {
Object obj = redisData.getStoreData();
if (obj == null) {
hDelete(redisKey, hashKey);
}
return obj;
}
}
/**
* 设置带过期时间的redis hash
*
* @param redisKey redis_key
* @param hashKey hash_key
* @param hashValue value
* @param expire 过期时间
* @param timeUnit 时间类型
*/
public static void hPutEx(String redisKey, String hashKey, Object hashValue, Long expire, TimeUnit timeUnit) {
RedisExpireData redisData = new RedisExpireData(hashValue, timeUnit.toMillis(expire));
hPut(redisKey, hashKey, JSONUtil.toJsonStr(redisData));
}
}
/**
......
package com.weface.common.utils;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 短信发送操作类
*/
@Slf4j
public class ShortMsgSend {
/**
* 看看社保
*/
//static String url = "http://114.55.5.4/hy/";
//static String uid = "90062";
//static String auth = "ec7fa119ecc34b385549e8e154e5bdd5";
/**
* 看看生活
*/
// private static final String url = "http://submit.10690221.com:9012/hy/";
// private static final String uid = "90063";
// private static final String auth = "c4daa5fe21eabe16a765eefe0573dbdf";
public static boolean sendMobileByRegister(String paramContent, String telPhone, Integer messageTemplate) throws IOException {
String url = null;
String uid = null;
String auth = null;
switch (messageTemplate) {
//看看生活
case 1:
url = "http://submit.10690221.com:9012/hy/";
uid = "90063";
auth = "c4daa5fe21eabe16a765eefe0573dbdf";
break;
//看看社保
case 2:
url = "http://114.55.5.4/hy/";
uid = "90062";
auth = "ec7fa119ecc34b385549e8e154e5bdd5";
break;
default:
break;
}
if (url == null) {
log.error("短信模板参数错误:{}", messageTemplate);
return false;
}
return sendMobileByRegister(paramContent, telPhone, url, uid, auth);
}
private static boolean sendMobileByRegister(String paramContent, String telPhone, String url, String uid, String auth) throws IOException {
String content = java.net.URLEncoder.encode(paramContent, "gbk");
Map<String, Object> map = new HashMap<>();
map.put("uid", uid);
map.put("auth", auth);
map.put("mobile", telPhone);
map.put("expid", "0");
map.put("msg", content);
HttpRequest post = HttpUtil.createPost(url);
HttpResponse execute = post.form(map).execute();
int status = execute.getStatus();
if (status == 200) {
String postResult = execute.body();
log.error("{}的短信发生结果:{}", telPhone, postResult);
System.out.println(postResult);
try {
return postResult.split(",")[0].equals("0");
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
/*
* 功能描述:
* @auther: 信息
* @date: 2018/12/24 17:30
*/
public static String Mesresult = "请您于6月10日之前,通过“看看卫健”软件,完成高龄补贴资格认证,每年3月、6月、9月、12月的1-10日为认证时间,不认证将停发或终止补贴";
public static void main(String[] args) {
String telphone = "15538250098";
String msg = "尊敬的用户,请尽快完成社保认证,领取养老金。认证下载链接http://dwz.date/eHEH";
System.out.println(msg.length());
try {
boolean sabeResult = sendMobileByRegister(msg, telphone, 1);
if (sabeResult) {
System.out.println("短信发送成功");
} else {
System.out.println("短信发送失败");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
package com.weface.common.utils;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
/**
* @author : Administrator
* @date : 2022/2/16 14:58
*/
public class SnowIdUtil {
private static final Snowflake SNOWFLAKE;
static {
SNOWFLAKE = IdUtil.getSnowflake(1, 1);
}
/**
* 通过雪花算法获取id,统一封装调用
*
* @return id
*/
public static Long nextId() {
return SNOWFLAKE.nextId();
}
}
package com.weface.common.validator;
import com.weface.code.CommonResult;
import com.weface.code.ResultCode;
import com.weface.dto.InformForm;
import org.apache.commons.lang3.StringUtils;
/**
* @author : Administrator
* @date : 2022/4/21 14:28
*/
public class ValidatorParam {
public static CommonResult validPushSingleAlias(InformForm informForm) {
String body = informForm.getBody();
if (body.length() > 60) {
return CommonResult.failed(ResultCode.CONTENT_MORE_LENGTH);
}
Integer pushType = informForm.getPushType();
if (pushType != null && pushType == 1) {
String className = informForm.getClassName();
String classTitle = informForm.getClassTitle();
String needLogin = informForm.getNeedLogin();
if (StringUtils.isEmpty(className) || StringUtils.isEmpty(classTitle) || StringUtils.isEmpty(needLogin)) {
return CommonResult.failed(ResultCode.PARAMS_ERROR);
}
}
String cid = informForm.getCid();
String phone = informForm.getPhone();
Integer messageTemplate = informForm.getMessageTemplate();
if (StringUtils.isEmpty(cid) || StringUtils.isEmpty(phone) || messageTemplate == null) {
return CommonResult.failed(ResultCode.PARAMS_ERROR);
}
return null;
}
}
......@@ -33,11 +33,9 @@ public class ValidatorUtils {
throws RRException {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
StringBuilder msg = new StringBuilder();
for (ConstraintViolation<Object> constraint : constraintViolations) {
msg.append(constraint.getMessage()).append("\n");
throw new RRException(constraint.getMessage(), 10001);
}
throw new RRException(msg.toString());
}
}
}
package com.weface.component;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.weface.common.utils.SnowIdUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
......@@ -49,7 +49,7 @@ public class GeTuiPush {
public void toSinglePush(String alia) {
Map<String, Object> param = new HashMap<>();
param.put("request_id", String.valueOf(IdUtil.createSnowflake(1, 1).nextId()));
param.put("request_id", String.valueOf(SnowIdUtil.nextId()));
Map<String, Object> audience = new HashMap<>();
List<String> alias = new ArrayList<>();
alias.add(alia);
......@@ -75,7 +75,7 @@ public class GeTuiPush {
public void toSingleBatchPush(String alia) {
Map<String, Object> param = new HashMap<>();
param.put("request_id", String.valueOf(IdUtil.createSnowflake(1,1).nextId()));
param.put("request_id", String.valueOf(SnowIdUtil.nextId()));
Map<String, Object> audience = new HashMap<>();
List<String> alias = new ArrayList<>();
alias.add(alia);
......
package com.weface.component;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.weface.code.CommonResult;
......@@ -14,12 +11,15 @@ import com.weface.common.exception.RRException;
import com.weface.common.utils.Base64Util;
import com.weface.common.utils.HttpUtil;
import com.weface.common.utils.RedisUtil;
import com.weface.common.utils.SnowIdUtil;
import com.weface.config.GeTuiApp;
import com.weface.config.GeTuiConfig;
import com.weface.dto.InformForm;
import com.weface.service.PushLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
......@@ -38,6 +38,9 @@ import java.util.concurrent.TimeUnit;
@Slf4j
public class GeTuiService {
@Autowired
private PushLogService pushLogService;
@Resource
private GeTuiApp geTuiApp;
public static final String GE_TUI_BASE_URL = "https://restapi.getui.com/v2/";
......@@ -51,7 +54,7 @@ public class GeTuiService {
private final static long TIMEOUT = (12 * 60 * 60);
/**
* 获取token并缓存一份
* 统一获取个推token
*
* @param key 缓存key
* @return 从缓存中拿token
......@@ -192,25 +195,6 @@ public class GeTuiService {
return null;
}
/**
* 获取appId
*
* @param appName app名称
* @return appId
*/
public String getAppId(String appName) {
return getConfig(appName).getAppId();
}
/**
* 获取app配置
*
* @param appName app名称
* @return app配置
*/
public GeTuiConfig getConfig(String appName) {
return geTuiApp.getApps().get(appName);
}
/**
* 获取看看生活个像
......@@ -278,36 +262,198 @@ public class GeTuiService {
}
/**
* 【toSingle】执行别名单推
* 转换推送token
*
* @param key 应用名称
* @return 应用token
*/
private String getPushToken(String key) {
String token = null;
switch (key) {
//看看生活
case "kksh":
token = getAuthToken("kk_sh_token_ge_tui");
break;
//看看社保
case "kksb":
token = getAuthToken("kk_sb_token_ge_tui");
break;
case "kkwj":
token = getAuthToken("kk_wj_token_ge_tui");
break;
case "kkmz":
token = getAuthToken("kk_mz_token_ge_tui");
break;
default:
break;
}
return token;
}
/**
* 群推
*
* @param informForm 推送消息
* @return 执行状态
*/
public CommonResult listPush(InformForm informForm) {
try {
String type = informForm.getEquipmentType();
String appId = getAppId(type);
String pushToken = getPushToken(type);
if (StringUtils.isBlank(pushToken)) {
return CommonResult.failed();
}
Integer speed = informForm.getSpeed();
informForm.setSpeed(speed == null ? 0 : speed);
MessageTemplate template = getTemplate(informForm);
template.setGroup_name("toApp");
Map<String, Object> map = convertBeanToMap(informForm.getDevice(), false, 1, template);
//请求url
String url = GE_TUI_BASE_URL + appId + "/push/all";
log.info("执行群推");
String result = generalPost(url, pushToken, map);
if (result == null) {
return CommonResult.failed();
}
JSONObject jsonObject = JSONObject.parseObject(result);
if ((jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0)) {
JSONObject data = jsonObject.getJSONObject("data");
if (data != null) {
//保存单推结果
pushLogService.saveLog(data, informForm, appId);
}
return CommonResult.success(data);
}
} catch (UnsupportedEncodingException e) {
log.error("执行群推失败:{}", e.getMessage());
e.printStackTrace();
}
return CommonResult.failed();
}
/**
* 别名单推
*
* @param messageTemplate 应用id
* @param appId 消息模板
* @param token 接口访问凭据
* @return 消息推送结果
* @param informForm 推送消息
* @return 执行结果
*/
public String singlePushAlias(Integer device, MessageTemplate messageTemplate, String appId, String token) throws UnsupportedEncodingException {
Map<String, Object> map = convertBeanToMap(device, false, 1, messageTemplate);
public CommonResult pushSingleAlias(InformForm informForm) {
try {
String type = informForm.getEquipmentType();
String appId = getAppId(type);
String pushToken = getPushToken(type);
if (StringUtils.isBlank(pushToken)) {
return CommonResult.failed();
}
MessageTemplate template = getTemplate(informForm);
String[] split;
String cid = informForm.getCid();
if (cid.contains(",")) {
split = cid.split(",");
} else {
split = new String[]{cid};
}
template.setAudience(new MessageTemplate.Audience(split));
template.setGroup_name("toSingleAlias");
Map<String, Object> map = convertBeanToMap(informForm.getDevice(), false, 1, template);
//请求url
String url = GE_TUI_BASE_URL + appId + "/push/single/alias";
log.info("执行别名单推");
return generalPost(url, token, map);
String result = generalPost(url, pushToken, map);
log.error("推送结果:{}", result);
if (StringUtils.isEmpty(result)) {
return CommonResult.failed();
}
JSONObject jsonObject = JSONObject.parseObject(result);
if ((jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0)) {
JSONObject data = jsonObject.getJSONObject("data");
if (data != null) {
//保存单推结果
pushLogService.saveLog(data, informForm, appId);
}
return CommonResult.success();
}
} catch (UnsupportedEncodingException e) {
log.error("执行别名单推失败:{}", e.getMessage());
e.printStackTrace();
}
return CommonResult.failed();
}
/**
* 【toSingle】执行cid单推
*
* @param device 设备类型
* @param messageTemplate 消息
* @param appId appId
* @param token 鉴权
* @param informForm 推送消息
* @return 执行结果
*/
public String singlePushCid(Integer device, MessageTemplate messageTemplate, String appId, String token) throws UnsupportedEncodingException {
Map<String, Object> map = convertBeanToMap(device, false, 0, messageTemplate);
public CommonResult pushSingleCid(InformForm informForm) {
try {
String type = informForm.getEquipmentType();
String appId = getAppId(type);
String pushToken = getPushToken(type);
if (StringUtils.isBlank(pushToken)) {
return CommonResult.failed();
}
MessageTemplate template = getTemplate(informForm);
String[] split;
String cid = informForm.getCid();
if (cid.contains(",")) {
split = cid.split(",");
} else {
split = new String[]{cid};
}
template.setAudience(new MessageTemplate.Audience(split));
template.setGroup_name("toSingleCid");
Map<String, Object> map = convertBeanToMap(informForm.getDevice(), false, 0, template);
//请求url
String url = GE_TUI_BASE_URL + appId + "/push/single/cid";
log.info("执行cid单推");
return generalPost(url, token, map);
String result = generalPost(url, pushToken, map);
if (StringUtils.isEmpty(result)) {
return CommonResult.failed();
}
JSONObject jsonObject = JSONObject.parseObject(result);
if ((jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0)) {
JSONObject data = jsonObject.getJSONObject("data");
if (data != null) {
//保存单推结果
pushLogService.saveLog(data, informForm, appId);
}
return CommonResult.success();
}
} catch (UnsupportedEncodingException e) {
log.error("执行别名单推失败:{}", e.getMessage());
e.printStackTrace();
}
return CommonResult.failed();
}
/**
* 将内容转为推送模板
*
* @param informForm 推送数据
* @return 推送模板
*/
private MessageTemplate getTemplate(InformForm informForm) {
MessageTemplate messageTemplate = new MessageTemplate();
messageTemplate.setSettings(new MessageTemplate.Settings(3600000, informForm.getSpeed()));
MessageTemplate.PushMessage pushMessage = new MessageTemplate.PushMessage();
MessageTemplate.PushMessage.Transmission transmission = new MessageTemplate.PushMessage.Transmission();
transmission.setTitle(informForm.getTitle());
transmission.setContent(informForm.getBody());
transmission.setUrl(informForm.getUrl());
int pushType = informForm.getPushType() == null ? 0 : informForm.getPushType();
transmission.setPushType(pushType);
if (pushType == 1) {
transmission.setClassTitle(informForm.getClassTitle());
transmission.setClassName(informForm.getClassName());
transmission.setNeedLogin(informForm.getNeedLogin());
}
pushMessage.setTransmission(transmission);
messageTemplate.setPush_message(pushMessage);
return messageTemplate;
}
/**
......@@ -378,87 +524,6 @@ public class GeTuiService {
return generalPost(url, token, map);
}
/**
* 群推
*
* @param informForm 消息
* @return 执行状态
*/
public CommonResult listPush(InformForm informForm) {
MessageTemplate messageTemplate = new MessageTemplate();
try {
GeTuiConfig kksh = getConfig("kksh");
GeTuiConfig kksb = getConfig("kksb");
GeTuiConfig kkwj = getConfig("kkwj");
GeTuiConfig kkmz = getConfig("kkmz");
Integer device = informForm.getDevice();
if (device == null) {
device = 4;
}
Integer speed = informForm.getSpeed();
messageTemplate.setSettings(new MessageTemplate.Settings(3600000, speed == null ? 0 : speed));
MessageTemplate.PushMessage pushMessage = new MessageTemplate.PushMessage();
MessageTemplate.PushMessage.Transmission transmission = new MessageTemplate.PushMessage.Transmission();
transmission.setTitle(informForm.getTitle());
transmission.setContent(informForm.getBody());
transmission.setUrl(HtmlUtil.unescape(informForm.getUrl()));
pushMessage.setTransmission(transmission);
messageTemplate.setPush_message(pushMessage);
String result = null;
switch (informForm.getEquipmentType()) {
//看看生活
case "kksh":
String kk_sh_token_ge_tui = getAuthToken("kk_sh_token_ge_tui");
result = listPushToApp(device, messageTemplate, kksh.getAppId(), kk_sh_token_ge_tui);
break;
//看看社保
case "kksb":
String kk_sb_token_ge_tui = getAuthToken("kk_sb_token_ge_tui");
result = listPushToApp(device, messageTemplate, kksb.getAppId(), kk_sb_token_ge_tui);
break;
case "kkwj":
String kk_wj_token_ge_tui = getAuthToken("kk_wj_token_ge_tui");
result = listPushToApp(device, messageTemplate, kkwj.getAppId(), kk_wj_token_ge_tui);
break;
case "kkmz":
String kk_mz_token_ge_tui = getAuthToken("kk_mz_token_ge_tui");
result = listPushToApp(device, messageTemplate, kkmz.getAppId(), kk_mz_token_ge_tui);
break;
default:
break;
}
if (result == null) {
return CommonResult.failed();
}
JSONObject jsonObject = JSONObject.parseObject(result);
if ((jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0)) {
JSONObject data = jsonObject.getJSONObject("data");
return CommonResult.success(data);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return CommonResult.failed();
}
/**
* 【toApp】执行群推
*
* @param messageTemplate 请求参数
* @param token token
* @return 执行结果
*/
public String listPushToApp(Integer device, MessageTemplate messageTemplate, String appId, String token) throws UnsupportedEncodingException {
Map<String, Object> map = convertBeanToMap(device, false, 1, messageTemplate);
//请求url
String url = GE_TUI_BASE_URL + appId + "/push/all";
log.info("执行群推");
return generalPost(url, token, map);
}
/**
* 实体类封装为map
*
......@@ -471,7 +536,7 @@ public class GeTuiService {
}
//设置请求唯一标识号,10-32位之间;如果request_id重复,会导致消息丢失
Map<String, Object> map = new HashMap<>();
map.put("request_id", String.valueOf(IdUtil.getSnowflake(1, 1).nextId()));
map.put("request_id", String.valueOf(SnowIdUtil.nextId()));
//设置任务组名
if (StringUtils.isNotBlank(messageTemplate.getGroup_name())) {
......@@ -509,42 +574,61 @@ public class GeTuiService {
}
}
//获取推送消息转为map 不转为下划线,忽略空值
MessageTemplate.PushMessage push_message = messageTemplate.getPush_message();
Map<String, Object> push_messages = BeanUtil.beanToMap(push_message, false, true);
MessageTemplate.PushMessage pushMessage = messageTemplate.getPush_message();
Map<String, Object> pushMessages = BeanUtil.beanToMap(pushMessage, false, true);
//透传消息内容,与notification、revoke 三选一,都填写时报错,长度 ≤ 3072
MessageTemplate.PushMessage.Transmission transmission = push_message.getTransmission();
String str = "{\"content\": \"%s\", \"push_type\": \"0\", \"title\": \"%s\", \"url\": \"%s\"}";
String intent = String.format(str, transmission.getContent(), transmission.getTitle(), transmission.getUrl());
push_messages.put("transmission", intent);
MessageTemplate.PushMessage.Transmission transmission = pushMessage.getTransmission();
String intent = getIntent(transmission);
pushMessages.put("transmission", intent);
//撤回消息时使用(仅撤回厂商通道消息,支持的厂商有小米、VIVO),与notification、transmission三选一,都填写时报错(消息撤回请勿填写策略参数)
MessageTemplate.PushMessage.Revoke revoke = push_message.getRevoke();
MessageTemplate.PushMessage.Revoke revoke = pushMessage.getRevoke();
if (revoke != null) {
//设置撤回消息
Map<String, Object> revokes = BeanUtil.beanToMap(revoke, false, true);
push_messages.put("revoke", revokes);
pushMessages.put("revoke", revokes);
}
//设置推送消息
map.put("push_message", push_messages);
map.put("push_message", pushMessages);
//设置厂商通道
map.put("push_channel", setChannel(push_message));
map.put("push_channel", setChannel(pushMessage));
return map;
}
/**
* 封装intent
*
* @param transmission 推送数据
* @return intent
*/
private String getIntent(MessageTemplate.PushMessage.Transmission transmission) {
Integer pushType = transmission.getPushType();
String intent;
if (pushType == 0) {
String str = "{\"content\": \"%s\", \"push_type\": \"0\", \"title\": \"%s\", \"url\": \"%s\"}";
intent = String.format(str, transmission.getContent(), transmission.getTitle(), transmission.getUrl());
} else {
String str = "{\"content\":\"%s\",\"push_type\":\"1\",\"title\":\"%s\",\"className\":\"%s\",\"classTitle\":\"%s\",\"needLogin\":\"%s\"}";
intent = String.format(str, transmission.getContent(), transmission.getTitle(), transmission.getClassName(), transmission.getClassTitle(), transmission.getNeedLogin());
}
return intent;
}
/**
* 设置推送渠道
*
* @param push_message 消息
* @return json
*/
public cn.hutool.json.JSONObject setChannel(MessageTemplate.PushMessage push_message) throws UnsupportedEncodingException {
private Map<String, Object> setChannel(MessageTemplate.PushMessage push_message) throws UnsupportedEncodingException {
Map<String, Object> channel = new HashMap<>();
//获取ios配置
channel.put("ios", getIosChannel(push_message));
//获取android配置
channel.put("android", getAndroidChannel(push_message));
return JSONUtil.parseFromMap(channel);
return channel;
}
/**
......@@ -553,7 +637,7 @@ public class GeTuiService {
* @param push_message 消息
* @return ios配置
*/
private Map<String, Object> getIosChannel(MessageTemplate.PushMessage push_message) throws UnsupportedEncodingException {
private Map<String, Object> getIosChannel(MessageTemplate.PushMessage push_message) {
Map<String, Object> ios = new HashMap<>();
ios.put("type", "notify");
// ios.put("auto_badge", "+1");
......@@ -567,8 +651,7 @@ public class GeTuiService {
alert.put("body", transmission.getContent());
aps.put("alert", alert);
ios.put("aps", aps);
String str = "{\"content\": \"%s\", \"push_type\": \"0\", \"title\": \"%s\", \"url\": \"%s\"}";
String intent = String.format(str, transmission.getContent(), transmission.getTitle(), transmission.getUrl());
String intent = getIntent(transmission);
ios.put("payload", intent);
return ios;
}
......@@ -589,14 +672,44 @@ public class GeTuiService {
notification.put("click_type", "intent");
String pack = "com.weface.kksocialsecurity";
String component = pack + "/com.weface.kksocialsecurity.activity.WellcomeActivity";
String str = "intent://com.weface.kksocialsecurity/localopen?push_type=0&url=%s#Intent;scheme=kankan;package=%s;component=%s;S.kkparam={\"content\": \"%s\", \"push_type\": \"0\", \"title\": \"%s\", \"url\": \"%s\"};end";
String intent = String.format(str, URLEncoder.encode(transmission.getUrl(), "UTF-8"), pack, component, transmission.getContent(), transmission.getTitle(), URLEncoder.encode(transmission.getUrl(), "UTF-8"));
String str = "intent://com.weface.kksocialsecurity/localopen?push_type=%d&url=%s#Intent;scheme=kankan;package=%s;component=%s;S.kkparam={\"content\": \"%s\", \"push_type\": \"%d\", \"title\": \"%s\", \"url\": \"%s\"};end";
Integer pushType = transmission.getPushType();
String url;
int push;
if (pushType == 0) {
url = URLEncoder.encode(transmission.getUrl(), "UTF-8");
push = 0;
} else {
url = transmission.getClassName();
push = 2;
}
String intent = String.format(str, push, url, pack, component, transmission.getContent(), push, transmission.getTitle(), url);
notification.put("intent", intent);
ups.put("notification", notification);
android.put("ups", ups);
return android;
}
/**
* 获取appId
*
* @param appName app名称
* @return appId
*/
public String getAppId(String appName) {
return getConfig(appName).getAppId();
}
/**
* 获取app配置
*
* @param appName app名称
* @return app配置
*/
public GeTuiConfig getConfig(String appName) {
return geTuiApp.getApps().get(appName);
}
/**
* post请求通用
*
......
......@@ -3,15 +3,13 @@ package com.weface.component;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.weface.common.utils.SnowIdUtil;
import com.weface.entity.MenuTagsEntity;
import com.weface.entity.UserTagEntity;
import com.weface.entity.UserMenusEntity;
import com.weface.entity.UserTagEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -38,7 +36,6 @@ public class MenuService {
*/
public List<UserMenusEntity> getTagUser(Map<String, Object> map, List<UserTagEntity> userInfo) {
try {
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
//获取所有用户标签
List<Map<String, Object>> userTag = Convert.convert(new TypeReference<List<Map<String, Object>>>() {
}, map.get("userTag"));
......@@ -62,7 +59,7 @@ public class MenuService {
for (Long aLong : list) {
//填充数据
UserMenusEntity userMenusEntity = new UserMenusEntity();
userMenusEntity.setId(snowflake.nextId());
userMenusEntity.setId(SnowIdUtil.nextId());
userMenusEntity.setUserId(uid);
userMenusEntity.setTagsId(aLong);
userMenusEntity.setIsValid(1);
......
......@@ -107,7 +107,7 @@ public class MessageTemplate implements Serializable {
private String content;
private String url;
//0:h5 1:app原生
private String push_type;
private Integer pushType;
//跳转功能名称
private String className;
//功能标题
......
......@@ -4,8 +4,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.concurrent.ThreadPoolExecutor;
......@@ -32,6 +34,14 @@ public class ExecutorConfig {
return taskExecutor;
}
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("SpringTaskThread-");
return taskScheduler;
}
}
......@@ -6,6 +6,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import java.util.HashMap;
import java.util.Map;
/**
* Filter配置
......@@ -16,8 +18,8 @@ import javax.servlet.DispatcherType;
public class FilterConfig {
@Bean
public FilterRegistrationBean xssFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
public FilterRegistrationBean<XssFilter> xssFilterRegistration() {
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns("/*");
......@@ -25,4 +27,25 @@ public class FilterConfig {
registration.setOrder(Integer.MAX_VALUE);
return registration;
}
/**
* 注册 签名校验过滤器
*/
@Bean
public FilterRegistrationBean<SignValidateFilter> signValidateFilter() {
final String include = "/push/single/alias,/push/single/cid";
//不拦截的url列表
final String excludes = "";
//拦截url列表
FilterRegistrationBean<SignValidateFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new SignValidateFilter());
bean.setName("signValidateFilter");
//设置拦截的url
bean.addUrlPatterns(include.split(","));
//设置不拦截
Map<String, String> initParameters = new HashMap<>(1);
initParameters.put("excludes", excludes);
bean.setInitParameters(initParameters);
return bean;
}
}
package com.weface.config;
import cn.hutool.core.io.IoUtil;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
/**
* @author Aleyn
* 1.重复获取HttpServletRequest中的inputStream 用以获取json请求参数
* 2.请求参数为二进制数据,controller无法正常映射,需要重写参数
* @since 2021/11/19 16:00
*/
public class OnceRequestWrapper extends HttpServletRequestWrapper {
/**
* json请求参数
*/
private final String body;
/**
* Map参数
*/
private final Map<String, String[]> params = new HashMap<>();
public OnceRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = getJsonBody(request);
//将参数表,赋予给当前的Map以便于持有request中的参数
this.params.putAll(request.getParameterMap());
}
/**
* 重载构造方法
*/
public OnceRequestWrapper(HttpServletRequest request, Map<String, Object> extendParams) throws IOException {
this(request);
//这里将扩展参数写入参数表
addAllParameters(extendParams);
}
private String getJsonBody(HttpServletRequest request) throws IOException {
String body;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IoUtil.copy(request.getInputStream(), baos);
body = baos.toString();
return body;
}
/**
* @return ServletInputStream 重写getInputStream()
*/
@Override
public ServletInputStream getInputStream() {
//每次调用此方法时将数据流中的数据读取出来,然后再回填到InputStream之中
//解决通过@RequestBody和@RequestParam(POST方式)读取一次后控制器拿不到参数问题
final ByteArrayInputStream bais = new ByteArrayInputStream(this.body.getBytes());
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() {
return bais.read();
}
};
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
/**
* 在获取所有的参数名,必须重写此方法,否则对象中参数值映射不上
*/
@Override
public Enumeration<String> getParameterNames() {
return new Vector(params.keySet()).elements();
}
/**
* 重写getParameter方法
*
* @param name 参数名
* @return 返回参数值
*/
@Override
public String getParameter(String name) {
String[] values = params.get(name);
if (values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {
String[] values = params.get(name);
if (values == null || values.length == 0) {
return null;
}
return values;
}
/**
* 增加多个参数
*
* @param otherParams 增加的多个参数
*/
public void addAllParameters(Map<String, Object> otherParams) {
for (Map.Entry<String, Object> entry : otherParams.entrySet()) {
addParameter(entry.getKey(), entry.getValue());
}
}
/**
* 增加参数
*
* @param name 参数名
* @param value 参数值
*/
public void addParameter(String name, Object value) {
if (value != null) {
if (value instanceof String[]) {
params.put(name, (String[]) value);
} else if (value instanceof String) {
params.put(name, new String[]{(String) value});
} else {
params.put(name, new String[]{String.valueOf(value)});
}
}
}
}
package com.weface.config;
import java.io.Serializable;
/**
* @author : Administrator
* @date : 2022/4/21 10:58
*/
public class RedisExpireData implements Serializable {
private static final long serialVersionUID = 1L;
private Object storeData;
private Long expire;
private Long dataTime;
public RedisExpireData(Object data, Long expire) {
this.storeData = data;
this.expire = expire;
this.dataTime = System.currentTimeMillis();
}
/**
* 获取对应的expire数据
*
* @return java.lang.String
*/
public Object getStoreData() {
Long curr = System.currentTimeMillis();
if (curr - this.dataTime > this.expire) {
return null;
} else {
return this.storeData;
}
}
public void setStoreData(Object storeData) {
this.storeData = storeData;
}
public Long getExpire() {
return expire;
}
public void setExpire(Long expire) {
this.expire = expire;
}
public Long getDataTime() {
return dataTime;
}
public void setDataTime(Long dataTime) {
this.dataTime = dataTime;
}
}
package com.weface.config;
import cn.hutool.json.JSONUtil;
import com.weface.code.CommonResult;
import com.weface.code.ResultCode;
import com.weface.common.utils.CommonUtil;
import com.weface.common.utils.Constant;
import com.weface.common.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.FilterConfig;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @author Aleyn
* @since 2021/11/20 13:00
*/
@Slf4j
public class SignValidateFilter implements Filter {
/**
* 参数签名过期时间 2分钟
*/
public static final long EXPIRE_TIME = 1000 * 60 * 2;
public static final String TIME_NAME = "timestamp";
public static final String SIGN_NAME = "sign";
public static final String SECRET_KEY = "KkweFace95271125";
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) {
log.info("初始化filter");
//不拦截的部分
String tempExcludes = filterConfig.getInitParameter("excludes");
if (!CommonUtil.isEmpty(tempExcludes)) {
String[] url = tempExcludes.split(",");
excludes.addAll(Arrays.asList(url));
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
corsConfig(response);
String ipAddr = IPUtils.getIpAddr(request);
log.info("调用了{}", request.getServletPath() + "方法");
log.info("请求IP地址为:{}", ipAddr);
//不拦截的
if (handleExcludeUrl(request)) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
//进行签名校验
checkParamAndSign(request, response, filterChain);
}
}
/**
* 设置允许跨域
*
* @param response 响应头
*/
private void corsConfig(HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "*");
//这里“Access-Token”是我要传到后台的内容key
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Expose-Headers", "*");
}
/**
* 签名校验
*/
public void checkParamAndSign(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
String timestamp = request.getHeader(TIME_NAME);
String sign = request.getHeader(SIGN_NAME);
if (CommonUtil.isEmpty(timestamp) || CommonUtil.isEmpty(sign)) {
this.fail(response, ResultCode.NOT_SIGN_ERROR);
return;
}
long now = System.currentTimeMillis();
if (now - (Long.parseLong(timestamp)) > EXPIRE_TIME) {
this.fail(response, ResultCode.REQUEST_EXPIRE_ERROR);
return;
}
Map<String, Object> param = new HashMap<>();
param.put(TIME_NAME, timestamp);
//请求类型
String contentType = request.getContentType() == null ? "" : request.getContentType().trim().toLowerCase();
//json参数
boolean isJson = contentType.contains("application/json");
//iso中使用application/x-www-form-urlencoded请求时,参数会转为multipart/form-data模式
boolean isMultiPart = contentType.contains("multipart/form-data");
OnceRequestWrapper requestWrapper = null;
if (isJson) {
requestWrapper = new OnceRequestWrapper(request);
//获取参数
String body = requestWrapper.getBody();
if (!CommonUtil.isEmpty(body)) {
if (JSONUtil.isJson(body)) {
Map<String, Object> bodyMap = JSONUtil.toBean(body, Map.class);
param.putAll(bodyMap);
} else {
//请求参数不是json
fail(response, ResultCode.CANNOT_ANALYSIS_PARAM_ERROR);
}
}
} else if (isMultiPart) {
String data = request.getParameter("Data");
if (data != null && JSONUtil.isJson(data)) {
//参数转为map
Map map = JSONUtil.parseObj(data).toBean(Map.class);
param.putAll(map);
requestWrapper = new OnceRequestWrapper(request, param);
}
} else {
//其他参数
Enumeration<String> names = request.getParameterNames();
Map<String, Object> parameterMap = new HashMap<>();
while (names.hasMoreElements()) {
String element = names.nextElement();
String value = request.getParameter(element);
parameterMap.put(element, value);
}
param.putAll(parameterMap);
}
if (CommonUtil.apiParamSign(param, SECRET_KEY).equals(sign)) {
if (isJson | isMultiPart) {
filterChain.doFilter(requestWrapper, response);
} else {
filterChain.doFilter(request, response);
}
} else {
fail(response, ResultCode.SIGN_VALID_FAIL_ERROR);
}
}
private boolean handleExcludeUrl(HttpServletRequest request) {
String url = request.getServletPath();
String method = request.getMethod();
// GET DELETE 不过滤
if (method == null || method.matches(Constant.MethodType.GET.getValue()) || method.matches(Constant.MethodType.DELETE.getValue())) {
return true;
}
return CommonUtil.matches(url, excludes);
}
@Override
public void destroy() {
log.info("销毁filter");
}
public void fail(ServletResponse response, ResultCode code) {
response.setContentType("application/json;charset=UTF-8");
CommonResult<Object> failed = CommonResult.failed(code);
try {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(JSONUtil.toJsonStr(failed).getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
package com.weface.controller;
import com.weface.code.PushResultCode;
import com.weface.service.PushCallBackService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @author : Administrator
* @date : 2022/4/19 13:51
*/
@RestController
@RequestMapping("/push")
public class PushCallBackController {
@Autowired
private PushCallBackService pushCallBackService;
@PostMapping("/call/back/info")
public PushResultCode callBackForPush(HttpServletRequest request) {
return pushCallBackService.saveCallBackInfo(request);
}
}
\ No newline at end of file
package com.weface.controller;
import com.weface.code.CommonResult;
import com.weface.common.validator.ValidatorParam;
import com.weface.common.validator.ValidatorUtils;
import com.weface.component.GeTuiService;
import com.weface.dto.InformForm;
import com.weface.dto.MsgDTO;
import com.weface.dto.PushDTO;
import com.weface.service.PushService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.groups.Default;
/**
* @author Administrator
*/
......@@ -39,7 +38,28 @@ public class PushController {
}
@PostMapping("/all")
public CommonResult pushAll(@Validated({Default.class}) InformForm informForm) {
public CommonResult pushAll(InformForm informForm) {
ValidatorUtils.validateEntity(informForm, InformForm.PushValid.class);
return geTuiService.listPush(informForm);
}
@PostMapping("/single/alias")
public CommonResult pushSingleAlias(@RequestBody InformForm informForm) {
ValidatorUtils.validateEntity(informForm, InformForm.PushValid.class);
CommonResult commonResult = ValidatorParam.validPushSingleAlias(informForm);
if (commonResult != null) {
return commonResult;
}
return geTuiService.pushSingleAlias(informForm);
}
@PostMapping("/single/cid")
public CommonResult pushSingleCid(@RequestBody InformForm informForm) {
ValidatorUtils.validateEntity(informForm, InformForm.PushValid.class);
CommonResult commonResult = ValidatorParam.validPushSingleAlias(informForm);
if (commonResult != null) {
return commonResult;
}
return geTuiService.pushSingleCid(informForm);
}
}
package com.weface.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.weface.entity.PushCallBackEntity;
import org.apache.ibatis.annotations.Mapper;
/**
*
*
* @author admin
* @date 2022-04-20 09:54:09
*/
@Mapper
public interface PushCallBackDao extends BaseMapper<PushCallBackEntity> {
}
package com.weface.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.weface.entity.PushLogEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author admin
* @date 2022-04-20 09:54:09
*/
@Mapper
public interface PushLogDao extends BaseMapper<PushLogEntity> {
/**
* 根据时间查询推送日志
*
* @param time 时间
* @return 推送日志
*/
List<PushLogEntity> getPushLogByTime(@Param("time") Integer time);
}
......@@ -10,15 +10,16 @@ import javax.validation.constraints.NotBlank;
@Data
public class InformForm {
//标题
@NotBlank
@NotBlank(message = "标题不能为空",groups = {PushValid.class})
private String title;
//内容
@NotBlank
@NotBlank(message = "内容不能为空",groups = {PushValid.class})
private String body;
//跳转url
@NotBlank(message = "url不能为空",groups = {PushValid.class})
private String url;
//推送类型 0:h5 1:原生
private String push_type;
private Integer pushType;
//跳转功能名称
private String className;
//功能标题
......@@ -26,11 +27,21 @@ public class InformForm {
//是否需要登录
private String needLogin;
//请求应用名称首字母小写 例:看看生活->kksh
@NotBlank
@NotBlank(message = "应用名称不能为空",groups = {PushValid.class})
private String equipmentType;
//推送设备 4 android 1: ios
private Integer device;
//定速推送,例如100,个推控制下发速度在100条/秒左右,0表示不限速
private Integer speed;
//推送目标
private String cid;
//推送手机号
private String phone;
//推送模板
private Integer messageTemplate;
public interface PushValid{
}
}
package com.weface.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
*
*
* @author admin
* @date 2022-04-20 09:54:09
*/
@Data
@TableName("tb_push_call_back")
public class PushCallBackEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
private Long id;
/**
* 应用 ID
*/
private String appid;
/**
* 接收人CID
*/
private String cid;
/**
* 任务 ID(即 ContentID)
*/
private String taskid;
/**
* 消息 ID
*/
private String msgid;
/**
* 结果码(200 -- 成功,400 -- 推送苹果接口失败, 401 -- 用户不存在,402 -- 非活跃用户,500 -- 系统内部异常)目前只有 200 和 400,后续版本扩展。
*/
private String code;
/**
* 推送结果描述
*/
private String descStr;
/**
* 签名
*/
private String sign;
/**
* 回执 ID
*/
private String actionid;
/**
* 回执上传时间
*/
private Long recvtime;
/**
* 根据配置返回
*/
private String alias;
/**
* 状态
*/
private Integer status;
/**
* 是否删除 1:未删除 0 :删除
*/
@TableLogic(value = "1", delval = "0")
@TableField(fill = FieldFill.INSERT)
private Integer isValid;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}
package com.weface.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @author admin
* @date 2022-04-20 09:54:09
*/
@Data
@TableName("tb_push_log")
public class PushLogEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
private Long id;
/**
* 应用名称
*/
private String appName;
/**
* 任务id
*/
private String taskId;
/**
* 推送内容
*/
private String result;
/**
* 目标手机号
*/
private String phone;
/**
* 推送的短信模板
*/
private Integer messageTemplate;
/**
* 推送目标(别名/cid)
*/
private String pushTarget;
/**
* 推送内容
*/
private String pushContent;
/**
* 到达状态 1001:已推送 1002:已到达 1003:已发送短信
*/
private Integer arriveStatus;
/**
* 备用字段
*/
private String bas1;
/**
* 逻辑删除 1:未删除 0:删除
*/
@TableLogic(value = "1", delval = "0")
@TableField(fill = FieldFill.INSERT)
private Integer isValid;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
*
*/
private Date updateTime;
}
package com.weface.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.weface.code.PushResultCode;
import com.weface.entity.PushCallBackEntity;
import javax.servlet.http.HttpServletRequest;
/**
* @author admin
* @email admin@163.com
* @date 2022-04-20 09:54:09
*/
public interface PushCallBackService extends IService<PushCallBackEntity> {
public PushResultCode saveCallBackInfo(HttpServletRequest request);
}
package com.weface.service;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.IService;
import com.weface.dto.InformForm;
import com.weface.entity.PushLogEntity;
import java.util.List;
/**
* @author admin
* @date 2022-04-20 09:54:09
*/
public interface PushLogService extends IService<PushLogEntity> {
/**
* 保存日志
*
* @param data 返回数据
* @param informForm 推送数据
* @param appId 应用id
*/
public void saveLog(JSONObject data, InformForm informForm, String appId);
/**
* 查询日志
*
* @param taskId 任务id
* @return 日志信息
*/
public PushLogEntity getPushLog(String taskId);
/**
* 查询推送日志
*
* @param time 时间
* @return 推送日志
*/
public List<PushLogEntity> getPushLogByTime(Integer time);
}
package com.weface.serviceimpl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weface.code.CommonResult;
import com.weface.common.utils.BeanUtils;
import com.weface.common.utils.SnowIdUtil;
import com.weface.dao.MenuTagsDao;
import com.weface.dto.MenuTagsForm;
import com.weface.entity.MenuTagsEntity;
......@@ -24,7 +23,7 @@ import java.util.stream.Collectors;
* @author Administrator
*/
@Slf4j
@Transactional
@Transactional(rollbackFor = {Exception.class})
@Service("menuTagsService")
public class MenuTagsServiceImpl extends ServiceImpl<MenuTagsDao, MenuTagsEntity> implements MenuTagsService {
......@@ -69,9 +68,8 @@ public class MenuTagsServiceImpl extends ServiceImpl<MenuTagsDao, MenuTagsEntity
try {
MenuTagsEntity menuTagsEntity = new MenuTagsEntity();
BeanUtil.copyProperties(menuTagsForm, menuTagsEntity, BeanUtils.getNullPropertyNames(menuTagsForm));
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
menuTagsEntity.setId(snowflake.nextId());
menuTagsEntity.setId(SnowIdUtil.nextId());
String tagCode = "";
boolean flag = false;
while (!flag) {
......
package com.weface.serviceimpl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weface.code.PushResultCode;
import com.weface.common.utils.*;
import com.weface.config.GeTuiApp;
import com.weface.config.GeTuiConfig;
import com.weface.dao.PushCallBackDao;
import com.weface.entity.PushCallBackEntity;
import com.weface.entity.PushLogEntity;
import com.weface.service.PushCallBackService;
import com.weface.service.PushLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author : Administrator
* @date : 2022/4/19 14:08
*/
@Service("pushCallBackService")
@Slf4j
@Transactional(rollbackFor = {Exception.class})
public class PushCallBackServiceImpl extends ServiceImpl<PushCallBackDao, PushCallBackEntity> implements PushCallBackService {
@Resource
private GeTuiApp geTuiApp;
@Autowired
private PushLogService pushLogService;
/**
* 保存推送回调
*
* @param request 回调请求
* @return 执行结果
*/
@Override
public PushResultCode saveCallBackInfo(HttpServletRequest request) {
try {
List<PushCallBackEntity> list = getCallBackInfo(request);
if (list.isEmpty()) {
return PushResultCode.error();
}
for (PushCallBackEntity callBackInfo : list) {
String appId = callBackInfo.getAppid();
String taskId = callBackInfo.getTaskid();
String str = appId + callBackInfo.getCid() + taskId + callBackInfo.getMsgid() + getMasterSecret(appId);
String sign = Base64Util.md5Encode(str);
if (!callBackInfo.getSign().equals(sign)) {
return PushResultCode.error();
}
if (taskId.startsWith("RASS")) {
Object hashValue = RedisUtil.HashOps.hGet(Constant.PUSH_TASK_INFO, taskId);
if (hashValue != null) {
PushLogEntity pushLog = pushLogService.getPushLog(taskId);
if (pushLog != null) {
//更新推送日志
pushLog.setArriveStatus(1002);
pushLogService.updateById(pushLog);
log.error("推送回调消息:{}", taskId);
//持久化回调日志
callBackInfo.setId(SnowIdUtil.nextId());
callBackInfo.setUpdateTime(new Date());
callBackInfo.setStatus(1);
this.save(callBackInfo);
}
}
}
}
return PushResultCode.ok();
} catch (IOException e) {
log.error("处理回调函数异常:{}", e.getMessage());
e.printStackTrace();
}
return PushResultCode.error();
}
/**
* 获取应用密钥
*
* @param appId 应用id
* @return 应用密钥
*/
private String getMasterSecret(String appId) {
String masterSecret = null;
Map<String, GeTuiConfig> apps = geTuiApp.getApps();
for (Map.Entry<String, GeTuiConfig> entry : apps.entrySet()) {
if (appId.equals(entry.getValue().getAppId())) {
masterSecret = entry.getValue().getMastersecret();
break;
}
}
return masterSecret;
}
/**
* 解析请求数据
*
* @param request 请求
* @return 解析后回调对象
* @throws IOException 网络流异常
*/
public static List<PushCallBackEntity> getCallBackInfo(HttpServletRequest request) throws IOException {
byte[] bytes = HttpUtil.getRequestInputStream(request);
String callBackList = new String(bytes);
Pattern re = Pattern.compile("(\\{.*?})");
Matcher matcher = re.matcher(callBackList);
List<PushCallBackEntity> list = new ArrayList<>();
while (matcher.find()) {
String group = matcher.group(1);
log.info("回调信息:{}", group);
PushCallBackEntity callBackInfo = JSONObject.parseObject(group, PushCallBackEntity.class);
String desc = JSONObject.parseObject(group).getString("desc");
callBackInfo.setDescStr(desc);
list.add(callBackInfo);
}
return list;
}
}
package com.weface.serviceimpl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weface.common.utils.Constant;
import com.weface.common.utils.DES;
import com.weface.common.utils.RedisUtil;
import com.weface.common.utils.SnowIdUtil;
import com.weface.dao.PushLogDao;
import com.weface.dto.InformForm;
import com.weface.entity.PushLogEntity;
import com.weface.service.PushLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
@Transactional(rollbackFor = {Exception.class})
@Service("pushLogService")
public class PushLogServiceImpl extends ServiceImpl<PushLogDao, PushLogEntity> implements PushLogService {
@Override
public void saveLog(JSONObject data, InformForm informForm, String appId) {
try {
List<PushLogEntity> logList = new ArrayList<>();
for (String key : data.keySet()) {
PushLogEntity pushLogEntity = new PushLogEntity();
Long id = SnowIdUtil.nextId();
pushLogEntity.setId(id);
pushLogEntity.setAppName(informForm.getEquipmentType());
pushLogEntity.setTaskId(key);
String str = data.toString();
if (str.length() > 200) {
pushLogEntity.setResult(str.substring(0, 200));
} else {
pushLogEntity.setResult(str);
}
String phone = informForm.getPhone();
if (StringUtils.isNotEmpty(phone)) {
DES des = DES.getInstanceDes();
pushLogEntity.setPhone(des.encrypt(phone));
}
Integer messageTemplate = informForm.getMessageTemplate();
if (messageTemplate != null) {
pushLogEntity.setMessageTemplate(messageTemplate);
}
pushLogEntity.setPushTarget(informForm.getCid() == null ? "all" : informForm.getCid());
pushLogEntity.setPushContent(informForm.getBody());
pushLogEntity.setArriveStatus(1001);
pushLogEntity.setUpdateTime(new Date());
logList.add(pushLogEntity);
RedisUtil.HashOps.hPutEx(Constant.PUSH_TASK_INFO, key, String.valueOf(id), 2L, TimeUnit.HOURS);
}
if (!CollectionUtils.isEmpty(logList)) {
this.saveBatch(logList);
}
} catch (Exception e) {
log.error("保存推送日志错误:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 查询日志
*
* @param taskId 任务id
* @return 日志信息
*/
@Override
public PushLogEntity getPushLog(String taskId) {
List<PushLogEntity> list = this.list(new LambdaQueryWrapper<PushLogEntity>()
.eq(PushLogEntity::getTaskId, taskId));
if (!CollectionUtils.isEmpty(list)) {
return list.get(0);
} else {
return null;
}
}
/**
* 查询推送日志
*
* @param time 时间
* @return 推送日志
*/
@Override
public List<PushLogEntity> getPushLogByTime(Integer time) {
return this.baseMapper.getPushLogByTime(time);
}
}
\ No newline at end of file
......@@ -2,12 +2,11 @@ package com.weface.serviceimpl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weface.code.CommonResult;
import com.weface.common.utils.SnowIdUtil;
import com.weface.dao.UserMenusDao;
import com.weface.dto.UserMenuFrom;
import com.weface.entity.UserMenusEntity;
......@@ -24,7 +23,7 @@ import java.util.stream.Collectors;
@Slf4j
@Service("userMenusService")
@Transactional
@Transactional(rollbackFor = {Exception.class})
public class UserMenusServiceImpl extends ServiceImpl<UserMenusDao, UserMenusEntity> implements UserMenusService {
/**
......@@ -81,10 +80,9 @@ public class UserMenusServiceImpl extends ServiceImpl<UserMenusDao, UserMenusEnt
return CommonResult.failed("用户标签已存在");
}
List<UserMenusEntity> userMenusEntities = new ArrayList<>(tagsId.length);
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
for (String aLong : saveTags) {
UserMenusEntity userMenusEntity = new UserMenusEntity();
userMenusEntity.setId(snowflake.nextId());
userMenusEntity.setId(SnowIdUtil.nextId());
userMenusEntity.setUserId(userId);
userMenusEntity.setTagsId(Convert.toLong(aLong));
userMenusEntity.setCreateTime(new Date());
......
package com.weface.task;
import cn.hutool.core.collection.CollUtil;
import com.weface.common.utils.RedisUtil;
import cn.hutool.json.JSONUtil;
import com.weface.common.utils.*;
import com.weface.component.MenuService;
import com.weface.config.RedisExpireData;
import com.weface.entity.MenuTagsEntity;
import com.weface.entity.PushLogEntity;
import com.weface.entity.UserMenusEntity;
import com.weface.entity.UserTagEntity;
import com.weface.service.MenuTagsService;
import com.weface.service.PushLogService;
import com.weface.service.UserMenusService;
import com.weface.service.UserTagService;
import lombok.extern.slf4j.Slf4j;
......@@ -14,18 +18,18 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
/**
* @author Administrator
* @CreateUser: Administrator
* @CreateTime: 2021/11/4
*/
@Component
......@@ -50,10 +54,90 @@ public class UserTagsTask {
@Autowired
private ThreadPoolTaskExecutor asyncServiceExecutor;
@Autowired
private PushLogService pushLogService;
/**
* 查询推送日志时间
*/
private static final Integer TIME = 2;
/**
* 查询未推送消息成功记录,发送短信通知
*/
@Scheduled(cron = "0 0 0/1 * * ? ")
public void sendMessage() {
try {
log.info("开始执行短信发送任务");
List<PushLogEntity> list = pushLogService.getPushLogByTime(TIME);
List<PushLogEntity> updateBatch = null;
if (!CollectionUtils.isEmpty(list)) {
updateBatch = new ArrayList<>(list.size());
DES des = DES.getInstanceDes();
for (PushLogEntity pushLogEntity : list) {
String phone = pushLogEntity.getPhone();
if (StringUtils.isNotEmpty(phone)){
if (CommonUtil.isBase64(phone)) {
phone = des.decrypt(phone);
}
String pushContent = pushLogEntity.getPushContent();
Integer messageTemplate = pushLogEntity.getMessageTemplate();
Integer arriveStatus = pushLogEntity.getArriveStatus();
if (1001 == arriveStatus) {
boolean b = ShortMsgSend.sendMobileByRegister(pushContent, phone, messageTemplate);
if (b) {
log.info("执行短信发送成功");
pushLogEntity.setArriveStatus(1003);
pushLogEntity.setUpdateTime(new Date());
updateBatch.add(pushLogEntity);
}
}
}
}
}
if (updateBatch != null) {
pushLogService.updateBatchById(updateBatch);
}
} catch (IOException e) {
log.error("执行短信发送失败:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 更新推送任务id缓存
*/
@Scheduled(cron = "0 0 3 * * ?")
public void updateRedisHashKey() {
try {
log.error("开始更新任务缓存");
HashSet<Object> hashSet = new HashSet<>();
Set<Object> keys = RedisUtil.HashOps.hKeys(Constant.PUSH_TASK_INFO);
for (Object key : keys) {
Object hashValue = RedisUtil.HashOps.hGet(Constant.PUSH_TASK_INFO, key.toString());
log.error("缓存任务信息:{}", hashValue);
if (hashValue != null) {
RedisExpireData redisData = JSONUtil.toBean(hashValue.toString(), RedisExpireData.class);
Object obj = redisData.getStoreData();
if (obj == null) {
hashSet.add(key);
}
}
}
if (!hashSet.isEmpty()) {
RedisUtil.HashOps.hDelete(Constant.PUSH_TASK_INFO, hashSet.toArray());
}
} catch (Exception e) {
log.error("更新任务缓存失败:{}", e.getMessage());
e.printStackTrace();
}
}
/**
* 更新用户标签
*/
// @Scheduled(cron = "0 0 23 * * ?")
@Scheduled(cron = "0 0 23 * * ?")
public void updateUserTags() {
try {
//获取每次处理的id起始值
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.weface.dao.PushCallBackDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.weface.entity.PushCallBackEntity" id="pushCallBackMap">
<result property="id" column="id"/>
<result property="appid" column="appid"/>
<result property="cid" column="cid"/>
<result property="taskid" column="taskid"/>
<result property="msgid" column="msgid"/>
<result property="code" column="code"/>
<result property="descStr" column="desc_str"/>
<result property="sign" column="sign"/>
<result property="actionid" column="actionId"/>
<result property="recvtime" column="recvtime"/>
<result property="alias" column="alias"/>
<result property="status" column="status"/>
<result property="isValid" column="is_valid"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.weface.dao.PushLogDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.weface.entity.PushLogEntity" id="pushLogMap">
<result property="id" column="id"/>
<result property="appName" column="app_name"/>
<result property="taskId" column="task_id"/>
<result property="result" column="result"/>
<result property="phone" column="phone"/>
<result property="messageTemplate" column="message_template"/>
<result property="pushTarget" column="push_target"/>
<result property="pushContent" column="push_content"/>
<result property="arriveStatus" column="arrive_status"/>
<result property="bas1" column="bas1"/>
<result property="isValid" column="is_valid"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="getPushLogByTime" resultMap="pushLogMap">
SELECT *
FROM tb_push_log
WHERE is_valid = 1
AND arrive_status = 1001
AND create_time > DATE_SUB(
NOW(),
INTERVAL #{time} HOUR)
</select>
</mapper>
\ No newline at end of file
package com.weface;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.weface.code.CommonResult;
import com.weface.common.utils.CommonUtil;
import com.weface.common.utils.RedisUtil;
import com.weface.common.utils.SnowIdUtil;
import com.weface.component.GeTuiService;
import com.weface.component.MenuService;
import com.weface.component.MessageTemplate;
import com.weface.config.GeTuiApp;
import com.weface.config.SignValidateFilter;
import com.weface.dto.InformForm;
import com.weface.entity.MenuTagsEntity;
import com.weface.entity.UserMenusEntity;
......@@ -31,11 +32,9 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
......@@ -57,9 +56,6 @@ class PushMessageApplicationTests {
@Autowired
private GeTuiService geTuiService;
@Resource
private GeTuiApp geTuiApp;
@Test
void contextLoads() {
}
......@@ -112,45 +108,11 @@ class PushMessageApplicationTests {
}
}
@Test
void testConventTemplate() throws UnsupportedEncodingException {
InformForm informForm = new InformForm();
// String[] alias = {"kksh_10131492"};
String[] alias = {"kksh_59354"};
String token = geTuiService.getAuthToken("kk_sh_token_ge_tui");
// String token = geTuiService.getAuthToken("kk_sb_token_ge_tui");
informForm.setTitle("河南一名小学生确诊阳性!");
informForm.setBody("1月23日新增一例本土确诊病例!为11岁小学生");
informForm.setUrl("https://kk.weface.com.cn/news/page/?id=c0933d0e2fc85f7333b6202dff0e611c&type=hot&from=101");
MessageTemplate messageTemplate = new MessageTemplate();
messageTemplate.setAudience(new MessageTemplate.Audience(alias));
messageTemplate.setSettings(new MessageTemplate.Settings(3600000, 0));
MessageTemplate.PushMessage pushMessage = new MessageTemplate.PushMessage();
MessageTemplate.PushMessage.Transmission transmission = new MessageTemplate.PushMessage.Transmission();
transmission.setTitle(informForm.getTitle());
transmission.setContent(informForm.getBody());
transmission.setUrl(informForm.getUrl());
pushMessage.setTransmission(transmission);
messageTemplate.setPush_message(pushMessage);
String s = geTuiService.singlePushAlias(4, messageTemplate, geTuiService.getAppId("kksh"), token);
// String s = geTuiService.singlePushAlias(1, messageTemplate, geTuiService.getAppId("kksb"), token);
System.out.println(s);
}
@Test
void testRevoke() {
Map<String, Object> map = new HashMap<>();
map.put("request_id", String.valueOf(IdUtil.getSnowflake(1, 1).nextId()));
map.put("request_id", String.valueOf(SnowIdUtil.nextId()));
map.put("audience", "all");
Map<String, Object> push_message = new HashMap<>();
......@@ -166,7 +128,7 @@ class PushMessageApplicationTests {
}
@Test
void testPush() {
void testUserTags() {
//获取标签列表
List<MenuTagsEntity> tags = menuTagsService.list();
List<String> list = Collections.singletonList("d7e78cfa76e1c61699925ec9bb960d53");
......@@ -276,22 +238,6 @@ class PushMessageApplicationTests {
System.out.println(first_map);
}
@Test
void testRandom() {
String token = "54_qYwZpVbWrJDkflE1ha61B4SPwdhNVoCE6g_YG9zL0PL2ki6pZYsNKK__l2fMfmjRyt3C_EIiTq2Hnnla5MK8bGLckSUXUN14_A2UKMhF9xsVHQswPd6MnmVxV1YkSAyFVLEpF76kuCbBmps7GZOfAFAWPE";
// String token = "54_hksRqu53_0Jmw_lopjrJh4Ofzqzb_289qRkfZXxIVhBhk4vjSFH-20sbf6LUg8X1Go4tkVoISnFTSWiyKKUB1Pw8-KKNM8W6GsSpGsj85_fTtm5Uus7ncmkQCS_LxTAybYsUfsU6VaBm6hnHKJSeAAAUTC";
RedisUtil.StringOps.setEx("kksh_wechat:mini_program_token:10011", token, 5400, TimeUnit.SECONDS);
// String appId = "wx0c0e88fde84cc81c";
// String secret = "45aae2597122419a74297d5987965013";
// String code = "ce863cb4acfa518fc6893686d3e9480a0fd5b4b4ba99dd3d68d5ac4e50775943";
// String userPhone = getUserPhone("10011", code);
// System.out.println(userPhone);
}
private static Map<String, String> getAppId(String programType) {
String appId;
String secret;
......@@ -391,4 +337,55 @@ class PushMessageApplicationTests {
}
return null;
}
@Test
public void testSingleAlias() {
InformForm informForm = new InformForm();
informForm.setTitle("缴电费充值通知");
informForm.setBody("尊敬的用户您好,您的户");
informForm.setUrl("mineEarnGold");
informForm.setPushType(1);
informForm.setClassName("mineEarnGold");
informForm.setClassTitle("我的金币");
informForm.setNeedLogin("1");
informForm.setEquipmentType("kksh");
informForm.setCid("kksh_59354");
CommonResult commonResult = geTuiService.pushSingleAlias(informForm);
System.out.println(commonResult);
}
@Test
public void tesPushApp() {
InformForm informForm = new InformForm();
informForm.setTitle("缴电费充值通知");
informForm.setBody("尊敬的用户您好,您的户");
informForm.setUrl("mineEarnGold");
informForm.setPushType(1);
informForm.setClassName("mineEarnGold");
informForm.setClassTitle("我的金币");
informForm.setNeedLogin("1");
informForm.setEquipmentType("kksh");
CommonResult commonResult = geTuiService.listPush(informForm);
System.out.println(commonResult);
}
@Test
public void testSign() {
// d9c57eada1389691d86ff4d62787d3cc
Map<String, Object> map = new HashMap<>();
map.put("title", "花费充值");
map.put("body", "尊敬的用户您好,您的户");
map.put("url", "https://docs.getui.com/getui/mobile/vendor/report/");
map.put("pushType", "0");
map.put("equipmentType", "kksh");
map.put("cid", "kksh_59354");
map.put("messageTemplate", "1");
map.put("phone", "15538250098");
long l = System.currentTimeMillis();
System.out.println(l);
map.put("timestamp", l);
String s = CommonUtil.apiParamSign(map, SignValidateFilter.SECRET_KEY);
System.out.println(s);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment