【问题标题】:How can I easily call a java class (which queries a database) and return usable results to a JSP?如何轻松调用 java 类(查询数据库)并将可用结果返回给 JSP?
【发布时间】:2012-06-19 23:39:13
【问题描述】:

我是学习 JSP 和 Servlet 的新手。我有一个 Java 类,它调用一个存储过程并从数据库返回一个状态列表(这是我学习时的测试用例,其他更复杂的操作稍后会出现)。状态列表应返回到 JSP 以在表单中显示/使用等...现在,我很高兴通过 JSP 页面打印数据以了解它的存在。

但是,当我从 JSP 调用 Java 代码时,结果对象似乎返回为 null,因此无法访问任何数据。我也尝试将数据作为 ResultSet 对象返回,但结果是一样的。我确实知道从 SQL 调用存储过程时有效。此外,我将 Java 代码作为响应 doPost 请求的 servlet 并且工作正常...

我可能遗漏/无法理解什么?这可能吗?

package edu.XXXX.ais.userapp;

import java.sql.*;
import java.util.*;

public class DBQueries {

    public static Vector<String> getStatesList() {
        Vector<String> results = new Vector<String>();
        Connection con = null;  
        try {

            // Example of executing a stored procedure
            Class.forName("com.mysql.jdbc.Driver");
            con = DriverManager.getConnection ("jdbc:mysql://hostname:3306/dbName","username","password");
            CallableStatement cs = con.prepareCall("{call getStatesList()}");
            ResultSet rs = cs.getResultSet();

            while (rs.next()) {
                results.add(rs.getString(1));
            }
        } catch (SQLException e) {
            System.err.println("Servlet could not display records." + e);

        } catch (ClassNotFoundException e) {
            System.err.println("JDBC driver not found." + e);

        } finally {
            try {
                if (con != null) {
                    con.close();
                    con = null;
                }

            } catch (SQLException e) {
                System.err.println(e);
            }
        }
        return results;
    }
}

调用上述Java代码的JSP页面(期望能收到结果...)

<html>
<head>
<title>Foo</title>
</head>

<body>
<h3>List of states via a servlet call to the database</h3>
<%@ page import="java.util.*" %>
<%@ page import="edu.XXXX.ais.userapp.DBQueries" %>

<%
    Vector rs = DBQueries.getStatesList();
    if (rs != null)
        for (int index = 0; index < rs.size(); index++) {
            out.println("Name : " + (String) rs.get(index));
        }
%>

</body>
</html>

产生的Tomcat错误如下:

org.apache.jasper.JasperException: An exception occurred processing JSP page /states.jsp at line 12

9: <%@ page import="edu.XXXX.ais.userapp.DBQueries" %>
10: 
11: <%
12:     Vector rs = DBQueries.getStatesList();
13:     if (rs != null)
14:         for (int index = 0; index < rs.size(); index++) {
15:             out.println("Name : " + (String) rs.get(index));


Stacktrace:
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:568)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:470)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause

java.lang.NullPointerException
    edu.XXXX.ais.userapp.DBQueries.getStatesList(Unknown Source)
    org.apache.jsp.states_jsp._jspService(states_jsp.java:75)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

