前言
@RequestParam注解有一个默认值设置,如果前端不传这个参数的话,将采用这个默认值,但问题在于这是死的,需求是千变万化的,如何根据不同用户设置不同默认值?
这就可以自定义一个ArgumentResolver,SpringMVC有众多ArgumentResolver实现类,这些战士在后台默默等待解析参数,当有人询问某个战士这个参数的类型你能不能处理时,如果能,他将做出回应,并他返回一个对象。
如最常用的RequestParamMethodArgumentResolver则负责处理标有RequestParam注解的参数,或者未标但参数是基本类型的情况。
这时候我们就可以继承他,先让他处理,如果他返回了null,则表示没有值,然后在执行我们的逻辑。
实现
自定义注解
先写一个用于替换RequestParam的注解。
参数有两个,方法名、方法所在类,用于标识默认值从哪个类的哪个方法下返回。
@Target(AnnotationTarget.VALUE_PARAMETER)
annotation class RequestParamOrDefaultValue(val methodName: String = "", val targetClass: KClass<*>) {
}
默认值参数转换器
这里我们从ConfigurableBeanFactory拿到处理默认值的类实例,然后通过MethodHandle去调用,他同我们常用的反射API一样,可以动态调用方法,使用MethodHandle更简单。
class DefaultValueHandlerMethodArgumentResolver : RequestParamMethodArgumentResolver {
private var beanFactory: ConfigurableBeanFactory? = null
constructor(useDefaultResolution: Boolean) : super(useDefaultResolution) {}
constructor(beanFactory: ConfigurableBeanFactory?, useDefaultResolution: Boolean) : super(beanFactory, useDefaultResolution) {
this.beanFactory = beanFactory
}
override fun resolveName(name: String, parameter: MethodParameter, request: NativeWebRequest): Any? {
//先交给父类获取
val result = super.resolveName(name, parameter, request)
if (result != null) return result
val requestParamOrDefaultValue = parameter.getParameterAnnotation(RequestParamOrDefaultValue::class.java)
try {
//处理默认值的类实例
var targetBean = beanFactory!!.getBean(requestParamOrDefaultValue!!.targetClass.java)
val targetMethodHandle = MethodHandles.lookup().findVirtual(DefaultValueHandler::class.java, requestParamOrDefaultValue!!.methodName, getMethodType())
return targetMethodHandle.bindTo(targetBean).invoke()
}catch (e:Exception){
e.printStackTrace()
}
return null
}
private fun getMethodType(): MethodType {
return MethodType.methodType(Any::class.java)
}
override fun supportsParameter(parameter: MethodParameter): Boolean {
return parameter.hasParameterAnnotation(RequestParamOrDefaultValue::class.java)
}
}
配置
继承WebMvcConfigurer,增加自定义参数转化器。
@Configuration
class SysWebMvcConfig : WebMvcConfigurer, BeanFactoryPostProcessor {
private var beanFactory: ConfigurableListableBeanFactory? = null
override fun postProcessBeanFactory(beanFactory: ConfigurableListableBeanFactory) {
this.beanFactory = beanFactory
}
override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
super.addArgumentResolvers(resolvers)
resolvers.add(DefaultValueHandlerMethodArgumentResolver(beanFactory,true))
}
}
默认值处理类
@Component
class DefaultValueHandler {
public fun getDefaultTimer(): Any {
return LocalDateTime.now().toString()
}
}
测试
@RestController
class TestController {
@PostMapping("/")
fun test(@RequestParamOrDefaultValue(targetClass = DefaultValueHandler::class, methodName = "getDefaultTimer") timer: String): String {
return timer;
}
}
如下是传递了参数的情况
未传递参数的情况