Compare commits

...

5 Commits
test ... master

  1. 5
      pom.xml
  2. 9
      src/main/java/com/lh/bean/RedisKey.java
  3. 35
      src/main/java/com/lh/config/CORSFilter.java
  4. 16
      src/main/java/com/lh/config/CandidateCacheRepository.java
  5. 7
      src/main/java/com/lh/controller/VoteController.java
  6. 2
      src/main/java/com/lh/exception/MyException.java
  7. 14
      src/main/java/com/lh/service/VoteServiceImpl.java
  8. 53
      src/main/java/com/lh/until/Utils.java
  9. 2
      src/main/resources/application.properties

5
pom.xml

@ -69,6 +69,11 @@
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.25</version>
</dependency>
</dependencies> </dependencies>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>

9
src/main/java/com/lh/bean/RedisKey.java

@ -0,0 +1,9 @@
package com.lh.bean;
public interface RedisKey {
String KEY_PREFIX = "homilychart-vote-";
String CACHE_KEY_VOTE_COUNT = KEY_PREFIX + "vote_count:";
String CACHE_KEY_VOTE_STATUE = KEY_PREFIX + "vote_status:";
String CACHE_KEY_CANDIDATE = KEY_PREFIX + "candidate:";
}

35
src/main/java/com/lh/config/CORSFilter.java

@ -0,0 +1,35 @@
package com.lh.config;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CORSFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Credentials", "true");
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "*");
if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
response.getWriter().println("ok");
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) {
}
}

16
src/main/java/com/lh/config/CandidateCacheRepository.java

