Spring MVC:如何读取和更改@PathVariable值

问题描述 投票:1回答:2

这个问题与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;
}
java spring spring-mvc spring-aop
2个回答
3
投票

好的,我就是这样做的。

由于我们不能继承注释,因此@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
}

0
投票

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>
© www.soinside.com 2019 - 2024. All rights reserved.