带有 Spring Boot 的 JSON 和 HTML 控制器

Posted

技术标签:

【中文标题】带有 Spring Boot 的 JSON 和 HTML 控制器【英文标题】:Controller for JSON and HTML with Spring Boot 【发布时间】:2015-02-01 10:24:02 【问题描述】:

我正在编写一个应用程序,其中我需要对某些对象进行 CRUD 操作。我需要能够为人类用户提供 html 页面,并为其他应用程序提供 JSON。现在我的“阅读”网址如下所示:

GET  /foo/id      -> Serves HTML
GET  /rest/foo/id -> Serves JSON
etc.

这似乎有点多余。我宁愿有这样的东西:

GET /foo/id.html OR /foo/id -> Serves HTML
GET /foo/id.json              -> Serves JSON

Spring Boot 可以做到这一点吗?如果有,怎么做?

我知道如何返回 JSON:

@RequestMapping(value = "/foo/id", method = RequestMethod.GET, produces = "application/json")
public Object fetch(@PathVariable Long id) 
    return ...;

我也知道如何返回 HTML:

@RequestMapping("/app/page.html")
String index(@PathVariable String page) 
    if(page == null || page.equals(""))
        page = "index";
    return page;

但我不确定如何让控制器根据请求执行其中一项操作。

【问题讨论】:

【参考方案1】:

实际上,您将 REST Web 服务与 html 页面混合在一起,这是一种不好的做法。 如果你想建立一些真正伟大的东西,这是我的建议。 在您的控制器中仅编写 CRUD 操作,所有 html/css/js 都保存在某个静态文件夹中,当您想要查看 ui 部分时 - 只需调用该静态 index.html 文件 您可以在此处阅读更多相关信息 - http://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot

但如果你真的想像现在这样做,这里有解决方案:

@RequestMapping(value = "/foo/id", method = RequestMethod.GET)
public Object serve(final HttpServletRequest req, final HttpServletResponse resp, @PathVariable final Long id) 
    String header = req.getHeader("Accept");

    // If Accept header will be text/html - then we are forwarding to jsp page.
    if(header.equals("text/html")) 
        req.getRequestDispatcher("login.jsp").forward(req, resp);
    

    // In other cases we are returning json and setting appropriate headers.
    resp.setHeader("Content-Type", "application/json");
    Object object = "Some string";

    return object;

【讨论】:

我当然想使用好的做法。我没有为 HTML 页面使用静态文件夹的原因是因为我认为这会删除我正在使用的 Thymeleaf 模板。 如果你想使用好的实践,你为什么要用rest web service来模板引擎呢?js世界里有很多模板引擎。 RESTful 我想我只是基于我在 Ruby 的 Rails 框架中看到的模型。 我真的不明白为什么 Ivan 被否决了,OP 接受了他的批评,他实际上提出了一个有效的观点。哎呀,我猜为时已晚两年【参考方案2】:

这是 Spring Boot 的默认行为。唯一的事情是您必须标记@RequestMapping 之一才能生成JSON。示例:

@Controller
class HelloController 

    // call http://<host>/hello.json
    @RequestMapping(value = "/hello", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public MyObject helloRest() 
        return new MyObject("hello world");
    

    // call http://<host>/hello.html or just http://<host>/hello 
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String helloHtml(Model model) 
        model.addAttribute("myObject", new MyObject("helloWorld"));
        return "myView";
    

阅读更多:http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc 和 http://spring.io/blog/2013/06/03/content-negotiation-using-views

【讨论】:

没有理由使用两种处理程序方法。这就是 ContentNegotationViewResolver 的用途 这并不完全正确。如果调用经典 HTML 页面,您可能需要执行其他操作。 ContentNegotiationViewResolver 只是其中一个选项,这就是为什么我链接了解释这两种方法的文章。

以上是关于带有 Spring Boot 的 JSON 和 HTML 控制器的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:JSON将带有时区的日期和时间反序列化为LocalDateTime

在 Angular5 和 Spring Boot 中上传带有 JSON 数据的文件

Spring Boot - 返回带有对象数组的 JSON

Spring Boot休眠类型异常创建带有JSON字段的表

缺少 JSON 密钥(在带有 kotlin 的 Spring-boot 上使用 @JsonComponent)

如何使用 Spring Boot 序列化带有连字符的 JSON?