@ -10,6 +10,8 @@ import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.util.Set; import java.util.Set;
import static com.lh.bean.RedisKey.CACHE_KEY_CANDIDATE;
@Repository @Repository
public class CandidateCacheRepository { public class CandidateCacheRepository {
@ -27,7 +29,7 @@ public class CandidateCacheRepository {
// 保存候选人信息到 Redis // 保存候选人信息到 Redis
public void saveCandidate(Candidate candidate) { public void saveCandidate(Candidate candidate) {
String key = "candidate:" + candidate.getJwCode();
String key = CACHE_KEY_CANDIDATE + candidate.getJwCode();
// 确保所有值都是字符串类型 // 确保所有值都是字符串类型
redisTemplate.opsForHash().put(key, "id", String.valueOf(candidate.getId())); redisTemplate.opsForHash().put(key, "id", String.valueOf(candidate.getId()));
@ -37,12 +39,12 @@ public class CandidateCacheRepository {
redisTemplate.opsForHash().put(key, "votes", String.valueOf(candidate.getVotes())); redisTemplate.opsForHash().put(key, "votes", String.valueOf(candidate.getVotes()));
// 更新 ZSET // 更新 ZSET
redisTemplate.opsForZSet().add("candidate:votes", candidate.getJwCode(), candidate.getVotes());
redisTemplate.opsForZSet().add(CACHE_KEY_CANDIDATE + "votes", candidate.getJwCode(), candidate.getVotes());
} }
// 获取候选人详细信息 // 获取候选人详细信息
public Candidate getCandidate(String jwCode) { public Candidate getCandidate(String jwCode) {
String key = "candidate:" + jwCode;
String key = CACHE_KEY_CANDIDATE + jwCode;
Candidate candidate = new Candidate(); Candidate candidate = new Candidate();
Object idObj = redisTemplate.opsForHash().get(key, "id"); Object idObj = redisTemplate.opsForHash().get(key, "id");
@ -68,17 +70,17 @@ public class CandidateCacheRepository {
// 获取所有候选人的 jwCode 按投票数排序 // 获取所有候选人的 jwCode 按投票数排序
public Set<Object> getCandidateJwCodesByVotes() { public Set<Object> getCandidateJwCodesByVotes() {
return redisTemplate.opsForZSet().reverseRange("candidate:votes", 0, -1);
return redisTemplate.opsForZSet().reverseRange(CACHE_KEY_CANDIDATE + "votes", 0, -1);
} }
// 删除 Redis 中所有候选人数据 // 删除 Redis 中所有候选人数据
public void deleteAllCandidatesFromCache() { public void deleteAllCandidatesFromCache() {
Set<Object> jwCodes = redisTemplate.opsForZSet().range("candidate:votes", 0, -1);
Set<Object> jwCodes = redisTemplate.opsForZSet().range(CACHE_KEY_CANDIDATE + "votes", 0, -1);
if (jwCodes != null) { if (jwCodes != null) {
for (Object jwCode : jwCodes) { for (Object jwCode : jwCodes) {
redisTemplate.delete("candidate:" + jwCode);
redisTemplate.delete(CACHE_KEY_CANDIDATE + jwCode);
} }
} }
redisTemplate.delete("candidate:votes");
redisTemplate.delete(CACHE_KEY_CANDIDATE + "votes");
} }
} }

7
src/main/java/com/lh/controller/VoteController.java

@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.*;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.Map;
@CrossOrigin @CrossOrigin
@RestController @RestController
@ -29,12 +30,14 @@ public class VoteController {
} }
//获取所有候选人 //获取所有候选人
@PostMapping ("/getCandidates") @PostMapping ("/getCandidates")
public RespBean getCandidates(@RequestBody String token) throws IOException {
public RespBean getCandidates(@RequestBody Map<String, String> query) throws IOException {
String token = query.get("token");
//System.out.println(token); //System.out.println(token);
////将token的值分离出来 ////将token的值分离出来
//int startIndex = token.indexOf('=') + 1; // 找到等号的位置并移动到等号后一位 //int startIndex = token.indexOf('=') + 1; // 找到等号的位置并移动到等号后一位
//String tokenValue = token.substring(startIndex); // 提取等号后面的部分 //String tokenValue = token.substring(startIndex); // 提取等号后面的部分
token = "token=" + URLEncoder.encode(token.substring(10, token.length() - 2), "UTF-8");
// token = "token=" + URLEncoder.encode(token.substring(10, token.length() - 2), "UTF-8");
token = "token=" + URLEncoder.encode(token, "UTF-8");
System.out.println(token); System.out.println(token);
String voterJwcode = String.valueOf(new Utils().getJwcode(token)); String voterJwcode = String.valueOf(new Utils().getJwcode(token));

2
src/main/java/com/lh/exception/MyException.java

@ -1,6 +1,6 @@
package com.lh.exception; package com.lh.exception;
public class MyException extends Exception{
public class MyException extends RuntimeException {
public MyException(String msg) { public MyException(String msg) {
super(msg); super(msg);
} }

14
src/main/java/com/lh/service/VoteServiceImpl.java

@ -24,6 +24,8 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.lh.bean.RedisKey.*;
@Service @Service
public class VoteServiceImpl implements VoteService { public class VoteServiceImpl implements VoteService {
@ -67,7 +69,7 @@ public class VoteServiceImpl implements VoteService {
throw new MyException("候选人不存在"); throw new MyException("候选人不存在");
} }
String redisKey = "vote_count:" + voterJwcode + ":" + LocalDateTime.now().toLocalDate();
String redisKey = CACHE_KEY_VOTE_COUNT + voterJwcode + ":" + LocalDateTime.now().toLocalDate();
String currentVoteCountStr = stringRedisTemplate.opsForValue().get(redisKey); String currentVoteCountStr = stringRedisTemplate.opsForValue().get(redisKey);
int voteCountToday = currentVoteCountStr == null ? 0 : Integer.parseInt(currentVoteCountStr); int voteCountToday = currentVoteCountStr == null ? 0 : Integer.parseInt(currentVoteCountStr);
@ -75,19 +77,19 @@ public class VoteServiceImpl implements VoteService {
throw new MyException("今日投票次数已达上限"); throw new MyException("今日投票次数已达上限");
} }
String voteStatusKey = "vote_status:" + voterJwcode + ":" + candidateJwcode;
String voteStatusKey = CACHE_KEY_VOTE_STATUE + voterJwcode + ":" + candidateJwcode;
Boolean hasVoted = stringRedisTemplate.hasKey(voteStatusKey); Boolean hasVoted = stringRedisTemplate.hasKey(voteStatusKey);
if (hasVoted != null && hasVoted) { if (hasVoted != null && hasVoted) {
throw new MyException("您已经为该候选人投票,不能重复投票"); throw new MyException("您已经为该候选人投票,不能重复投票");
} }
String candidateKey = "candidate:" + candidateJwcode;
String candidateKey = CACHE_KEY_CANDIDATE + candidateJwcode;
// 使用 Redis Hash 增加候选人投票数 // 使用 Redis Hash 增加候选人投票数
redisTemplate.opsForHash().increment(candidateKey, "votes", 1); redisTemplate.opsForHash().increment(candidateKey, "votes", 1);
// 使用 Redis ZSet 增加候选人投票数 // 使用 Redis ZSet 增加候选人投票数
redisTemplate.opsForZSet().incrementScore("candidate:votes", candidateJwcode, 1);
redisTemplate.opsForZSet().incrementScore(CACHE_KEY_CANDIDATE + "votes", candidateJwcode, 1);
// 更新 Redis 中的投票次数 // 更新 Redis 中的投票次数
redisTemplate.opsForValue().increment(redisKey, 1); redisTemplate.opsForValue().increment(redisKey, 1);
@ -146,7 +148,7 @@ public class VoteServiceImpl implements VoteService {
} }
private void markVotedStatus(String voterJwcode, List<Candidate> candidateList) { private void markVotedStatus(String voterJwcode, List<Candidate> candidateList) {
String voteStatusKeyPrefix = "vote_status:" + voterJwcode + ":";
String voteStatusKeyPrefix = CACHE_KEY_VOTE_STATUE + voterJwcode + ":";
Set<String> votedKeys = stringRedisTemplate.keys(voteStatusKeyPrefix + "*"); Set<String> votedKeys = stringRedisTemplate.keys(voteStatusKeyPrefix + "*");
if (votedKeys != null) { if (votedKeys != null) {
@ -188,7 +190,7 @@ public class VoteServiceImpl implements VoteService {
public boolean resetVote() throws MyException { public boolean resetVote() throws MyException {
if (voterMapper.resetVote() && candidatesMapper.resetVotes()) { if (voterMapper.resetVote() && candidatesMapper.resetVotes()) {
//删除redis所有缓存 //删除redis所有缓存
redisTemplate.delete(redisTemplate.keys("*"));
redisTemplate.delete(redisTemplate.keys(KEY_PREFIX + "*"));
candidateCacheRepository.deleteAllCandidatesFromCache(); candidateCacheRepository.deleteAllCandidatesFromCache();
} else { } else {
throw new MyException("重置投票失败"); throw new MyException("重置投票失败");

53
src/main/java/com/lh/until/Utils.java

@ -1,8 +1,11 @@
package com.lh.until; package com.lh.until;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.lh.bean.RespBean;
import com.lh.bean.dto.TokenDTO; import com.lh.bean.dto.TokenDTO;
import com.lh.exception.MyException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
@ -11,22 +14,31 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@Slf4j @Slf4j
@Component @Component
public class Utils { public class Utils {
@Resource
private StringRedisTemplate stringRedisTemplate;
// 编码Token
static String url;
@PostConstruct
public void initAnalysisTokenUrl() {
boolean isProd = Arrays.asList(SpringUtil.getActiveProfiles()).contains("prod");
if (isProd) {
url = SpringUtil.getProperty("homilychart.token.analysis.url.prod");
} else {
url = SpringUtil.getProperty("homilychart.token.analysis.url.test");
}
}
// 获取token中的信息 // 获取token中的信息
public TokenDTO analysisToken(String token) throws IOException { public TokenDTO analysisToken(String token) throws IOException {
// 编码Token
String url = "http://39.101.133.168:8828/hljw/api/v2/member/info";
// 创建HttpClient实例 // 创建HttpClient实例
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 创建POST请求 // 创建POST请求
@ -39,22 +51,23 @@ public class Utils {
// 发送请求并获取响应 // 发送请求并获取响应
try (CloseableHttpResponse response = httpClient.execute(postRequest)) { try (CloseableHttpResponse response = httpClient.execute(postRequest)) {
int responseCode = response.getStatusLine().getStatusCode(); // 获取状态码 int responseCode = response.getStatusLine().getStatusCode(); // 获取状态码
// 检查响应状态
if (responseCode == 200) {
// 读取响应体 // 读取响应体
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
// 使用Jackson解析JSON响应体
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonResponse = objectMapper.readTree(responseBody);
JsonNode dataNode = jsonResponse.get("data");
TokenDTO tokenDTO = new TokenDTO();
tokenDTO.setJwcode(dataNode.get("jwcode").asInt());
tokenDTO.setUsername(dataNode.get("username").asText());
return tokenDTO;
log.info("[Utils] exec analysisToken url:{}, requestBody:{}, responseCode:{}, responseBody:{}", url, token, responseCode, responseBody);
// 获取不到用户状态
if (responseCode != 200 || StrUtil.isEmpty(responseBody)) {
throw new MyException("用户状态获取失败");
} }
else {
throw new RuntimeException("Failed : HTTP error code : " + responseCode);
// 将token进行解析为RespBean
RespBean bean = JSONUtil.toBean(responseBody, RespBean.class);
if (bean.getCode() != 200) {
throw new MyException("用户状态获取失败");
} }
return JSONUtil.toBean(bean.getData().toString(), TokenDTO.class);
} }
} }
} }

2
src/main/resources/application.properties

@ -37,3 +37,5 @@ spring.redis.jedis.pool.min-idle=1
# 每日最大投票次数 # 每日最大投票次数
vote.limit.daily=3 vote.limit.daily=3
homilychart.token.analysis.url.test = http://39.101.133.168:8828/hljw/api/v2/member/info
homilychart.token.analysis.url.prod = https://api.homilychart.com/hljw/api/v2/member/info
Loading…
Cancel
Save