メインスレッド以外でUIを変更する方法

Androidアプリにおいて、メイン(UI)スレッド以外のスレッドで、UIを変更しようとすると、実行時に下記の例外が発生する。
これは「UI部品の操作はUIスレッドから行わなければならない」というAndroidの制約のためである。

今回は、メイン(UI)スレッド以外から、UI操作を行う方法を紹介する。

<発生する例外>

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
  at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6566)
  at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:911)
  at android.view.View.requestLayout(View.java:18814)
  at android.view.View.requestLayout(View.java:18814)
  at android.view.View.requestLayout(View.java:18814)
  ...

<例外が発生するソースコード>

MainActivity.java

package biz.accele.samplethreadui;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        final Button   btn1;
        final TextView txt1;

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn1 = (Button)findViewById(R.id.btn1);
        txt1 = (TextView)findViewById(R.id.txt1);

        btn1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                // 別スレッドを実行
                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        // 別スレッドでUIを変更しようとしている
                        txt1.setText("本日は晴天なり");
                    }
                }).start();
            }
        });
    }
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Go"/>

    <TextView
        android:id="@+id/txt1"
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

<例外を回避して、別スレッドからUIを変更する方法>

具体的な方法としては、Handlerを使用して、別スレッドからメイン(UI)スレッドに処理を依頼することになる。

MainActivity.java

package biz.accele.samplethreadui;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        final Button   btn1;
        final TextView txt1;

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn1 = (Button)findViewById(R.id.btn1);
        txt1 = (TextView)findViewById(R.id.txt1);

        // メイン(UI)スレッドでHandlerのインスタンスを生成する
        final Handler handler = new Handler();

        btn1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                // 別スレッドを実行
                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        // Handlerを使用してメイン(UI)スレッドに処理を依頼する
                        handler.post(new Runnable() {
                            @Override
                            public void run() {

                                txt1.setText("本日は晴天なり");
                            }
                        });
                    }
                }).start();
            }
        });
    }
}

activity_main.xml

変更なし

今回の例の様にUI上のテキストを変更するために別スレッドにすることは無いと思うが、時間のかかる処理を別スレッドで実行し、その結果をUI上に反映したいことは、よくあるケースである。
その際は今回紹介した方法を試して頂きたい。

Enjoy Programing!!

WebView上でのリクエストをフックする方法

Androidアプリ上でWebページを表示したい場合は「WebView」を使用することになる。
今回はWebViewで表示したWebページ上のリンクがユーザによりタップされた場合に、それをアプリで検知する方法を紹介する。

<方法概要>

1.WebViewでWebページを表示できる様にする
2.WebViewにWebViewClientを設定する

<方法詳細>

1.WebViewでWebページを表示できる様にする

1.1.パーミッションの設定

「<uses-permission android:name="android.permission.INTERNET" />」をAndroidManifest.xmlに追加する。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="biz.accele.samplewebview" >

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
1.2.画面レイアウトを定義するxmlファイルにWebViewを追加する

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <WebView
        android:id="@+id/webView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>
1.3.表示するURLを指定する

MainActivity.java

package biz.accele.samplewebview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // WebViewの取得
        WebView webView1 = (WebView) findViewById(R.id.webView1);

        // 表示するURLを指定
        webView1.loadUrl("https://www.google.co.jp/");
    }
}

ここまででアプリを実行すれば、Googleのトップページがアプリ内に表示される。

f:id:MoonMtLab:20160825231805p:plain:w200

2.WebViewにWebViewClientを設定する

今回の本題である、Webページ上のリンクがタップされたことをアプリで検知するために、WebViewにWebViewClientを設定する。

WebViewにWebViewClientを設定するためには、WebViewクラスの「setWebViewClient」メソッドを使用する。
また、Webページ上のリンクがタップされたことをアプリで検知するためには、WebViewClientクラスの「shouldOverrideUrlLoading」メソッドをオーバーライドし、そこに検知後の処理を記述することで実施できる。

今回は単純にするために、タップされたリンクのURLを表示する例を準備した。

MainActivity.java

