Spring Boot。RestController的转发

4

我正在实现一个替换短链接的机制。

我需要将请求转发到另一个控制器。我找到了在Spring模型中如何执行此操作的示例,但我不知道在RestControllers中应该如何进行。

以下是我找到的示例(使用模型):

@Controller
public class ShrotLinkForwardController {

   @RequestMapping("/s/*")
   public String myMethod(HttpServletRequest request) {
       return "forward:/difmethod";
   }
}

也许我在寻找错误的方向,需要创建一个过滤器?

更新:我不知道最终的端点是什么,在转发方法中计算。因此,我不能自动装配其他控制器。


根据您的更新:如果无法自动装配控制器,则使用“return”forward:/ forwardURL”方法,如我的答案所建议。 - Triet Doan
4个回答

5

有两种方法可以实现你想要的。

1. 直接在目标控制器上调用方法。

控制器只是普通的Spring bean,你可以通过自动装配获取它。

@Controller
public class ShrotLinkForwardController {

  @Autowired
  OtherController otherController;

  @RequestMapping("/s/*")
  public String myMethod(Model model) {
    otherController.doStuff();
    return ...;
  }
}

2. 通过返回字符串触发转发

要触发转发,请尝试返回一个String而不是ModelAndView

这是您在问题中提到的方法。请注意,语法应该是forward:/forwardURL。冒号后面的字符串是指向另一个控制器的URL,而不是方法名。

@Controller
public class ShrotLinkForwardController {

  @RequestMapping("/s/*")
  public String myMethod(Model model) {
    return "forward:/forwardURL";
  }
}

谢谢帮助!我不知道使用@Controller注释和字符串返回值时,会转发到@RestController的普通方法!这正是我在寻找的。 - Kornext
1
@Triet Doan 就已发布的答案进行一些备注。“Trigger the redirect....”最好改为“触发转发...”。重定向和转发是完全不同的技术路径,在这里提供的答案中,“forward:/forwardURL”的处理方式提供的是转发而非重定向。 - Panagiotis Bougioukos

4

您可以注入目标控制器并直接调用方法。

@Controller
public class ShortLinkForwardController {

   @Autowired
   private RestController target;

   @RequestMapping("/s/*")
   public String myMethod(HttpServletRequest request) {
       return target.myMethod(request);
   }
}

注意: 与路径相关的请求属性仍将指向“/s/*”
或者使用ResponseEntity并设置目标位置...
public ResponseEntity<Void> myMethod(HttpServletRequest request) {
  return ResponseEntity.status(302).location(URI.create(...)).build();  
}

1

所有答案都是关于返回字符串

但我找到了另一种解决方案

也许它可以帮助某些人解决我的问题,尤其是当您需要从一个REST端点向另一个REST端点进行转发时。它也可以应用于您的情况。

@RestController
public class CustomerController {
    @GetMapping("/forwarding_endpoint")
    public void makeForward(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().getServletContext().getRequestDispatcher("/forward_endpoint").forward(request, response);
    }
}

0
更新。我不知道最终的端点,它是在转发方法中计算的。所以,我不能自动装配其他控制器,但我不明白如何在RestControllers中实现它。
我可以看到可能存在一些设计问题的迹象,因此我将尝试解释可能存在的问题以及如何根据最佳实践进行处理。
如果您的要求是向另一个控制器进行转发,那么这可能是三个可能问题的迹象:
  1. 你说你想转发的另一个控制器需要完成的工作可以提取到服务层中的服务方法中。然后两个控制器都可以调用同一个服务方法,而不必让每个控制器知道另一个控制器。

  2. 你的需求也可能是以下问题的指标。你需要两个控制器完全出于同样的实际原因,以便它们提供完全相同的输入和输出,但可以从2个不同的URL中使用。如果是这种情况,那么你可以只使用1个控制器,并允许它在两个URL上执行。请参见以下代码以实现此目的:

    @RequestMapping({"/s/*", "/s2/*})
    public String myMethod(HttpServletRequest request) {
        return "some response";
    }
    
  3. 你只需要向客户端公开1个URL,该URL将提供所有内容。然后转发的方法也不会对你有所帮助,因为如果客户端愿意,他将能够直接访问其他转发的控制器。在这种情况下,你可以实现1个单一的控制器,然后根据需要构建不同的响应。你可以在RestController中实现这一点,尽管Sonar和其他代码审查工具不建议通过标记方法返回ResponseEntity<?>来实现。例如:

    @RequestMapping("/s/*")
    public ResponseEntity<?> myMethod(HttpServletRequest request) {
        if (condition 1) {
            return new ResponseEntity<YourObject1>(HttpStatus.OK);
        } else if (condition 2) {
            return new ResponseEntity<YourObject2>(HttpStatus.OK);
        } else {
            return new ResponseEntity<YourObject3>(HttpStatus.OK);
        }
    }
    

    尽管这种最后的选择不被认为是最佳实践,但对于这个需求,我没有看到其他出路。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接