Java 向WebMVC端点添加(自定义)解码器

Java 向WebMVC端点添加(自定义)解码器,java,spring,spring-mvc,Java,Spring,Spring Mvc,我有一个WebMVC端点: @RequestMapping(path = "/execution/{id}", method = RequestMethod.POST) public ResponseEntity<...> execute(@PathVariable String id) { ... } 请注意@DecodedIdentifier注释。我知道它不存在,但希望它能解释我的意图。我知道这在Jersey的JAX-RS实现中是可能的,但是Sprin

我有一个WebMVC端点:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable String id) {
   ...
}
请注意
@DecodedIdentifier
注释。我知道它不存在,但希望它能解释我的意图。我知道这在Jersey的JAX-RS实现中是可能的,但是Spring的WebMVC呢


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

尽管您可以使用注释,但我建议您为此使用自定义解码器

按照您的示例,您可以这样做

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

公共类解码器标识符{
私有最终字符串id;
公共解码器标识符(字符串id){
this.id=id;
}
公共字符串getId(){
返回此.id;
}
}
然后,为自定义类定义一个
转换器。它可以执行Base64解码:

公共类DecodedIdentifierConverter实现转换器{
@凌驾
公共解码器标识符转换(字符串源){
返回新的DecodedIdentifier(Base64.getDecoder().decode(source));
}
}
为了向Spring介绍此转换器,您有几个选项

如果您运行的是Spring Boot,那么您所要做的就是将该类注释为
@组件
,该组件将负责
转换器
的注册

@组件
公共类DecodeDidIdentifierConverter实现转换器{
@凌驾
公共解码器标识符转换(字符串源){
返回新的DecodedIdentifier(Base64.getDecoder().decode(source));
}
}
确保配置组件扫描,以便Spring可以检测类中的
@组件
注释

如果您使用的是不带Spring Boot的Spring MVC,则需要:

@配置
@EnableWebMvc
公共类WebConfig实现WebMVCConfiguer{
@凌驾
公共void addFormatters(FormatterRegistry注册表){
addConverter(新的DecodedIdentifierConverter());
}
}
注册
转换器
后,您可以在
控制器中使用它

@RequestMapping(path=“/execution/{id}”,method=RequestMethod.POST)
公共响应执行(@PathVariable DecodedIdentifier id){
...
}
您还可以遵循其他选项。请考虑阅读,它将为您提供关于问题的进一步信息。 作为旁注,上面提到的文章指出,您可以在类中直接定义
valueOf
方法,该类将存储转换服务的结果,在您的示例中是
DecodedIdentifier
,它将允许您摆脱
Converter
类:老实说,我从未尝试过这种方法,我不知道在什么条件下它可以工作。话虽如此,如果它有效,它可以简化您的代码。请,如果你认为合适的话,试试看。 更新

感谢@Aman的评论,我仔细阅读了Spring文档。在那之后,我发现,尽管我认为前面提到的转换方法更适合于用例——您实际上正在执行转换——另一个可能的解决方案可能是使用定制

我已经知道Spring使用这种机制来执行多重转换,但我不知道有可能实现答案中提出的最初想法。考虑注释,比如,它非常有意义。事实上,这种方法在Stackoverflow中已有描述(参见中的公认答案)

在您的案例中(基本上是上述案例答案的抄本):

首先,定义
DecodedIdentifier
注释:

import java.lang.annotation.Documented;
导入java.lang.annotation.ElementType;
导入java.lang.annotation.Retention;
导入java.lang.annotation.RetentionPolicy;
导入java.lang.annotation.Target;
@记录
@保留(RetentionPolicy.RUNTIME)
@目标({ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.ANNOTATION_TYPE})
public@interface解码器标识符{
}
事实上,您可以考虑通过包括(例如)处理信息的编码来丰富注释

然后,创建相应的
注释FormatterFactory

import java.text.ParseException;
导入java.util.Base64;
导入java.util.Collections;
导入java.util.Locale;
导入java.util.Set;
导入org.springframework.context.support.EmbeddedValueResolutionSupport;
导入org.springframework.format.AnnotationFormatterFactory;
导入org.springframework.format.Formatter;
导入org.springframework.format.Parser;
导入org.springframework.format.Printer;
导入org.springframework.stereotype.Component;
@组成部分
公共类DecodeDidIdentifierFormatterFactory扩展了EmbeddedValueResolutionSupport
实现AnnotationFormatterFactory{
@凌驾
公共设置getPrinter(DecodeDidIdentifier注释,类字段类型){
返回此.getFormatter(注释);
}
@凌驾
公共解析器getParser(DecodedIdentifier注释,类fieldType){
返回此.getFormatter(注释);
}
专用格式化程序getFormatter(DecodedIdentifier注释){
返回新格式化程序(){
@凌驾
公共字符串解析(字符串文本、区域设置)引发ParseException{
//如果注释可以提供有关
//若要使用编码,此逻辑将具有高度可重用性
返回新字符串(Base64.getDecoder().decode(text));
}
@凌驾
公共字符串打印(字符串对象、区域设置){
返回对象;
}
};
}
}
在Spring MVC配置中注册工厂:

@配置
@EnableWebMvc
公共类WebConfig实现WebMVCConfiguer{
@凌驾
公共void addFormatters(FormatterRegi
@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable @DecodedIdentifier String id) {
   ...
}
public class DecodedIdentifierArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(DecodedIdentifier.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String value = webRequest.getParameterValues(parameter.getParameterName())[0];
        return Base64.getDecoder().decode(value);
    }
}