当前位置: 首页 > 知识库问答 >
问题:

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

谷弘致
2023-03-14

在我现在的公司,我们正在启动一个新项目,它将是Java的REST API,部署在像Tomcat这样的servlet容器中。在我以前使用REST框架的经验中,如JAX-RS与泽西、JBOSS REST Easy、Spring MVC,我知道使用像这样的框架比直接编写Servlet来处理请求有什么优势。

(当然,我们知道上述框架仍在幕后使用servlet)

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

以下是我的理由:

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

例子:

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

使用servlets,您至少需要以下内容:

映射web中每个servlet的url。xml(在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>

然后在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) 适应性。上述框架允许您轻松地向应用程序添加功能,否则您将需要手动添加这些功能,如使用多种媒体类型的输入和输出。例如,使服务返回xml或json或任何其他内容,具体取决于accept标头。像SpringMVC和Jersey这样的框架使得为您的请求、响应配置序列化器/反序列化器变得非常容易。

3)REST最佳实践。通常,这些框架是建立在对REST API所遵循的最佳实践的坚实理解之上的,并且是基于REST体系结构的标准来定义的,这使得构建一个坚实且符合标准的应用程序变得更加容易。另一方面,Servlet给你一个如此高的自由度来处理你的请求/响应,以至于很难意识到你根本没有被RESTful。

还有别的吗?

共有3个答案

富涛
2023-03-14

首先,我会考虑用两个有“Hello World”servlet的应用程序设置一个简单的测试——一个有纯servlet,一个有Spring MVC或Apache CXF或您选择的框架。然后运行性能测试来证明(希望)性能命中是无关紧要的。

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

  • 身份验证/安全性
  • 记录原始请求(如果需要)
  • 可以与业务逻辑分开的标题和内容转换

此外,还有一些工具插入到这些框架中,它们将生成文档(WADL/WSDLs/Enounciate)和客户端类库。还有一些测试库可以用来生成针对知名框架的自动化测试。

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

暨宸
2023-03-14

几个月前,我发表了一条评论,说我支持纯Servlet3.0解决方案,反对使用RESTMVC框架。

使用数月后,我确认我的选择!

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

以下是我的工作示例

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;
}  

也许这些框架有一个您绝对需要的特性,但对我来说,它应该足够决定性,值得额外的lib来处理。

正如法国作家Antoine de Saint Exupery所说:

“完美不是在没有更多的东西可以补充的时候,而是在没有什么东西可以带走的时候。”。

我把杰克逊带走是为了更接近它:-)

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

蔚楷
2023-03-14

让我用我的答案来做魔鬼代言人吧。

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

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

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

最后,如果您关心样板,请将您在servlet中编写的代码放在某个实用程序类中,并在多个servlet中使用它。当你(像大多数人一样)可能只使用框架的一小部分功能时,这比随身携带框架的巨大负载要好。

 类似资料:
  • 001/电视购买/约翰·史密斯/真 002/冰箱购买/让·史密斯/假

  • 我对Springboot很陌生。我需要创建一个接受Excel文件的rest API。我需要使用excel文件中的数据来执行操作。我知道如何用@RequestParam和@RequestBody创建API,但不知道如何为excel文件创建API。我没有将文件存储在数据库中,所以不需要模型。我在网上搜索,但看到所有的资源谈论通过客户端上传文件。我想对我的API中收到的文件进行操作。

  • 问题内容: 我对React.js还是很陌生,但是在探索它时,我期望我做不到的事情。 说我有一个组成部分: 这是将其添加到DOM的唯一方法吗? 我希望在定义组件之后能够直接在HTML中执行类似的操作: 我想念什么吗?谢谢 问题答案: 不,使用是“唯一的方法”。 您可能会期望像Webcomponents这样的东西,您可以在其中定义自定义元素并将其放入HTML中,但这不是React的工作方式(也许)。

  • 最简单的Servlet类就是继承HttpServlet类的空类,如下面代码如示: public class EmptyServlet extends HttpServlet { } 在访问EmptyServlet时会显示如图4.3所示的异常信息。   图4.3 访问EmptyServlet抛出的异常 从错误信息可以看出,抛出异常的原因是由于EmptyServlet不支持GET方法所导致。实际上

  • 我正在使用现有的Java代码,其中在部署的系统上有一个现有的JDBC连接池机制,并且有一个已经存在的获取JDBC连接的设置。我想利用这一点来创建MyBatis SqlSession对象,而不创建配置、数据源和其他东西 我的代码已经创建了对象,并为其提供了所需的资源。我想利用这一点,获得对象,并从此使用MyBatis。 我不希望MyBatis管理连接池,确定使用哪个数据源等等,这可能吗?

  • Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。 可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。调用 Servlet 前调用所有附加的 Servlet 过滤器。 Servlet 过滤器是可用于 Servlet