这个问题与this非常相似,但我不知道从哪里开始。
假设我有这样的动作:
@GetMapping("/foo/{id}")
public Collection<Foo> listById(@PathVariable("id") string id) {
return null;
}
怎么可以拦截listById
方法并改变id
的值(例如:concat a string,pad with zero 0)?
我的情况是,大多数ID都是左边填充零(长度不同),我不想把它留给我的ajax调用。
预期的解决方案:
@GetMapping("/foo/{id}")
public Collection<Foo> listById(@PathVariablePad("id", 4) string id) {
// id would be "0004" on "/foo/4" calls
return null;
}
好的,我就是这样做的。
由于我们不能继承注释,因此@PathVariable
的目标只是参数,我们必须创建一个新的注释,如下所示:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface PathVariablePad {
int zeros() default 0;
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
}
现在我们需要创建一个HandlerMethodArgumentResolver
。在这种情况下,因为我想要的是用零填充@PathVariable
,我们将继承PathVariableMethodArgumentResolver
,如下所示:
public class PathVariablePadderMethodArgumentResolver extends PathVariableMethodArgumentResolver {
private String leftPadWithZeros(Object target, int zeros) {
return String.format("%1$" + zeros + "s", target.toString()).replace(' ', '0'); // Eeeewwwwwwwwwwww!
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(PathVariablePad.class);
}
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
PathVariablePad pvp = parameter.getParameterAnnotation(PathVariablePad.class);
return new NamedValueInfo(pvp.name(), pvp.required(), leftPadWithZeros("", pvp.zeros()));
}
@Override
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
PathVariablePad pvp = parameter.getParameterAnnotation(PathVariablePad.class);
return leftPadWithZeros(super.resolveName(name, parameter, request), pvp.zeros());
}
}
最后,让我们注册我们的方法参数解析器(xml):
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="my.package.PathVariablePadderMethodArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
用法非常简单,继承人如何做到这一点:
@GetMapping("/ten/{id}")
public void ten(@PathVariablePad(zeros = 10) String id) {
// id would be "0000000001" on "/ten/1" calls
}
@GetMapping("/five/{id}")
public void five(@PathVariablePad(zeros = 5) String id) {
// id would be "00001" on "/five/1" calls
}
Spring @InitBinder
注释和WebDataBinder
类将帮助您在控制器方法调用之前拦截参数并处理它的值。
文档:
完整代码模式:
@RestController
public class FooController {
@InitBinder
private void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
super.setValue("000" + text);
}
} );
}
@GetMapping(value = "/foo/{id}")
public Foo sayHello(
@PathVariable(value = "id") String id
) {
return new Foo(id);
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class Foo {
@XmlElement(name = "id")
private String id;
public Foo(String id) {
this.id = id;
}
public Foo() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
}
用法:
curl http://localhost:8080/foo/10 | xmllint --format -
响应:
<foo>
<id>00010</id>
</foo>