1. Introduction

In Java development, most interfaces need user login to execute business logic, so there will be a lot of repeated code for verifying user login and obtaining user information, which is not easy to be complicated, but also easy to miss.

2. How does Spring implement request parameter injection

public class User {
    private Long id;
    private String name;
}

@GetMapping("param")
public String param(User user) {
    System.out.println(user);
    return "param";
}
Copy the code

In Spring, to retrieve queryString parameters, simply add an argument of the same name to the Controller method or an object with the same name as a field. This approach is elegant and isolates HttpRequest’s API, which is a nice touch. Spring to realize this kind of elegant way of injection, it depends on the extended interface HandlerMethodArgumentResolver

3. The extension HandlerMethodArgumentResolver

public interface HandlerMethodArgumentResolver {

	boolean supportsParameter(MethodParameter parameter);

	@Nullable
	Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}
Copy the code

SupportsParameter HandlerMethodArgumentResolver defines two methods, to determine whether or not to perform injection parameters, resolveArgument execution parameter parsed and into the Controller method.

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

    boolean required(a) default true;

}
Copy the code

First we need to define an annotation @userInfo to mark the object we want to inject. The annotation needs to be implemented at run time. @userInfo has a Reqiured property that marks whether the interface must be logged in to be accessible, for some interfaces that display different data depending on whether the user is logged in or not.

@GetMapping("/required")
public String required(@UserInfo User user) {
    System.out.println(user);
    return "required";
}

@GetMapping("notRequired")
public String notRequired(@UserInfo(required = false) User user) {
    System.out.println(user);
    return "not required";
}
Copy the code

Add the User parameter to Controller with the @userinfo tag

public class Token2UserResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // The method argument has the @userinfo flag
        return parameter.hasParameterAnnotation(UserInfo.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        / / get the @ the UserInfo
        UserInfo userInfo = parameter.getParameterAnnotation(UserInfo.class);
        // Get access-token from header
        String token = webRequest.getHeader("access-token");
        if ((token == null || token.isEmpty())) {
            if (userInfo.required()) {
                // If the token does not exist and you must log in to the interface, throw an exception and return the corresponding status code to the preceding segment together with unified exception processing
                throw new RuntimeException("401");
            } else {
                // If you do not have to log in, do not process it
                return null; }}// Parse the token into a User object
        User user = null;
        if (token.equals("token-a")) {
            user = new User(1L."user-A");
        } else if (token.equals("token-b")) {
            user = new User(2L."user-B");
        }
        returnuser; }}Copy the code

Implement HandlerMethodArgumentResolver, this simple analytical process, simulates a token can be used in practical development redis or JWT scheme implementation. It is important to note that this is not just about injecting user information, but also about enforcing interface logins. When the @userInfo attribute is true, an exception will be thrown if there is no login, and unified exception handling allows for access control and elegant responses.

@Configuration
public class MyConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(newToken2UserResolver()); }}Copy the code

Finally, add Token2UserResolver to the parser chain via WebMvcConfigurer provided by Spring. The result is an elegant user information parsing tool. The business developer can focus on the implementation of the business without worrying about obtaining and verifying user information.