package biz.accele.samplewebview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // WebViewの取得
        WebView webView1 = (WebView) findViewById(R.id.webView1);

        // WebViewClientの設定
        webView1.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {

                Log.d("--- ログ --->", "タップされたリンクのurl:" + url);

                return true;
            }
        });

        // 表示するURLを指定
        webView1.loadUrl("https://www.google.co.jp/");
    }
}

アプリを実行して、Webページ内のリンクをタップすれば、logcatにリンクのURLが出力される。

08-25 20:12:36.401    5902-5902/biz.accele.samplewebview D/--- ログ --->﹕ タップされたリンクのurl:https://www.google.co.jp/webhp?output=search&tbm=isch&tbo=u



ただ、リンクのURLはログに表示されるが、画面がそのURLに遷移することはない。
これは、「WebViewClient#shouldOverrideUrlLoading」の戻り値として「true」を設定しているためである。
リンク先に遷移したい場合は、上記の戻り値を「false」に設定することで実施できる。

Enjoy Programing!!

ブログを新設しました

ブログを新設しました。
以下の記事は「MoonMt.Lab IT開発技術 調査報告書」から移行したものです。

Android(Java)でメソッドの呼び出し元を確認する方法

筆者は他人が作成したコードを分析する時によく使います。
呼び出し元の「クラス名」「メソッド名」「行数」が標準出力に表示されます。

StackTraceElement ste = Thread.currentThread().getStackTrace()[3];
System.out.println("caller class:" + ste.getClassName() + " metho:" + ste.getMethodName() + " line:" + ste.getLineNumber());

iOSアプリ開発で日時を扱う時の注意点(暦と24時間表示の設定)

今回は、iOSアプリ開発で日時を扱う時の注意点を紹介する。
日付型である「NSDate」型を、文字列型である「NSString」に変換する際、「NSDateFormatter」クラスを使用することが一般的である。
ただ、NSDateFormatterの設定によっては意図しない変換が行われることがあるので注意が必要である。

現在日時を「yyyy/MM/dd HH:mm:ss」形式の文字列に変換する場合、最小限の実装は以下の様になる。

//現在時刻を取得する
NSDate *now = [NSDate date];
    
//フォーマッターをインスタンス化する
NSDateFormatter *df = [[NSDateFormatter alloc] init];
    
//変換フォーマットの設定
df.dateFormat  = @"yyyy/MM/dd HH:mm:ss";
    
//NSDate型からNSString型にフォーマットに従って変換する
NSString *strDate = [df stringFromDate:now];
    
//結果をログに出力する    
NSLog(@"文字列時刻:%@", strDate);


このロジックを動作させた場合、iOS端末の設定によって、結果に以下の様なバラつきが起こる。

No. 24時間表示 結果
1 西暦 ON 2015/03/21 11:08:31
2 和暦 ON 0027/03/21 11:09:03
3 西暦 OFF 2015/03/21 午前11:10:24

「暦」の設定は[設定]>[一般]>[言語と地域]>[カレンダ]で行い、「24時間表示の設定」は[設定]>[一般]>[日付と時刻]>[24時間表示]で行う。

No.2の「年」部分と、No.3の「時間」部分は、多くの実装者が望む結果とは異なっていると思われる。
実装者が望む結果は「No.2とNo.3の結果もNo.1と同じであること」と考えている。

よって、No.2とNo.3の結果がNo.1と同じになる、NSDateFormatterの設定を紹介する。
下記の様にNSDateFormatterの設定に3行追加する。

//現在時刻を取得する
NSDate *now = [NSDate date];

//フォーマッターをインスタンス化する
NSDateFormatter *df = [[NSDateFormatter alloc] init];

df.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  //...(1)
df.locale   = [NSLocale systemLocale];       //...(2)
df.timeZone = [NSTimeZone systemTimeZone];   //...(2)

//変換フォーマットの設定
df.dateFormat  = @"yyyy/MM/dd HH:mm:ss";

//NSDate型からNSString型にフォーマットに従って変換する
NSString *strDate = [df stringFromDate:now];

//結果をログに出力する
NSLog(@"文字列時刻:%@", strDate);


<ソースコード解説>

番号 説明
(1) NSDateFormatterのcalendar属性に「NSGregorianCalendar」を設定することで、端末の暦の設定による結果のバラつきをなくす。
(2) NSDateFormatterのlocale属性・timeZone属性を明示的に設定することで、端末の24時間表示の設定による結果のバラつきをなくす。


