后台管理系统的通用权限解决方案(十)如何自定义SpringMVC的参数解析器
文章目录
- 1 参数解析器介绍
- 2 参数解析器案例
- 2.1 案例需求
- 2.2 案例实战
1 参数解析器介绍
我们在开发中,可能会写以下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
接口:
可以看到,此接口包含两个接口方法:supportsParameter
和resolveArgument
。当supportsParameter
方法返回true时,才会调用resolveArgument
方法。
2 参数解析器案例
2.1 案例需求
在实际项目中,绝大部分操作都是基于“当前登录用户”进行的,业务逻辑中一般也需要获取“当前登录用户”的信息。
常用的做法是,在过滤器中解析token得到当前登录用户的信息,并将需要的信息放入request域,那在Controller方法中就可以通过HttpServletRequest
对象获取到当前登录用户信息。
而通过参数解析器的做法,是和HttpServletRequest
对象已有直接声明,让Springmvc帮我们自动注入,而无需再放入request域。
2.2 案例实战
- 1)创建maven工程
resolver-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>com.hsgx</groupId>
<artifactId>resolver-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
- 2)创建实体类
LoginUser
package com.itweid.resolver.pojo;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
public class LoginUser {
private Integer id;
private String username;
private LocalDateTime loginTime;
}
- 3)创建
UserController
类
package com.itweid.resolver.controller;
import com.itweid.resolver.pojo.LoginUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/user")
public class UserController {
// 获取当前登录用户信息
@GetMapping("/getLoginUser")
public String getLoginUser(LoginUser loginUser) {
return loginUser.toString();
}
}
- 4)创建启动类
package com.itweid.resolver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ResolverApp {
public static void main(String[] args) {
SpringApplication.run(ResolverApp.class, args);
}
}
- 5)启动项目,访问
http://127.0.0.1:8080/user/getLoginUser
由结果可知,虽然访问成功了,但返回的信息全为空,说明在Controller方法中,直接使用LoginUser
对象暂时是无法注入的。
而为了能够自动注入LoginUser
对象,我们可以通过Spring提供的参数解析器来实现。
- 6)创建
LoginUser
注解,只有标注了该注解的参数才会自动注入
package com.itweid.resolver.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoginUser {
}
- 7)创建参数解析器类,实现
HandlerMethodArgumentResolver
接口
package com.itweid.resolver.resolver;
import com.itweid.resolver.pojo.LoginUser;
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;
import java.time.LocalDateTime;
public class LoginUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 如果Controller方法的参数类型为LoginUser,
// 同时还加入了@LoginUser注解,则返回true
if (parameter.getParameterType().equals(LoginUser.class) &&
parameter.hasParameterAnnotation(com.itweid.resolver.annotation.LoginUser.class)) {
return true;
}
return false;
}
// 当supportsParameter方法返回true时执行此方法
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
System.out.println("参数解析器执行了...");
// 此处直接模拟了一个LoginUser对象,实际项目中可能需要从请求头中获取登录用户的令牌然后进行解析,
// 最终封装成LoginUser对象返回即可,这样在Controller的方法形参就可以直接引用到LoginUser对象了
LoginUser loginUser = new LoginUser(1,"admin", LocalDateTime.now());
return loginUser;
}
}
- 8)创建配置类,用于注册自定义的参数解析器
package com.itweid.resolver.config;
import com.itweid.resolver.resolver.LoginUserMethodArgumentResolver;
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 {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new LoginUserMethodArgumentResolver());
}
}
- 9)修改
UserController
类的getLoginUser()
方法,在LoginUser参数前加入@LoginUser
注解
// 获取当前登录用户信息
@GetMapping("/getLoginUser")
public String getLoginUser(@com.itweid.resolver.annotation.LoginUser LoginUser loginUser) {
return loginUser.toString();
}
- 10)重启项目,访问
http://127.0.0.1:8080/user/getLoginUser
有结果可知,返回的LoginUser
对象的属性已经有值了,这是因为在我们访问Controller的方法时,Spring框架会调用我们自定义的参数解析器的supportsParameter
方法来判断是否执行resolveArgument
方法。
如果Controller方法的参数类型为LoginUser
并且加入了@LoginUser
注解,则执行resolveArgument
方法,此方法的返回结果将赋值给Controller方法中声明的LoginUser
参数,即完成了参数绑定。
…
本节完,更多内容查阅:后台管理系统的通用权限解决方案
延伸阅读:后台管理系统的通用权限解决方案(九)后台管理系统的通用权限解决方案(九)SpringBoot整合jjwt实现登录认证鉴权