带有数据库设计的 Servlet

Posted

技术标签:

【中文标题】带有数据库设计的 Servlet【英文标题】:Servlets with Database design 【发布时间】:2011-10-25 19:11:37 【问题描述】:

我有一个关于使用 Servlet 和 JDBC 的一般性问题。

例如,我有一个名为 MyDatabaseManager 的类,它提供了函数

公共布尔更新用户(用户用户)... 公共布尔删除用户(用户用户)... 公共布尔inserUser(用户用户)...

,这些函数将访问和操作数据库。

我的问题是关于 Servlet 的实现。我目前正在使用三个 Servlet(UpdateUserServlet、InsertUserServlet 和 DeleteUserServlet),每个 Servlet 都调用 MyDatabaseManager 实例(这里只有一个实例,使用单例模式)函数。 (例如,UpdateUserServlet 调用 MyDatabaseManager.updateUser ...)。

我认为这是使用 Servlet 和数据库最直接的方式。但我不确定这是否是正确的做法。例如,这在工业界是如何实施的。

【问题讨论】:

这很快就被接受了,我看到这被接受了,而我正在扭动我的帖子。 【参考方案1】:

在工业界,我们都是为了简单。例如,对于从浏览器到服务器再到持久性存储(数据库)的用户交互,我们遵循这些方法。

首先是MVC 模式。这将允许我们完全为从浏览器到服务器的每个用户交互编写一个 Servlet。这允许我们做以下事情:

允许控制器处理用户请求并将其链接到我们的用户操作(我们的模型)。该模型允许我们编写业务逻辑来响应用户数据。

在当今的 Java 世界中,存在满足我们 MVC 要求的框架。出现在 Java 框中的是JSF(JavaServer Faces)。

对于后端,我们肯定使用数据库,但我们也很聪明,使用ORM(对象关系映射)将我们的现实问题建模为对象模型,以及如何最好地保存(存储)这些对象模型。有的使用ERM(Entity-Relational Modelling)来设计语义数据模型。

在中间,业务逻辑,我们添加一个服务(作为业务逻辑层)不想关心在哪里读/写数据,只要他们能看到它想要的数据。为此,添加了一个服务层来促进这一点。本质上我们有这种效果。

public class ActionServlet extends HttpServlet 

    //Action registration
    public void init() 
        ActionMapping mapping = .....; //some instatiation
        mapping.setAction("/userRegistration", UserRegistrationAction.class);

        //Save it in Application Scope
        getServletContext().setAttribute("actionConfig", mapping);
    

    private void doAction(HttpServletRequest request, HttpServletResponse response) throws Exception 
        String path = request.getPathInfo();

        Action action = ((ActionMapping)getServletContext().getAttribute("actionConfig")).getAction(path);
        if (action == null) 
            throw new Exception("No action of '" + path + "' found.");
        

        action.execute(request, response);
    

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws Exception 
        doAction(request, response);
    

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception 
        doAction(request, response);
    



public abstract class Action 

    public abstract void execute(HttpServletRequest request, HttpServletResponse response) throws Exception;

    protected void dispatch(HttpServletRequest request, String path) 

        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    



public class UserRegistrationAction extends Action 

    public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception 
        //Business Logic goes here...
        //Call DAO,
        UserRegistrationDAO dao = ; //Some DAO instantation
        User user = createUserFromForm(request);
        dao.save(user);

        dispatch(request, "success");
    

关于持久性,Java 5 及更高版本带有JPA。您可以使用任何形式的 ORM,具体取决于您的项目范围。有 Hibernate(它也支持 JPA),或者如果您愿意,可以编写自己的 DAO。

还有一点,将所有这些过程粘合在一起很乏味。幸运的是,我们有框架可以帮助我们更轻松地制作上面的漂亮示例。像JBoss Seam 这样的框架就是这样做的,它完全使用Java 规范。现在,选择简单的设计模型和 MVC(用于学习目的)。当您习惯了架构后,请使用框架。

【讨论】:

【参考方案2】:

这肯定是设计选择的问题,您可以采用像 Spring、Struts 等这样的框架,这会更容易。或者,如果你想使用经典的 servlet 请求/响应模式,我建议创建一个父 servlet,它会拦截请求并将其传递给正确的方法来执行请求。

此外,您还可以选择各种 ORM 解决方案,例如 Hibernate、JPA 等。您可以使用它们来处理您的数据库访问操作。然而,如果您选择坚持使用经典的 JDBC 调用,您可以使用Filters and Handlers 来决定哪些调用提供包装数据库连接和操作。

【讨论】:

【参考方案3】:

很难回答,因为那里有数百种设计模式!我知道一个关于数据库管理的好方法叫做 DAO(数据访问对象)。我经常使用这个。我建议你看看。

