[Eclipse/Tomcat] MavenのwebappプロジェクトでServlet+JSP の続き。
参考情報
- Apache Tomcat 8 (8.0.53) - JNDI Datasource HOW-TO
- server.xmlを使用せずにJNDIでデータベースの接続設定を一元化する - 初めてのVPS構築
概要
元のソースだと、データベースサーバのアドレスなどの接続情報をJavaのソースコード内に記述していてメンテナンス性に欠ける。
そこでJNDIを使用して外部のXMLファイルに接続情報を定義するようにする。
前提として、「Mavenプロジェクトのmaven-archtype-webapp
」で作成したプロジェクト(おそらく「動的Webプロジェクト」含む)が対象。
「Tomcatプロジェクト」の場合は後述
サーバ情報の定義
context.xmlファイルの作成
WEB-INF
と同じ階層にMETA-INF
ディレクトリを作成し、その直下にcontext.xml
ファイルを作成する。
[次へ]へテンプレートを選んだりできるみたいだけど、特に利用できるものがなさそう(見つけられなかった)ので、この画面で[完了]してファイル作成。
context.xmlにDB情報を記述
DBがMySQLの場合。
Apache Tomcat 8 (8.0.53) - JNDI Datasource HOW-TO の"MySQL DBCP Example"の「2. Context configuration」参照
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- maxTotal: Maximum number of database connections in pool. Make sure
you configure your mysqld max_connections large enough to handle all of your
db connections. Set to -1 for no limit. -->
<!-- maxIdle: Maximum number of idle database connections to retain in pool.
Set to -1 for no limit. See also the DBCP documentation on this and the minEvictableIdleTimeMillis
configuration parameter. -->
<!-- maxWaitMillis: Maximum time to wait for a database connection to become
available in ms, in this example 10 seconds. An Exception is thrown if this
timeout is exceeded. Set to -1 to wait indefinitely. -->
<!-- username and password: MySQL username and password for database connections -->
<!-- driverClassName: Class name for the old mm.mysql JDBC driver is org.gjt.mm.mysql.Driver
- we recommend using Connector/J though. Class name for the official MySQL
Connector/J driver is com.mysql.jdbc.Driver. -->
<!-- url: The JDBC connection url for connecting to your MySQL database. -->
<Resource
name="jdbc/memoapp_db"
auth="Container"
type="javax.sql.DataSource"
maxTotal="100"
maxIdle="30"
maxWaitMillis="10000"
username="memoapp"
password="memoapp"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/memoapp_db" />
</Context>
Tomcatのサイトから記述内容をパクッコピーして、name
、username
、password
、url
の部分を環境に合わせて変更する。
MySQL以外のDBを使用している場合は、DBに合わせた内容に変更する。
web.xmlの設定
今度はWEB-INF/web.xml
ファイルを編集する。
(Tomcatプロジェクトだとこのファイルは存在しないので作成する必要がある)
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4"
>
<description>memo app</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/memoapp_db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
ただしTomcatのサイトに載っている上記の記述内容(version 2.4)と、EclipseのMavenプロジェクト(maven-archetype-webapp)が生成するデフォルトのweb.xml(version 2.3)はDTD宣言の有無など大きく違う。
とはいえ、2.3でもサンプルの<resource-ref>
の部分を<web-app>
に入れればOK
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MemoAppMain</servlet-name>
<display-name>MemoAppMain</display-name>
<description></description>
<servlet-class>jp.example.www.MemoAppMain</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MemoAppMain</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/memoapp_db</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
MySQLへの接続コード
変更点は以下の通り
try {
Class.forName("com.mysql.cj.jdbc.Driver");
- con = DriverManager.getConnection(url, user, pass);
+ Context initContext = new InitialContext();
+ Context envContext = (Context)initContext.lookup("java:/comp/env");
+ DataSource ds = (DataSource)envContext.lookup("jdbc/memoapp_db");
+ con = ds.getConnection();
+ System.out.println("con: " + con);
smt = con.createStatement();
接続情報を引数にDriverManager.getConnection()
をコールしていたのを削除し、Context#lookup()
でXMLに定義したjdbc/memoapp_db
というリソースを探して接続する、という処理に変更する。
この変更によって、Javaコード内にMySQLのサーバ情報や認証情報を持たずに済むようになる。
備考
web.xmlのバージョン
web.xmlのバージョン別DTD・XSDの宣言方法 | KATSUMI KOKUZAWA'S BLOG
JavaでWebアプリを作る場合、Mavenのmaven-archetype-webappテンプレートを利用しています。 非常に便利なのですが、Servlet 3.1が出ている今、 生成されたwe.xmlがServlet 2.3の記述になっていてちょっと古すぎます
ということで、各バージョンごとのweb.xmlの書き方が載っている。
Tomcat8であれば3.1は使用できるっぽいので、新しい書き方に書き直すのもアリ。
Eclipseの場合、web.xmlの変更以外に<eclipse-project-path>/.settings/org.eclipse.wst.common.project.facet.core.xml
にもバージョン情報を持っており、手動で修正することで新規作成メニューでサーブレットを作成する際にもバージョンに合わせた動作になる。
本来はEclipseのプロジェクトプロパティのプロジェクト・ファセットで「動的Webモジュール」のバージョンを変更するものだと思われるが、なぜか画面から変更できないため、ファイルの内容の<installed facet="jst.web" version="3.1"/>
の部分を直接編集する。(これが正しい対応かわからないけど…)
Tomcatプロジェクトの場合
Tomcatプロジェクトで作成したプロジェクトの場合、META-INF/context.xml
を作成しても、EclipseからTomcatを起動した場合にプロジェクトの情報としてファイルを参照してくれない。
Tomcatプロジェクトの場合は、context.xmlに記述する<Resource>
タグの内容をプロジェクトプロパティのTomcat設定の「その他の情報」に記述しておくと、実行時に読み込まれる。
(もしくは、Tomcat自体の設定として、<tomcat-dir>/conf/context.xml
も読み込まれる)