Commit 3f619aba authored by huangjiamin's avatar huangjiamin

getPass

parent 063dd026
...@@ -8,6 +8,7 @@ import com.edgec.browserbackend.browser.service.Impl.IpResourceServiceImpl; ...@@ -8,6 +8,7 @@ import com.edgec.browserbackend.browser.service.Impl.IpResourceServiceImpl;
import com.edgec.browserbackend.browser.service.IpResourceService; import com.edgec.browserbackend.browser.service.IpResourceService;
import com.edgec.browserbackend.common.auth.Securitys; import com.edgec.browserbackend.common.auth.Securitys;
import com.edgec.browserbackend.common.commons.error.ClientRequestException; import com.edgec.browserbackend.common.commons.error.ClientRequestException;
import com.edgec.browserbackend.common.lock.MongoDistributedLock;
import com.edgec.browserbackend.common.utils.ResponseUtil; import com.edgec.browserbackend.common.utils.ResponseUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -19,6 +20,8 @@ import java.security.Principal; ...@@ -19,6 +20,8 @@ import java.security.Principal;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static com.edgec.browserbackend.common.lock.MongoDistributedLockKey.RENEWIP;
/** /**
* @author JMW * @author JMW
*/ */
...@@ -64,6 +67,10 @@ public class IpController { ...@@ -64,6 +67,10 @@ public class IpController {
public ResultDto renewIp(Principal principal, @RequestBody IpResourceRequestDto ipResourceRequestDto) { public ResultDto renewIp(Principal principal, @RequestBody IpResourceRequestDto ipResourceRequestDto) {
String logs = "【renewIp】 "; String logs = "【renewIp】 ";
log.info("{}, params : {}", logs, principal.getName()); log.info("{}, params : {}", logs, principal.getName());
boolean lock = MongoDistributedLock.getLock(RENEWIP, principal.getName(), 2000);
if (!lock) {
return ResponseUtil.error("");
}
try { try {
return ResponseUtil.success(ipResourceService.renewIp(principal.getName(), ipResourceRequestDto)); return ResponseUtil.success(ipResourceService.renewIp(principal.getName(), ipResourceRequestDto));
} catch (ClientRequestException e) { } catch (ClientRequestException e) {
...@@ -72,6 +79,8 @@ public class IpController { ...@@ -72,6 +79,8 @@ public class IpController {
} catch (Exception e) { } catch (Exception e) {
log.error("{}, Exception : {}", logs, e.getMessage(), e); log.error("{}, Exception : {}", logs, e.getMessage(), e);
return ResponseUtil.error(e.getMessage()); return ResponseUtil.error(e.getMessage());
} finally {
MongoDistributedLock.releaseLock(RENEWIP, principal.getName());
} }
} }
......
package com.edgec.browserbackend.common.lock;
import com.edgec.browserbackend.common.commons.core.ApplicationContextProvider;
import org.springframework.data.mongodb.core.MongoTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* MongoDB分布式锁工具类
*
* @author JMW
*/
public class MongoDistributedLock {
static MongoLockRepository mongoLockRepository;
private static final String VALUE = "value";
static {
mongoLockRepository = new MongoLockRepository(ApplicationContextProvider.getBean(MongoTemplate.class));
}
/**
* 获得锁的步骤:
* 1、首先判断锁是否被其他请求获得;如果没被其他请求获得则往下进行;
* 2、判断锁资源是否过期,如果过期则释放锁资源;
* 3.1、尝试获得锁资源,如果value=1,那么获得锁资源正常;(在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。)
* 3.2、value>1,则表示当前请求在尝试获取锁资源过程中,其他请求已经获取了锁资源,即当前请求没有获得锁;
* !!!注意,不需要锁资源时,及时释放锁资源!!!。
*
* @param lockKey 加锁字段
* @param lockKeyValue 加锁字段
* @param expire 加锁时间
* @return
*/
public static boolean getLock(MongoDistributedLockKey lockKey, String lockKeyValue, long expire) {
String key = lockKey.getKey(lockKeyValue);
List<MongoLock> mongoLocks = mongoLockRepository.getByKey(key);
//判断该锁是否被获得,锁已经被其他请求获得,直接返回
if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() >= System.currentTimeMillis()) {
return false;
}
//释放过期的锁
if (mongoLocks.size() > 0 && mongoLocks.get(0).getExpire() < System.currentTimeMillis()) {
releaseLockExpire(key, System.currentTimeMillis());
}
//!!(在高并发前提下)在当前请求已经获得锁的前提下,还可能有其他请求尝试去获得锁,此时会导致当前锁的过期时间被延长,由于延长时间在毫秒级,可以忽略。
Map<String, Object> mapResult = mongoLockRepository.incrByWithExpire(key, 1, System.currentTimeMillis() + expire);
//如果结果是1,代表当前请求获得锁
if ((Integer) mapResult.get(VALUE) == 1) {
return true;
//如果结果>1,表示当前请求在获取锁的过程中,锁已被其他请求获得。
} else if ((Integer) mapResult.get(VALUE) > 1) {
return false;
}
return false;
}
/**
* 释放锁
*
* @param lockKey 释放字段
* @param lockKeyValue 释放字段
*/
public static void releaseLock(MongoDistributedLockKey lockKey, String lockKeyValue) {
String key = lockKey.getKey(lockKeyValue);
Map<String, Object> condition = new HashMap<>(1);
condition.put("key", key);
mongoLockRepository.remove(condition);
}
/**
* 释放过期锁
*
* @param key 释放的字段
* @param expireTime 释放的时间限制
*/
private static void releaseLockExpire(String key, long expireTime) {
mongoLockRepository.removeExpire(key, expireTime);
}
}
package com.edgec.browserbackend.common.lock;
/**
* MongoDB分布式锁key
*
* @author JMW
*/
public enum MongoDistributedLockKey {
/**
* 续费
*/
RENEWIP("renewIp");
private String key;
MongoDistributedLockKey(String key) {
this.key = key;
}
public String getKey(String value) {
return key + "-" + value;
}
}
package com.edgec.browserbackend.common.lock;
import org.springframework.data.annotation.Id;
/**
* MongoDB分布式锁实体类
*
* @author JMW
*/
public class MongoLock {
@Id
private String key;
private double value;
private long expire;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public long getExpire() {
return expire;
}
public void setExpire(long expire) {
this.expire = expire;
}
}
package com.edgec.browserbackend.common.lock;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.*;
/**
* MongoDB分布式锁Repository
*
* @author JMW
*/
@Repository
public class MongoLockRepository {
private MongoTemplate mongoTemplate;
public MongoLockRepository(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
public List<MongoLock> getByKey(String _id) {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(_id));
return mongoTemplate.find(query, MongoLock.class);
}
/**
* 指定_id自增increment(原子加),并设置过期时间
*
* @param _id 加锁的字段
* @param increment +1
* @param expire 生存时间
* @return 返回查询结果
*/
public Map<String, Object> incrByWithExpire(String _id, double increment, long expire) {
//筛选
Query query = new Query();
query.addCriteria(new Criteria("_id").is(_id));
//更新
Update update = new Update();
update.inc("value", increment);
update.set("expire", expire);
//可选项
FindAndModifyOptions options = FindAndModifyOptions.options();
//没有则新增
options.upsert(true);
//返回更新后的值
options.returnNew(true);
Map<String, Object> resultMap = new HashMap<>(15);
resultMap.put("value", Double.valueOf((Objects.requireNonNull(mongoTemplate.findAndModify(query, update, options, MongoLock.class))).getValue()).intValue());
resultMap.put("expire", (Objects.requireNonNull(mongoTemplate.findAndModify(query, update, options, MongoLock.class))).getExpire());
return resultMap;
}
/**
* 根据value删除过期的内容
*
* @param _id 删除的字段
* @param expireTime 删除的时间限制
*/
public void removeExpire(String _id, long expireTime) {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(_id));
query.addCriteria(Criteria.where("expire").lt(expireTime));
mongoTemplate.remove(query, MongoLock.class);
}
public void remove(Map<String, Object> condition) {
Query query = new Query();
Set<Map.Entry<String, Object>> set = condition.entrySet();
int flag = 0;
for (Map.Entry<String, Object> entry : set) {
query.addCriteria(Criteria.where(entry.getKey()).is(entry.getValue()));
flag = flag + 1;
}
if (flag == 0) {
query = null;
}
assert query != null;
mongoTemplate.remove(query, MongoLock.class);
}
}
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