gpt4 book ai didi

java - 添加(自定义)解码器到 WebMVC 端点

转载 作者:行者123 更新时间:2023-12-04 02:30:44 26 4
gpt4 key购买 nike

我有一个 WebMVC 端点:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable String id) {
...
}

在这里,提供的id应该首先被解码。是否可以定义一个“在后台”执行此操作的注释;也就是说,在调用端点之前?内容如下:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable @DecodedIdentifier String id) {
...
}

注意 @DecodedIdentifier 注释。我知道它不存在,但它有希望解释我的意图。我知道这对于 Jersey 的 JAX-RS 实现是可能的,但是 Spring 的 WebMVC 呢?

在这里,我使用的是 base64 解码,但我想知道是否也可以注入(inject)自定义解码器。

最佳答案

虽然您可以使用注释,但我建议您使用自定义 Converter为此目的。

按照你的例子,你可以做这样的事情。

首先,您需要定义一个适合转换的自定义类。例如:

public class DecodedIdentifier {
private final String id;

public DecodedIdentifier(String id) {
this.id = id;
}

public String getId() {
return this.id;
}
}

然后,为您的自定义类定义一个Converter。它可以进行Base64解码:

public class DecodedIdentifierConverter implements Converter<String, DecodedIdentifier> {

@Override
public DecodedIdentifier convert(String source) {
return new DecodedIdentifier(Base64.getDecoder().decode(source));
}
}

为了将此转换器告知 Spring,您有多种选择。

如果您正在运行 Spring Boot,您所要做的就是将类注释为 @Componentauto configuration logic将负责 Converter 注册。

@Component
public class DecodedIdentifierConverter implements Converter<String, DecodedIdentifier> {

@Override
public DecodedIdentifier convert(String source) {
return new DecodedIdentifier(Base64.getDecoder().decode(source));
}
}

请务必配置您的组件扫描,以便 Spring 可以检测到类中的 @Component 注释。

如果您在不使用 Spring Boot 的情况下使用 Spring MVC,则需要 register the Converter 'manually' :

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DecodedIdentifierConverter());
}
}

Converter 注册后,您可以在您的Controller 中使用它:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable DecodedIdentifier id) {
...
}

您还可以遵循其他选项。请考虑阅读 this article ,它将为您提供有关该问题的更多信息。

作为旁注,上面提到的文章 indicates你可以直接在类中定义一个 valueOf 方法来存储转换服务的结果,在你的例子中是 DecodedIdentifier ,它会让你摆脱Converter类:老实说,我从来没有尝试过这种方法,我不知道它在什么条件下可以工作。话虽如此,如果它有效,它可以简化您的代码。如果您认为合适,请尝试一下。

更新

感谢@Aman 的评论,我仔细阅读了 Spring 文档。在那之后,我发现,虽然我认为上述转换方法更适合用例——你实际上是在执行转换——另一种可能的解决方案是使用自定义 Formatter .

我已经知道 Spring 使用这种机制来执行多次转换,但我不知道可以 register a custom formatter based on an annotation ,答案中提出的最初想法。考虑像 DateTimeFormat 这样的注释,这是完全有道理的。事实上,这种方法之前已在 Stackoverflow 中进行了描述(请参阅 this question 中已接受的答案)。

在您的情况下(基本上是上面针对您的情况提到的答案的转录):

首先,定义您的 DecodedIdentifier 注释:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface DecodedIdentifier {
}

事实上,您可以考虑通过包括例如处理信息的编码来丰富注释。

然后,创建对应的AnnotationFormatterFactory:

import java.text.ParseException;
import java.util.Base64;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;

import org.springframework.context.support.EmbeddedValueResolutionSupport;
import org.springframework.format.AnnotationFormatterFactory;
import org.springframework.format.Formatter;
import org.springframework.format.Parser;
import org.springframework.format.Printer;
import org.springframework.stereotype.Component;

@Component
public class DecodedIdentifierFormatterFactory extends EmbeddedValueResolutionSupport
implements AnnotationFormatterFactory<DecodedIdentifier> {

@Override
public Set<Class<?>> getFieldTypes() {
return Collections.singleton(String.class);
}

@Override
public Printer<?> getPrinter(DecodedIdentifier annotation, Class<?> fieldType) {
return this.getFormatter(annotation);
}

@Override
public Parser<?> getParser(DecodedIdentifier annotation, Class<?> fieldType) {
return this.getFormatter(annotation);
}

private Formatter getFormatter(DecodedIdentifier annotation) {
return new Formatter<String>() {
@Override
public String parse(String text, Locale locale) throws ParseException {
// If the annotation could provide some information about the
// encoding to be used, this logic will be highly reusable
return new String(Base64.getDecoder().decode(text));
}

@Override
public String print(String object, Locale locale) {
return object;
}
};
}
}

在您的 Spring MVC 配置中注册工厂:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new DecodedIdentifierFormatterFactory());
}
}

最后,在您的 Controller 中使用注释,完全按照您在问题中指出的那样:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable @DecodedIdentifier String id) {
...
}

关于java - 添加(自定义)解码器到 WebMVC 端点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64370226/

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