gpt4 book ai didi

java - 将带破折号的 URL 参数映射到 Spring Web MVC 中的对象

转载 作者:搜寻专家 更新时间:2023-11-01 02:05:48 24 4
gpt4 key购买 nike

如果您在请求中使用 camelCase 参数,则使用 Spring MVC 将 URL 请求参数映射到对象是相当简单的,但是当以连字符分隔的值出现时,如何将它们映射到对象?

引用示例:

Controller :

@RestController
public class MyController {

@RequestMapping(value = "/search", method = RequestMethod.GET)
public ResponseEntity<String> search(RequestParams requestParams) {
return new ResponseEntity<>("my-val-1: " + requestParams.getMyVal1() + " my-val-2: " + requestParams.getMyVal2(), HttpStatus.OK);
}

}

保存参数的对象:

public class RequestParams {

private String myVal1;
private String myVal2;

public RequestParams() {}

public String getMyVal1() {
return myVal1;
}

public void setMyVal1(String myVal1) {
this.myVal1 = myVal1;
}

public String getMyVal2() {
return myVal2;
}

public void setMyVal2(String myVal2) {
this.myVal2 = myVal2;
}
}

这样的请求可以正常工作:

GET http://localhost:8080/search?myVal1=foo&myVal2=bar

但是,我想要的是带有连字符的请求映射到对象,如下所示:

GET http://localhost:8080/search?my-val-1=foo&my-val-2=bar

我需要在 Spring 中配置什么才能将带有连字符的 url 请求参数映射到对象中的字段?请记住,我们可能有许多参数,因此使用每个字段的 @RequestParam 注释并不理想。

最佳答案

我扩展了 ServletRequestDataBinder 和 ServletModelAttributeMethodProcessor 来解决这个问题。

考虑到您的域对象可能已经使用@JsonProperty 或@XmlElement 进行注释以进行序列化。这个例子假设是这种情况。但是您也可以为此目的创建自己的自定义注释,例如@MyParamMapping。

带注释的域类的示例是:

public class RequestParams {

@XmlElement(name = "my-val-1" )
@JsonProperty(value = "my-val-1")
private String myVal1;

@XmlElement(name = "my-val-2")
@JsonProperty(value = "my-val-2")
private String myVal2;

public RequestParams() {
}

public String getMyVal1() {
return myVal1;
}

public void setMyVal1(String myVal1) {
this.myVal1 = myVal1;
}

public String getMyVal2() {
return myVal2;
}

public void setMyVal2(String myVal2) {
this.myVal2 = myVal2;
}
}

您将需要一个 SerletModelAttributeMethodProcessor 来分析目标类、生成映射、调用您的 ServletRequestDataBinder。

    public class KebabCaseProcessor extends ServletModelAttributeMethodProcessor {

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

@Autowired
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

private final Map<Class<?>, Map<String, String>> replaceMap = new ConcurrentHashMap<Class<?>, Map<String, String>>();

@Override
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest nativeWebRequest) {
Object target = binder.getTarget();
Class<?> targetClass = target.getClass();
if (!replaceMap.containsKey(targetClass)) {
Map<String, String> mapping = analyzeClass(targetClass);
replaceMap.put(targetClass, mapping);
}
Map<String, String> mapping = replaceMap.get(targetClass);
ServletRequestDataBinder kebabCaseDataBinder = new KebabCaseRequestDataBinder(target, binder.getObjectName(), mapping);
requestMappingHandlerAdapter.getWebBindingInitializer().initBinder(kebabCaseDataBinder, nativeWebRequest);
super.bindRequestParameters(kebabCaseDataBinder, nativeWebRequest);
}

private static Map<String, String> analyzeClass(Class<?> targetClass) {
Field[] fields = targetClass.getDeclaredFields();
Map<String, String> renameMap = new HashMap<String, String>();
for (Field field : fields) {
XmlElement xmlElementAnnotation = field.getAnnotation(XmlElement.class);
JsonProperty jsonPropertyAnnotation = field.getAnnotation(JsonProperty.class);
if (xmlElementAnnotation != null && !xmlElementAnnotation.name().isEmpty()) {
renameMap.put(xmlElementAnnotation.name(), field.getName());
} else if (jsonPropertyAnnotation != null && !jsonPropertyAnnotation.value().isEmpty()) {
renameMap.put(jsonPropertyAnnotation.value(), field.getName());
}
}
if (renameMap.isEmpty())
return Collections.emptyMap();
return renameMap;
}
}

此 KebabCaseProcessor 将使用反射来获取您的请求对象的映射列表。然后它将调用 KebabCaseDataBinder - 传入映射。

@Configuration
public class KebabCaseRequestDataBinder extends ExtendedServletRequestDataBinder {

private final Map<String, String> renameMapping;

public KebabCaseRequestDataBinder(Object target, String objectName, Map<String, String> mapping) {
super(target, objectName);
this.renameMapping = mapping;
}

protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
super.addBindValues(mpvs, request);
for (Map.Entry<String, String> entry : renameMapping.entrySet()) {
String from = entry.getKey();
String to = entry.getValue();
if (mpvs.contains(from)) {
mpvs.add(to, mpvs.getPropertyValue(from).getValue());
}
}
}
}

现在剩下的就是将此行为添加到您的配置中。以下配置覆盖了@EnableWebMVC 提供的默认配置,并将此行为添加到您的请求处理中。

@Configuration
public static class WebContextConfiguration extends WebMvcConfigurationSupport {
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(kebabCaseProcessor());
}

@Bean
protected KebabCaseProcessor kebabCaseProcessor() {
return new KebabCaseProcessor(true);
}
}

感谢@Jkee。此解决方案源自他在此处发布的示例:How to customize parameter names when binding spring mvc command objects .

关于java - 将带破折号的 URL 参数映射到 Spring Web MVC 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33924200/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com