<実行結果>

No. 24時間表示 結果
1 西暦 ON 2015/03/21 11:54:03
2 和暦 ON 2015/03/21 11:54:34
3 西暦 OFF 2015/03/21 11:54:53

取得形式にバラつきがなくなる事が確認できた。

Enjoy Programing!!

<お勧め書籍>

詳解 Objective-C 2.0 第3版
iOSアプリ開発技術者として仕事をするのであれば、必ず読んでおくべき書籍である。
筆者も何度も繰り返し精読している。

REST風サービスをJavaEEで構築する方法13(SQLログ編)

今回はEntityManagerで実行したSQLをログに出力する方法を紹介する。

REST風サービスをJavaEEで構築する方法09(DB接続設定編)で生成した「persistence.xml」を編集する。
プロジェクトツリー上の[構成ファイル]>[persistence.xml]をダブルクリックしてファイルを開き、上部の【ソース】ボタンを押下する。

表示されたxmlファイルの「properties」タグに下記の2行を追加する。

<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>

※「properties」タグが存在しない場合は追加する

追加した結果、「persistence.xml」ファイルが下記の様な状態であることを確認する。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="SampleRestPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/sample_db</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <validation-mode>NONE</validation-mode>
    <properties>
      <property name="eclipselink.logging.level.sql" value="FINE"/>
      <property name="eclipselink.logging.parameters" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

<動作確認>
プロジェクトを実行し、DBに対してSQLが発行される様な処理を実行する。
NetBeansの「出力」タブの「GlassFish Server 4.1」タブに、実行されたSQLSQL中の変数にバインドされた値が出力される。

普通:   select s.ID, d.DETAIL_ID, s.NAME, d.REMARKS from SAMPLE_TBL s, SAMPLE_DETAIL_TBL d where s.ID = d.ID and   d.REMARKS = ? and   d.DETAIL_ID = ? order by s.ID, d.DETAIL_ID;
	bind => [LMNOPQRSTUV, 02]

Enjoy Programing!!


<関連記事>
REST風サービスをJavaEEで構築する方法01(導入編)
REST風サービスをJavaEEで構築する方法02(雛形プロジェクト編)
REST風サービスをJavaEEで構築する方法03(RESTクライアント編)
REST風サービスをJavaEEで構築する方法04(各メソッド編)
REST風サービスをJavaEEで構築する方法05(パラメータの受け取り編)
REST風サービスをJavaEEで構築する方法06(JSON返却編1)
REST風サービスをJavaEEで構築する方法07(JSON返却編2)
REST風サービスをJavaEEで構築する方法08(Logic層編)
REST風サービスをJavaEEで構築する方法09(DB接続設定編)
REST風サービスをJavaEEで構築する方法10(DAO層編1)
REST風サービスをJavaEEで構築する方法11(DAO層編2)
REST風サービスをJavaEEで構築する方法12(DAO層編3)
・REST風サービスをJavaEEで構築する方法13(SQLログ編)[本記事]


<お勧め書籍>

わかりやすいJavaEEウェブシステム入門
JavaEEに関して基本的なことが分かり易く記述されている。
JavaEEに関する最初の1冊としてお勧めである。
Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava
「金魚本」の愛称を持つJavaEEの教科書的な書籍である。
JavaEEを腰を据えて学びたい人にお勧めする1冊!!

REST風サービスをJavaEEで構築する方法12(DAO層編3)

前回SQLを使用して、1つテーブルに対して検索する方法を紹介した。
今回はSQLを使用して、複数テーブルを結合した検索の方法を紹介する。

<前提条件>
下記の記事を読了していること。
REST風サービスをJavaEEで構築する方法01(導入編)
REST風サービスをJavaEEで構築する方法02(雛形プロジェクト編)
REST風サービスをJavaEEで構築する方法03(RESTクライアント編)
REST風サービスをJavaEEで構築する方法04(各メソッド編)
REST風サービスをJavaEEで構築する方法05(パラメータの受け取り編)
REST風サービスをJavaEEで構築する方法06(JSON返却編1)
REST風サービスをJavaEEで構築する方法07(JSON返却編2)
REST風サービスをJavaEEで構築する方法08(Logic層編)
REST風サービスをJavaEEで構築する方法09(DB接続設定編)
REST風サービスをJavaEEで構築する方法10(DAO層編1)
REST風サービスをJavaEEで構築する方法11(DAO層編2)

