And*_*rew 4 java spring spring-mvc
如果您在请求中使用camelCase参数,则使用Spring MVC将URL请求参数映射到对象是相当简单的,但是当使用连字符分隔值时,如何将这些参数映射到对象?
参考示例:
控制器:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
保持参数的对象:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
像这样的请求工作正常:
GET http://localhost:8080/search?myVal1=foo&myVal2=bar
Run Code Online (Sandbox Code Playgroud)
但是,我想要的是用连字符映射到对象的请求,如下所示:
GET http://localhost:8080/search?my-val-1=foo&my-val-2=bar
Run Code Online (Sandbox Code Playgroud)
我需要在Spring中配置什么来将带连字符的url请求参数映射到对象中的字段?请记住,我们可能有许多参数,因此对每个字段使用@RequestParam注释并不理想.
小智 5
我扩展了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;
}
}
Run Code Online (Sandbox Code Playgroud)
您将需要一个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;
}
}
Run Code Online (Sandbox Code Playgroud)
此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());
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在剩下的就是将此行为添加到您的配置中.以下配置将覆盖@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);
}
}
Run Code Online (Sandbox Code Playgroud)
应该给@Jkee.这个解决方案是他在这里发布的一个例子的衍生物: 如何在绑定spring mvc命令对象时自定义参数名称.
| 归档时间: |
|
| 查看次数: |
4221 次 |
| 最近记录: |