SpringMVC usa anotaciones para obtener datos en la sesión

SpringMVC usa anotaciones para obtener datos en la sesión

1. Uso de HandlerMethodArgumentResolver

  En términos generales, obtenemos los datos en la sesión, como el usuario de inicio de sesión LoginUserVO, inyectamos HttpSession en el método y luego ejecutamos el
atributo LoginUserVO = (LoginUserVO) session.getAttribute ("login_user_key");
para obtenerlo, debido al lugar utilizado Más a menudo, es repugnante tener que escribir código repetitivo y conversión de datos cada vez;

  SpringMVC nos permite usar anotaciones o inyectar datos directamente desde el método sin anotaciones a través de la interfaz HandlerMethodArgumentResolver, al igual que HttpServletRequest, como los siguientes efectos:

// 首先在登录时候将当前用户的信息放入 session 中;
request.getSession().setAttribute("login_user_key", loginUser);

// 直接通过自定义标签 @LoginUserBody 获取 session 中的 登录用户数据;
@PutMapping(value = "operation")
public boolean testArgument(@LoginUserBody LoginUserVO loginUser) {
    
    
    System.out.println(loginUser.getTrueName() + " 这里的 loginUser 已经获取");
    return true;
}

  ¿Entonces, cómo funciona?
  Primero, defina una anotación personalizada

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUserBody {
    
    
}

  Luego implemente la interfaz HandlerMethodArgumentResolver

public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
    
    
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
    
    
        // 判断方法的这个参数是否是否使用了 @LoginUserBody
        return parameter.hasParameterAnnotation(LoginUserBody.class);
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
            throws Exception {
    
    
        // 返回 session 中的用户数据
        return webRequest.getNativeRequest(HttpServletRequest.class).getSession().
            getAttribute("login_user_key");
    }
}

  Finalmente, registre el HandlerMethodArgumentResolver personalizado en Spring. Hay principalmente dos formas, una es para proyectos Spring tradicionales y la otra es para proyectos Springboot. Springboot se configura implementando WebMvcConfigurer.

@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
    
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    
    
        resolvers.add(new LoginUserArgumentResolver());
    }
}

  El proyecto de primavera tradicional está configurado en XML:

<mvc:annotation-driven>
	<mvc:argument-resolvers>
	    <bean class="com.xxx.LoginUserArgumentResolver"/>
	</mvc:argument-resolvers>
<mvc:annotation-driven>

2. Principio de implementación

  Primero, comenzamos a leer el código fuente de DispatcherServlet. Después de que DispatcherServlet reciba la solicitud, procesará todo el negocio a través de doDispatch (), por lo que aquí rastrearemos el código de doDispatch ();
  primero, DispatcherServlet llamará a HandlerAdapter para llamar a la interfaz MVC. HandlerAdapter es una interfaz de procesamiento, MVC usa AbstractHandlerMethodAdapter de forma predeterminada

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
    
    ModelAndView mv = null;
	...
    // 调用 HandlerAdapter 实现对 MVC 接口的调用
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    ...
}

  En AbstractHandlerMethodAdapter.handle (), la solicitud se reenvía al método handleInternal ()

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
    
    
    return handleInternal(request, response, (HandlerMethod) handler);
}

  handleInternal () es una función reservada para la implementación de subclase. La implementación predeterminada es RequestMappingHandlerAdapter, que llama a invokeHandlerMethod () en handleInternal () para implementar la ejecución del método y el procesamiento del valor de retorno. El flujo es el siguiente:

protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    
	...
    // 调用 handlerMethod
    mav = invokeHandlerMethod(request, response, handlerMethod);
	...
}
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    
	......
    // 执行 invokeAndHandle 调用接口
    invocableMethod.invokeAndHandle(webRequest, mavContainer);
	......
}
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
	Object... providedArgs) throws Exception {
    
    
	// 调用方法并获取到返回值
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    ......
}
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {
    
    
	// 获取参数,也就是说,参数的处理都是这里完成的
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	...
}
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
    
    
	// 获取接口参数
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
    
    
       ...
       // 这里的argumentResolvers 实际上是 HandlerMethodArgumentResolverComposite
        if (this.argumentResolvers.supportsParameter(parameter)) {
    
    
            args[i] = this.argumentResolvers.resolveArgument(
                parameter, mavContainer, request, this.dataBinderFactory);
        }   
    }
    return args;
}

  A través del proceso anterior, podemos saber que Spring juzgará y procesará los parámetros en HandlerMethodArgumentResolverComposite. El código principal es el siguiente:

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
    
    
	private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
    
    
		return (getArgumentResolver(parameter) != null);
	}
	@Override
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
    
		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}
	@Nullable
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    
    
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
    
    
			for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
    
    
				if (methodArgumentResolver.supportsParameter(parameter)) {
    
    
					result = methodArgumentResolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}
}

  HandlerMethodArgumentResolverComposite encapsula una colección HandlerMethodArgumentResolver, que contiene todo HandlerMethodArgumentResolver. Cuando se selecciona HandlerMethodArgumentResolver, realiza un bucle para juzgar y luego selecciona el que cumple las condiciones y lo ejecuta;

Supongo que te gusta

Origin blog.csdn.net/qq_36845919/article/details/108352039
Recomendado
Clasificación