【SpringMVC应用篇】SpringMVC 参数解析器

  • 参数解析器介绍
  • 参数解析器案例
  • pom
  • User
  • UserController
  • 启动类
  • @CurrentUser
  • 参数解析器类
  • 配置类


参数解析器介绍

参数解析器属于spring-web包中提供的组件,springmvc框架中对应提供了很多参数解析器。例如我们开发的Controller代码如下:

@RestController
@RequestMapping("/user")
public class UserController{
    @PostMapping("/save")
    //此处request对象就是通过Springmvc提供的参数解析器帮我们注入的
    public String saveUser(HttpServletRequest request){
        return "success";
    }
}

在上面的saveUser方法中,我们声明了一个类型为HttpServletRequest的参数,这个对象就是通过springmvc提供的ServletRequestMethodArgumentResolver这个参数解析器帮我们注入的。同样如果我们需要使用HttpServletResponse对象,也可以直接在方法上加入这个参数即可,此时springmvc会通过ServletResponseMethodArgumentResolver这个参数解析器帮我们注入。

在项目开发中我们也可以根据需要自定义参数解析器,需要实现HandlerMethodArgumentResolver接口:

public interface HandlerMethodArgumentResolver {
    boolean supportsParameter(MethodParameter var1);

    @Nullable
    Object resolveArgument(MethodParameter var1, 
                            @Nullable ModelAndViewContainer var2, 
                            NativeWebRequest var3, 
                            @Nullable WebDataBinderFactory var4) throws Exception;
}

可以看到此接口包含两个接口方法:supportsParameterresolveArgument

supportsParameter方法返回true时,才会调用resolveArgument方法。

参数解析器案例

本案例要实现的功能为:通过在Controller的方法参数上加入@CurrentUser注解来注入当前登录用户对象。

pom

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
</parent>

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
 </dependency>

User

@Data
@AllArgsConstructor
public class User implements Serializable {
    private Long id;
    private String username;
}

UserController

@RestController
@RequestMapping(value = "/user")
public class UserController {
    //获取当前系统登录用户
    @GetMapping("/getCurrentUser")
    public String getCurrentUser(User user) {
        String name = user.getUsername();
        System.out.println("UserController getCurrentUser方法...");
        return user.toString();
    }
}

启动类

@SpringBootApplication
public class ArgumentResolverApp {
    public static void main(String[] args) {
        SpringApplication.run(ArgumentResolverApp.class,args);
    }
}

此时可以启动项目并且访问:http://localhost:8080/user/getCurrentUser,可以发现虽然能够访问成功,但是user对象的属性都是空的。为了能够获得当前系统登录用户,我们可以通过Spring提供的参数解析器来实现。

@CurrentUser

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

参数解析器类

创建参数解析器类,需要实现HandlerMethodArgumentResolver接口

/**
 * 自定义参数解析器
 */
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
    public CurrentUserMethodArgumentResolver() {
        System.out.println("CurrentUserMethodArgumentResolver自定义参数解析器初始化...");
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //如果Controller的方法参数类型为User同时还加入了CurrentUser注解,则返回true
        if (parameter.getParameterType().equals(User.class) &&
                parameter.hasParameterAnnotation(CurrentUser.class)) {
            return true;
        }
        return false;
    }

    //当supportsParameter方法返回true时执行此方法
    @Override
    public Object resolveArgument(MethodParameter parameter, 
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, 
                                  WebDataBinderFactory binderFactory) throws Exception {
        System.out.println("参数解析器...");
        //此处直接模拟了一个User对象,实际项目中可能需要从请求头中获取登录用户的令牌然后进行解析,
        //最终封装成User对象返回即可,这样在Controller的方法形参就可以直接引用到User对象了
        User user = new User(1L,"admin");
        
        return user;
    }
}

配置类

创建配置类,用于注册自定义参数解析器

@Configuration
public class ArgumentResolverConfiguration implements WebMvcConfigurer {
    public CurrentUserMethodArgumentResolver getCurrentUserMethodArgumentResolver(){
        return new CurrentUserMethodArgumentResolver();
    }

    @Override
    //注册自定义参数解析器
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(getCurrentUserMethodArgumentResolver());
    }
}

修改UserController,在User参数前加入@CurrentUser注解

@RestController
@RequestMapping(value = "/user")
public class UserController {
    //获取当前系统登录用户
    @GetMapping("/getCurrentUser")
    //注意:需要在User参数前加入CurrentUser注解
    public String getCurrentUser(@CurrentUser User user) {
        String name = user.getUsername();
        System.out.println("UserController getCurrentUser方法...");
        return user.toString();
    }
}

重新启动项目访问,发现user对象的属性已经有值了,这是因为我们在Controller方法的User参数前加入了@CurrentUser注解,在我们访问Controller的方法时Spring框架会调用我们自定义的参数解析器的supportsParameter方法来判断是否执行resolveArgument方法,如果Controller方法的参数类型为User并且加入了@CurrentUser注解则执行resolverArgument方法,此方法的返回结果将赋值给我们的Controller方法中声明的user参数,即完成了参数绑定。