Java 不直接写 Servlet 来创建 REST API 的原因

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21947300/
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-08-13 11:33:44  来源:igfitidea点击:

Reasons for not directly writing Servlets for creating a REST API

javarestspring-mvcservletsjax-rs

提问by raspacorp

In my current company we are starting a new project that will be a REST API in Java, deployed in a servlet container like Tomcat. In my previous experience using REST frameworks like JAX-RS with Jersey, JBOSS REST Easy, Spring MVC I know what are some of the advantages of using a framework like those over writing directly the Servlets for processing the requests.

在我目前的公司中,我们正在启动一个新项目,该项目将是 Java 中的 REST API,部署在 Tomcat 等 servlet 容器中。在我之前使用 JAX-RS 和 Jersey、JBOSS REST Easy、Spring MVC 等 REST 框架的经验中,我知道使用像直接编写 Servlet 来处理请求的框架有哪些优点。

(Of course we know that the mentioned frameworks still use Servlets under the covers)

(当然我们知道上面提到的框架仍然在幕后使用 Servlets)

I am finding difficult to convince them. As they are proposing to write servlets thinking it is better for performance (which can be the case but I think the overhead of using one of those frameworks should be insignificant for a REST API).

我发现很难说服他们。因为他们提议编写 servlet,认为它对性能更好(可能是这种情况,但我认为使用这些框架之一的开销对于 REST API 来说应该是微不足道的)。

Here are my reasons:

以下是我的理由:

1) Less boilerplate and more concise code(which is easier to maintain and test). With a JAX-RS framework or SpringMVC you can define a REST resource very easily by writing methods with annotations indicating the PATH of the resource, the http method to use, query and url parameters, headers like encoding accepted, etc.

1)更少的样板和更简洁的代码(更易于维护和测试)。使用 JAX-RS 框架或 SpringMVC,您可以通过编写带有注释的方法来非常轻松地定义 REST 资源,这些注释指示资源的 PATH、要使用的 http 方法、查询和 url 参数、接受的编码等标头。

Example:

例子:

@GET
@Path("/users")
@Produces({MediaType.APPLICATION_JSON}) 
public UserList getUsers(@QueryParam("group") String group) {
    return userService.findUsers(group);
}

With servlets you will need at least something like this:

使用 servlet,您至少需要这样的东西:

Map the url for each servlet in web.xml (Which is not necessary in and above Servlet 3.0):

在 web.xml 中映射每个 servlet 的 url(在 Servlet 3.0 及以上版本中不需要):

<servlet>
    <servlet-name>UsersServlet</servlet-name>
    <servlet-class>test.UsersServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UsersServlet</servlet-name>
    <url-pattern>/users</url-pattern>
</servlet-mapping>

Then inside the servlet class:

然后在 servlet 类中:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    String group = request.getParameter("group");
    response.setContentType("application/json");
    PrintWriter out = response.getWriter();
    JsonSerializer someJsonSerializer = new JsonSerializer();
    String json = someJsonSerializer.serialize(userService.findUsers(group));      
    out.print(json);
}

2) Adaptability. The mentioned frameworks allow you to easily add features to your application that otherwise you will need to do it manually, like using multiple media type inputs and outputs. For example making a service to return xml or json or any other depending on the accept header. Frameworks like SpringMVC and Jersey make it very easy to configure serializers/deserializers for your requests, responses.

2)适应性。提到的框架允许您轻松地向应用程序添加功能,否则您将需要手动完成,例如使用多种媒体类型的输入和输出。例如,使服务返回 xml 或 json 或任何其他取决于接受标头的服务。像 SpringMVC 和 Jersey 这样的框架可以很容易地为您的请求、响应配置序列化器/反序列化器。

3) REST best practices. Normally those frameworks are built over a solid understanding of the best practices to be followed by a REST API and are defined based on standards of the REST architecture which makes easier to build a solid and standard conforming application. In the other hand Servlets give you a so high level of freedom on how to process your requests/responses that it will be more difficult to realize that you are not being RESTfull at all.

3) REST 最佳实践。通常,这些框架建立在对 REST API 应遵循的最佳实践的深刻理解之上,并基于 REST 架构的标准进行定义,这使得构建可靠且符合标准的应用程序变得更加容易。另一方面,Servlet 在如何处理请求/响应方面为您提供了如此高的自由度,以至于您很难意识到您根本不是 RESTfull。

Any other?

任何其他?

回答by Geoff Genz

First, I would consider setting up a simple test with two applications which have a "Hello World" servlet -- one with pure servlets, one with Spring MVC or Apache CXF or your framework of choice. Then run a performance test to prove (hopefully) that the performance hit is insignificant.

首先,我会考虑使用两个具有“Hello World”servlet 的应用程序设置一个简单的测试——一个带有纯 servlet,一个带有 Spring MVC 或 Apache CXF 或您选择的框架。然后运行性能测试以证明(希望如此)性能影响是微不足道的。

Also, serializers and deserializers are one good example, but the interceptor/filter pattern that is available in these frameworks is very useful for other things as well:

此外,序列化器和反序列化器是一个很好的例子,但这些框架中可用的拦截器/过滤器模式对于其他事情也非常有用:

  • Authentication/Security
  • Logging of raw requests if needed
  • Header and content transformations that can be kept separate from business logic
  • 认证/安全
  • 如果需要,记录原始请求
  • 可以与业务逻辑分开的标题和内容转换

