教育サーバーのページ
オンラインテキスト目次
システムプログラミング演習

データベースとの連携 (Servlet)

1. データベースの検索

次のプログラム JdbcFruitTable.java は、指定したWebサーバ下の ディレクトリ(アプリケーションのルートディレクトリ/WEB-INF/classes)下に格納されているコンパイル済みのServletファイルを実行することで、ブラウザ上にデータベースの検索結果をテキスト表示するプログラムである。


import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
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.sql.*;
import javax.servlet.ServletConfig;


public class JdbcFruitTable extends HttpServlet {

    public void init(ServletConfig config) throws ServletException {
        super.init(config);       
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {

        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<title>FRUIT_TBLテーブルの内容</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<table border=¥"1¥"><tr><th>番号</th><th>名前</th><th>金額</th></tr>");

        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");

            stmt = con.createStatement();

            rs = stmt.executeQuery("select no, name, price from fruit");
            while (rs.next()) {
                out.println("<tr>");
                out.println("<td>" + rs.getInt("no") + "</td>" );
                out.println("<td>" + rs.getString("name") + "</td>" );
                out.println("<td>" + rs.getInt("price") +  "</td>" );
                out.println("</tr>");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { rs.close(); } catch (Exception e) {}
            try { stmt.close(); } catch (Exception e) {}
            try { con.close(); } catch (Exception e) {}
        }

        out.println("</table>");
        out.println("</body>");
        out.println("</html>");
        out.close();
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }
    
    public String getServletInfo() {
        return "Short description";
    }
    
}

たとえば、Webサーバが動いているホストlocalhostのWebアプリケーション のルートディレクトリ下の WEB-INF/classesディレクトリに格納されている コンパイル済みのServletファイルJdbcFruitTable.class(テキストファイルは JdbcFruitTable.java)を実行する。そうすると、指定された データベースに接続され、SQL文により検索がおこなわれ、その結果がブラウザ上 に表示される。

プログラム JdbcFruitTable.java の説明

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
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.sql.*;
import javax.servlet.ServletConfig;

では、JdbcFruitTable.javaにおいて、Servlet APIならびに JDBC APIを構成するクラスライブラリ(パッケージ)を使えるように 宣言している。

クラス定義は、次のようにおこなわれる。

public class JdbcFruitTable extends HttpServlet {
ここでは、JdbcFruitTableクラスが定義される。通常のServletは、 HttpServletクラスを拡張して定義することが多く、 JdbcFruitTable.javaでも、HttpServletクラスを拡張する。

Servletのクラス内では、以下のようなinitメソッドが定義される。 initメソッドは、Servletがロードされた後で、Servletコンテナ から一度だけ呼び出され、Servletの初期化をおこなう。 次に、NetBeansに組み込まれたデータベース管理システムMySQLの JDBCドライバのロードをおこなう。JDBCドライバは、MySQL用の com.mysql.jdbc.Driverを用いる。

public void init(ServletConfig config) throws ServletException {
        super.init(config);       
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

destroyメソッドでは、Servletが破棄される前に、Servletコンテナ から呼び出される。このメソッドも、initメソッドと同様に、行う 処理がなければ、メソッドをオーバーライドする必要はない。

    public void destroy() {      
    }

JdbcFruitTable.javaでは、クライアントからの要求を GETメソッドで受け取るために、doGetメソッドに処理を記述する。 POSTメソッドの場合には、doPostメソッドに処理を記述する。 processRequestメソッドは、doGetメソッドとdoPostメソッドで 呼び出されるメソッドを定義している。両者のメソッドでおこなう 処理を共通にするために、processRequestメソッドとしてひとつの メソッドとして実装している。このメソッドでは、本プログラムの 主処理が以下のようにおこなわれる。

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, java.io.IOException {
      response.setContentType("text/html; charset=UTF-8");
      PrintWriter out = response.getWriter();
      out.println("<!DOCTYPE html>");
      out.println("<html>");
      out.println("<head>");
      out.println("<title>FRUIT_TBLテーブルの内容</title>");
      out.println("</head>");
      out.println("<body>");
      out.println("<table border=¥"1¥"><tr><th>番号</th><th>名前</th><th>金額</th></tr>");
      Connection con = null;
      Statement stmt = null;
      ResultSet rs = null;
      try {
          con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");
          stmt = con.createStatement();
          rs = stmt.executeQuery("select no, name, price from fruit");
          while (rs.next()) {
              out.println("<tr>");
              out.println("<td>" + rs.getInt("no") + "</td>");
              out.println("<td>" + rs.getString("name") + "</td>");
              out.println("<td>" + rs.getInt("price") + "</td>");
              out.println("</tr>");
            }
      } catch (Exception e) {
          e.printStackTrace();
      } finally {
          try { rs.close(); } catch (Exception e) {}
          try { stmt.close(); } catch (Exception e) {}
          try { con.close(); } catch (Exception e) {}
      }
      out.println("</table>");
      out.println("</body>");
      out.println("</html>");
      out.close();
  }

まず、Servletからの出力データ(ここでは、 HTML文書)の形式を指定するために、以下のように、 HttpServletResponseオブジェクトのsetContentTypeメソッドを 呼び出す。

      response.setContentType("text/html; charset=UTF-8"); 

次に、setContentTypeメソッドで設定した後、以下のように、 getWriterメソッドを呼び出して、ブラウザへの表示に使う PrintWriterオブジェクトを取得する。

    java.io.PrintWriter out = response.getWriter();

そして、以下では、上記で取得したPrintWriterオブジェクトの printlnメソッドが呼び出され、引数で渡したメッセージが ブラウザに表示される。

      out.println("<!DOCTYPE html>");
      out.println("<html>");
      out.println("<head>");
      out.println("<title>FRUIT_TBLテーブルの内容</title>");
      out.println("</head>");
      out.println("<body>");
      out.println("<table border=¥"1¥"><tr><th>番号</th><th>名前</th><th>金額</th></tr>");

以下では、データベータのアクセスに必要な処理をおこなう。 まず、必要な変数の初期化をおこなう。

      Connection con = null;
      Statement stmt = null;
      ResultSet rs = null;

try節の中では、データベースに接続するConnectionオブジェクトの取得 をおこなう。ここでは、接続するデータベースのURLを"jdbc:mysql://localhost/test"、ユーザ名が"root"を、パスワードを"tuis2019system"としている。

       con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");
それから、データベース操作を行うためのStatementオブジェクトの取得 をおこなう。

       stmt = con.createStatement();

さらに、SQL文を実行して、結果を得るために、以下のような 処理をおこなう。

       rs = stmt.executeQuery(
         "select no, name, price from fruit");

そして、得られた結果をレコードごとに表示するために、 以下の処理を実行する。具体的には、レコードのno フィールド、nameフィールド、priceフィールドを順番に表示する。 ここでは、検索結果が格納されたResultSetオブジェクトから、 指定されたフィールド名に対応する値が表示される。

       while (rs.next()) {
           out.println("<tr>");
           // レコードのCUSTOMER_NUMフィールドを表示
           out.println("<td>" + rs.getInt("no") + "</td>");
           // レコードのNAMEフィールドを表示
           out.println("<td>" + rs.getString("name") + "</td>");
           // レコードのPHONEフィールドを表示
           out.println("<td>" + rs.getInt("price") + "</td>");
           out.println("</tr>");
         }

finally節では、最終的におこなわれるデータベースとの接続が クローズが記述されている。

      try { rs.close(); } catch (Exception e) {}
      try { stmt.close(); } catch (Exception e) {}
      try { con.close(); } catch (Exception e) {}
通常、Servletでは、doGetメソッドとdoPostメソッドのどちら かは必ず存在すると考えられる。JdbcFruitTable.java では、Servletでおこなう処理の内容を共通化して、同じ処理が doGetメソッドとdoPostメソッドでおこなわれるようにしている。

doGetメソッドは、上述したJdbcFruitTable.javaの doGetメソッドと同様に、引数にHttpServletRequestオブジェクトと HttpServletRequestオブジェクトを取る。前者のオブジェクトには、 Servletへの入力が、後者のオブジェクトにはServletからの出力が 格納される。doGetメソッドの処理では、上述したprocessRequest メソッドを呼び出す。

    protected void doGet(HttpServletRequest request, 
             HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }

doPostメソッドは、ServletにHTTPリクエストのPOSTメソッドで アクセスされた時に、Servletコンテナから呼び出される。 通常、HTMLフォームを使ってブラウザからアクセスする時に、 このメソッドが呼び出される。doPostメソッドの処理でも、doGet メソッドと同様に、上述したprocessRequestメソッドを呼び出す。

    protected void doPost(HttpServletRequest request, 
             HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }

getServletInfoメソッドは、Servletに関する説明を表示する 場合に用いる。

    public String getServletInfo() {
        return "Short description";
    }

2. データの更新

以下のJdbcUpdate.htmlでは、Formタグのaction属性の値には、 送信ボタンが押された時に、テキスト入力フィールドに入力された文字列を ServletであるJdbcUpdate.javaに渡すことを指定している。

<!DOCTYPE HTML>

<HTML>
  <HEAD>
    <TITLE>データベースの変更</TITLE>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </HEAD>
  <BODY>
  <FORM method=POST action='JdbcUpdate'>
    <TABLE border='1'>
      <TR><TH>NO</TH><TD><INPUT type=text name='no'/></TD></TR>
      <TR><TH>NAME</TH><TD><INPUT type=text name='name'/></TD></TR>
      <TR><TH>PRICE</TH><TD><INPUT type=text name='price'/></TD></TR>
      <TR><TD><INPUT type=submit value='送信'/></TD></TR>
    </TABLE>
  </FORM>
  </BODY>
</HTML>

次のプログラム JdbcUpdate.java は、指定したWebサーバ下の ディレクトリ(アプリケーションのルートディレクトリ/WEB-INF/classes)下に 格納されているコンパイル済みのServletファイルを実行することで、 ブラウザ上にデータベースの変更結果をテキスト表示するプログラムである。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
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 javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;
import java.sql.*;
import javax.servlet.ServletConfig;

public class JdbcUpdate extends HttpServlet {
    
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void destroy() {
        
    }
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        Connection con = null;
        Statement stmt = null;
        try {
            con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");

            stmt = con.createStatement();

            String no = request.getParameter("no");
            String name = request.getParameter("name");
            String price = request.getParameter("price");

            StringBuffer buf = new StringBuffer();
            buf.append("update fruit set ");
            buf.append("name = '");
            buf.append(name);
            buf.append("', price = '");
            buf.append(price);
            buf.append("' where no = ");
            buf.append(no);
            stmt.executeUpdate(buf.toString());
            
            try { stmt.close(); } catch (Exception e) {}
            try { con.close(); } catch (Exception e) {}

            ServletContext cx = getServletContext();
            RequestDispatcher rd = cx.getRequestDispatcher("/JdbcFruitTable");

            rd.forward(request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }
    
    public String getServletInfo() {
        return "Short description";
    }
    
}

たとえば、Webサーバが動いているホストlocalhostのWebアプリケーションの ルートディレクトリ下の WEB-INF/classesディレクトリに格納されている コンパイル済みのServletファイルJdbcUpdate.class(テキストファイルは JdbcUpdate.java)を実行する。そうすると、指定された データベースに接続され、SQL文によりデータの変更がおこなわれ、 その結果がブラウザ上に表示される。

プログラム JdbcUpdate.java の説明

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
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 javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;
import java.sql.*;
import javax.servlet.ServletConfig;
では、JdbcUpdate.javaにおいて、Servlet APIならびに JDBC APIを構成するクラスライブラリ(パッケージ)を使えるように 宣言している。

クラス定義は、次のようにおこなわれる。

public class JdbcUpdate extends HttpServlet {
ここでは、JdbcUpdateクラスが定義される。通常のServletは、 HttpServletクラスを拡張して定義することが多く、 JdbcUpdate.javaでも、HttpServletクラスを拡張する。

Servletのクラス内では、以下のようなinitメソッドが定義される。 initメソッドは、Servletがロードされた後で、Servletコンテナ から一度だけ呼び出され、Servletの初期化をおこなう。 次に、データベース管理システムMySQLのJDBCドライバのロード をおこなう。JDBCドライバは、MySQL用の com.mysql.jdbc.lDriverを用いる。

public void init(ServletConfig config) throws ServletException {
        super.init(config);       
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

destroyメソッドでは、Servletが破棄される前に、Servletコンテナ から呼び出される。このメソッドも、initメソッドと同様に、行う 処理がなければ、メソッドをオーバーライドする必要はない。

    public void destroy() {      
    }

JdbcUpdate.javaでは、クライアントからの要求を GETメソッドで受け取るために、doGetメソッドに処理を記述する。 POSTメソッドの場合には、doPostメソッドに処理を記述する。 processRequestメソッドは、doGetメソッドとdoPostメソッドで 呼び出されるメソッドを定義している。両者のメソッドでおこなう 処理を共通にするために、processRequestメソッドとしてひとつの メソッドとして実装している。以下では、processRequestメソッドの 動作について説明する。

 protected void processRequest(HttpServletRequest request, HttpServletResponse response)
 throws ServletException, java.io.IOException {

     Connection con = null;
     Statement stmt = null;
     try {
         con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");

         stmt = con.createStatement();

         String no = request.getParameter("no");
         String name = request.getParameter("name");
         String price = request.getParameter("price");

         StringBuffer buf = new StringBuffer();
         buf.append("update fruit set ");
         buf.append("name = '");
         buf.append(name);
         buf.append("', price = '");
         buf.append(price);
         buf.append("' where no = ");
         buf.append(no);
         stmt.executeUpdate(buf.toString());
            
         try { stmt.close(); } catch (Exception e) {}
         try { con.close(); } catch (Exception e) {}

         ServletContext cx = getServletContext();
         RequestDispatcher rd = cx.getRequestDispatcher("/JdbcFruitTable");

         rd.forward(request, response);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

このメソッドでは、データベータのアクセス処理がおこなわれる。 まず、必要な変数の初期化をおこなう。

      Connection con = null;
      Statement stmt = null;

try節の中では、データベースに接続するConnectionオブジェクトの取得 をおこなう。ここでは、接続するデータベースのURLを "jdbc:mysql://localhost/test"、ユーザ名が"root"を、 パスワードを"tuis2019system"とする。

       con = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "tuis2019system");
それから、データベース操作を行うためのStatementオブジェクトの取得 をおこなう。

       stmt = con.createStatement();

さらに、データベース操作に必要な値をrequestオブジェクトから 取得する。

      String no = request.getParameter("no");
      String name = request.getParameter("name");
      String price = request.getParameter("price");

そして、実行するためのSQL文を作成する。

         StringBuffer buf = new StringBuffer();
         buf.append("update fruit set ");
         buf.append("name  = '");
         buf.append(name);
         buf.append("', price = '");
         buf.append(price);
         buf.append("' where no = ");
         buf.append(no);

上記で作成されたSQL文を実行して、結果を得るために、以下のような 処理をおこなう。

      stmt.executeUpdate(buf.toString());

finally節では、最終的におこなわれるデータベースとの接続が クローズが記述されている。

      try { stmt.close(); } catch (Exception e) {}
      try { con.close(); } catch (Exception e) {}

そして、前述したデータベースを検索するServet JdbcFruitTable.javaを呼び出すために、 RequestDispatcherオブジェクトを取得する。

         ServletContext cx = getServletContext();
         RequestDispatcher rd = cx.getRequestDispatcher("/JdbcFruitTable");

RequestDispatcherオブジェクトのforwardメソッドを呼び出すことで、 JdbcFruitTable.javaサーブレットを呼び出し、データベースの 検索をおこなう。

         rd.forward(request, response);

通常、Servletでは、doGetメソッドとdoPostメソッドのどちら かは必ず存在すると考えられる。JdbcUpdate.java では、Servletでおこなう処理の内容を共通化して、同じ処理が doGetメソッドとdoPostメソッドでおこなわれるようにしている。

doGetメソッドは、上述したJdbcFruitTable.javaの doGetメソッドと同様に、引数にHttpServletRequestオブジェクトと HttpServletRequestオブジェクトを取る。前者のオブジェクトには、 Servletへの入力が、後者のオブジェクトにはServletからの出力が 格納される。doGetメソッドの処理では、上述したprocessRequest メソッドを呼び出す。

    protected void doGet(HttpServletRequest request, 
             HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }

doPostメソッドは、ServletにHTTPリクエストのPOSTメソッドで アクセスされた時に、Servletコンテナから呼び出される。 通常、HTMLフォームを使ってブラウザからアクセスする時に、 このメソッドが呼び出される。doPostメソッドの処理でも、doGet メソッドと同様に、上述したprocessRequestメソッドを呼び出す。

    protected void doPost(HttpServletRequest request, 
             HttpServletResponse response)
    throws ServletException, java.io.IOException {
        processRequest(request, response);
    }

getServletInfoメソッドは、Servletに関する説明を表示する 場合に用いる。

    public String getServletInfo() {
        return "Short description";
    }

3. 演習問題

問題-1

NetBeansを使って、上のプログラムJdbcFruitTable.java を実行し、その結果も表示せよ。

問題-2

上のプログラムJdbcFruitTable.javaを参考にして、 "fruit"テーブルを、降順にpriceでソートし、no、 name、priceからなるテーブルを表示するプログラム JdbcFruitTable1.javaを作成・実行し、その結果を表示せよ。

問題-3

上のプログラムJdbcFruitTable.javaを参考にして、 "fruit"テーブルから、noが4以上、またはnameがmeronであるレコードを検索し、 その結果を、no、name、priceからなるテーブルとして表示する プログラムJdbcFruitTable2.javaを作成・実行し、 その結果を表示せよ。なお、このプログラムでは、表示されたテーブルの レコード数も求めるものとする。

問題-4

上のプログラムJdbcFruitTable.javaを参考にして、 "fruit"テーブルから、priceが100から200までのレコードを 検索し、さらにpriceで昇順にソートした結果を、no、name、proceから なるテーブルとして表示するプログラムJdbcFruitTable3.java を作成・実行し、その結果を表示せよ。

問題-5

上のプログラムJdbcUpdate.javaを、上のJdbcUpdate.htmlから実行 し、その結果も表示せよ。

Webシステムプログラミング演習


Yasuo NAGAI