【问题标题】:Web User Interface for a Java applicationJava 应用程序的 Web 用户界面
【发布时间】:2010-11-19 23:41:35
【问题描述】:

我正在尝试为 Java 应用程序创建 Web 用户界面。用户界面将非常简单,由一个带有供用户提出查询的表单的页面和一个结果页面组成——有点像谷歌的搜索引擎或 Ask.com。

我对 Java 的基本 API 非常熟悉,但是我没有太多在 Web 环境中使用 Java 的经验(虽然我使用过 ASP.NET),所以我正在寻找一些建议:

  • 我应该使用什么 Web 应用程序服务器请注意,我的界面非常轻巧,我只想要快速、易于启动/重置的东西/stop 并(重新)部署我的应用程序。此外,我需要它在多种环境上工作,即 GNU/Linux、Mac OS X 和 Windows XP/Vista。此外,我正在使用antEclipse,所以如果我可以轻松添加一些ant 目标用于服务器管理,和/或使用IDE 管理服务器,那就太好了。我研究过 TomcatJetty,后者似乎非常轻巧且易于安装和部署。这是理想的,因为 GUI 仅用于演示目的,我可能需要将它部署在不同的计算机上。不过Tomcat已经存在了很长时间,而且看起来更加成熟。

  • 至于 网页,Java 服务器页面看起来很合适,因为它们对于我想要完成的任务(处理表单并输出结果)来说似乎足够简单,但我很乐意听取建议。

  • 我还有另一个要求,需要我解释应用程序的“基本”工作流程:基本上,我有一个类Engine,它有一个方法run(String),它将处理用户的输入并返回结果展示。此类是应用程序的核心。现在,我想实例化这个类一次,因为它需要大量内存,并且需要很长时间才能启动,所以我想在应用程序/服务器启动时创建它,并为应用程序的整个范围存储该引用(即,直到我停止服务器)。然后,对于每个用户请求,我只需调用Engine 实例的run 方法,并显示其结果。 如何在 Java 中实现这一点?

