ITを基礎からやってくブログ

とにかく基礎からやってくんです。基礎が大事なんです。

基礎からWebアプリ#3

基礎からWebアプリ#3です。

2.Java Servlet (Tomcat利用)

JDKインストール

OpenJDK1.7でいきます。

yum -y install java-1.7.0-openjdk-devel

Tomcatインストール

Tomcat公式ページによると、Java1.7に対応している最新は8.0系です。
Tomcat8を入れます。

まずは起動用のユーザを作成。
セキュリティの観点から、普通nologin設定で作成します。

useradd -s /sbin/nologin tomcat

次にインストール。

# Tomcatバイナリダウンロード
wget http://ftp.tsukuba.wide.ad.jp/software/apache/tomcat/tomcat-8/v8.0.33/bin/apache-tomcat-8.0.33.tar.gz
# /usr/local配下に解凍
# -Cオプションをつけることで、解凍先のフォルダへcdする手間が省けます。
tar -C /usr/local -zxvf apache-tomcat-8.0.33.tar.gz
# 権限をtomcatユーザに設定
chown -R tomcat:tomcat /usr/local/apache-tomcat-8.0.33
# tomcatインストールディレクトリへのシンボリックリンク作成
ln -s /usr/local/apache-tomcat-8.0.33 /usr/local/tomcat

Tomcat起動

同梱の起動シェルをtomcatユーザで実行します。

sudo -u tomcat /usr/local/tomcat/bin/startup.sh 

JAVA_HOMEとかCATALINA_HOMEとかはstartup.shの中の処理で自動で認識してくれるみたいです。
確実にやるなら/etc/profileか、Tomcatのbinにsetenv.shを作成して書いておく必要があります。

また、サーバとして使うなら本当は自動起動設定とかするべきなんだけど、今回は置いておきます。

Tomcatの詳細についてはググる"Google検索:tomcat linux 入門"

環境変数等の設定

環境変数を設定します。
先述の通り、tomcat起動時は必要な環境変数をいい感じに自動設定してくれますが、 tomcatユーザ以外にも明示的に環境変数を指定しておいたほうが無難なので設定します。
/etc/profileに環境変数を書けば全ユーザに反映されます。
以下を追記。

export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk.x86_64 //同じ階層にJREのディレクトリもあるので間違えないよう
export CATALINA_HOME=/usr/local/tomcat
export CLASSPATH=".:$JAVA_HOME/lib:$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib/*"

CLASSPATHは、ディレクトリ指定で書く場合、そのディレクトリに入っている.classファイルは読み込んでくれますが.jarファイルは読み込んでくれません。
.jarファイルを読み込むにはファイル名を明示するか、*を書いてあげる必要があります。

コンパイル時に明示的に指定してもいいです。
servlet関連のjarなら、javac -cp $CATALINA_HOME/lib/servlet-api.jar [javaソースファイル名])

/etc/profileはユーザログイン時に一度だけ読み込まれますが、ひとまず今は強制読込しておきます。

source /etc/profile

Servletを書く

前回作ったHTMLをベタ書きするのは面白くないので、外部のCSVファイルにデータを書いて読み込む方式にします。

DailyReportServlet.java

import java.io.*;
import java.text.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class DailyReportServlet extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html; charset=SHIFT_JIS");
    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>daily report</title>");
    out.println("<style type=\"text/css\">");
    out.println("table {");
    out.println("border-collapse: collapse;");
    out.println("width: 500px;");
    out.println("}");
    out.println("th {");
    out.println("text-align: center;");
    out.println("border: solid 1px;");
    out.println("padding: 0.5em;");
    out.println("background-color: #6666FF;");
    out.println("}");
    out.println("td {");
    out.println("text-align: center;");
    out.println("border: solid 1px;");
    out.println("padding: 0.5em;");
    out.println("}");
    out.println("</style>");
    out.println("</head>");

    out.println("<body>");
    out.println("<table>");
    out.println("<tr>");
    out.println("<th>日付</th>");
    out.println("<th>体重</th>");
    out.println("<th>体脂肪率</th>");
    out.println("<th>内臓脂肪レベル</th>");
    out.println("</tr>");

    try{
      File repotblFile = new File("../../reporttable.csv");
      BufferedReader br = new BufferedReader(new FileReader(repotblFile));
  
      StringTokenizer token;
      String line;
  
      while((line = br.readLine()) != null){
              token = new StringTokenizer(line, ",");
        out.println("<tr>");
        while(token.hasMoreTokens()){
                out.println("<td>" + token.nextToken() + "</td>");
              }
        out.println("</tr>");
      }
  
      br.close();
    }catch(FileNotFoundException e){
      out.println("System Error: Data file is not found.");
    }

    out.println("</table>");
    out.println("</body>");
    out.println("</html>");
  }
}

・・・いやあ、不格好なソースですね。

コンパイル、デプロイ

TomcatのWebアプリ配置フォルダ階層は下記の通り。

  • $CATALINA_HOME
    • webapps
      • [Webアプリ名]

今回のWebアプリ名はdailyreportとします。
dailyreportディレクトリとその配下のディレクトリをtomcatユーザをオーナーとして作成し、 $CATALINA_HOME/webapps/dailyreport/WEB-INF/classes にDailyReportServlet.javaを置いて、コンパイルします。

javac DailyReportServlet.java

次にweb.xmlを作成し、下記の通り記載。

<?xml version="1.0" encoding="ISO-8859-1"?>
<!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>

<servlet>
<servlet-name>dailyreport</servlet-name>
<servlet-class>DailyReportServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>dailyreport</servlet-name>
<url-pattern>/servlet/dailyreport</url-pattern>
</servlet-mapping>

</web-app>

Tomcatへの接続

この時点で、Tomcatを再起動すれば以下のURLでServletを実行できます。

sudo -u tomcat /usr/local/tomcat/bin/shutdown.sh
sudo -u tomcat /usr/local/tomcat/bin/startup.sh

http://hostname:8080/dailyreport/servlet/dailyreport

f:id:quatrefromage:20160412082037p:plain

しかしせっかくなのでApache連携して、ポート80で接続できるようにします。

Apache-Tomcat連携(AJP)

AJPとはApacheJavaコンテナを連携させるために使うプロトコルとのことです。

実装としてはmod_jkとmod_proxy_http、mod_proxy_ajpの選択肢があるようですが、 参考記事 *1 *2 *3 によると、

  • mod_jkは非標準だが古くからあり、デファクトスタンダード
  • mod_proxy系は新しめの実装で、標準サポートのため導入も容易
  • mod_proxy系はApache2.2以降で使える
  • 性能差は諸説あるが、それほど気にならないのではないか、という意見あり

mod_proxy系には少々性能面での不安がある程度で、メリットのほうが大きそうです。
今回は勉強用なので、新しい方のmod_proxy_ajpを使うことにします。

mod_proxy_ajpは標準で、かつApacheの設定上デフォルトでロードされるので、 設定ファイルを1つ追加するだけで設定できます。

ajp : まだプログラマーですが何か?にしたがって、 /etc/httpd/conf.d/proxy_ajp.confを以下の設定で作成します。

ProxyPass /dailyreport ajp://localhost:8009/dailyreport/servlet/dailyreport

Apacheを再起動して、以下のURLに接続すればさっきと同じ結果が得られます。

service httpd restart

http://hostname/dailyreport

f:id:quatrefromage:20160412081555p:plain

起動はTomcatApacheの順にしないとだめです。

次回

次回は3.JSP (Tomcat利用)です。