接続するDB(MySQL)に下記のテーブルが作成されていること。
(前回まで使用してきた「SAMPLE_TBL」と結合するテーブルとして追加する)


テーブル名:SAMPLE_DETAIL_TBL

No. カラム名 主キー 制約
1 ID CHAR 4 NOT NULL
2 DETAIL_ID CHAR 2 NOT NULL
3 REMARKS VARCHAR 256   -

<全体像から見た位置づけ>
CompositeKeyクラスを作成する。EntityクラスとDao層クラスを追加作成する。

<手順概要>
1.CompositeKeyクラスを作成する
2.Entityクラスを作成する
3.Dao層クラスを作成する
4.Logic層・Api層・index.htmlを編集する

<手順詳細>
1.CompositeKeyクラスを作成する
Entityクラスでは主キーを表す「@Id」を付与できるプロパティは基本的に1つだけである。
複数の列の組み合わせをキーとする場合は、キーの要素となるプロパティを持つ、CompositeKeyクラスを作成し、Entityクラスの@IdClassアノテーションで指定する必要がある。

プロジェクトツリー上で右クリックし、[新規]>[Javaクラス]を選択する。
表示されたダイアログのクラス名に「SampleJoinKey」(※)、パッケージに「lab.moonmt.SampleRest.entity.key」(※)と設定し、【終了(F)】ボタンを押下する。
(※)任意の名前をつけることができる。

作成されたクラスを下記の様に編集する。

package lab.moonmt.SampleRest.entity.key;

import java.io.Serializable;

public class SampleJoinKey implements Serializable {
    
    public String id;           //...(1)			
    public String detail_id;	//...(1)
	
	//...(※※)
}


ソースコード解説

番号 説明
(1) 複合キーを構成する列名をプロパティとして定義する。

ここまで記述して、(※※)付近で右クリックし「コードの挿入...」を選択する。

表示されたメニューで「equals()およびhashCode()...」を押下する。

それぞれのメソッドに含めるフィールドを聞かれるので、すべてにチェックをいれて、【生成】ボタンを押下する。

メソッドが自動生成されて、下記の様な状態になったことを確認する。

package lab.moonmt.SampleRest.entity.key;

import java.io.Serializable;
import java.util.Objects;

public class SampleJoinKey implements Serializable {
    
    public String id;
    public String detail_id;

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 97 * hash + Objects.hashCode(this.id);
        hash = 97 * hash + Objects.hashCode(this.detail_id);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final SampleJoinKey other = (SampleJoinKey) obj;
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        if (!Objects.equals(this.detail_id, other.detail_id)) {
            return false;
        }
        return true;
    }
}

2.Entityクラスを作成する
プロジェクトツリー上で右クリックし、[新規]>[Javaクラス]を選択する。
表示されたダイアログのクラス名に「SampleJoinEntity」(※)、パッケージに「lab.moonmt.SampleRest.entity」(※)と設定し、【終了(F)】ボタンを押下する。
(※)任意の名前をつけることができる。

作成されたクラスを下記の様に編集する。

package lab.moonmt.SampleRest.entity;

import lab.moonmt.SampleRest.entity.key.SampleJoinKey;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;

@Entity
@IdClass(value=SampleJoinKey.class)			//...(1)
@NamedNativeQueries({					//...(2)
@NamedNativeQuery(					//...(3)
        name="joinSql",
        query="select s.ID, d.DETAIL_ID, s.NAME, d.REMARKS " +
              "from SAMPLE_TBL s, SAMPLE_DETAIL_TBL d " +
              "where s.ID = d.ID " +
              "order by s.ID, d.DETAIL_ID;",
        resultClass=SampleJoinEntity.class),
@NamedNativeQuery(					//...(4)
        name="joinSql2",
        query="select s.ID, d.DETAIL_ID, s.NAME, d.REMARKS " +
              "from SAMPLE_TBL s, SAMPLE_DETAIL_TBL d " +
              "where s.ID = d.ID " +
              "and   d.REMARKS = ?remarks " +
              "and   d.DETAIL_ID = ?dId " +
              "order by s.ID, d.DETAIL_ID;",
        resultClass=SampleJoinEntity.class)
})
public class SampleJoinEntity implements Serializable {
    
