package com.wangzaiplus.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 在需要保证 接口防刷限流 的Controller的方法上使用此注解 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface AccessLimit { int maxCount();// 最大访问次数 int seconds();// 固定时间, 单位: s }
package com.wangzaiplus.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 在需要保证 接口幂等性 的Controller的方法上使用此注解 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ApiIdempotent { }
package com.wangzaiplus.test.controller; import com.wangzaiplus.test.annotation.AccessLimit; import com.wangzaiplus.test.annotation.ApiIdempotent; import com.wangzaiplus.test.common.ServerResponse; import com.wangzaiplus.test.pojo.Mail; import com.wangzaiplus.test.service.TestService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.Errors; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") @Slf4j public class TestController { @Autowired private TestService testService; @ApiIdempotent @PostMapping("testIdempotence") public ServerResponse testIdempotence() { return testService.testIdempotence(); } @AccessLimit(maxCount = 5, seconds = 5) @PostMapping("accessLimit") public ServerResponse accessLimit() { return testService.accessLimit(); } @PostMapping("send") public ServerResponse sendMail(@Validated Mail mail, Errors errors) { if (errors.hasErrors()) { String msg = errors.getFieldError().getDefaultMessage(); return ServerResponse.error(msg); } return testService.send(mail); } }
package com.wangzaiplus.test.controller; import com.wangzaiplus.test.common.ServerResponse; import com.wangzaiplus.test.service.TokenService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/token") public class TokenController { @Autowired private TokenService tokenService; @GetMapping public ServerResponse token() { return tokenService.createToken(); } }
package com.wangzaiplus.test.service; import com.wangzaiplus.test.common.ServerResponse; import javax.servlet.http.HttpServletRequest; public interface TokenService { ServerResponse createToken(); void checkToken(HttpServletRequest request); }
package com.wangzaiplus.test.service.impl; import com.wangzaiplus.test.common.Constant; import com.wangzaiplus.test.common.ResponseCode; import com.wangzaiplus.test.common.ServerResponse; import com.wangzaiplus.test.exception.ServiceException; import com.wangzaiplus.test.service.TokenService; import com.wangzaiplus.test.util.JedisUtil; import com.wangzaiplus.test.util.RandomUtil; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.text.StrBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; @Service public class TokenServiceImpl implements TokenService { private static final String TOKEN_NAME = "token"; @Autowired private JedisUtil jedisUtil; @Override public ServerResponse createToken() { String str = RandomUtil.UUID32(); StrBuilder token = new StrBuilder(); token.append(Constant.Redis.TOKEN_PREFIX).append(str); jedisUtil.set(token.toString(), token.toString(), Constant.Redis.EXPIRE_TIME_MINUTE); return ServerResponse.success(token.toString()); } @Override public void checkToken(HttpServletRequest request) { String token = request.getHeader(TOKEN_NAME); if (StringUtils.isBlank(token)) {// header中不存在token token = request.getParameter(TOKEN_NAME); if (StringUtils.isBlank(token)) {// parameter中也不存在token throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg()); } } if (!jedisUtil.exists(token)) { throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); } Long del = jedisUtil.del(token); if (del <= 0) { throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg()); } } }
package com.wangzaiplus.test.common; public class Constant { public interface Redis { String OK = "OK"; Integer EXPIRE_TIME_MINUTE = 60;// 过期时间, 60s, 一分钟 Integer EXPIRE_TIME_HOUR = 60 * 60;// 过期时间, 一小时 Integer EXPIRE_TIME_DAY = 60 * 60 * 24;// 过期时间, 一天 String TOKEN_PREFIX = "token:"; String MSG_CONSUMER_PREFIX = "consumer:"; String ACCESS_LIMIT_PREFIX = "accessLimit:"; } public interface LogType { Integer LOGIN = 1;// 登录 Integer LOGOUT = 2;// 登出 } public interface MsgLogStatus { Integer DELIVERING = 0;// 消息投递中 Integer DELIVER_SUCCESS = 1;// 投递成功 Integer DELIVER_FAIL = 2;// 投递失败 Integer CONSUMED_SUCCESS = 3;// 已消费 } }