In addition, there are tools that plug into these frameworks that will generate documentation (WADLs/WSDLs/Enunciate) and client class libraries. There are also testing libraries that can be used to generate automated tests against well known frameworks.

此外,还有一些工具可以插入到这些框架中,这些工具将生成文档(WADLs/WSDLs/Enunciate)和客户端类库。还有一些测试库可用于针对众所周知的框架生成自动化测试。

I used to reinvent the wheel too. But it no longer makes sense (if it ever did.)

我也曾经重新发明轮子。但它不再有意义(如果它曾经有过。)

回答by stepanian

Let me play the devil's advocate with my answer.

让我用我的答案装扮魔鬼的拥护者。

First, you don't need to add the servlets to the web.xml file. Servlets 3.0 allow you to use annotations.

首先,您不需要将 servlet 添加到 web.xml 文件中。Servlets 3.0 允许您使用注释

Second, there really is a significant performance hit with these frameworks. See these benchmarks

其次,这些框架确实对性能造成了重大影响。查看这些基准

Third, you can use GSONwithin a servlet, which is faster than Hymanson (used by default in Spring and Jersey). This gets you even more performance especially considering that performance is critical to your requirements.

第三,您可以在 servlet 中使用GSON,它比 Hymanson 更快(在 Spring 和 Jersey 中默认使用)。这会让您获得更高的性能,尤其是考虑到性能对您的要求至关重要。

Finally, if you are concerned about boilerplate, put that code that you wrote inside the servlet in some utility class and use it from multiple servlets. That beats carrying around a framework's huge load when you (like most people) would probably be using a small fraction of its functionality.

最后,如果您担心样板文件,请将您在 servlet 中编写的代码放在某个实用程序类中,并在多个 servlet 中使用它。当您(像大多数人一样)可能会使用框架功能的一小部分时,这胜过承担框架的巨大负载。

回答by Pedreiro

For me the real advantage of using Spring MVC is the increase of productivity. Writing everything from scratch to tune things up make sense if you need a really customized application. Although it can be cool to create something new with no frameworks at all, when it gets bigger, you will face problems that were already solved by hundreds of damn good developers. Using Spring MVC will save you a lot of time that you would probably waste reinventing the wheel and even more time when you will have to train someone to deal with your awesome custom code.

对我来说,使用 Spring MVC 的真正优势是生产力的提高。如果您需要一个真正定制的应用程序,从头开始编写一切以进行调整是有意义的。尽管在完全没有框架的情况下创建新东西可能很酷,但当它变得更大时,您将面临已经由数百名优秀开发人员解决的问题。使用 Spring MVC 将为您节省大量时间,您可能会浪费重新发明轮子的时间,甚至在您必须培训某人处理您出色的自定义代码时还会有更多时间。

回答by Orden

Serveral monthes ago I put a comment saying that I was for the pure Servlet 3.0 solution against the use of RES MVC frameworks.

几个月前,我发表评论说我反对使用 RES MVC 框架的纯 Servlet 3.0 解决方案。

After monthes of usage, I confirm my choice!

经过几个月的使用,我确认了我的选择!

I tried to install Hymanson and others frameworks but it needs more work than writing the extra 5 lines of code and I don't have to cope with an extra software component to setup, learn, update...

我尝试安装 Hymanson 和其他框架,但它比编写额外的 5 行代码需要更多的工作,而且我不必处理额外的软件组件来设置、学习、更新......

Here is my working example:

这是我的工作示例:

package example;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;

/**@WebServlet(name = "booking", urlPatterns = { "/api/v1/booking" })*/
public class BookingWs extends javax.servlet.http.HttpServlet {

    public static final Logger LOGGER = LoggerFactory.getLogger(BookingWs.class);

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        try {
            // Used for JSON handling
            Gson gson = new Gson(); 

            // De-serialize from request
            BookingRequest bRequest = gson.fromJson(request.getReader(), BookingRequest.class);

            // Do your business logic.
            BookingResponse bResponse = new BookingResponse();
            bResponse.request = bRequest;
            bResponse.accepted = "bar".equalsIgnoreCase(bRequest.type);
            bResponse.reason = bResponse.accepted ? "Welcome" : "Only bar table booking left";

            // Serialize and send response back;
            response.setContentType("application/json");
            PrintWriter pw = response.getWriter();
            gson.toJson(bResponse, pw);
        } catch (Throwable t) {
            response.setStatus(500);
            PrintWriter pw = response.getWriter();
            pw.write("{\"error\":\"" + t.getLocalizedMessage() + "\"}");
        }
    }
}

class BookingRequest{
    String type;
    int seats;
    String name;
    long requiredTimestamp;
}

class BookingResponse{
    BookingRequest request;
    boolean accepted;
    String reason;
}  

Maybe theses frameworks have a feature you need absolutely, but for me it should be decisive enought to worth the hassle of extra libs.

也许这些框架有一个你绝对需要的功能,但对我来说,它应该是决定性的,值得额外库的麻烦。

As a French author Antoine de Saint Exupery said:

正如法国作家安托万·德·圣·埃克苏佩里 (Antoine de Saint Exupery) 所说:

"Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away".

“完美不是在没有什么可添加的时候实现,而是在没有什么可以带走的时候实现”。

I took away Hymanson to get closer to it :-)

我带走了Hyman逊以接近它:-)

(Yes I have to admit, I used GSON, but it's a small jar, without any configuration needed).

(是的,我不得不承认,我使用了 GSON,但它是一个小罐子,不需要任何配置)。