admin
2019-08-15 868a5e893ddb55cdac77f952c3790a700e6b2713
解决请求并发所带来的问题
7个文件已修改
268 ■■■■■ 已修改文件
fanli/src/main/java/com/yeshi/fanli/aspect/RequestSerializableAspect.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/controller/TestController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/SMSController.java 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/UserInfoController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/UserMsgController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/service/impl/monitor/BusinessEmergent110ServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/util/Constant.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
fanli/src/main/java/com/yeshi/fanli/aspect/RequestSerializableAspect.java
@@ -2,7 +2,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@@ -14,25 +13,55 @@
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.yeshi.utils.JsonUtil;
import com.yeshi.fanli.log.LogHelper;
import com.yeshi.fanli.util.Constant;
import com.yeshi.fanli.util.StringUtil;
import com.yeshi.fanli.util.annotation.RequestSerializableByKey;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Component
@Aspect
@Order(4)
public class RequestSerializableAspect {
    @Resource
    private EhCacheCacheManager cacheManager;
    private JedisPool jedisPool;
    @Around("execution(public * com.yeshi.fanli.controller.client.*.*(..))")
    private ExpressionParser parser = new SpelExpressionParser();
    private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
    /**
     * 获取表达的值
     *
     * @param spELString
     * @param joinPoint
     * @return
     */
    public String generateKeyBySpEL(String spELString, ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod());
        Expression expression = parser.parseExpression(spELString);
        EvaluationContext context = new StandardEvaluationContext();
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        return expression.getValue(context).toString();
    }
    @Around("execution(public * com.yeshi.fanli.controller.client.*.*.*(..))")
    public Object requestSerializable(ProceedingJoinPoint joinPoint) throws IOException {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
@@ -41,64 +70,73 @@
        try {
            Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(joinPoint.getSignature().getName(),
                    targetMethod.getParameterTypes());
            Object[] args = joinPoint.getArgs();
            PrintWriter out = null;
            String[] strings = methodSignature.getParameterNames();
            Map<String, ParamsTypeValue> map = new HashMap<>();
            Class<?>[] types = methodSignature.getParameterTypes();
            for (int i = 0; i < strings.length; i++) {
                map.put(strings[i], new ParamsTypeValue(types[i], args[i]));
                if (args[i] instanceof PrintWriter) {
                    out = (PrintWriter) args[i];
                }
            }
            if (realMethod.isAnnotationPresent(RequestSerializableByKey.class)) {
                RequestSerializableByKey rs = realMethod.getAnnotation(RequestSerializableByKey.class);
                String[] strings = methodSignature.getParameterNames();
                Class<?>[] types = methodSignature.getParameterTypes();
                Map<String, ParamsTypeValue> map = new HashMap<>();
                Object[] args = joinPoint.getArgs();
                PrintWriter out = null;
                for (int i = 0; i < strings.length; i++) {
                    map.put(strings[i], new ParamsTypeValue(types[i], args[i]));
                    if (args[i] instanceof PrintWriter) {
                        out = (PrintWriter) args[i];
                    }
                }
                String key = rs.key();
                ParamsTypeValue tv = null;
                if (key.indexOf(".") > -1) {
                    tv = map.get(key.split("\\.")[0]);
                } else {
                    tv = map.get(key);
                }
                Object value = tv.value;
                Class<?> type = tv.type;
                // 暂时只支持2层嵌套
                if (key.indexOf(".") > -1) {
                    String child = key.split("\\.")[1];
                cacheKey = generateKeyBySpEL(key, joinPoint);
                try {// redis做原子性保护
                    if (!StringUtil.isNullOrEmpty(cacheKey)) {
                        cacheKey = joinPoint.getTarget().getClass().getName() + "." + targetMethod.getName() + "-"
                                + cacheKey;
                        cacheKey = "rs-" + StringUtil.Md5(cacheKey);
                        // jiedis原子性做拦截
                        Jedis jedis = jedisPool.getResource();
                        try {
                            Constant.waitingThreadSet.add(Thread.currentThread().getId());
                            long result = 0;
                            long startTime = System.currentTimeMillis();
                            // 等待响应
                            while (result <= 0) {
                                result = jedis.setnx(cacheKey, "1");
                                if (result <= 0) {
                                    try {
                                        Thread.sleep(50);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    if (System.currentTimeMillis() - startTime > 1000 * 60L) {
                                        Constant.waitingThreadSet.remove(Thread.currentThread().getId());
                                        out.print(JsonUtil.loadFalseResult("连接超时"));
                                        return null;
                                    }
                                }
                            }
                            if (result > 0) {
                                try {
                                    return joinPoint.proceed();
                                } catch (Throwable e) {
                                    e.printStackTrace();
                                    LogHelper.errorDetailInfo(e);
                                } finally {
                                    jedis.del(cacheKey);
                                    Constant.waitingThreadSet.remove(Thread.currentThread().getId());
                                }
                            }
                        } finally {
                            jedisPool.returnResource(jedis);
                        }
                    }
                } catch (Exception e) {// 原子性保护出错
                    try {
                        Field f = type.getDeclaredField(child);
                        f.setAccessible(true);
                        Object obj = f.get(value);
                        if (obj != null) {
                            cacheKey = obj.toString();
                        }
                    } catch (NoSuchFieldException e) {
                        return joinPoint.proceed();
                    } catch (Throwable e1) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    if (value != null) {
                        cacheKey = value.toString();
                    }
                }
                if (!StringUtil.isNullOrEmpty(cacheKey)) {
                    cacheKey = joinPoint.getTarget().getClass().getName() + "." + targetMethod.getName() + "-"
                            + cacheKey;
                    Cache cache = cacheManager.getCache("rsCache");
                    ValueWrapper element = cache.get(cacheKey);
                    if (element != null && element.get() != null) {
                        // 服务器繁忙
                        if (out != null) {
                            out.print(JsonUtil.loadFalseResult(2001, "服务器繁忙"));
                        }
                        return null;
                    } else {
                        cache.put(cacheKey, "1");
                        LogHelper.errorDetailInfo(e1);
                    }
                }
            }
@@ -114,16 +152,16 @@
        } catch (Throwable e) {
            e.printStackTrace();
            LogHelper.errorDetailInfo(e);
        } finally {
            if (!StringUtil.isNullOrEmpty(cacheKey)) {
                Cache cache = cacheManager.getCache("rsCache");
                cache.put(cacheKey, null);
            }
        }
        return null;
    }
    // 测试代码
    public void test() {
    }
    class ParamsTypeValue {
        Class<?> type;
        Object value;
fanli/src/main/java/com/yeshi/fanli/controller/TestController.java
@@ -56,6 +56,7 @@
import com.yeshi.fanli.util.FileUtil;
import com.yeshi.fanli.util.RedisManager;
import com.yeshi.fanli.util.StringUtil;
import com.yeshi.fanli.util.TimeUtil;
import com.yeshi.fanli.util.db.MongoDBManager;
import com.yeshi.fanli.util.factory.goods.GoodsDetailVOFactory;
import com.yeshi.fanli.util.jd.JDApiUtil;
@@ -63,6 +64,8 @@
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Controller
@RequestMapping("test")
@@ -93,12 +96,15 @@
    @Resource
    private ConfigService configService;
    @Resource
    private HongBaoManageService hongBaoManageService;
    @Resource
    private InviteMaterialService inviteMaterialService;
    @Resource
    private JedisPool jedisPool;
    @RequestMapping(value = "testimg")
    public void testImg(HttpServletRequest request, PrintWriter out) {
@@ -423,9 +429,10 @@
            e.printStackTrace();
        }
    }
    /**
     * 插入邀请素材
     *
     * @param out
     */
    @RequestMapping(value = "getJingFenList")
@@ -448,7 +455,7 @@
                    Gson gson = JsonUtil.getConvertBigDecimalToStringSubZeroBuilder(new GsonBuilder())
                            .excludeFieldsWithoutExposeAnnotation().setDateFormat("yyyy-MM-dd").create();
                    for (JDGoods goods : goodsList) {
                        GoodsDetailVO goodsDetailVO = GoodsDetailVOFactory.convertJDGoods(goods, fanLiRate,    shareRate);
                        GoodsDetailVO goodsDetailVO = GoodsDetailVOFactory.convertJDGoods(goods, fanLiRate, shareRate);
                        array.add(gson.toJson(goodsDetailVO));
                    }
                }
@@ -462,4 +469,9 @@
            e.printStackTrace();
        }
    }
    @RequestMapping(value = "getWaitingThreadsCount")
    public void getWaitingThreadsCount(PrintWriter out) {
        out.print(Constant.waitingThreadSet.size());
    }
}
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/SMSController.java
@@ -31,18 +31,18 @@
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private ForbiddenUserIdentifyCodeService forbiddenUserIdentifyCodeService;
    // 发送短信
    @RequestSerializableByKey(key = "#phone+'-'+#uid+'-'+#type")
    @RequestMapping(value = "sendSMS", method = RequestMethod.POST)
    public void sendMSM(AcceptData acceptData, String phone, Long uid, Integer type, PrintWriter out) {
        sendMSM(acceptData, phone, uid, type, StringUtil.Md5(phone + "-" + "-" + uid + "-" + type), out);
    }
    @RequestSerializableByKey(key = "key")
    public void sendMSM(AcceptData acceptData, String phone, Long uid, Integer type, String key, PrintWriter out) {
        try {
            if (phone.contains("**") && uid != null && uid > 0) {
@@ -68,10 +68,10 @@
            out.print(JsonUtil.loadFalseResult(e.getCode(), e.getMsg()));
        }
    }
    /**
     * 1.5.3  登录发送短信
     * 1.5.3 登录发送短信
     *
     * @param acceptData
     * @param phone
     * @param uid
@@ -84,18 +84,19 @@
            return;
        }
        phone = phone.replaceAll(" ", "");
        sendMSNnew(phone,slideVerify, 1, StringUtil.Md5(phone + "-" + acceptData.getDevice()), out);
        sendMSNnew(phone, slideVerify, 1, StringUtil.Md5(phone + "-" + acceptData.getDevice()), out);
    }
    /**
     * 1.5.3 绑定发送短信
     *
     * @param acceptData
     * @param phone
     * @param uid
     * @param out
     */
    @RequestSerializableByKey(key = "#acceptData.device+'-'+#phone")
    @RequestMapping(value = "sendMSMBind", method = RequestMethod.POST)
    public void sendMSMBind(AcceptData acceptData, String phone, boolean slideVerify, PrintWriter out) {
        if (phone == null || !StringUtil.isMobile(phone.replaceAll(" ", ""))) {
@@ -103,27 +104,28 @@
            return;
        }
        phone = phone.replaceAll(" ", "");
        // 判断手机号码是否被封禁
//        ForbiddenUserIdentifyCode identifyCode1 = forbiddenUserIdentifyCodeService
//                .listByTypeAndIdentifyCode(ForbiddenUserIdentifyCodeTypeEnum.phone, phone);
//        if (identifyCode1 != null && identifyCode1.getEffective() != null && identifyCode1.getEffective()) {
//            out.print(JsonUtil.loadFalseResult(9001,"该电话号码被占用"));
//            return;
//        }
//
        // ForbiddenUserIdentifyCode identifyCode1 =
        // forbiddenUserIdentifyCodeService
        // .listByTypeAndIdentifyCode(ForbiddenUserIdentifyCodeTypeEnum.phone,
        // phone);
        // if (identifyCode1 != null && identifyCode1.getEffective() != null &&
        // identifyCode1.getEffective()) {
        // out.print(JsonUtil.loadFalseResult(9001,"该电话号码被占用"));
        // return;
        // }
        //
        // 判断手机号码是否被封禁
        UserInfo phoneUser = userInfoService.getEffectiveUserInfoByPhone(phone);
        if (phoneUser != null) {
            out.print(JsonUtil.loadFalseResult(9001,"该电话号码被占用"));
            out.print(JsonUtil.loadFalseResult(9001, "该电话号码被占用"));
            return;
        }
        sendMSNnew(phone,slideVerify, 2, StringUtil.Md5(phone + "-" + acceptData.getDevice()), out);
        sendMSNnew(phone, slideVerify, 2, StringUtil.Md5(phone + "-" + acceptData.getDevice()), out);
    }
    @RequestSerializableByKey(key = "key")
    public void sendMSNnew(String phone, boolean slideVerify, int type, String key, PrintWriter out) {
        try {
            int count = 0;
@@ -135,31 +137,30 @@
                // 绑定验证码
                cachekey = "sendMSNBindCount" + phone;
            }
            if (cachekey == null) {
                out.print(JsonUtil.loadFalseResult(1,"发送失败"));
                out.print(JsonUtil.loadFalseResult(1, "发送失败"));
                return;
            }
            String cacheValue = redisManager.getCommonString(cachekey);
            if (!StringUtil.isNullOrEmpty(cacheValue)) {
                count = Integer.parseInt(cacheValue);
                // 限制3次
                if (count >= 3) {
                    out.print(JsonUtil.loadFalseResult(3,"验证码次数超限,请稍后再试"));
                    out.print(JsonUtil.loadFalseResult(3, "验证码次数超限,请稍后再试"));
                    return;
                }
            }
            if (count == 2 && !slideVerify) {
                out.print(JsonUtil.loadFalseResult(2,"需要滑动验证"));
                out.print(JsonUtil.loadFalseResult(2, "需要滑动验证"));
                return;
            }
            }
            // 缓存一个小时
            count ++;
            count++;
            redisManager.cacheCommonString(cachekey, count + "", 60 * 60);
            if (type == 1) {
                // 登录验证码
                smsService.sendLoginVCode(phone, 4);
@@ -167,9 +168,9 @@
                // 绑定验证码
                smsService.sendBindVCode(phone, 4);
            }
            out.print(JsonUtil.loadTrueResult("发送成功"));
        } catch (SMSException e) {
            out.print(JsonUtil.loadFalseResult(e.getCode(), e.getMsg()));
        } catch (Exception e) {
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/UserInfoController.java
@@ -1077,7 +1077,7 @@
     * @param type
     * @param out
     */
    @RequestSerializableByKey(key = "uid")
    @RequestSerializableByKey(key = "#uid")
    @RequestMapping(value = "extractmoneynew", method = RequestMethod.POST)
    public void extractMoneyNew(AcceptData acceptData, long uid, BigDecimal money, String vcode,
            HttpServletRequest request, int type, PrintWriter out) {
fanli/src/main/java/com/yeshi/fanli/controller/client/v1/UserMsgController.java
@@ -79,6 +79,7 @@
import com.yeshi.fanli.util.TimeUtil;
import com.yeshi.fanli.util.VersionUtil;
import com.yeshi.fanli.util.account.UserUtil;
import com.yeshi.fanli.util.annotation.RequestSerializableByKey;
import com.yeshi.fanli.util.factory.CommonGoodsFactory;
import com.yeshi.fanli.util.factory.msg.UserMsgVOFactory;
import com.yeshi.fanli.util.taobao.TaoKeApiUtil;
@@ -635,6 +636,7 @@
     * @param type
     * @param out
     */
    @RequestSerializableByKey(key="#acceptData.device")
    @RequestMapping(value = "getHomeMsgListNew", method = RequestMethod.POST)
    public void getHomeMsgListNew(AcceptData acceptData, Long uid, PrintWriter out) {
        if (uid != null && uid == 0)
fanli/src/main/java/com/yeshi/fanli/service/impl/monitor/BusinessEmergent110ServiceImpl.java
@@ -17,7 +17,7 @@
@Service
public class BusinessEmergent110ServiceImpl implements BusinessEmergent110Service {
    String[] phones = new String[] { "18581318252", "15025351808", "18696787365" };
    String[] phones = new String[] { "18581318252", "15025351808" };
    private static Map<String, List<String>> map = new HashMap<>();
    private static long shareTime = 0L;
fanli/src/main/java/com/yeshi/fanli/util/Constant.java
@@ -1,6 +1,10 @@
package com.yeshi.fanli.util;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.yeshi.utils.annotation.MapUtil;
import com.yeshi.fanli.entity.config.AlipayConfig;
import com.yeshi.fanli.entity.config.ConstantConfig;
@@ -9,7 +13,6 @@
import com.yeshi.fanli.entity.config.WXGZConfig;
import com.yeshi.fanli.entity.config.ZNXConfig;
import com.yeshi.fanli.util.taobao.TaoBaoUtil;
import org.yeshi.utils.annotation.MapUtil;
public class Constant {
    public static boolean IS_TASK = false;
@@ -161,12 +164,12 @@
    public static final String WEBPAGE_SIGN_KEY = "@?,223Hbb88lll";
    // public static final String TAOKE_ANDROID_APPKEY = "24587154";
    // public static final String TAOKE_IOS_APPKEY = "24838852";
    // 新人抽奖-最大次数
    public static final int MAX_COUNT_LOTTERY_NEWBIES = 5;
    // 线程等待数量
    public static Set<Long> waitingThreadSet = new HashSet<>();
    static {
        if (smsConfig == null) {