1.创建UserArgumentResolver自定义解析器
package com.hspedu.seckill.config;
import com.hspedu.seckill.pojo.User;
import com.hspedu.seckill.service.UserService;
import com.hspedu.seckill.util.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author TTc
* @version 1.0
* @date 2024/3/18 9:09
*/
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private UserService userService;
//如果这个方法返回 true 才会执行下面的 resolveArgument 方法
// 返回 false 不执行下面的方法
@Override
public boolean supportsParameter(MethodParameter parameter) {
//获取参数是不是 user 类型
Class<?> aClass = parameter.getParameterType();
//如果为 t, 就执行 resolveArgument
return aClass == User.class;
}
/**
* 这个方法,类似拦截器,将传入的参数,取出 cookie 值,然后获取对应的User 对象* 并把这个 User 对象作为参数继续传递.
* @param parameter
* @param mavContainer
* @param webRequest
* @param binderFactory
* @return
* @throws Exception
*/
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request =webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response =webRequest.getNativeResponse(HttpServletResponse.class);
String ticket = CookieUtil.getCookieValue(request, "userTicket");
if (!StringUtils.hasText(ticket)) {
return null;
}
//根据 cookie-ticket 到 Redis 获取 User
return userService.getUserByCookie(ticket, request, response);
}
}
2.创建WebConfig实现WebMvcConfigurer接口
package com.hspedu.seckill.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author TTc
* @version 1.0
* @date 2024/3/18 9:16
*/
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserArgumentResolver userArgumentResolver;
// 静态资源加载
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
// 将我们自定义的UserArgumentResolver 解析器加入到HandlerMethodArgumentResolver 列表
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers){
resolvers.add(userArgumentResolver);
}
}
3.Controller接口参数示例
/**
* 增加方法, 获取到秒杀路径 , 随机生成的
* user 对象是哪里来的?, 已经登录过,存放到了 Redis 中
*
* @param user 自定义校验器返回user对象
* @param goodsId
* @return
*/
@RequestMapping(value = "/path", method = RequestMethod.GET)
@ResponseBody
/**
* @AccessLimit(second = 5, maxCount = 5, needLogin = true)
* 1. 使用注解的方式完成通用的接口防刷功能
* 2. second = 5, maxCount = 5 5 秒内,最多 5 次请求,否性进行限流* 3. needLogin = true 表示需要登录
*/
@AccessLimit(second = 5, maxCount = 5, needLogin = true)
// public RespBean getPath(User user, Long goodsId, String captcha) {
public RespBean getPath(User user, Long goodsId, String captcha, HttpServletRequest request) {
if (user == null) {
return RespBean.error(RespBeanEnum.SESSION_ERROR);
}
//验证用户输入的验证码
boolean check = orderService.checkCaptcha(user, goodsId, captcha);
if (!check) {
return RespBean.error(RespBeanEnum.CAPTCHA_ERROR);
}
//创建真正的地址
String url = orderService.createPath(user, goodsId);
return RespBean.success(url);
}