Java Web应用程序MVC方法需要批评

时间:2010-11-12 00:23:21

标签: java model-view-controller web-applications

我有一个servlet,它调用传递形式和对象的通用actions(取决于操作需要的内容)

CommitmentServlet.java

CommitmentListDAO clDAO = new CommitmentListDAO();
CommitmentItemForm form = new CommitmentItemForm(clDAO);
CommitmentItem obj = new CommitmentItem();

actionMap.put(null, new ListAction(form);
actionMap.put("list", new ListAction(form);
actionMap.put("view", new ViewAction(form, obj)
actionMap.put("delete", new DeleteAction(form, obj);
actionMap.put("edit", new EditAction(form, obj);

ControllerAction action = (ControllerAction) actionMap.get(request.getParameter("method"));
action.service(request, response);

EditAction.java

public class EditAction implements ControllerAction {
  private Form form;
  private Object obj;

public EditAction(Form form, Object obj) {
    this.form = form;
    this.obj = obj;
}

public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    obj = form.edit(request);

    request.setAttribute("obj", obj);
    request.setAttribute("form", form);

    if (form.isSucces()) {
        RequestDispatcher view = request.getRequestDispatcher(success page);
        view.forward(request, response);
    }
    else {
        RequestDispatcher view = request.getRequestDispatcher(failure page);
        view.forward(request, response);
    }
}
}

实际业务逻辑位于传递给通用操作的form对象中 通用操作允许我快速获取任何新对象的CRUD控制器功能。我只需要编写业务逻辑form,例如此处

CommitmentItemForm.java

public Object edit(HttpServletRequest request) {
    CommitmentItem commitmentItem = null;
    STKUser authenticatedUser = (STKUser) request.getSession().getAttribute("STKUserSession");
    String ownedByBadge = null;
    List deptSupervisorList = null;

    try {
        deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment()); //<--- Static call is it OK??
        commitmentItem = CommitmentListDAO.retreive(request.getParameter("commitment_id"), authenticatedUser);
        ownedByBadge = commitmentItem.getOwned_by();
    }
    catch (DAOException e) {
        setError(FORM_RESULTS, e.getMessage());
    }
    catch (ValidatorException e) {
        // ValidatorExceptions are thrown when the DAO can not find a record
        setError(FORM_RESULTS, e.getMessage());
        LOGGER.log(Level.INFO, e.getMessage(), authenticatedUser);
    }

    if (ownedByBadge != null) {
        if (ownedByBadge.equals(authenticatedUser.getBadge()) || ownedByBadge.equals(authenticatedUser.getAtaBadge())) {
        }
        else {
            setError(FORM_RESULTS, "You are not authorized to edit this data.");
            LOGGER.log(Level.INFO, "Error - You are not authorized to edit this data '" + commitmentItem.getCommitment_id() + "'", authenticatedUser);
        }
    }
    request.setAttribute("deptSupervisorList", deptSupervisorList);  // <--- Is this acceptable to do???
    return commitmentItem;
}

1)是我设置请求属性并在正统方法中返回对象的方法吗? 2)我正在进行静态调用以获取deptSupervisorList。这是在寻求麻烦吗? 3)我的servlet,通用操作,业务表单是否是一种不使用框架开发java Web应用程序的可接受方法?

编辑: 有什么区别?

Static
deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment()); 

VS

non-static
STKUserDAO userDAO = new STKUserDAO();
deptSupervisorList = userDAO.getList(authenticatedUser.getDepartment()); 


public static List getList(String dept) throws DAOException {
   ...
}

1 个答案:

答案 0 :(得分:2)

首先注意一些事项:

  • 这是主观的
  • 我同意SidCool的看法,答案是看一下现有的一些Web应用程序框架。如果有的话,只是为了了解他们是如何做到的。
  • 我是依赖注入的忠实粉丝