    @Id
    private String id;					//...(5)
    
    @Id
    private String detail_id;				//...(5)

    private String name;
    
    private String remarks;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getDetail_id() {
        return detail_id;
    }

    public void setDetail_id(String detail_id) {
        this.detail_id = detail_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }
}


ソースコード解説

番号 説明
(1) @IdClassアノテーションを使用して、手順1で作成したCompositeKeyクラスを指定している。
(2) NamedNativeQueriesアノテーションを使用して、複数のSQLを記述することを宣言している。
(3) @NamedNativeQueryアノテーションを使用して、1つ目のSQLを記述している。(記述しているSQLは2つのテーブルを結合している)
(4) @NamedNativeQueryアノテーションを使用して、2つ目のSQLを記述している。(記述しているSQLは2つのテーブルを結合している)
(5) (1)でCompositeKeyクラスを@IdClassで指定しているので、複数のプロパティに@Idをつけても警告が発生しない。

3.Dao層クラスを作成する
プロジェクトツリー上で右クリックし、[新規]>[Javaクラス]を選択する。
表示されたダイアログのクラス名に「SampleJoinDao」(※)、パッケージに「lab.moonmt.SampleRest.dao」(※)と設定し、【終了(F)】ボタンを押下する。
(※)任意の名前をつけることができる。

作成されたクラスを下記の様に編集する。

package lab.moonmt.SampleRest.dao;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import lab.moonmt.SampleRest.entity.SampleJoinEntity;

@Stateless
public class SampleJoinDao {
    
    @PersistenceContext
    private EntityManager em;
    
    public List<SampleJoinEntity> getJoinInfo(){
        
        Query query = em.createNamedQuery("joinSql");   //...(1)
        
        return query.getResultList();                   //...(3)
    }
    
    public List<SampleJoinEntity> getJoinInfo2(String dId, String remarks){
        
        Query query = em.createNamedQuery("joinSql2");   //...(1)
        query.setParameter("dId", dId);                  //...(2)
        query.setParameter("remarks", remarks);          //...(2)
        
        return query.getResultList();                    //...(3)
    }
}

ソースコード解説

番号 説明
(1) エンティティマネージャの「createNamedQuery」メソッドを使用して、Entityクラスに記述したSQL文を読み込む。引数はEntityクラスでSQL文につけた名前を指定する。
(2) SQL文中の変数に対して値を設定している。
(3) SQL文を実行し、結果を呼び出し元に返却している。

4.Logic層・Api層・index.htmlを編集する
手順3で追加したメソッドが呼び出される様に、Logic層・Api層クラスおよびindex.htmlファイルを編集する。
詳細は割愛する。

Enjoy Programing!!


<関連記事>
REST風サービスをJavaEEで構築する方法01(導入編)
REST風サービスをJavaEEで構築する方法02(雛形プロジェクト編)
REST風サービスをJavaEEで構築する方法03(RESTクライアント編)
REST風サービスをJavaEEで構築する方法04(各メソッド編)
REST風サービスをJavaEEで構築する方法05(パラメータの受け取り編)
REST風サービスをJavaEEで構築する方法06(JSON返却編1)
REST風サービスをJavaEEで構築する方法07(JSON返却編2)
REST風サービスをJavaEEで構築する方法08(Logic層編)
REST風サービスをJavaEEで構築する方法09(DB接続設定編)
REST風サービスをJavaEEで構築する方法10(DAO層編1)
REST風サービスをJavaEEで構築する方法11(DAO層編2)
・REST風サービスをJavaEEで構築する方法12(DAO層編3)[本記事]
REST風サービスをJavaEEで構築する方法13(SQLログ編)


<お勧め書籍>

わかりやすいJavaEEウェブシステム入門
JavaEEに関して基本的なことが分かり易く記述されている。
JavaEEに関する最初の1冊としてお勧めである。
Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava
「金魚本」の愛称を持つJavaEEの教科書的な書籍である。
JavaEEを腰を据えて学びたい人にお勧めする1冊!!