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

2023-12-06

我有一个 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 解码,但我想知道是否也可以注入自定义解码器。


虽然您可以使用注释,但我建议您使用自定义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在你的例子中,它会让你摆脱Converterclass:说实话,我从来没有尝试过这种方法,而且我不知道在什么条件下它可以起作用。话虽如此,如果它有效,它可以简化您的代码。如果您认为合适,请尝试一下。

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());
    }
}

最后,在你的代码中使用注释Controllers,正如您在问题中指出的那样:

@RequestMapping(path = "/execution/{id}", method = RequestMethod.POST)
public ResponseEntity<...> execute(@PathVariable @DecodedIdentifier String id) {
   ...
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将(自定义)解码器添加到 WebMVC 端点 的相关文章

随机推荐

  • OrientDB ETL 加载 CSV,其中顶点在一个文件中,边在另一个文件中

    我有一些数据位于 2 个 CSV 文件中 一个包含顶点 另一个文件包含另一个文件中的边 我正在研究如何使用 ETL 来设置它 已经接近但还没有完全实现 它基本上可以工作 但我的边缘有属性 我不确定它们是否正确加载 这个问题很有帮助 但我仍然
  • CorePlot MonoMac 绑定崩溃

    我正在尝试使用 Monomac 的 CorePlot 0 9 绑定 但这似乎是一项艰巨的任务 monotouch 示例的构建和运行没有任何问题 但我不需要那个 由于绑定中仅存在 CorePlotiOS dll 因此我必须自己为 osx 构建
  • 在 asp.net 中获取 BIOS 日期

    我检查管理员是否有许可证 所以我每月检查一次登录 现在我使用系统日期进行检查 但管理员更改系统日期 所以我想要日期 BIOS 日期 string crt val crt mont crt year dt v objdata select u
  • Powershell - 等待输入 10 秒 [重复]

    这个问题在这里已经有答案了 inputYN Read Host defaults to y in 10 sec y n 如果用户在 10 秒内没有提供任何输入 则默认 inputYN应转到 是 并继续执行下一个任务 你的问题引起了我的兴趣
  • java swing JTextField 设置 PlaceHolder [重复]

    这个问题在这里已经有答案了 我创建了一个 JTextField 现在我想在该 JTextField 上设置占位符 但我不知道如何 请帮忙 这是我的代码 JTextField database new JTextField Enter Dat
  • 使用 PyAudio 进行流式传输时修改音量

    我正在尝试流式传输 WAV 文件 同时剥离其中一个声道 因此它仅在一个扬声器上播放 同时降低音量 我使用 PyAudio 的原因是我必须能够 一次传输多个文件 从特定扬声器 左 右 播放声音 中断声音文件的播放 并且无法找到任何其他允许这些
  • Visual Studio 2015 社区中缺少通用应用程序模板

    我仍然无法在已安装的 Visual Studio 2015 Community 中创建新的通用应用程序 我认为原因是我运行的是 Windows 8 1 今天我升级到Windows 10 但没有可用的 通用应用程序 模板 我已经安装了 Win
  • 使用 Grails 在电子邮件中发送图像

    我正在使用 Grails邮件插件发送电子邮件 我想在电子邮件正文中发送图像 而不是作为附件 我想要的是图像显示在电子邮件正文本身中 就像在新闻通讯中一样 我试过 img style display block height 100px wi
  • git push --force,在幕后

    当你使用 force 进行 git push 时到底会发生什么 我已经在网上搜索了大约一个小时 我能找到的最相关的答案是 Same as git push but force the push even if it results in a
  • 如何将列表项从字符串转换为整数?

    我有一个字符串列表列表 如下所示l 1 2 3 4 5 6 2 3 2 3 4 我想从第 2 项开始将列表视为 int 以下代码实现了目的 但没有将列表项转换为 int gt gt gt l i 2 for i in range len l
  • 在管理中列出过滤器和搜索结果

    在我覆盖之后get search results方法 list filter不起作用 但搜索字段按我的预期工作 class NaruceniProduktiAdmin admin ModelAdmin search fields broj
  • 使用 Eloquent/Raw Laravel 查询的 Group Concat

    我有一个以 Eloquent 形式存储的对象结构 item id 2 item color Black item size L item Quantity 5 item id 2 item color Black item size M i
  • 为什么将列表转换为集合比将生成器转换为集合更快?

    这是一个例子 gt gt gt from timeit import timeit gt gt gt print timeit y for y in range 100 number 100000 0 7025867114395824 gt
  • 简单的素数程序 - 线程 C# 的奇怪问题

    这是我的代码 using System using System Collections Generic using System Linq using System Text using System Threading namespac
  • 删除工作表/图表事件 VBA

    我试图在删除工作表 Excel 时触发宏 自 2010 年以来 出现了不同的删除事件 应用程序级别 Application SheetBeforeDelete 事件 工作簿级别 Workbook SheetBeforeDelete 事件 工
  • 在Shiny R中,有没有办法在observeEvent之后立即运行observeEvent而没有延迟(renderUI的问题)?

    好吧 我的标题有点令人困惑 但让我解释一下 我正在使用 renderUI 来获取音频标签 但是 我想以较低的音量启动音频 因为它太大声了 下面的代码工作正常 除了因为我添加了延迟 它以较高的音量开始 然后迅速转到较低的音量 但它仍然非常明显
  • 世博会开发者菜单未显示

    我正在使用 expo 工具并进行原生反应 没有任何问题 但在我的模拟器上升级 Expo Go 应用程序后 出现了问题 开发者菜单不会像以前那样显示 并且菜单中的项目不会显示 我的expo go版本 2 25 1 我正在使用 Genymoti
  • 张量流成本函数是张量,而不是标量 - 为什么?优化失败

    以下代码可以运行 但不起作用 变量cost总是一个充满 1 0 的张量 但为什么呢 我估计了一个标量 因为 1x5 矩阵乘以 5x1 矩阵就是一个标量 优化时偏差和权重也不会改变 我究竟做错了什么 KI Model x tf placeho
  • luasocket的问题

    我试图从 lua 套接字读取一些 二进制 数据 但上面的代码不会终止重复循环 我如何知道流已到达末尾 client require socket client socket connect www google com 80 client
  • 将(自定义)解码器添加到 WebMVC 端点

    我有一个 WebMVC 端点 RequestMapping path execution id method RequestMethod POST public ResponseEntity lt gt execute PathVariab