虽然您可以使用注释,但我建议您使用自定义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,您所要做的就是将该类注释为@Component
和自动配置逻辑会照顾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 MVC 而不使用 Spring Boot,则需要注册Converter“手动”:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DecodedIdentifierConverter());
}
}
After Converter
注册后,您可以在您的Controller
:
@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable DecodedIdentifier id) {
...
}
您还可以遵循其他选项。请考虑阅读本文,它将为您提供有关该问题的更多信息。
作为旁注,上述文章表示你可以直接定义一个valueOf
类中的方法将存储转换服务的结果,DecodedIdentifier
在你的例子中,它会让你摆脱Converter
class:说实话,我从来没有尝试过这种方法,而且我不知道在什么条件下它可以起作用。话虽如此,如果它有效,它可以简化您的代码。如果您认为合适,请尝试一下。
UPDATE
感谢@Aman 的评论,我仔细阅读了 Spring 文档。之后,我发现,虽然我认为上述转换方法更适合用例 - 您实际上正在执行转换 - 另一种可能的解决方案可能是使用自定义Formatter.
我已经知道 Spring 使用这种机制来执行多重转换,但我不知道可以根据注释注册自定义格式化程序,答案中提出的原始想法。考虑像这样的注释DateTimeFormat,这是完全有道理的。事实上,这种方法之前已经在 Stackoverflow 中描述过(请参阅中接受的答案)这个问题).
对于您的情况(基本上是上述针对您的情况提到的答案的转录):
首先,定义你的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
s,正如您在问题中指出的那样:
@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable @DecodedIdentifier String id) {
...
}