在上一篇中Redis實戰之session共享,我們知道了通過Redis實現session共享了,那麼token怎麼續命呢?怎麼刷新用戶呢?本來咱們就通過攔截器來實現這兩個功能。
凱哥自己開發的,領取外賣、打車、咖啡、買菜、各大電商的優惠券的公¥衆¥號。如下圖:
正文開始
登錄攔截器優化:
先來看看現在攔截器情況:
攔截流程:
當攔截器攔截需要攔截到的url時候,纔會在攔截器中更新用戶token的過期時間。那如果,訪問了不被攔截的路徑,就不會給token續命的。這樣就會導致用戶token過期,而重新登錄的。這樣是不對的。
攔截了哪些路徑?在config/MvcConfig中
當訪問以上這些路徑的是,就不會自動更新用戶的token過期時間了。
優化:我們可以在現有攔截器簽名價格攔截器:
將獲取用戶,存放threadLocal及刷新token放到新的攔截器中。
第一個攔截器就叫做:刷新token攔截器;第二個攔截器就叫做:用戶攔截器
創建刷新token的攔截器:
import cn.hutool.core.bean.BeanUtil; import com.hmdp.dto.UserDTO; import com.hmdp.utils.UserHolder; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.concurrent.TimeUnit; import static com.hmdp.constants.RedisConstants.LOGIN_USER_TOKEN_KEY; import static com.hmdp.constants.RedisConstants.LOGIN_USER_TOKEN_TTL; /** * @author 凱哥Java * @description 刷新用戶token的爛機器 * @company */ public class RefreshTokenInterceptor implements HandlerInterceptor { private StringRedisTemplate stringRedisTemplate; /** * 因爲這個類不能被spring管理,所以不能直接注入RedisTemplate對象。通過構造函數傳遞 * * @param stringRedisTemplate */ public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1:從請求中獲取到token String token = request.getHeader("authorization"); if (StringUtils.isEmpty(token)) { return true; } //2:基於token獲取redis中用戶對象 String key = LOGIN_USER_TOKEN_KEY + token; Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key); //3:判斷 if (userMap.isEmpty()) { return true; } //將map轉對象 UserDTO user = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false); UserHolder.saveUser(user); //刷新token的過期時間 stringRedisTemplate.expire(key, LOGIN_USER_TOKEN_TTL, TimeUnit.MINUTES); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }
修改用戶攔截器:
import com.hmdp.utils.UserHolder; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author 凱哥Java * @description 登錄攔擊器 * @company */ public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判斷是否需要攔截 if (UserHolder.getUser() == null) { response.setStatus(401); return false; } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }
修改MvcCofig。將兩個攔截器添加進去,並設置攔截順序:
import com.hmdp.interceptor.RefreshTokenInterceptor; import com.hmdp.interceptor.UserInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; /** * @author 凱哥Java * @description mvn的配置-添加攔截器 * @company */ @Configuration public class MvcConfig implements WebMvcConfigurer { @Resource private StringRedisTemplate stringRedisTemplate; @Override public void addInterceptors(InterceptorRegistry registry) { //登錄攔截器 registry.addInterceptor(new UserInterceptor()) .excludePathPatterns( "/shop/**", "/voucher/**", "/shop-type/**", "/upload/**", "/blog/hot", "/user/code", "/user/login" ).order(1); //刷新token攔截器 registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0); } }