关于springboot:SpringBoot-参数别名实现

7次阅读

共计 3921 个字符,预计需要花费 10 分钟才能阅读完成。

SpringBoot 参数别名实现

首发于 Dale‘s blog

背景与痛点

我的项目中经常出现一种状况:定了某个参数之后,前端又要求改参数名字,而你又不想因为这个名字而扭转代码的优雅,于是就须要领有一个参数对应两个参数名的能力。
具体来说:业务领有自定义协定,在 java 实体中定义的名字是全名,例如:name getter、setter 别离为 getName()setName(String name)
然而,在协定转发的过程中须要应用简写来优化音讯体的大小 {"nm":"Dale"}, 不晓得何种起因,前端要求应用nm 对应原有的name

思路

应用 注解 设置参数的别名,将别名与实体的参数名绑定。而后再利用 ExtendedServletRequestDataBinder.addBindValues 从新将别名对应的值与实体的参数名对应。有些拗口,以背景中的例子为例:接管到的参数为 nm,值为Dale。通过绑定之后,将nm 的值绑定到 name 上。

废话不多,间接上代码。

代码

ValueFrom

/**
 * 申请参数别名注解
 *
 * @author Dale
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValueFrom {

    /**
     * 参数别名列表
     */
    String[] value();
}

AliasDataBinder

/**
 * 别名数据绑定
 *
 * @author Dale
 */
public class AliasDataBinder extends ExtendedServletRequestDataBinder {public AliasDataBinder(Object target, String objectName) {super(target, objectName);
    }

    @Override
    protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {super.addBindValues(mpvs, request);
        Class<?> targetClass = Objects.requireNonNull(getTarget()).getClass();
        Class<?> targetFatherClass = targetClass.getSuperclass();
        // 利用反射获取类的字段
        Field[] fields = targetClass.getDeclaredFields();
        Field[] superFields = targetFatherClass.getDeclaredFields();

        for (Field field : fields) {ValueFrom valueFromAnnotation = field.getAnnotation(ValueFrom.class);
            if (mpvs.contains(field.getName()) || valueFromAnnotation == null) {continue;}
            for (String alias : valueFromAnnotation.value()) {if (mpvs.contains(alias)) {mpvs.add(field.getName(), Objects.requireNonNull(mpvs.getPropertyValue(alias)).getValue());
                    break;
                }
            }
        }
        // 将参数绑定到父类上
        for (Field field : superFields) {ValueFrom valueFromAnnotation = field.getAnnotation(ValueFrom.class);
            if (mpvs.contains(field.getName()) || valueFromAnnotation == null) {continue;}
            for (String alias : valueFromAnnotation.value()) {if (mpvs.contains(alias)) {mpvs.add(field.getName(), Objects.requireNonNull(mpvs.getPropertyValue(alias)).getValue());
                    break;
                }
            }
        }
    }
}

AliasModelAttributeMethodProcessor

从新注入DataBinder

/**
 * 参数别名绑定 processor
 *
 * @author Dale
 */
public class AliasModelAttributeMethodProcessor extends ServletModelAttributeMethodProcessor {

    private ApplicationContext applicationContext;

    public AliasModelAttributeMethodProcessor(boolean annotationNotRequired) {super(annotationNotRequired);
    }

    public void setApplicationContext(ApplicationContext applicationContext){this.applicationContext = applicationContext;}

    @Override
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
        // 从新注入 databinder
        AliasDataBinder aliasDataBinder = new AliasDataBinder(binder.getTarget(), binder.getObjectName());
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = applicationContext.getBean(RequestMappingHandlerAdapter.class);
        Objects.requireNonNull(requestMappingHandlerAdapter.getWebBindingInitializer()).initBinder(aliasDataBinder);
        aliasDataBinder.bind(Objects.requireNonNull(request.getNativeRequest(ServletRequest.class)));
    }
}

最初利用 WebMvcConfigurer.addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) 注入AliasModelAttributeMethodProcessor

WebMvcConfiguration

/**
 * web mvc 配置
 *
 * @author Dale
 */
@Component
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {AliasModelAttributeMethodProcessor aliasModelAttributeMethodProcessor = new AliasModelAttributeMethodProcessor(true);
        aliasModelAttributeMethodProcessor.setApplicationContext(applicationContext);
        // 注入 AliasModelAttributeMethodProcessor
        resolvers.add(aliasModelAttributeMethodProcessor);
        WebMvcConfigurer.super.addArgumentResolvers(resolvers);
    }
}

应用

在定义传入参数的时候应用注解设置别名

RequestParam

/**
 * 发送音讯必要参数
 *
 * @author baoxulong
 */
public class RequestParam {
    /**
     * name
     */
    @NotNull(message = "name is required!")
    @ValueFrom(value = "nm")
    private String name;
    
    public String getName() {return name;}

    public void setName(String name) {this.name = name;}
    
}

NameController

/**
 * name 控制器
 *
 * @author Dale
 */
@RestController
@RequestMapping("name")
public class NameController {@PostMapping("set")
    public JsonResult set(@Valid RequestParam requestParam) {
        // todo::
        return JsonResult.success();}
    
}

总结

以上是 SpringBoot 设置参数别名的办法代码实记,深度不高,找工夫再深挖。

正文完
 0