回答你的问题:

  • 在请求属性中传递数据并不好,因为:它不是类型安全的;它是一个看不见的东西 - 如果你能看到类型签名中的输出对象总是更好;在某些时候,你会发现自己想要在同名的请求属性中存储两件事
  • 依赖注入是未来的发展方向。进行静态调用是不好的,因为:你现在已经将两个对象紧密耦合,使得重用更加困难,并且使测试更加困难
  • 我肯定会看看其他一些框架。他们中的大多数往往只有一个调度servlet,我想你最终会编写一个非常相似的servlet lot 。许多框架也将使用反射尝试尽可能早地尽可能早地完成请求和POJO之间的转换。

其他:

  • 您的所有操作都是关闭参数,即?method = [list,view,delete,edit]。通常最好使用路线(例如,index.html通常用于'列表')。

从评论中回答您的反馈/问题:

在旧版Java上运行

哇,太糟糕了。但是,有一些框架可以在Java 1.4上运行。 Spring MVC将是我的推荐,但还有更多here。也就是说,我建议查看其他框架的原因不仅仅是使用它们,而是更多地受到它们的启发。编写自己的Web应用程序框架实际上是一个成熟的仪式,可以很有趣。在如此受限的环境中编写它只会增加挑战。

我建议:

  • 尝试最近的Java框架甚至非Java框架(例如Ruby on Rails),只是为了看看有什么可能
  • 在编写自己的唯一框架时,只需使用1个servlet并分发给各种“控制器”。这样做的原因是Servlet并不擅长将整个应用程序放在一起(Spring MVC所做的是,使用ContextListener加载'应用程序',然后servlet和过滤器从ServletContext中查找'应用程序')< / LI>

静态

的紧耦合

紧耦合是指两个物体彼此无法使用的情况。你问,为什么这很糟糕?因为您永远不能将代码重用于其他内容(例如,如果您决定从文件加载一些数据,引入缓存层,在不同的项目中使用它等)。最重要的是,有些人会说,很难对它进行测试。这是因为您不能只是将您静态调用的对象替换为另一个对象。接口通常用于解耦对象,但实际上,您可以通过在依赖注入中设置对象来做到这一点(这是一种复杂的说法:将它放在构造函数中或作为setter)。

OO并且是土木工程师

一切都很好。我认识的一些最好的程序员并没有这样开始。对我来说,使用依赖注入模式是默认编写“好”代码的一种很棒的方法。注意:如果查看依赖注入,则不需要框架。您只需要在一个地方构建所有对象,并且所有对象都应该在构造函数或setter中获取所有依赖项。不允许使用静态方法或单例。

有什么区别

更好地说明我的意思的另一种“有什么区别”将是这样的:

// code in your application builder
// assuming an interface called UserDAO
UserDAO userDAO = new STKUserDAO();
CommitmentItemForm form = new CommitmentItemForm(userDao);


public class CommitmentItemForm {

  private final UserDAO userDao;
  public CommitmentItemForm(UserDAO userDao) { this.userDao = userDao; }

  public Object edit(HttpServletRequest request) {
    ...
    deptSupervisorList = userDao.getList(authenticatedUser.getDepartment());
    ...
  }

}

VS

public class CommitmentItemForm {

  public CommitmentItemForm()

  public Object edit(HttpServletRequest request) {
    ...
    deptSupervisorList = STKUserDAO.getList(authenticatedUser.getDepartment());
    ...
  }

}

静态方法肯定看起来不那么有用,为什么它如此糟糕?从本质上讲,这是因为在静态版本中,除了STKUserDAO之外,你永远不能从任何东西中查找deptSupervisorList。在非静态版本中,您可以提供UserDAO接口的任何实现。这意味着您可以使用相同的CommitmentItemForm代码,无论是否:

  • 您是在测试中进行的,并且您正在创建一个模拟版本的UserDAO,每次都返回一个异常,以便您可以测试
  • 您发现需要从JSON HTTP REST Web服务或文件中检索部门列表

从CommitmentItemForm的签名中也很明显,它需要UserDAO才能运行(因为它在构造函数中是必需的)。

如果您使用所有代码执行此操作,这将是您的代码之一,您会发现您的代码不仅更灵活,更可测试,更可重用以及您突然发现需要更改的部分在未来更好地孤立。