概要
Eclipse GlassFish 5.1.0を利用したJakarta EE 8 Webアプリケーションの開発環境の構築手順をまとめたメモです。
IDEにはIntelliJ IDEAを使用します。
環境
- Windows 10 Professional 1909
- GlassFish 5.1.0
- Oracle JDK 1.8.0_231
- IntelliJ IDEA 2019.3
参考
- [Eclipse EE4J] (https://projects.eclipse.org/projects/ee4j)
- [Jakarta® EE] (https://jakarta.ee/)
- [Eclipse GlassFish] (https://projects.eclipse.org/projects/ee4j.glassfish)
- [Java EE 8 の新機能概要のご紹介] (https://yoshio3.com/2014/12/19/java-ee-8-new-features/)
用語のおさらい
Java EE
[JavaEE の概要] (https://www.oracle.com/technetwork/jp/java/javaee/overview/index.html)
Java Platform, Enterprise Edition(Java EE)はコミュニティ主導のエンタープライズ・ソフトウェアの標準です。Java EEはJava Community Processを使って開発されており、業界の専門家、営利団体とオープンソース団体、Javaユーザー・グループ、さらに数え切れないほど多くの個人が貢献しています。
EE4J
Eclipse Enterprise for Java (EE4J) is an open source initiative to create standard APIs, implementations of those APIs, and technology compatibility kits for Java runtimes that enable development, deployment, and management of server-side and cloud-native applications.
------------------------------------------------------------------------------------------------
Eclipse Enterprise for Java(EE4J)は、標準API、それらのAPIの実装、およびサーバー側およびクラウドネイティブアプリケーションの開発、展開、管理を可能にするJavaランタイム用の技術互換性キットを作成するためのオープンソースイニシアチブです。
[EE4J (Eclipse Enterprise for Java)] (https://projects.eclipse.org/projects/ee4j)は、Eclipse Foundationのトップレベルプロジェクトで、プロジェクト管理委員会(PMC)がJakarta EEの仕様、API、TCK、およびリファレンス実装の開発・管理を行います。
Jakarta EE
Jakarta EEは、[Jakarta EE Working Group] (https://www.eclipse.org/org/workinggroups/jakarta_ee_charter.php) (2018年4月設立)が管理するプラットフォームです。
Java EEがOracleからEclipse Foundationへ移管されることが決まったのが2017年9月、それから約2年後の2019年9月に最初のリリースである[Jakarta EE 8] (https://projects.eclipse.org/jakartaee/releases/8)がリリースされました(機能的にはJava EE 8と同じです)。
2018年2月26日にJava EEに代わる名称がJakarta EEに決まったと[アナウンス] (https://eclipse-foundation.blog/2018/02/26/and-the-name-is/)がありましたが、そのときに下記の名称も新しくなると告知されました。
- Java EE → Jakarta EE
- Glassfish → Eclipse Glassfish
- Java Community Process (JCP) → Jakarta EE Working Group (Jakarta EE)
- Oracle development management → EE4J, PMC
Eclipse GlassFish
[Eclipse GlassFish] (https://projects.eclipse.org/projects/ee4j.glassfish) 5.1.0は、Java EE 8互換と認定されたアプリケーションサーバで、2019年1月にリリースされました。
このバージョンは、GlassFishがOracleからEclipse Foundationへ移管されてからリリースされた最初のバージョンです(ただしAPIや実装は、[Oracle GlassFish Open source Edition 5.0.1] (https://javaee.github.io/glassfish/)と基本的に変わりません)。
次のバージョン 5.2.0は、Jakarta EE 8互換と認定されるということです。
なお、Jakarta EE 8互換と認定されたアプリケーションサーバに[Payara® Server] (https://www.payara.fish/software/payara-server/)もあります。
Eclipse GlassFishのインストールと起動
ここからGlassFishサーバのインストールから起動までの一連の手順を説明します。
※この記事では特に断りのない場合『Eclipse GlassFish』を『GlassFish』と記載します。
ダウンロード
2020年1月現在、Full Profile (Full Platform)とそのサブセットであるWeb Profileがダウンロードページよりダウンロードできます。
この2つのProfileの違いは[Java EE Web Profile vs Java EE Full Platform] (https://stackoverflow.com/questions/24239978/java-ee-web-profile-vs-java-ee-full-platform)と、[Java™ EE 8 のテクノロジー] (https://www.oracle.com/technetwork/jp/java/javaee/tech/index.html)、[Jakarta EE Web Profile 8] (https://jakarta.ee/specifications/webprofile/8/)などで確認できます。
この記事ではWeb Profile版を使用します。
補足:Web Profileのコンポーネント
Component | Version | JSR | Compatible Implementations |
---|---|---|---|
[Servlet] (https://jakarta.ee/specifications/servlet/4.0/) | 4.0 | JSR-369 | Eclipse GlassFish 5.1 |
[Server Pages (JSP)] (https://jakarta.ee/specifications/pages/2.3/) | 2.3 | JSR-245 | Eclipse GlassFish 5.1 |
[Expression Language (EL)] (https://jakarta.ee/specifications/expression-language/3.0/) | 3.0 | JSR-341 | EE4J Implementation of Expression Language 3.0.3 |
[Debugging Support for Other Languages] (https://jakarta.ee/specifications/debugging/1.0/) | 1.0 | JSR-45 | Eclipse GlassFish 5.1 |
[Standard Tag Library (JSTL)] (https://jakarta.ee/specifications/tags/1.2/) | 1.2 | JSR-52 | Eclipse GlassFish 5.1 |
[Server Faces (JSF)] (https://jakarta.ee/specifications/faces/2.3/) | 2.3 | JSR-372 | Mojarra 2.3.13 |
[RESTful Web Services (JAX-RS)] (https://jakarta.ee/specifications/restful-ws/2.1/) | 2.1 | JSR-370 | Eclipse Jersey 2.28 |
[WebSocket] (https://jakarta.ee/specifications/websocket/1.1/) | 1.1 | JSR-356 | Eclipse GlassFish 5.1 |
[JSON Processing (JSON-P)] (https://jakarta.ee/specifications/jsonp/1.1/) | 1.1 | JSR-374 | Eclipse JSON Processing 1.1.5 |
[JSON Binding (JSON-B)] (https://jakarta.ee/specifications/jsonb/1.0/) | 1.0 | JSR-367 | Eclipse Yasson 1.0.3 |
[Annotations] (https://jakarta.ee/specifications/annotations/1.3/) | 1.3 | JSR-250 | Jakarta Annotations |
[Enterprise Beans (EJB)] (https://jakarta.ee/specifications/enterprise-beans/3.2/) | 3.2 Lite | JSR-345 | Eclipse Glassfish 5.1 |
[Transactions (JTA)] (https://jakarta.ee/specifications/transactions/1.3/) | 1.3 | JSR-907 | Eclipse GlassFish 5.1.0 |
[Persistence (JPA)] (https://jakarta.ee/specifications/persistence/2.2/) | 2.2 | JSR-338 | EclipseLink 2.7.4 |
[Bean Validation] (https://jakarta.ee/specifications/bean-validation/2.0/) | 2.0 | JSR-380 | Hibernate Validator 6.0.17 |
[Managed Beans] (https://jakarta.ee/specifications/managedbeans/1.0/) | 1.0 | Eclipse Glassfish 5.1 | |
[Interceptors] (https://jakarta.ee/specifications/interceptors/1.2/) | 1.2 | JSR-318 | Eclipse GlassFish 5.1 |
[Contexts and Dependency Injection] (https://jakarta.ee/specifications/cdi/2.0/) | 2.0 | JSR-365 | Weld 3.1.1.Final |
[Dependency Injection] (https://jakarta.ee/specifications/dependency-injection/1.0/) | 1.0 | JSR-330 | Weld 2.3.8.Final/Weld 3.1.1.Final |
[Security] (https://jakarta.ee/specifications/security/1.0/) | 1.0 | JSR-375 | Eclipse Soteria 1.0.1 |
[Authentication] (https://jakarta.ee/specifications/authentication/1.1/) | 1.1 | JSR-196 | Eclipse GlassFish 5.1 |
インストール
インストールはダウンロードしたアーカイブファイルを展開するだけです。
この記事ではインストールディレクトリを下記にしました。以降はこのディレクトリを%GLASSFISH_HOME%
と表記します。
D:\dev\glassfish-web-5.1.0
環境変数pathにbinディレクトリを追加します。
%GLASSFISH_HOME%\bin
JDKについて
現時点ではJDK 9以降のバージョンでは正常に動作しないためJDK 1.8を利用します。なお、環境変数JAVA_HOMEがJDK 1.8を指していれば下記の対応は不要です。
%GLASSFISH_HOME%\glassfish\config\asenv.bat
の最後に下記を追加します。
set AS_JAVA=C:\Program Files\Java\jdk1.8.0_231
起動と停止
起動と停止は%GLASSFISH_HOME%\bin
ディレクトリにあるasadminコマンド (asadmin.bat)で行います。
起動
起動時に<ドメイン名>を指定しますが、作成されているドメインが1つだけの場合はドメイン名を省略できます。
インストール直後はデフォルトでdomain1
というドメインしか登録されていないので省略できます(ドメインについては後述します)。
> asadmin start-domain <ドメイン名>
下記はサーバ起動時のログです。起動に成功すると管理コンソールとサンプルのアプリケーションにアクセスできるようになります。Admin Port: 4848
と表示されているように管理コンソールはポート4848でアクセスできます。
> asadmin start-domain
Waiting for domain1 to start ...............................
Successfully started the domain : domain1
domain Location: D:\dev\glassfish-web-5.1.0\glassfish\domains\domain1
Log File: D:\dev\glassfish-5.1.0\glassfish\domains\domain1\logs\server.log
Admin Port: 4848
Command start-domain executed successfully.
管理コンソール
GlassFishサーバの管理タスクを実行するブラウザベースのツールです。(管理コンソールの使い方はその都度説明します。)
http://localhost:4848
Web Profile版
参考: Full Profile版 (管理できるリソースの種類が増えています)
サンプルのアプリケーション
以下のURLにアクセスするとサンプルアプリケーション(Welcomeページのようなもの)にアクセスできます。
このアプリケーションは8080(HTTP)、8081(HTTPS)の2つのポートをリッスンしています。
http://localhost:8080
停止
停止、再起動もドメイン名の指定は起動時と同じルールです。
> asadmin stop-domain <ドメイン名>
再起動
> asadmin restart-domain <ドメイン名>
以上がインストールから起動までの説明になります。
管理ツール
前述の『起動と停止』の項目で触れた通りGlassFishサーバの管理タスクを実行するツールに、CLIのasadminコマンドとGUIの管理コンソールがあります。どちらもほぼ同じ管理タスクを実行できます。
asadminコマンド
> asadmin [asadmin options] [subcommand [options] [operands]]
asadmin options
long | short | default |
---|---|---|
--host | -H | localhost |
--port | -p | 4848 |
--user | -u | |
--passwordfile | -W | |
--terse | -t | false |
--secure | -s | false |
--echo | -e | false |
--interactive | -I | run from a console window = true / run without a console window = false |
--detach | false | |
--help | -? |
サブコマンド
start-domain
やstop-domain
などをサブコマンドと呼びます。サブコマンドの使い方は--help
オプションで確認できます。
たとえばstart-domain
サブコマンドの使い方は下記の方法で調べられます。
> asadmin start-domain --help
ローカル/リモート
サブコマンドにはローカルサブコマンドとリモートサブコマンドがあります。その違いは以下に引用した通りです。
ローカルサブコマンド
A local subcommand can be run without a running domain administration server (DAS).
However, to run the subcommand and have access to the installation directory and the domain directory, the user must be logged in to the machine that hosts the domain.
---------------------------------------------------------------------------------------------
ローカルサブコマンドは、実行中のドメイン管理サーバー(DAS)なしで実行できます。
ただし、サブコマンドを実行してインストールディレクトリとドメインディレクトリにアクセスするには、ドメインをホストするマシンにログインする必要があります。
リモートサブコマンド
A remote subcommand is always run by connecting to a DAS and running the subcommand there.
A running DAS is required.
---------------------------------------------------------------------------------------------
リモートサブコマンドは、DASに接続し、そこでサブコマンドを実行することにより常に実行されます。
実行中のDASが必要です。
マルチコマンドモード
asadminコマンドにはマルチコマンドモードもあります。サブコマンドを指定せずにasadminとだけ実行するとマルチコマンドモードに入ります。
> asadmin
Use "exit" to exit and "help" for online help.
asadmin>
管理者ユーザのパスワードを設定
デフォルトの管理者ユーザはadmin
です。パスワードが設定されていないので管理コンソールには誰でもアクセスできますが、パスワードを設定することでログイン認証を行うことができます。
管理コンソールで設定
Configurations
→ server-config
→ Security
→ Realms
→ admin-realm
→ Manage Users
をクリックします。
asadminコマンドで設定
> asadmin change-admin-password
Enter admin user name [default: admin]> (enter)
Enter the admin password> (enter)
Enter the new admin password> ********* (new password)
Enter the new admin password again> ********* (new password)
Command change-admin-password executed successfully.
パスワードを設定すると未ログインで管理コンソールへアクセスするとログイン画面が表示されます。
またasadminコマンドの実行時にも同様にログインが求められます。
> asadmin list-commands
Enter admin user name> admin
Enter admin password for user "admin"> **********
一度login
サブコマンドでログインを行えば、以降はログインは不要になります。
> asadmin login
Enter admin user name [Enter to accept default]> admin
Enter admin password> **********
Login information relevant to admin user name [admin] for host [localhost] and admin port [4848] stored at [C:\Users\USERNAME\.gfclient\pass] successfully.
Make sure that this file remains protected. Information stored in this file will be used by administration commands to manage associated domain.
Command login executed successfully.
ドメイン
ドメインとは
GlassFishサーバインスタンスやそのコンフィグレーション、各種リソース、ライブラリ、アプリケーションのデプロイ領域のまとまりをドメインと呼びます。
インストールした1つのGlassFishサーバで複数のドメインを管理することができます。ドメインは互いに独立しているので、あるドメインの変更が他のドメインに影響を与えることはありません。
なお、README.txtに記載されている通りGlassFishサーバのインストール直後はデフォルトでdomain1
というドメインが作成されています。
The default domain called 'domain1' is installed and preconfigured.
--------------------------------------------------------------------------
「domain1」というデフォルトのドメインがインストールされ、事前設定されています。
ドメインの作成
create-domain
サブコマンドで新しいドメインを作成できます。この例ではdomain2
というドメインを作成します。
なお、開発用途であれば新しくドメインを作成する必要はありません。
> asadmin create-domain --adminport 4849 domain2
Enter admin user name [Enter to accept default "admin" / no password]>
Using port 4849 for Admin.
Default port 8080 for HTTP Instance is in use. Using 51549
Using default port 7676 for JMS.
Default port 3700 for IIOP is in use. Using 51550
Default port 8181 for HTTP_SSL is in use. Using 51551
Using default port 3820 for IIOP_SSL.
Using default port 3920 for IIOP_MUTUALAUTH.
Default port 8686 for JMX_ADMIN is in use. Using 51552
Using default port 6666 for OSGI_SHELL.
Using default port 9009 for JAVA_DEBUGGER.
Distinguished Name of the self-signed X.509 Server Certificate is:
[CN=home-dev-pc.mshome.net,OU=GlassFish,O=Oracle Corporation,L=Santa Clara,ST=California,C=US]
Distinguished Name of the self-signed X.509 Server Certificate is:
[CN=home-dev-pc.mshome.net-instance,OU=GlassFish,O=Oracle Corporation,L=Santa Clara,ST=California,C=US]
Domain domain2 created.
Domain domain2 admin port is 4849.
Domain domain2 allows admin login as user "admin" with no password.
Command create-domain executed successfully.
ドメインの一覧はlist-domains
サブコマンドで確認できます。この通り作成直後のドメインは起動していません。
> asadmin list-domains
domain1 running
domain2 not running
Command list-domains executed successfully.
ドメイン名を指定してdomain2
を起動します。
> asadmin start-domain domain2
Waiting for domain2 to start .......................
Successfully started the domain : domain2
domain Location: D:\dev\glassfish-web-5.1.0\glassfish\domains\domain2
Log File: D:\dev\glassfish-web-5.1.0\glassfish\domains\domain2\logs\server.log
Admin Port: 4849
Command start-domain executed successfully.
jpsで確認するとドメイン毎にJVMプロセスが起動していることがわかります。
> jps -l
17056 jdk.jcmd/sun.tools.jps.Jps
15112 com.sun.enterprise.glassfish.bootstrap.ASMain
5208 com.sun.enterprise.glassfish.bootstrap.ASMain
ドメイン管理サーバ (DAS)
1つのドメインにデフォルトでserver
という名前のGlassFishサーバインスタンスが作成・実行されています。このサーバインスタンスでドメインの管理を行うので、ドメイン管理サーバ (DAS / Domain Administration Server)と呼びます。
下図はサーバインスタンスの情報を確認するページです。このページ上部のボタンでインスタンスの停止や再起動、ログの確認が行えます。
下線を引いたConfiguration:のserver-config
とは、このサーバインスタンスのコンフィグレーションで、下図のような設定項目があります。ちなみにdefault-config
という名前のConfigurationはデフォルト設定値(テンプレート)で、新しくConfigurationを作成するときのコピー元として使えます。
仮想サーバ
A virtual server, sometimes called a virtual host, is an object that allows the same physical server to host multiple Internet domain names.
----------------------------------------------------------------------------
仮想サーバーは、仮想ホストとも呼ばれ、同じ物理サーバーが複数のインターネットドメイン名をホストできるようにするオブジェクトです。
GlassFishサーバインスタンス内に、さらに仮想サーバを作成することができます。
デフォルトでは__asadmin
とserver
という名前の仮想サーバが作成されていて、管理コンソールは__asadmin
で実行されています。
server
は開発環境でアプリケーションの開発、テストで必要となる仮想サーバです。
仮想サーバの作成
Configurations
→ server-config
→ Virtual Servers
→ New...
をクリックします。
Idにserver2
と入力し、その他の項目はこのままでOK
をクリックして登録します。
下図は登録後です。
次にNetwork Listenerを追加します。
Configurations
→ server-config
→ Network Config
→ Network Listeners
→ New...
をクリックします。
NameとProtocolにhttp-listener-3
と入力、Default Virtual Serverに先ほど登録したserver2
を選択します。
Port、Address、Thread Poolは図の通りとしてOK
をクリックして登録します。
下図は登録後です。
登録した仮想サーバserver2
の編集画面を開き、下線を引いた項目を編集して更新します。
ドキュメントルート(Docroot)に指定したD:\var\www\server2
にindex.htmlを作成し、下記のアドレスにアクセスすると作成したページが表示されます。
http://localhost:8082
list-virtual-servers
サブコマンドで仮想サーバの一覧を取得することができます。
> asadmin list-virtual-servers
server
__asadmin
server2
Command list-virtual-servers executed successfully.
デフォルトではポート4848のドメインの結果を返すので、他のドメインの仮想サーバを調べたいときは下記のように--port
オプションでポートを指定します。
> asadmin --port 4849 list-virtual-servers
server
__asadmin
Command list-virtual-servers executed successfully.
現時点での状態
この時点でのドメインと仮想サーバは下記の通りです。
ドメイン
> asadmin list-domains -l
DOMAIN ADMIN_HOST ADMIN_PORT RUNNING RESTART_REQUIRED
domain1 localhost 4848 true false
domain2 localhost 4849 true false
Command list-domains executed successfully.
仮想サーバ
> asadmin list-virtual-servers
server
__asadmin
server2
Command list-virtual-servers executed successfully.
> asadmin --port 4849 list-virtual-servers
server
__asadmin
Command list-virtual-servers executed successfully.
リソースの管理
GlassFishサーバが管理するリソースにJDBC Resourceがあります。
JDBC Resourceの登録
JDBC Resourceを登録するには、Database Vendorが提供するJDBC Driverの登録と、JDBC Connection Poolの登録を行う必要があります。
以下は、MySQL Database用のJDBC Resourceの登録手順になります。
MySQL Connector/Jのダウンロードと配置
[MySQL Community Downloads] (https://dev.mysql.com/downloads/connector/j/)よりMySQL Connector/Jのアーカイブファイルをダウンロードします。2020年1月現在の最新バージョン8.0.18をダウンロードし、適当なディレクトリへ展開しておきます。
jarファイルを登録するには、エクスプローラなどで直接コピーする方法とadd-library
サブコマンドを使う方法があります。
直接コピーする場合は、サーバーを停止した状態でmysql-connector-java-8.0.18.jar
を%GLASSFISH_HOME%\glassfish\domains\domain1\lib
にコピーします。
(なお、%GLASSFISH_HOME%\glassfish\lib
にコピーすると全ドメインで有効になります。)
add-library
サブコマンドを使う場合はサーバーを停止する必要はありませんが、再起動が必要です。
> asadmin add-library .\mysql-connector-java-8.0.18.jar
Command add-library executed successfully.
list-libraries
サブコマンドで登録したライブラリを確認できます。
> asadmin list-libraries
mysql-connector-java-8.0.18.jar
Command list-libraries executed successfully.
Databaseの準備
データベースにはMySQL 8.0.17を利用します。動作検証用に下記のデータベース、ユーザ、テーブルを作成します。
CREATE DATABASE IF NOT EXISTS test_db
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'test_user'@'localhost'
IDENTIFIED BY 'test_user'
PASSWORD EXPIRE NEVER;
GRANT ALL ON test_db.* TO 'test_user'@'localhost';
CREATE TABLE IF NOT EXISTS memo (
id BIGINT AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
description TEXT NOT NULL,
done BOOLEAN DEFAULT FALSE NOT NULL,
updated TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL,
PRIMARY KEY (id)
) CHARACTER SET = utf8mb4, COLLATE utf8mb4_general_ci;
JDBC Connection Poolsの登録
Resources
→ JDBC
→ JDBC Connection Pools
→ New...
をクリックします。
Pool NameにMySQLConnPool
と入力、Resource TypeとDatabase Driver Vendorは図の通り選択します。
この例ではResource Typeにjavax.sql.DataSource
を選択しましたが、java.sql.Driver
を選択することもできます。
Additional Propertiesは図の通り入力、Finish
をクリックして登録します。なお黄色の下線のDatasource classnameはこの時点では変えられないので登録後に編集します。
Name | Value |
---|---|
user | test_user |
password | test_user |
databaseName | test_db |
serverName | localhost |
portNumber | 3306 |
sslMode | disabled |
allowPublicKeyRetrieval | true |
serverTimezone | Asia/Tokyo |
下図は登録後です。
編集画面を開きDatasource Classnameにcom.mysql.cj.jdbc.MysqlDataSource
と入力します。利用するJDBC Driverがのバージョンが8.0以降の場合はこのクラス名を指定する必要があるためです。
次にAdvancedタブを開き図のConnection validationのRequired
にチェックを入れ、Table Nameにdual
と入力してSave
をクリックして登録します。
Generalタブを開き図のPing
をクリックして通信できるか確認します。Ping Succeeded
と表示されれば成功です。
JDBC Resourceの登録
Resources
→ JDBC
→ JDBC Resources
→ New...
をクリックします。
JNDI Nameにjdbc/MySQLConnPool
と入力、Pool Nameに先ほど登録したMySQLConnPool
を選択しOK
をクリックして登録します。
下図は登録後です。
補足:Resource Typeにjavax.sql.Driverを選ぶ場合
Pool NameにMySQLConnPool2
と入力、Resource TypeとDatabase Driver Vendorは図の通り選択します。
黄色の下線のDriver Classnameはこの時点では変えられないので登録後に編集します。
プロパティを更新します。この画面でプロパティを追加しようとするとエラーが起きて正常に登録できないので、図の3項目だけ登録します。残りは登録後に追加します。
Name | Value |
---|---|
URL | jdbc:mysql://localhost:3306/test_db |
user | test_user |
password | test_user |
sslMode | DISABLED |
allowPublicKeyRetrieval | true |
serverTimezone | Asia/Tokyo |
登録後に再度編集画面を開き、Driver Classsnameをcom.mysql.cj.jdbc.Driver
で更新します。
残りのプロパティを追加します。
以上でJDBC Resourceの登録は完了です。
アプリケーションの開発とデプロイ
IDEにIntelliJ IDEAを利用します。
JetBrainsの公式ヘルプページ[Java EEアプリケーションの開発] (https://pleiades.io/help/idea/creating-and-running-your-first-java-ee-application.html)を参考にしました。
Application Serverの登録
+
アイコンをクリックしてメニューを表示、その中からGlassfish Server
を選択します。
GlassFishのインストールディレクトリを指定します。
OK
をクリックして登録します。
プロジェクトの作成
左側の選択項目からJava Enterprise
を選択、右側のProject SDK、Java EE version、Application Serverはそれぞれ図の通り選択します。
その下のAdditional Library And Frameworks:で、使用するLibraryとFrameworkにチェックを入れます。下図の下線を引いたものを使用しますが、黄色の下線を引いたJSON Processingだけは、この場でチェックを入れずにプロジェクト作成後に別途追加します。
web/WEB-INF/web.xml
jakarta.ejb-api.jar
jakarta.servlet.jsp-api.jar
jakarta.servlet-api.jar
bean-validator.jar
bean-validator-cdi.jar
web/WEB-INF/beans.xml
cdi-api.jar
cdi-api-fragment.jar
weld-integration.jar
weld-integration-fragment.jar
weld-osgi-bundle.jar
Configure...
をクリック、Downloading Options
でjavax.persistence-api-2.2.jar
のチェックを外します。
これはJavaEE Persistence
でjavax.persistence.jar
が組み込まれるためです。
lib/antlr-2.7.7.jar
lib/byte-buddy-1.10.2.jar
lib/classmate-1.5.1.jar
lib/dom4j-2.1.1.jar
lib/FastInfoset-1.2.15.jar
lib/hibernate-commons-annotations-5.1.0.Final.jar
lib/hibernate-core-5.4.9.Final.jar
lib/istack-commons-runtime-3.0.7.jar
lib/jandex-2.1.1.Final.jar
lib/javassist-3.24.0-GA.jar
lib/javax.activation-api-1.2.0.jar
lib/jaxb-api-2.3.1.jar
lib/jaxb-runtime-2.3.1.jar
lib/jboss-logging-3.3.2.Final.jar
lib/jboss-transaction-api_1.2_spec-1.1.1.Final.jar
lib/stax-ex-1.8.jar
lib/txw2-2.3.1.jar
JavaEE Persistence
ProviderにHibernate
を選択します。
src/META-INF/persistence.xml
lib/javax.persistence.jar
lib/javax.json.bind-api.jar
JSON Processing
ここでは組み込まず、プロジェクト作成後に追加します。
プロジェクト作成後の設定
プロジェクト作成直後のディレクトリです。
<PROJECT_ROOT>
|
+--- /lib
| |
| +--- antlr-2.7.7.jar
| +--- byte-buddy-1.10.2.jar
| +--- classmate-1.5.1.jar
| +--- dom4j-2.1.1.jar
| +--- FastInfoset-1.2.15.jar
| +--- hibernate-commons-annotations-5.1.0.Final.jar
| +--- hibernate-core-5.4.9.Final.jar
| +--- istack-commons-runtime-3.0.7.jar
| +--- jandex-2.1.1.Final.jar
| +--- javassist-3.24.0-GA.jar
| +--- javax.activation-api-1.2.0.jar
| +--- javax.json.bind-api.jar
| +--- javax.persistence.jar
| +--- jaxb-api-2.3.1.jar
| +--- jaxb-runtime-2.3.1.jar
| +--- jboss-logging-3.3.2.Final.jar
| +--- jboss-transaction-api_1.2_spec-1.1.1.Final.jar
| +--- stax-ex-1.8.jar
| +--- txw2-2.3.1.jar
|
+--- /src
| |
| +--- /META-INF
| |
| +--- persistence.xml
|
+--- /web
|
+--- /WEB-INF
| |
| +--- beans.xml
| |
| +--- web.xml
|
+--- index.jsp
<EXTERNAL LIBRARIES>
|
+--- GlassFish 5.1.0
| |
| +--- jakarta.ejb-api.jar
| +--- jakarta.servlet.jsp-api.jar
| +--- jakarta.servlet-api.jar
|
+--- GlassFish 5.1.0 - Bean Validation
| |
| +--- bean-validator.jar
| +--- bean-validator-cdi.jar
|
+--- GlassFish 5.1.0 - CDI : Contextes and Dependency Inejction
|
+--- cdi-api.jar
+--- cdi-api-fragment.jar
+--- weld-integration.jar
+--- weld-integration-fragment.jar
+--- weld-osgi-bundle.jar
パッケージの作成
srcディレクトリにcom.example.demoというパッケージを作成、さらにその下にcontroller、dto、ejb、entity、serviceパッケージを作成します。
/src
|
+--- /com
|
+--- /example
|
+--- /demo
|
+--- /controller
|
+--- /dto
|
+--- /ejb
|
+--- /entity
|
+--- /service
index.jspの修正とJSTLの追加
下図のようにjspでJSTLを使おうとするとtaglibのuriが解決できないというエラーが表示されます。
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<div>
<h1>Welcome</h1>
<div>
<ul>
<li><a href="${pageContext.request.contextPath}/memo">memo</a></li>
</ul>
</div>
</div>
</body>
</html>
JSPでjstlを利用できるようにライブラリを追加します。メニューバー → File
→ Project Structure
→ Project Settings
→ Libraries
→ +
アイコン → From Maven...
をクリックします。
検索欄にjavax.servlet:jstl
と入力して虫眼鏡
アイコンをクリックして検索実行 → 検索結果からjavax.servlet:jstl:1.2
をクリック → OK
ボタンをクリックしてライブラリに追加します。
JSON Processing
- 参考: [JSON Processing API documentation] (https://jakarta.ee/specifications/jsonp/1.1/apidocs/)
jakarta.json-apiの追加
JSON Processingが利用できるようにライブラリを追加します。メニューバー → Project Structure
→ Project Settings
→ Libraries
→ +
アイコン → From Maven...
をクリックします。
検索欄にjakarta.json:jakarta.json-api
と入力して虫眼鏡
アイコンをクリックして検索実行 → 検査結果からjakarta.json:jakarta.json-api:1.1.5
をクリック → OK
ボタンをクリックしてライブラリに追加します。
サンプルコード
package com.example.demo.dto;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
public class Phone {
private String home;
private String mobile;
public Phone() {
}
public Phone(String home, String mobile) {
this.home = home;
this.mobile = mobile;
}
public String getHome() {
return home;
}
public void setHome(String home) {
this.home = home;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public JsonObject toJsonObject() {
JsonObjectBuilder builder = Json.createObjectBuilder();
if (home != null) {
builder.add("home", home);
}
if (mobile != null) {
builder.add("mobile", mobile);
}
return builder.build();
}
@Override
public String toString() {
return "Phone{" +
"home='" + home + '\'' +
", mobile='" + mobile + '\'' +
'}';
}
}
package com.example.demo.dto;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.bind.annotation.JsonbProperty;
public class Person {
private String name;
private String gender;
private Integer age;
@JsonbProperty("phones")
private Phone phone;
public Person() {
}
public Person(String name, String gender, Integer age, Phone phone) {
this.name = name;
this.gender = gender;
this.age = age;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
public JsonObject toJsonObject() {
JsonObjectBuilder builder = Json.createObjectBuilder();
builder
.add("name", name)
.add("gender", gender)
.add("age", age);
if (phone != null) {
builder.add("phones", phone.toJsonObject());
}
return builder.build();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", phone=" + phone +
'}';
}
}
package com.example.demo.ejb;
import com.example.demo.dto.Person;
import javax.ejb.Stateless;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonPointer;
import javax.json.JsonValue;
import javax.json.stream.JsonCollectors;
import java.util.List;
@Stateless
public class PersonProcessor {
public JsonArray toJsonArray(List<Person> persons) {
return persons.stream()
.map(Person::toJsonObject)
.collect(JsonCollectors.toJsonArray());
}
public JsonArray replace(JsonArray jsonArray, String pointer, String replaceValue) {
JsonPointer p = Json.createPointer(pointer);
JsonArray newArray = p.replace(jsonArray, Json.createValue(replaceValue));
return newArray;
}
public JsonValue pickup(JsonArray jsonArray, String pointer) {
JsonPointer p = Json.createPointer(pointer);
if (p.containsValue(jsonArray)) {
JsonValue value = p.getValue(jsonArray);
return value;
}
return JsonValue.NULL;
}
}
JSON Binding
- 参考: [Jakarta JSON Binding 1.0.2 API Specification] (https://jakarta.ee/specifications/jsonb/1.0/apidocs/overview-summary.html)
サンプルコード
package com.example.demo.service;
import com.example.demo.dto.Person;
import javax.enterprise.context.Dependent;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
@Dependent
public class PersonService {
public List<Person> toList(String json) {
Jsonb jsonb = JsonbBuilder.create();
List<Person> persons = jsonb.fromJson(json, new ArrayList<Person>(){}.getClass().getGenericSuperclass());
return persons;
}
public List<Person> toList(Reader reader) {
Jsonb jsonb = JsonbBuilder.create();
List<Person> persons = jsonb.fromJson(reader, new ArrayList<Person>(){}.getClass().getGenericSuperclass());
return persons;
}
}
package com.example.demo.controller;
import com.example.demo.dto.Person;
import com.example.demo.service.PersonService;
import com.example.demo.ejb.PersonProcessor;
import javax.inject.Inject;
import javax.json.JsonArray;
import javax.json.JsonValue;
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.io.BufferedReader;
import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;
@WebServlet(urlPatterns = {"/person"})
public class PersonController extends HttpServlet {
private static final Logger log = Logger.getLogger(PersonController.class.getName());
@Inject
private PersonService personService;
@Inject
private PersonProcessor personProcessor;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/WEB-INF/views/person/list.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Person> persons;
try (BufferedReader reader = req.getReader()) {
// JSON Binding
persons = personService.toList(reader);
req.setAttribute("persons", persons);
}
// JSON Processing
JsonArray jsonArray = personProcessor.toJsonArray(persons);
JsonValue mobile = personProcessor.pickup(jsonArray, "/0/phones/mobile");
JsonValue home = personProcessor.pickup(jsonArray, "/1/phones/home");
req.setAttribute("mobile", mobile.toString());
req.setAttribute("home", home.toString());
req.getRequestDispatcher("/WEB-INF/views/person/list.jsp").forward(req, resp);
}
}
Inject
javax.injectの追加
@Inect
アノテーションが利用できるようにライブラリを追加します。メニューバー → Project Structure
→ Project Settings
→ Libraries
→ +
アイコン → From Maven...
をクリックします。
検索欄にjavax.inject:javax.injectと入力して虫眼鏡アイコンをクリックして検索実行 → 検査結果からjavax.inject:javax.inject:1をクリック → OKボタンをクリックしてライブラリに追加します。
web.xmlの修正とエラーページの追加
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/errors/404.jsp</location>
</error-page>
</web-app>
HTTPステータスコード404のときのエラーページを下記の場所に作成します。
/web
|
+--- /WEB-INF
|
+--- /views
|
+--- /errors
|
+--- 404.jsp
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head>
<title>404 Not Found</title>
</head>
<body>
<div>
<h1>404 Not Found</h1>
</div>
</body>
</html>
静的ファイルの追加
静的ファイルはwebディレクトリの直下に配置します。
/web
|
+--- /public
|
+--- /css
|
+--- base.css
inex.jspのheadタグ内に下記の行を追加します。
<link rel="stylesheet" href="public/css/base.css">
アプリケーションの動作確認
この時点の状態でアプリケーションが起動するか確認します。
画面右上のRun GlassFish 5.1.0
アイコンをクリックしてGlassFishサーバを起動します。
GlassFishサーバが起動すると自動的にブラウザが立ち上がり指定(デフォルトではトップページ、この例ではindex.jsp)のページが表示されます。
Application Serverのコンフィグレーション
URL
で表示するページのURLを指定します。また任意のドメインや仮想サーバでアプリケーションを起動したい場合はServer Domain
、Virtual Server
で指定します。
warファイルのビルド
ビルドの設定は初回だけです。
ビルドの設定
メニューバーのFile
→ Project Structure
→ Project Settings
→ Artifacts
→ +
アイコン → Web Application: Archive
→ For 'demo-javaee8:war exploded
をクリックします。
画面右側Output Layout
のdemo-javaee8_war.war
をクリックすると画面下にCreate Manifest...
ボタンが表示されるのでクリックします。
Manifestファイルの場所を/web/META-INF/MANIFEST.MF
に指定し、OK
ボタンをクリックして画面を閉じます。
ビルドの実行
メニューバーのBuild
→ Build Artifacts...
をクリックします。
demo-javaee8:war
→ Build
をクリックするとビルドが始まります。
下図の場所にwarファイルが出力されます。
warファイルをデプロイする
IDE上で実行するGlassFishサーバではなく、ローカル上で実行中のGlassFishサーバへwarファイルをデプロイします。
管理コンソールにもデプロイ機能がありますが2020年1月現在、デプロイしようとするとエラーが発生してデプロイできないため(Issue : [Can´t deploy applications from Web Console [deploy origPath is NULL]] (https://github.com/eclipse-ee4j/glassfish/issues/22739))、asadminコマンドでデプロイします。
なお、IntellJ IDEA上からもデプロイすることができますが、この記事では割愛します。
> asadmin deploy --contextroot=demo-javaee8 --name=demo-javaee8 /path/to/demo-javaee8_war.war
Application deployed with name demo-javaee8.
Command deploy executed successfully.
デプロイ時にドメインと仮想サーバを指定しなかった場合、ポート4848で実行中のドメインの仮想サーバすべてにアプリケーションがデプロイされます。
この記事の例でいえばdomain1
で仮想サーバserver
、server2
を実行しているのでこの2つにデプロイされます。
> asadmin list-virtual-servers
server
__asadmin
server2
Command list-virtual-servers executed successfully.
デプロイ後に下記のURLにアクセスすると同じアプリケーションが実行されていることが分かります。
# server
http://localhost:8080/demo-javaee8/
# server2
http://localhost:8082/demo-javaee8/
ポート4849で実行中のdomain2
に対してデプロイする場合は--port
を指定します。
> asadmin --port 4849 deploy --contextroot=demo-javaee8 --name=demo-javaee8 /path/to/demo-javaee8_war.war
管理コンソールでデプロイされているアプリケーションを確認する
管理コンソールでデプロイされているアプリケーションを確認することができます。
この画面でUndeploy、Enable/Disableなどの操作が行えます。DisableにしたアプリケーションにアクセスするとHTTPステータスコード404が返ります。
アプリケーションをアンデプロイする
アンデプロイは管理コンソールおよびasadminコマンドから行えます。アンデプロイではアプリケーション名を指定します。またデプロイ時と同様に、ポートと仮想サーバを指定しなければ仮想サーバにデプロイされているすべてのアプリケーションをアンデプロイします。
> asadmin undeploy demo-javaee8
Command undeploy executed successfully.
ポート4849で実行中のdomain2
に対するアンデプロイは--port
を指定します。
> asadmin --port 4849 undeploy demo-javaee8
Command undeploy executed successfully.
データベースアクセス処理の実装
次にJPAを使ったデータベースアクセス処理を実装します。
persistence.xmlの修正
jta-data-source
には管理コンソールで登録したJDBC Resourceのjdbd/MySQLConnPool
を指定します。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence 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_2.xsd"
version="2.2">
<persistence-unit name="default" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>jdbc/MySQLConnPool</jta-data-source>
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
</properties>
</persistence-unit>
</persistence>
Entity
package com.example.demo.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDateTime;
@Table(name = "memo")
@Entity
public class Memo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "description", nullable = false)
private String description;
@Column(name = "done", nullable = false)
private Boolean done;
@Column(name = "updated", nullable = false)
private LocalDateTime updated;
// ...アクセサ省略...
}
アプリケーションのビルドや実行には影響はありませんが、これを解決する場合はメニューバー → View
→ Tool Windows
→ Database
を開きDataSourceを追加します。
Database Tool Windowの+
アイコン → Data Source
→ MySQL
を選択します。
Databaseの接続に必要な項目を入力したら、Test Connection
ボタンをクリックして確認します。
メニューバー → View
→ Tool Windows
→ Persistence
→ demo-javaee8
を右クリック → Assign Data Sources...
→ 上記で追加したData Sourceを紐づけます。
Service
package com.example.demo.service;
import com.example.demo.entity.Memo;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.util.List;
import java.util.logging.Logger;
@Transactional
@Dependent
public class MemoService {
private final static Logger log = Logger.getLogger(MemoService.class.getName());
@Inject
private EntityManager em;
@PostConstruct
public void init() {
System.out.println("MemoService#init");
}
@PreDestroy
public void destroy() {
System.out.println("MemoService#destroy");
}
public Memo findById(Long id) {
log.info("MemoService#findById(" + id + ")");
TypedQuery<Memo> query = em.createQuery("SELECT m FROM Memo m WHERE m.id = :id", Memo.class)
.setParameter("id", id);
Memo memo = query.getSingleResult();
return memo;
}
public List<Memo> findAll() {
log.info("MemoService#findAll");
TypedQuery<Memo> query = em.createQuery("SELECT m FROM Memo m", Memo.class);
List<Memo> list = query.getResultList();
return list;
}
public void save(Memo memo) {
log.info("MemoService#save(" + memo.toString() + ")");
em.persist(memo);
em.flush();
}
}
EntityManagerを@Inject
アノテーションでインジェクトできるようにResourceクラスを作成します。
package com.example.demo;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
public class Resource {
@PersistenceUnit(unitName = "default")
private EntityManagerFactory emf;
@Produces
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void closeEntityManager(@Disposes EntityManager em) {
em.close();
}
}
Servlet
package com.example.demo.controller;
import com.example.demo.service.MemoService;
import com.example.demo.entity.Memo;
import javax.inject.Inject;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
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.io.BufferedReader;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
@WebServlet(urlPatterns = {"/memo"})
public class MemoController extends HttpServlet {
private static final Logger log = Logger.getLogger(MemoController.class.getName());
@Inject
private MemoService memoService;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Memo> memos = memoService.findAll();
req.setAttribute("memos", memos);
req.getRequestDispatcher("/WEB-INF/views/memo/list.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try (BufferedReader reader = req.getReader()) {
Memo memo = toMemo(reader);
memoService.save(memo);
req.setAttribute("memo", memo);
}
req.getRequestDispatcher("/WEB-INF/views/memo/list.jsp").forward(req, resp);
}
private static final JsonbConfig config = new JsonbConfig()
.withEncoding("UTF-8")
.withNullValues(Boolean.FALSE)
.withDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
private Memo toMemo(BufferedReader reader) {
Jsonb jsonb = JsonbBuilder.create(config);
Memo memo = jsonb.fromJson(reader, Memo.class);
return memo;
}
JSP
/web
|
+--- /WEB-INF
|
+--- /views
|
+--- /memo
|
+--- list.jsp
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>メモ一覧</title>
<link rel="stylesheet" href="public/css/base.css">
</head>
<body>
<div>
<h1>メモ一覧</h1>
<div>
<table>
<thead>
<tr>
<th>No</th>
<th>ID</th>
<th>タイトル</th>
<th>説明</th>
<th>完了</th>
<th>更新日</th>
</tr>
</thead>
<tbody>
<c:forEach items="${memos}" var="memo" varStatus="index">
<tr>
<td>${index}</td>
<td>${memo.id}</td>
<td>${memo.title}</td>
<td>${memo.description}</td>
<td>${memo.done}</td>
<td>${memo.updated}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</body>
</html>
補足
[Specifications] (https://jakarta.ee/specifications/)
Servlet
- [Jakarta Servlet 4.0] (https://jakarta.ee/specifications/servlet/4.0/)
- Maven
-
jakarta.servlet
:jakarta.servlet-api
:4.0.3
-
Server Pages (JSP)
- [Jakarta Server Pages 2.3] (https://jakarta.ee/specifications/pages/2.3/)
- Maven
-
jakarta.servlet.jsp
:jakarta.servlet.jsp-api
:2.3.6
-
Expression Language (EL)
[Jakarta Expression Language 3.0] (https://jakarta.ee/specifications/expression-language/3.0/)
- Maven
-
jakarta.el
:jakarta.el-api
:3.0.3
-
Debugging Support for Other Languages
- [Jakarta Debugging Support for Other Languages 1.0] (https://jakarta.ee/specifications/debugging/1.0/)
- Maven
Standard Tag Library (JSTL)
- [Jakarta Standard Tag Library 1.2] (https://jakarta.ee/specifications/tags/1.2/)
- Maven
-
jakarta.servlet.jsp.jstl
:jakarta.servlet.jsp.jstl-api
:1.2.7
-
Server Faces (JSF)
- [Jakarta Server Faces 2.3] (https://jakarta.ee/specifications/faces/2.3/)
- Maven
-
jakarta.faces
:jakarta.faces-api
:2.3.2
-
RESTful Web Services (JAX-RS)
- [Jakarta RESTful Web Services 2.1] (https://jakarta.ee/specifications/restful-ws/2.1/)
- Maven
-
jakarta.ws.rs
:jakarta.ws.rs-api
:2.1.6
-
WebSocket
- [Jakarta WebSocket 1.1] (https://jakarta.ee/specifications/websocket/1.1/)
- Maven
-
jakarta.websocket
:jakarta.websocket-api
:1.1.2
-
jakarta.websocket
:jakarta.websocket-client-api
:1.1.2
-
JSON Processing (JSON-P)
- [Jakarta JSON Processing 1.1] (https://jakarta.ee/specifications/jsonp/1.1/)
- Maven
-
jakarta.json
:jakarta.json-api
:1.1.6
-
JSON Binding (JSON-B)
- [Jakarta JSON Binding Specification 1.0] (https://jakarta.ee/specifications/jsonb/1.0/)
- Maven
-
jakarta.json.bind
:jakarta.json.bind-api
:1.0.2
-
Annotations
- [Jakarta Annotations 1.3] (https://jakarta.ee/specifications/annotations/1.3/)
- Maven
-
jakarta.annotation
:jakarta.annotation-api
:1.3.5
-
Enterprise Beans (EJB)
- [Jakarta Enterprise Beans 3.2] (https://jakarta.ee/specifications/enterprise-beans/3.2/)
- Maven
-
jakarta.ejb
:jakarta.ejb-api
:3.2.6
-
Transactions (JTA)
- [Jakarta Transactions 1.3] (https://jakarta.ee/specifications/transactions/1.3/)
- Maven
-
jakarta.transaction
:jakarta.transaction-api
:1.3.3
-
Persistence (JPA)
- [Jakarta Persistence 2.2] (https://jakarta.ee/specifications/persistence/2.2/)
- Maven
-
jakarta.persistence
:jakarta.persistence-api
:2.2.3
-
Bean Validation
- [Jakarta Bean Validation 2.0] (https://jakarta.ee/specifications/bean-validation/2.0/)
- Maven
-
jakarta.validation
:jakarta.validation-api
:2.0.2
-
Managed Beans
- [Jakarta Managed Beans 1.0] (https://jakarta.ee/specifications/managedbeans/1.0/)
- Maven
-
jakarta.annotation
:jakarta.annotation-api
:1.3.4
-
Interceptors
- [Jakarta Interceptors 1.2] (https://jakarta.ee/specifications/interceptors/1.2/)
- Maven
-
jakarta.interceptor
:jakarta.interceptor-api
:1.2.5
-
Contexts and Dependency Injection
- [Jakarta Context Dependency Injection 2.0] (https://jakarta.ee/specifications/cdi/2.0/)
- Maven
-
jakarta.enterprise
:jakarta.enterprise.cdi-api
:2.0.2
-
Dependency Injection
- [Jakarta Dependency Injection 1.0] (https://jakarta.ee/specifications/dependency-injection/1.0/)
- Maven
-
jakarta.inject
:jakarta.inject-api
:1.0
-
Security
- [Jakarta Security 1.0] (https://jakarta.ee/specifications/security/1.0/)
- Maven
-
jakarta.security.enterprise
:jakarta.security.enterprise-api
:1.0.2
-
Authentication
- [Jakarta Authentication 1.1] (https://jakarta.ee/specifications/authentication/1.1/)
- Maven
-
jakarta.security.auth.message
:jakarta.security.auth.message-api
:1.1.3
-