【问题讨论】:

    标签: java jsp servlets


    【解决方案1】:

    异常告诉你去哪里看:

    edu.XXXX.ais.userapp.DBQueries.getStatesList(Unknown Source)
    

    该方法中有一个空引用。我建议在没有 JSP 的情况下进行测试并使用调试器。

    您没有关闭您的StatementResultSet。那会导致悲伤。以与创建相反的顺序关闭它们,就像您执行 Connection 一样。

    对于初学者,请停止将 scriptlet 代码放入您的 JSP 中。那是 1999 年的风格;不要这样做。

    正确的做法是学习JSTL,只让你的JSP做显示任务。

    让 JSP 与代表它与数据库进行调解的 servlet 对话。

    使用应用服务器设置数据源。您的代码中不应包含连接信息。

    暂时忘记 servlet 和 JSP。从数据层开始。

    使用 POJO 编写,测试它,让它工作,然后把它放在一边。

    然后编写一个接收 HTTP 请求的 servlet,验证并绑定参数,使用您的数据访问层与数据库通信,然后将响应放入请求或会话范围以显示页面。

    它被称为 Model-2 MVC。这就是编写 Java Web 应用程序的方式。

    我会把 DBUtils 类写得更像这样:

    package edu.XXXX.ais.userapp;
    
    import java.sql.*;
    import java.util.*;
    
    public class DBQueries {
    
        public static List<String> getStates(Connection connection) throws SQLException {
            List<String> states = new ArrayList<String>();
            CallableStatement cs = null;
            ResultSet rs = null;
            try {
                cs = connection.prepareCall("{call getStatesList()}");
                boolean hasResultSet = cs.execute();
                rs = cs.getResultSet();    
                while (rs.next()) {
                    states.add(rs.getString(1));
                }
            } finally {
                close(rs);
                close(cs);
            }
            return states;
        }
    
        public static void close(ResultSet rs) {
            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        public static void close(Statement st) {
            try {
                if (st != null) {
                    st.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        public static void close(Connection conn) {
            try {
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    编写一个 JUnit 测试来证明您的 DBQueries 有效:

    package edu.XXX.ais.userapp;
    
    public class DBQueriesTest {
    
        // You have to initialize this; I'm deliberately leaving out some details.
        private Connection connection;
    
        @Test
        public void testGetStates() {
            List<String> actual = DbQueries.getStates(this.connection);
            List<String> expected = { "CT", "NY" };  // whatever
            Assert.assertEquals(expected, actual);
        }
    }
    

    【讨论】:

    • 谢谢大家。我有很多东西要学,我想知道我是否应该为此继续使用 PHP。这里似乎有如此多的技术层,很难知道从哪里开始以及建立在什么之上。你能告诉我更多关于“使用应用服务器设置数据源”的含义吗?人们使用哪些教程来学习所有这些堆栈?我发现的所有东西似乎都是旧的(因此是 1999 年的风格)或者假设您已经了解 JSP(不知道如何/从哪里了解 JSTL...)
    • 您必须将您的 JSP 部署到像 Tomcat 这样的应用服务器 - 应该维护数据源。我推荐 Hans Bergsten 的 O'Reilly 关于 JSP 的书。到目前为止,这是我所知道的关于这个主题的最好的书。
    【解决方案2】:

    在您的示例代码中,CallableStatement 不会在cs.getResultSet() 之前执行,因此rs 将为空,然后在执行rs.next() 时会出现NullPointerException

    CallableStatement cs = con.prepareCall("{call getStatesList()}");
    boolean bIsResultSetOrNot = cs.execute (); // <-- missed
    ResultSet rs = cs.getResultSet(); 
    

    确保语句被执行,并确保执行结果是ResultSet而不是更新计数。

    【讨论】:

    • 是的,这是我的致命缺陷,它阻止了结果。现在我正在学习上面列出的关于改进我的 MVC 和数据源使用的想法。谢谢柳岩!
    【解决方案3】:

    异常堆栈跟踪显示您在方法 DBQueries.getStatesList() 中有一个空指针。用 Exception 包围方法中的 try 块,并尝试查看是哪一行抛出它。我的猜测是 Connection 对象为空。

    如果是这样,请检查您在获取连接时传递的“主机名”的值。

    【讨论】:

      【解决方案4】:

      您正在尝试将字符串向量传递给向量。您的方法是Vector&lt;String&gt; getStatesList(),您正在引用NULL

      进入../Apache Tomcat/webapps/work 找到你编译的JSP 类。看看JSP那一行的错误。

      请使用 Spring Core JDBCTemplate 类连接到数据库,对于那些忘记关闭连接的人来说,这是一个非常好的类。 :) 不错

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-22
        • 1970-01-01
        • 2018-11-03
        • 2012-10-21
        • 1970-01-01
        • 2018-09-04
        • 2015-11-20
        • 2010-09-22
        相关资源
        最近更新 更多