Browse Source

。。。

WANG 6 years ago
parent
commit
09be042f40

+ 21 - 0
src/main/java/cn/com/qmth/examcloud/web/interceptor/GlobalSequenceLock.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.examcloud.web.interceptor;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 全局 请求顺序锁<br>
+ *
+ * @author WANGWEI
+ * @date 2019年2月22日
+ * @Copyright (c) 2018-2020 WANGWEI [QQ:522080330] All Rights Reserved.
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface GlobalSequenceLock {
+
+}

+ 126 - 0
src/main/java/cn/com/qmth/examcloud/web/interceptor/SeqlockInterceptor.java

@@ -0,0 +1,126 @@
+package cn.com.qmth.examcloud.web.interceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
+import cn.com.qmth.examcloud.commons.util.ThreadLocalUtil;
+import cn.com.qmth.examcloud.web.enums.HttpServletRequestAttribute;
+import cn.com.qmth.examcloud.web.redis.RedisClient;
+import cn.com.qmth.examcloud.web.support.ServletUtil;
+import cn.com.qmth.examcloud.web.support.StatusResponse;
+
+/**
+ * 顺序锁拦截器
+ *
+ * @author WANGWEI
+ * @date 2019年2月22日
+ * @Copyright (c) 2018-2020 WANGWEI [QQ:522080330] All Rights Reserved.
+ */
+public class SeqlockInterceptor implements HandlerInterceptor {
+
+	private static final ExamCloudLog LOG = ExamCloudLogFactory.getLog(SeqlockInterceptor.class);
+
+	/**
+	 * redis client
+	 */
+	private RedisClient redisClient;
+
+	private static final String GLOBAL_LOCK_PREFIX = "$_LOCK_G:";
+
+	private static final String SESSION_LOCK_PREFIX = "$_LOCK_S:";
+
+	private static final String LOCK_ATTRIBUTE = "$sequenceLock";
+
+	/**
+	 * 构造函数
+	 *
+	 * @param redisClient
+	 * @param exclusions
+	 */
+	public SeqlockInterceptor(RedisClient redisClient) {
+		super();
+		this.redisClient = redisClient;
+	}
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+			Object handler) throws Exception {
+		LOG.debug("preHandle... ...");
+
+		if (handler instanceof HandlerMethod) {
+
+			HandlerMethod handlerMethod = (HandlerMethod) handler;
+			GlobalSequenceLock globalSeqlock = handlerMethod
+					.getMethodAnnotation(GlobalSequenceLock.class);
+			SessionSequenceLock sessionSeqlock = handlerMethod
+					.getMethodAnnotation(SessionSequenceLock.class);
+
+			String mapping = (String) request
+					.getAttribute(HttpServletRequestAttribute.$_MAPPING.name());
+
+			if (null != globalSeqlock) {
+				String key = GLOBAL_LOCK_PREFIX + mapping;
+
+				if (redisClient.setIfAbsent(key, ThreadLocalUtil.getTraceId(), 60 * 5)) {
+					if (LOG.isDebugEnabled()) {
+						LOG.debug("partition locked");
+					}
+
+					request.setAttribute(LOCK_ATTRIBUTE, key);
+					return true;
+				} else {
+					response.setStatus(HttpStatus.CONFLICT.value());
+					ServletUtil.returnJson(new StatusResponse("409", "请稍后重试... ..."), response);
+					return false;
+				}
+
+			} else if (null != sessionSeqlock) {
+
+				User user = (User) request
+						.getAttribute(HttpServletRequestAttribute.$_ACCESS_USER.name());
+
+				String key = SESSION_LOCK_PREFIX + user.getKey();
+
+				if (redisClient.setIfAbsent(key, ThreadLocalUtil.getTraceId(), 60 * 5)) {
+					if (LOG.isDebugEnabled()) {
+						LOG.debug("sesssion locked");
+					}
+					request.setAttribute(LOCK_ATTRIBUTE, key);
+					return true;
+				} else {
+					response.setStatus(HttpStatus.CONFLICT.value());
+					ServletUtil.returnJson(new StatusResponse("409", "请稍后重试... ..."), response);
+					return false;
+				}
+			}
+		}
+
+		return true;
+	}
+
+	@Override
+	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
+			ModelAndView modelAndView) throws Exception {
+		LOG.debug("postHandle... ...");
+	}
+
+	@Override
+	public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+			Object handler, Exception ex) throws Exception {
+		LOG.debug("afterCompletion... ...");
+
+		Object key = request.getAttribute(LOCK_ATTRIBUTE);
+		if (null != key) {
+			redisClient.delete((String) key);
+		}
+	}
+
+}

+ 22 - 0
src/main/java/cn/com/qmth/examcloud/web/interceptor/SessionSequenceLock.java

@@ -0,0 +1,22 @@
+package cn.com.qmth.examcloud.web.interceptor;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * session级 请求顺序锁<br>
+ * 用一鉴权用户(必须是用户接入)顺序调用
+ *
+ * @author WANGWEI
+ * @date 2019年2月22日
+ * @Copyright (c) 2018-2020 WANGWEI [QQ:522080330] All Rights Reserved.
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SessionSequenceLock {
+
+}