参数解析器属于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; }
可以看到此接口包含两个接口方法:supportsParameter
和resolveArgument
。
当supportsParameter
方法返回true时,才会调用resolveArgument
方法。
本案例要实现的功能为:通过在Controller的方法参数上加入@CurrentUser注解来注入当前登录用户对象。
第一步:创建maven工程argumentResolver_demo并配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> </parent> <groupId>cn.itcast</groupId> <artifactId>argumentResolver_demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
第二步:创建application.yml
server: port: 9000
第三步:创建User实体类
package cn.itcast.entity; import lombok.AllArgsConstructor; import lombok.Data; import java.io.Serializable; @Data @AllArgsConstructor public class User implements Serializable { private Long id; private String username; }
第四步:创建UserController
package cn.itcast.controller; import cn.itcast.entity.User; import org.springframework.web.bind.annotation.*; @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(); } }
第五步:创建启动类
package cn.itcast; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ArgumentResolverApp { public static void main(String[] args) { SpringApplication.run(ArgumentResolverApp.class,args); } }
此时可以启动项目并且访问:http://localhost:9000/user/getCurrentUser
可以发现虽然能够访问成功,但是user对象的属性都是空的。为了能够获得当前系统登录用户,我们可以通过Spring提供的参数解析器来实现。
第六步:创建CurrentUser注解
package cn.itcast.anno; import java.lang.annotation.*; /** * 绑定当前登录用户 */ @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CurrentUser { }
第七步:创建参数解析器类,需要实现HandlerMethodArgumentResolver接口
package cn.itcast.resolver; import cn.itcast.anno.CurrentUser; import cn.itcast.entity.User; import org.springframework.core.MethodParameter; 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; /** * 自定义参数解析器 */ 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; } }
第八步:创建配置类,用于注册自定义参数解析器
package cn.itcast.config; import cn.itcast.resolver.CurrentUserMethodArgumentResolver; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @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注解
package cn.itcast.controller; import cn.itcast.anno.CurrentUser; import cn.itcast.entity.User; import org.springframework.web.bind.annotation.*; @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参数,即完成了参数绑定。