【问题讨论】:

    标签: java jsp tomcat jetty application-server


    【解决方案1】:
    1. 应用服务器。您认为 Tomcat 在运行时占用空间、学习量或...方面很重?我倾向于选择与 IDE 集成良好的东西。所以 Eclipse + Tomcat 或 Apache Geronimo,也许在它的 WebSphere Community Edition 伪装下可以完成这项工作。据我所知,这些足以满足您的需求,而且学习曲线非常易于管理。
    2. 是的 JSP。您可能会发现您的演示需求变得有点复杂。转到 JSF 的额外努力可能还没有回报 - 不错的小部件,例如日期选择器。
    3. 在您的处理过程中,您将拥有一个 servlet(或者如果您使用 JSF,则为一个动作类),该类可以有一个 Engine 类型的成员变量,该变量在启动时初始化,然后用于每个请求。要记住的是,许多用户将同时访问该 servlet,因此也访问该引擎。您的引擎是否可以安全地同时从多个线程中使用?

    在这一点上展开。在实现 JSP 时,有两个模型(具有一定的创造性)称为模型 1 和模型 2。请参阅 this explanation

    在模型 1 的情况下,您倾向于将代码直接放入 JSP,它充当控制器角色。 Persoanlly,即使在处理小型、快速开发的应用程序时,我也不这样做。我总是使用模型 2。但是,如果您选择,您可以将一些 Java 放入您的 JSP。

    <%  MyWorker theWorker = MyWorkerFactory.getWorker();
        // theWorker.work();
    %>
    

    我希望有这样的工厂,这样你就可以控制工人的创造。工厂会有类似的东西(举一个非常简单的例子)

    private static MyWorker s_worker = new MyWorker();
    public static synchronized getWorker() {
           return s_worker;
    }
    

    或者,您可以在第一次调用该方法时创建工作者。

    在模型 2 的情况下,您自然有一个 servlet,您将在其中放入一些代码,因此您可以只拥有

    private MyWorker m_worker = MyWorkerFactory.getWorker();
    

    这将在加载 servlet 时初始化。无需担心将其设置为在启动时加载,您只需知道它将在第一个请求运行之前初始化。 更好的是,使用 servlet 的 init() 方法。这保证在处理任何请求之前被调用,并且是此类工作的 servlet API 架构位置。

    public class EngineServlet extends HttpServlet {
    
    private Engine engine;
    
    // init is the "official" place for initialisation
    public void init(ServletConfig config) throws ServletException {
         super.init(config);
         engine = new Engine();
    } 
    

    【讨论】:

    • 感谢 cmets。 1)从某种意义上说,它似乎有许多我不需要的功能,而且似乎还需要一些额外的步骤来安装。另一方面,根据我从 Jetty 看到的情况,启动它所需要的只是运行java -jar start.jar。还有一个不错的 contrib 项目,它允许我使用 java -jar jetty-runner.jar application.war 运行我的应用程序,这非常酷,因为我想在不同的计算机上运行 Web 界面以进行演示。但是,Tomcat 似乎名声不错,所以这是一个艰难的选择。
    • 2) 对于(相当)复杂的应用程序来说,它确实是一个非常简单的界面,我认为我真的不需要更高级的小部件,但感谢您的建议。最终,我需要在结果页面上集成一些 API(例如 Google 地图),但我可能只是为此在 JSP 页面中编写 javascript 代码。
    • 3) 你能给我举个例子,使用 JSP 吗?从我目前所读的内容来看,我需要“激活”servlet 配置的load-on-startup,以便在服务器启动时加载它。但是我如何才能从 JSP 内部访问 servlet 的成员变量 Engine?基本上,我有一个带有输入文本字段的页面A.jsp,其内容将使用GET 传递到页面B.jsp。在此页面中,我需要获取Engine 实例,使用query string 的内容调用方法,并输出结果。
    • 另外,关于线程安全问题,除了创建Engine 之外,我并没有做太多更新。其他一切实际上只是繁重的处理。但是,我确实有一个使用FutureTask 并行化某些操作的类,但它们只是使用 Web API 来收集和返回结果。
    • 1)。听起来 Jetty 可以满足您的需求。我没用过,不能多说。 2)。我明白。 3)。添加到答案中。恐怕代码没有经过测试,但是这些概念应该可以帮助您入门。关键思想是您只是使用标准 Java 规则来初始化类。
    【解决方案2】:

    您需要学习的技术是 Sun Java Servlet 规范,因为这是所有重要的 Java 网络服务器都实现的。这使您能够编写 servlet,它可以完成服务器端所需的所有事情。然后,您可以针对任何与您的 iDe 配合良好的容器进行开发,并在生产中运行良好的任何其他容器上进行部署。

    你还需要学习基本的 HTML,否则你需要学习 JavaServer Faces 或类似的东西,这是一个相当大的嘴巴,以创建你需要的提交按钮和 HTML 表单中的其他条目。

    为了让您的引擎工作,您可以在 web.xml 中创建一个带有单例的 servlet,然后您可以调用它。绝对确定它是线程安全的,否则你会很痛苦。对于初学者,您可以声明您的调用 servlet 已同步,以确保在任何时候最多有一次 run() 调用处于活动状态。

    【讨论】:

    • 感谢 cmets。是的,我就是这么想的。我的目标是拥有一个轻量级容器,我可以在其中轻松部署应用程序以进行演示。但是,我最终可能需要永久托管应用程序,可能使用不同的容器。我确实知道 HTML 和其他 Web 技术(CSS/Javascript 等),因为我以前在 ASP.NET 中使用过它们。但是,我对使用 Java 进行 Web 应用程序开发还比较陌生。
    • 如果您编写一个符合标准的 Java Web 应用程序,哪个容器几乎无关紧要。 Tomcat 通常具有出色的 IDE 支持,这在开发时非常宝贵。现在,我很遗憾地说你还有一些学习要做:-)
    • 是的,我知道,我一直在阅读有关该主题的一些文章,无需抱歉; )。另外,如果可以的话,请评论我添加到问题中的代码。
    【解决方案3】:

    编辑:到目前为止,我已做出以下决定:

    • Web 应用服务器:Jetty
    • Java 服务器页面 用于视图;
    • 根据@djna 的建议,我阅读了几篇关于Model 2 的文章,并提出了这个解决方案(我还没有测试过,因为我需要在进入界面之前完成我的申请):

    form.jsp

    <form action="/servlet/EngineServlet" method="GET">
      <input type="text" name="text" />
    </form>
    

    EngineServlet.java

    public class EngineServlet extends HttpServlet {
      private Engine engine = new Engine(); 
      // does this make sure engine only gets instantiated one time in the entire lifespan of the web application; from what I've read from the servlet lifecycle, it seems like it, but I'd like to hear opinions
    
      public void doGet(HttpServletRequest request,
                        HttpServletResponse response) {
        String text = request.getParameter("text");
        ResultBean result = engine.run(text);
        request.setAttribute("result", result);
        RequestDispatcher dispatcher = request.getRequestDispatcher("result.jsp");
        dispatcher.forward(request, response); 
        // what's the difference between forward, and request.sendRedirect() ?
      }    
    }
    

    result.jsp

    <div>The result was: ${result.text}</div>
    

    您如何看待这个解决方案?对于具有 J2SE 背景的人来说可能不明显的任何问题?我还写了一些我在代码中作为 cmets 的疑问。谢谢。

    【讨论】:

    • Initialising engine: is "cleaner" 如果在 servlet init() 方法中完成,我已经修改了我的答案。 servlet 生命周期在j2ee.me/j2ee/tutorial/1_3-fcs/doc/Servlets4.html 中进行了讨论。您将看到在任何时候都会有一个 servlet 类的实例,因此在您的代码中一次会有一个 Engine 实例。应用服务器可以选择最终确定并重新初始化您的 servlet。我从来没有见过 App Server 这样做,但要 100% 确定要承担作为引擎单例的责任。请参阅下一条评论。
    • 引擎实例不超过一个可能很重要。或者从内存消耗的角度来看,它可能是非常可取的。在任何一种情况下,我都会说您不应该依赖客户端(在这种情况下为 servlet)来监督存在一个实例。而是使用我的答案中所示的工厂。 serlvet 说“给我一个 Engine”,工厂说“使用这个”,并且可以负责确保使用 Singleton Engine。这个解决方案可以适应不寻常的 servlet 生命周期事件,也可以适应未来的维护,如果你有两个 servlet 会发生什么?
    • 转发:servlet 做一些工作,收集一些数据,然后将 same 请求传递给 JSP 进行渲染。浏览器会看到 servlet 的 url。重定向:servet 向浏览器发送一个响应,说“不要显示这个,而是发送一个对 this 页面的请求”,一个不同的 URL。当原始请求做了一些您不想意外重复的工作(例如,支付一些钱)时,您使用后者。通过发送重定向,浏览器的历史可以有一系列“GET”显示请求,没有“POST”操作,如果重新提交将重复工作。
    • 非常感谢,您的指点和建议让我学到了很多关于 Java 的 Web/J2EE 方面的知识。我接受你的回答。如果可以的话,请评论一下我上面的 Model 2 实现,看看是否有可以改进的地方。
    【解决方案4】:

    假设这不是一个一次性的应用程序,将来不需要任何类型的更新/维护,我建议您使用Apache Wicket 做视图层,原因如下(阅读首先来自主页的简短信息摘要):

    • 由于 Wicket 将视图层分离并以干净的方式工作在 MVC 的模型层中,因此可以很容易地解释,视图与应用程序的其余部分完全分离,并且使用 Wicket 的IModel interface 链接来自控制器的数据以可靠的方式层到视图层。因此,您的控制器层可能是单个应用程序单例,只要您以这种方式使用它。
    • Wicket 代码非常易于维护,而且由于它是 OOP 框架而不是与其他类型的表达代码的标记混合的标记,因此可以非常轻松地扩展您的 Web 应用程序的功能。

    【讨论】:

    • 感谢 cmets。看起来很简洁,但我真的只需要一个“表单 => 提交 => 过程 => 显示结果”,因为它只是用于应用程序的演示目的。
    【解决方案5】:
    1. Jetty 是一个非常轻量级的容器,非常适合您的开发场景。

    2. 您可能希望查看Wicket 的渲染方面;与直接 UI 相比,您似乎更愿意执行类似代码的任务。

    3. 您描述的模式是单例模式。看看singleton in java 的谷歌搜索结果。

    【讨论】:

      【解决方案6】:
      1. 应用服务器:tomcat
      2. 网页:jsp
      3. 您需要一个单例类或具有静态方法的类。 警告:当心比赛条件。对于那些涉及更新/修改操作的方法,您可能需要使用 synchronized 关键字。

      【讨论】:

      • 您应该明确地让 Web 容器知道并管理线程不安全的 servlet。 Syncrhonized 让 JVM 来代替它,这可能会导致 Web 容器无响应。
      【解决方案7】:

      这是一个非常开放式的问题,根据您的要求,有大量可能的答案。编写 Web 应用程序的标准方法是使用 Java EE 平台,这意味着用于业务逻辑的 JSP、servlet 和 EJB。但是,有很多流行且有效的替代方案,例如 Spring、Seam、GWT,甚至更激进的替代方案,例如 JRuby on Rails。听起来您的需求非常简单,因此您可能想要使用像 Jetty + Servlets + JSP 这样的简单解决方案。

      我假设您的引擎可以同时处理多个请求?如果没有,您可能需要考虑找出一种将请求排队的方法,例如 JMS。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多