如何在不使用任何框架但 Tomcat + Servlet 的情况下实现关注点分离?

How to achieve separation of concerns without using any framework but Tomcat + Servlets?

我有一个运行良好的代码。重要部分如下:

我的模型class:

package biz.tugay.sakila.model;
/* User: koray@tugay.biz Date: 25/06/15 Time: 12:48 */

public class Actor {

    private long id;
    private String firstName;
    private String lastName;

    // Getters, setters... 
}

我的daoclass:

package biz.tugay.sakila.dao;
/* User: koray@tugay.biz Date: 25/06/15 Time: 12:12 */

import biz.tugay.sakila.model.Actor;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class ActorDao {

    protected static final Connection connection = DBConnector.getConnection();

    public List<Actor> getAllActors() throws SQLException {

        List<Actor> allActors = new ArrayList<Actor>();

        Statement stmt = connection.createStatement();
        String sql = "SELECT * FROM Actor";

        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()) {
            Actor actor = new Actor();
            actor.setFirstName(rs.getString("first_name"));
            // You get the idea... Setters again..
            allActors.add(actor);
        }

        rs.close();
        stmt.close();

        return allActors;
    }
}

DBConnector

package biz.tugay.sakila.dao;
/* User: koray@tugay.biz Date: 25/06/15 Time: 12:35 */

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnector {

    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost/sakila";
    static final String USER = "root";
    static final String PASS = "";

    private static Connection connection = null;

    public static final Connection getConnection() {
        if (connection != null) {
            return connection;
        } else {
            try {
                Class.forName(JDBC_DRIVER);
                connection = DriverManager.getConnection(DB_URL, USER, PASS);
                return connection;
            } catch (ClassNotFoundException e) {

            } catch (SQLException e) {

            }
            throw new UnsupportedOperationException();
        }
    }

}

我的Servletclass:

package biz.tugay.sakila.servlet;
/* User: koray@tugay.biz Date: 26/06/15 Time: 14:31 */

import biz.tugay.sakila.dao.ActorDao;
import biz.tugay.sakila.model.Actor;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

@WebServlet(urlPatterns = "/actors")
public class ActorServlet extends HttpServlet {

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

        ActorDao actorDao = new ActorDao();
        List<Actor> allActors = null;

        try {
            allActors = actorDao.getAllActors();
            req.setAttribute("allActors",allActors);
            req.getRequestDispatcher("/actors.jsp").forward(req, resp);
        } catch (SQLException e) {

        }
    }
}

/actors.jsp将向用户显示HTML table。

我自己使用 sakila 示例数据库 MySQL 提供的 进行了此练习。

我的问题是,如果不使用Spring或Struts之类的框架,如何实现更好的分离?例如,目前 ActorServlet 具体依赖于 ActorDao,我可以解决这个问题吗?如果可以,如何解决? ActorDao 也严重依赖于 DBConnector。例如,我希望能够创建一个 NoSQL 连接器并使用它,但我猜目前我不能?

第一步是抽象出一些接口。例如,将 ActorDao 设为接口,将实现移至 ActorDaoImpl 或其他任何地方。创建一个 ActorDaoFactory 给你一个 ActorDao ,在幕后是一个 ActorDaoImpl,但 servlet 不需要知道它。

第二步比较复杂...如果你想使用Tomcat,那么注入之类的就out了,但是你可以配置Tomcat 创建这些新接口并将它们放入 JNDI 中。这个过程可能太复杂了,不能在这里给出答案,但是 Tomcat documentation on JNDI 真的很好。这个过程基本上涉及创建一个工厂,就像我在上面提倡的那样,然后 Tomcat 通过配置调用该工厂。

一旦你这样做了,从 JNDI 中查找它们就像

一样简单
// Obtain our environment naming context
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");

// Look up our DAO
ActorDao ad = (ActorDao)envCtx.lookup("dao/actor");

祝你好运!