【问题标题】:Spring MVC request mapping - full request URISpring MVC 请求映射 - 完整的请求 URI
【发布时间】:2014-12-04 10:10:55
【问题描述】:

使用 REST api 创建或列出项目时,我还会返回整个资源路径。

例如,创建人员记录返回http://service:9000/person/1234作为响应。为了获得像http://service:9000 这样的架构、主机和端口部分,我从HttpServletRequest.getRequestURL() 获得的URL 中提取它。

示例(不是生产代码,但概念上相同):

@RequestMapping(value = "/person", method = RequestMethod.PUT)
public Object putPerson(
        @RequestParam(value = "name") String name,
            HttpServletRequest req) {

      long id = createPerson(name);
      String uriStart = RestUtils.getSchemeHostPortUrlPart(req
            .getRequestURL().toString());
      String uri = uriStart + "/person/" + id;
      Person person = new Person(name, id, uri);

      return person; //Serialized to json by Spring & Jackson
}

//Simple bean-like class
public class Person {  
//Getter methods for uri, name & id
}

由于这是一个在每种方法中都重复的样板代码,我想知道 Spring 是否不支持这一点,这在阅读它的文档时让我无法理解。

我的意思是在不需要HttpServletRequest 的情况下访问任一 URL,甚至更好的是仅访问其架构、主机、端口部分。

【问题讨论】:

  • 您能否更新以显示您对 URL 的操作?
  • 如果是认真的工作,注意:在现实世界中,应用服务器通常出于安全原因隐藏在反向代理后面:应用服务器知道的主机端口是 不是用户使用的那个。反向代理尽最大努力应对这种情况,但需要注意的是……

标签: java spring rest spring-mvc web-applications


【解决方案1】:

文档提供了很多 examples 用于使用 UriComponentsBuilder 构造 URI。

此外,如果您想让您的 REST API 更上一层楼,我建议您查看 Spring HATEOAS

顺便说一句:PUT 意味着您将发送的内容(请求正文)放置到发送它的位置(URL)。如果什么都没有,则创建新的东西,否则更新(替换)现有的东西。

这不是您的示例中发生的情况。正确的方法是 POST 到 /person 或 PUT 到该人自己的 URL,例如/person/1234,前提是你事先有身份证。

【讨论】:

  • PUT 也可用于创建,根据规范。一个类比是 Map 的 put,它创建或替换一个条目。虽然 OP 中的代码仅声明 createPerson
  • @iwat0qs 答案是这样说的:您可以 POST 到 /person 或 PUT 到该人自己的 URI,例如/person/1234
  • 啊,好吧。也许我误解了。我读过“替换”就像“替换已经存在的东西”一样,“PUT 到这个人自己的 URI”就像“PUT 到一个已经存在的人的 URI”中一样。例如。 MDN 是这样说的,以避免歧义:“HTTP PUT 请求方法创建一个新资源或用请求有效负载替换目标资源的表示。”。我没有投票或任何其他事情,这只是对您的回答的一个小小的澄清。因为否则可以理解,那个 PUT 只替换已经存在的东西,否则返回 404,例如
  • @iwat0qs 您的 404 示例提供了一个有趣的方面。我已经更新了我的答案以避免任何歧义。
【解决方案2】:

您可以在拦截器中构造 URI(在控制器方法之前执行)并将其作为属性并在控制器方法中使用。

【讨论】:

  • 您能否提供一些链接以及要查找的拦截器或关键字的示例?
  • 拦截器示例:mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example 拦截器是一个具有两个方法 preHandle 和 postHandle 的类,您可以使用它来拦截请求并添加标头、检索 url 或 uri...任何您想要的。它在级联中的控制器方法之前执行(您可以使用多个)
【解决方案3】:

我相信这很简单。看这个例子:

@RequestMapping(value = "/person", method = RequestMethod.PUT)
public Object putPerson(@RequestParam(value = "name") String name, HttpServletRequest req) {

  long id = createPerson(name);
  Person person = new Person(id, name, req);

  return person; //Serialized to json by Spring & Jackson
}

public class JsonResponse {

    private String url;

    public JsonResponse(HttpServletRequest request) {
        url = request.getRequestURI() + "?" + request.getQueryString();
    }

    public final String url() {
        return url;
    }
}

public class User extends JsonResponse {

    private Long   id;
    private String name;

    public User(Long id, String name, HttpServletRequest request) {
        super(request);
        this.id = id;
        this.name = name;
    }

    // Getter, Setter

}

【讨论】:

    【解决方案4】:

    你可以像这样使用org.springframework.web.servlet.support.ServletUriComponentsBuilder

    String uri = ServletUriComponentsBuilder.fromCurrentRequest()
        .replacePath("/person/{id}")
        .buildAndExpand(id)
        .toUriString();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多