java Spring MVC、Thymeleaf 和 REST

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33004831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 21:03:36  来源:igfitidea点击:

Spring MVC, Thymeleaf & REST

javaandroidrestspring-mvcthymeleaf

提问by WARREN-R

I currently have a project using a Spring controller and Thymeleaf to create a little browser app. The controller class is declared as

我目前有一个使用 Spring 控制器和 Thymeleaf 的项目来创建一个小的浏览器应用程序。控制器类声明为

@Controller public class MyController {

Inside the controller I have a GETdefined as

在控制器内部,我有一个GET定义为

@RequestMapping(value = "/foobars", method = RequestMethod.GET)
String index(Model model, --- more params ---) {
    //call repository and get foobarsList
    //model.addAttribute("foobars", foobarsList);
          ...
    return "foobars/foobarThymeleafTemplate"
}

The call repository and get foobarListis a call to a MongoRepositorydefined as:

通话信息库,并得到foob​​arList是一个呼叫MongoRepository定义为:

public interface FoobarRepository extends MongoRepository< ... cut for brevity> {

    @RestResource(rel = "by-id") 
    Marker findMarkerById(String id);

    ... additional @RestResources cut for brevity ...
}

Again, the Browser App looks great. The GETcalls the repository, populates the modelwith the list of foobars and Thymeleaf does it thing with that list.

同样,浏览器应用程序看起来很棒。该GET调用存储库,填充模式与foob​​ars的列表,并Thymeleaf做这件事与该名单。

PROBLEM:Now I need to access that same data from an AndroidApp and I would prefer to use REST and just consume JSON in the Android App. I want to keep Thymeleaf but will refactor the browser app if necessary.

问题:现在我需要从Android应用程序访问相同的数据,我更喜欢使用 REST 并且只在 Android 应用程序中使用 JSON。我想保留 Thymeleaf,但会在必要时重构浏览器应用程序。

QUESTION:Is there a way to somehow use the same @Controller or will I have to maintain a second FoobarRestController using @RestController with /restFoobars endpoints? The second REST controller works for sure but it seems kind of sloppy ... poor design.

问题:有没有办法以某种方式使用相同的 @Controller 或者我是否必须使用带有 /restFoobars 端点的 @RestController 来维护第二个 FoobarRestController?第二个 REST 控制器肯定可以工作,但它似乎有点草率……糟糕的设计。

Your thoughts and recommendations?

您的想法和建议?

Thanks again. -Rich

再次感谢。-富有的

回答by chrylis -cautiouslyoptimistic-

My preferred approach here is to use inheritance:

我的首选方法是使用继承:

@RequestMapping('/foobars')
abstract class FoobarBaseController {

    @RequestMapping
    abstract listAll()
}

@Controller
class FoobarHtmlController extends FoobarBaseController {
    @Override ModelAndView listAll() {
        new ModelAndView('foobars/foobarThymeleafTemplate', [foobars: foobarsList])
    }
}

@RestController
@RequestMapping('/foobars', produces = MediaType.APPLICATION_JSON_VALUE)
class FoobarJsonController extends FoobarBaseController {
    @Override Collection<Foobar> listAll() {
        foobarsList
    }
}

Alternatively, if there's significant work to be done checking inputs or the like, you can implement that in the BaseControllerand have an abstract listAllResponse(DomainObject foo)that then returns the appropriate ModelAndView(HTML) or DTO (JSON).

另外,如果有做显著工作检查输入或类似的,你可以实现的BaseController,并有abstract listAllResponse(DomainObject foo)那那么返回相应的ModelAndView(HTML)或DTO(JSON)。

The one pitfall of this approach is that you can't override just part of the @RequestMapping, so you do have to repeat the class's part of the mapping when you specify the producesparameter, but you can inherit the method-level mappings with no problem.

这种方法的一个缺陷是您不能只覆盖 的一部分@RequestMapping,因此在指定produces参数时必须重复映射的类部分,但是您可以毫无问题地继承方法级映射。

回答by Faraj Farook

Expose Crud

暴露原油

Use the @Controllerto do the work of handling HTML page and using the Repository you can expose the entity via rest API for the basic actions like crud by using SPRING-DATA-RESTto expose your entities. I think you are already doing it by looking at the code

使用@Controller来完成处理 HTML 页面的工作,并使用存储库,您可以通过用于 crud 等基本操作的 REST APISPRING-DATA-REST公开实体来公开您的实体。我想你已经通过查看代码做到了

 @RestResource(rel = "by-id") 
    Marker findMarkerById(String id);

Expose Business logic

暴露业务逻辑

If you want to expose any business logic, you have to create a Servicelayer and simply call it via your @Controllerfor the web page. and create another controller as @RestControllerfor the web API interface.

如果您想公开任何业务逻辑,您必须创建一个Service层并通过您@Controller的网页调用它。并@RestController为 Web API 接口创建另一个控制器。

You may note, you are not duplicating any code here, as the logic is written at the single point in the Service layer. But using different controllers for different purposes.

您可能会注意到,这里没有复制任何代码,因为逻辑是在服务层的单个点编写的。但是为了不同的目的使用不同的控制器。

As you don't need all the logic in web page to get exposed to API, use of separate controller for REST may be a clean design implementation for your code if you can namespace your code as app.weband app.api.

由于您不需要将网页中的所有逻辑都暴露给 API,因此如果您可以将代码命名为app.weband ,那么为 REST 使用单独的控制器可能是您代码的干净设计实现app.api

Food for thought

深思熟虑

Use a complete REST API implementation for web pages and android. Then use AngualarJSor backboneJsto do the client side implementation with HTML5. I think this is the future.

为网页和 android 使用完整的 REST API 实现。然后使用AngualarJSbackboneJs使用 HTML5 进行客户端实现。我认为这就是未来。

回答by Guy Pardon

You can use @RestController for both Thymeleaf HTML and REST/JSON it seems.

您似乎可以将 @RestController 用于 Thymeleaf HTML 和 REST/JSON。

The following works for me:

以下对我有用:

@RestController
@RequestMapping("/projects")
public class ProjectController {

        /**
         * A REST reponse (JSON)
         * 
         * @param name
         * @return
         */
        @GetMapping(value = "/{name}")
        public Project get(@PathVariable String name) {
            return new Project(1l, name); 
        }

        /**
         * A thymeleaf HTML response
         */
        @GetMapping(value = "/hello.html")
        public String getAsHtml() {
            return "hello"; //name of the html file in src/main/resources/templates
        }
}