不要误会我的意思,单例来容纳你的经理是个好主意。几乎我通常也是这样做的。但是,通常我有一个 DAOFactorySingleton,它几乎有责任在我的应用程序中生成所有类 DAO,这个工厂很好,因为我可以有一些 DataSource 规则,这个工厂只是从某个地方轮询并注入我的 DAO!因此,几乎每个 DAO 都不必关心 JDBC 连接之类的事情!

点击 2 个链接,了解有关 DAO 的更多信息! http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

http://community.jboss.org/wiki/GenericDataAccessObjects

第二个是配合hibernate使用的!你可以阅读它,而不是强制使用休眠。我真的很喜欢第二个,不过更复杂。

【讨论】:

谢谢,亚瑟。特别是对于链接。【参考方案4】:

业内很多使用ORM+依赖注入框架+事务管理器+数据库池库,例如Hibernate(ORM)+Spring DI(依赖注入)+Spring事务管理器(事务管理器)+Apache DBCP(数据库连接池) .

有时当使用 ORM 不合理时(例如非常简单的 DB 模式、ORM 性能开销由于应用程序的性质而令人望而却步等),开发人员可能会使用原始 JDBC。许多人仍然会使用依赖注入和数据库连接池。

使用依赖注入或数据库连接池是非常罕见的。也就是说,除非它是一个非常罕见的特殊应用程序,否则行业中的开发人员确实会使用依赖注入框架和数据库连接池。

在这种情况下,需要管理的状态由 DB 连接池框架管理,因此您不必担心状态管理或线程安全(只要您自己不在不同线程之间共享任何内容,并且遵循 DB 连接池框架的 API)。即,您不需要单例。如果您实现自己的数据库连接池,那么使用单例将是有意义的。

如果开发人员不想使用任何框架(例如,创建一个非常简单的工具),那么许多人只会每次都打开一个连接(对于每个线程)。在这种情况下,您再次不需要管理任何状态,因此您不需要单例。

【讨论】:

【参考方案5】:

现在人们并没有真正直接使用 servlet,他们使用允许您简化工作的框架,但是如果您真的想使用 servlet,您可以使用其他方法,doPut,将所有操作放在一个单独的一个中, doDelete 甚至创建自己的方法。以下是您将如何执行此操作的示例:

public abstract class BaseServlet extends HttpServlet 

    @Override
    protected void service(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException 
        String method = request.getParameter("_method");
        if ("form".equals(method)) 
            this.doForm(request, response);
         else 
            if ("delete".equals(method)) 
                this.doDelete(request, response);
             else 
        super.service(request, response);
            
        
   

   protected void doForm(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException 
        throw new UnsupportedOperationException();
   


如您所见,此 Servlet 在表单上使用特殊字段 _method 来决定调用什么特殊方法,如果 _method 不可用,它将使用通常的服务方法,将调用 doGetdoPost

下面是这个 servlet 的实现方式:

public class UsersServlet extends BaseServlet 

private UsersRepository cadastro = new UsersRepository();

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException 

    req.setAttribute("usuarios", cadastro.list());
    req.getRequestDispatcher("/usuarios/listar.jsp").forward(req, resp);



@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException 

    User usuario = this.getUser(req);

    usuario.setNome(req.getParameter("nome"));
    usuario.setEmail(req.getParameter("email"));
    usuario.setSenha(req.getParameter("senha"));

    this.cadastro.persist(usuario);

    resp.sendRedirect(req.getContextPath() + "/usuarios");



protected User getUser(HttpServletRequest req) 
    User usuario;

    if (req.getParameter("id") == null) 
        usuario = new Usuario();
     else 
        Long id = new Long(req.getParameter("id"));
        usuario = this.cadastro.search(id);
    

    return usuario;


@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException 
    User usuario = this.getUser(req);
    this.cadastro.remover(usuario);
    resp.sendRedirect(req.getContextPath() + "/usuarios");


@Override
protected void doForm(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException 

    User usuario = this.getUser(request);

    request.setAttribute("usuario", usuario);
    request.getRequestDispatcher("/usuarios/form.jsp").forward(request,
            response);



这样您就可以在一个 servlet 中完成所有工作。

【讨论】:

谢谢,这正是我要找的。接受。 这也是一个糟糕的反模式解决方案。 您愿意解释一下原因吗?这只是一个符合 REST 的 servlet。【参考方案6】:

Database 类上的 Singleton 听起来不错,尤其是因为它似乎包含更新/删除/插入代码。

如果您使用的是连接池,请确保您单例化 DataSourceFactory。

【讨论】:

以上是关于带有数据库设计的 Servlet的主要内容,如果未能解决你的问题,请参考以下文章

课程设计---快递管理系统(boostrap + servlet + jQuery + Redis + MySQL)

Web实验-Servlet控制层设计HTML-分层

javaweb基于servlet天气预报查询系统设计与实现(项目源码)

[javaEE] javaweb的mvc设计思想

如何用jsp,servlet完成一个简单的用户登录的MVC模式设计的实现

servlet数据传递