1-2 分布式session(二)

问题:
用户第一次登录之后会得到一个cookie,在以后每次的访问过程中都会携带这个cookie,后台所有的需要登录权限的controller都要先获取cookie中的token,再使用token从session中获取用户登录信息来完成用户身份认证,所以所有的controller中都加上身份认证的代码非常冗余,因此需要把相同的代码抽取出来。

解决:
Spring Boot中的WebMvcConfigurer(前身是WebMvcConfigurerAdapter)接口提供了很多的方法对网站进行个性化定制,例如配置拦截器、配置ViewController、配置Cors跨域等。其中,addArgumentResolvers()方法可以用在对于Controller中方法参数传入之前对该参数进行处理,然后将处理好的参数再传给Controller中的方法。所以身份认证可以放在这个方法中完成。这个方法只有一个参数:argumentResolvers,它存储了所有的参数解析器,自定义参数解析器后通过调用add()方法加入参数解析器列表。

public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add();
}

argumentResolver参数解析器原理

自定义参数解析器必须实现HandlerMethodArgumentResolver接口,supportsParameter()方法用于判断该参数是否使用该解析器,resolveArgument()方法是解析器的具体解析操作,所以整体逻辑就是框架会将每一个MethodParameter传入supportsParameter判断是否需要被处理,如果需要,就使用resolveArgument进行处理。
public interface HandlerMethodArgumentResolver {
    boolean supportsParameter(MethodParameter parameter);
    Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
	   NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}

自定义cookie解析器

定义UserArgumentResolver类实现HandlerMethodArgumentResolver接口,首先判断参数是不是MiaoshaUser类型,如果是就进行token校验。
package com.imooc.miaosha.config;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Service;
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 com.imooc.miaosha.domain.MiaoshaUser;
import com.imooc.miaosha.service.MiaoshaUserService;

@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

	@Autowired
	MiaoshaUserService userService;
	
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> clazz = parameter.getParameterType();
		return clazz==MiaoshaUser.class;
	}

	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 paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
		String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
		if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
			return null;
		}
		String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
		return userService.getByToken(response, token);
	}

	private String getCookieValue(HttpServletRequest request, String cookiName) {
		Cookie[]  cookies = request.getCookies();
		for(Cookie cookie : cookies) {
			if(cookie.getName().equals(cookiName)) {
				return cookie.getValue();
			}
		}
		return null;
	}
}

定义WebConfig类实现WebMvcConfigurer,然后将定义的参数解析器userArgumentResolver添加到参数解析器列表中。

package com.miaosha.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

public class WebConfig implements WebMvcConfigurer {

    @Autowired
    UserArgumentResolver userArgumentResolver;
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(userArgumentResolver);
    }
}

然后controller方法就比较干净简洁啦!

@RequestMapping("/to_list")
    public String list(Model model,MiaoshaUser user) {
    	model.addAttribute("user", user);
        return "goods_list";
    }

总结

首先springMVC在启动时会将所有的参数解析器放到HandlerMethodArgumentResolverComposite,HandlerMethodArgumentResolverComposite简单来说就是所有的参数解析器的链表,接下来就是从HandlerMethodArgumentResolverComposite参数解析器集合中选择一个支持对该parameter解析的参数解析器,然后使用该解析器进行参数解析并生成目标对象。
posted @ 2022-06-12 22:07  学海无涯#  阅读(31)  评论(0)    收藏  举报