为控制器和方法指定 URI

优质
小牛编辑
131浏览
2023-12-01

Spring MVC也提供了构造指定控制器方法链接的机制。以下面代码为例子,假设我们有这样一个控制器:

@Controller
@RequestMapping("/hotels/{hotel}")
public class BookingController {

    @RequestMapping("/bookings/{booking}")
    public String getBooking(@PathVariable Long booking) {

    // ...

    }
}

你可以通过引用方法名字的办法来准备一个链接:

UriComponents uriComponents = MvcUriComponentsBuilder
    .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42);

URI uri = uriComponents.encode().toUri();

在上面的例子中,我们为方法参数准备了填充值:一个long型的变量值21,以用于填充路径变量并插入到URL中。另外,我们还提供了一个值42,以用于填充其他剩余的URI变量,比如从类层级的请求映射中继承来的hotel变量。如果方法还有更多的参数,你可以为那些不需要参与URL构造的变量赋予null值。一般而言,只有@PathVariable@RequestParam注解的参数才与URL的构造相关。

还有其他使用MvcUriComponentsBuilder的方法。比如,你可以通过类似mock掉测试对象的方法,用代理来避免直接通过名字引用一个控制器方法(以下方法假设MvcUriComponentsBuilder.on方法已经被静态导入):

UriComponents uriComponents = MvcUriComponentsBuilder
    .fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

URI uri = uriComponents.encode().toUri();

上面的代码例子中使用了MvcUriComponentsBuilder类的静态方法。内部实现中,它依赖于ServletUriComponentsBuilder来从当前请求中抽取schema、主机名、端口号、context路径和servlet路径,并准备一个基本URL。大多数情况下它能良好工作,但有时还不行。比如,在准备链接时,你可能在当前请求的上下文(context)之外(比如,执行一个准备链接links的批处理),或你可能需要为路径插入一个前缀(比如一个地区性前缀,它从请求中被移除,然后又重新被插入到链接中去)。

对于上面所提的场景,你可以使用重载过的静态方法fromXxx,它接收一个UriComponentsBuilder参数,然后从中获取基本URL以便使用。或你也可以使用一个基本URL创建一个MvcUriComponentsBuilder对象,然后使用实例对象的fromXxx方法。如下面的示例:

UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

URI uri = uriComponents.encode().toUri();