- 投稿日:2020-07-07T18:35:00+09:00
CICS-Javaアプリケーションを動かす - (4)Spring Bootアプリ
はじめに
CICS TS for z/OSでは、Libertyの稼働がサポートされているので、CICS上でJavaEEアプリケーションを動かすことができます。
CICS TS V5.3からSpring Bootをサポートするようになったため、Spring BootのアプリケーションもCICS上で(CICS上のLibertyで)稼働できるようになりました。CICS上で動くということは、CICSの機能を使用するJCICSが使えるということなので、既存のCICSプログラムを呼び出すWebアプリ、CICS管理のVSAMやTSQをアクセスするWebアプリ、といったものがCICSだけで動く、さらにそれをSpring Bootフレームワークを使って開発できる、ということになります。この記事では、以下GitHubに提供されているCICS-SpringBootアプリのサンプルを動かしてみます。
cics-java-liberty-springboot-jcicsビルドの管理にはMaven or Gradleどちらも利用できるようになってますが、ここではGradleを使ってみます。
関連記事
CICS-Javaアプリケーションを動かす - (1)単純なサンプルアプリの稼働
CICS-Javaアプリケーションを動かす - (2)Mavenによるビルド管理
CICS-Javaアプリケーションを動かす - (3)Gradleによるビルド管理
CICS-Javaアプリケーションを動かす - (4)Spring Bootアプリ事前準備
※Gradleでデプロイへの管理まで行う場合、デプロイ先のCICSはCICSplex管理下にある必要があります。
開発環境(PC)
適当なJavaEE開発環境
EclipseやVS CodeなどJavaEEアプリケーション開発ができるものを適宜使用してください。
今回はサンプルをそのまま使うので特にソースの編集はしないので使わなくてもよいですが、通常はなんらかの開発環境使うことになるでしょう。Gradle, gitなどと連携できるとよいかも。
CICS Explorerを一緒に使うのであればEclipse使っておけばOK。CICS Explorer
こちらも必須ではありませんが、CICSの資源定義とか確認するのに使えます。
以下の辺りを参考にCICS ExplorerというEclipseベースのツールをダウンロードしてセットアップしておきます。
参考: Downloading and starting CICS Explorer
※このツールはCICS利用者は無償で使えるツールです。Gradle
以下の手順に従ってインストールします。
Installing Gradle
基本的には、ダウンロードしたものを解凍してパスを通すだけ。前提としてJava8以降が必要になります。
c:\>java -version java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)以下から現時点での最新版Gradle V6.5をダウンロードします(gradle-6.5.zip)。
Releases適当なディレクトリに展開します。(ここでは(c:\x\Gradle\gradle-6.5)
展開先のbin(C:\x\Gradle\gradle-6.5\bin)をPATHに追加します。確認
c:\>gradle -v ------------------------------------------------------------ Gradle 6.5 ------------------------------------------------------------ Build time: 2020-06-02 20:46:21 UTC Revision: a27f41e4ae5e8a41ab9b19f8dd6d86d7b384dad4 Kotlin: 1.3.72 Groovy: 2.5.11 Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019 JVM: 1.8.0_144 (Oracle Corporation 25.144-b01) OS: Windows 10 10.0 amd64これでOKです。
git
gitHubに提供されるサンプルを入手して使用するので、gitもインストールしておきます。
セットアップ方法などはその辺に転がってるので割愛。c:\>git --version git version 2.21.0.windows.1実行環境(z/OS, CICS)
サンプルを稼働させるCICSリージョンを用意します。
ここでは、CICSplex管理下のCT56B4A1という名前のリージョンを使うことにします。
そこに、Javaアプリケーションを稼働させるためのJVMServerという資源を追加します。
今回は、CICS-Liberty用のサンプル(JavaEEアプリケーション)を使用するので、Liberty用のJVMServerを作成しておきます。JVMプロファイル
USS上にJVMプロファイルを準備します。(JVMServerに関するプロパティーは実質このUSS上のファイルに指定します。JVMSERVER資源定義ではこのJVMプロファイルのファイル名をポイントすることになります。)
サンプルが提供されているのでそれをコピーして使用します。/var/cicsts/cicsts56/CT56B4A1/JVMProfiles というディレクトリを作成し、そこに/usr/lpp/cicsts/cicsts56/JVMProfiles/DFHOSGI.jvmprofile(CICS導入ディレクトリ下に配置されているOSGi用のサンプル定義)をコピーします。
環境に合わせて適宜カスタマイズします。DFHWLP.jvmprofile抜粋JAVA_HOME=/usr/lpp/java/J8.0_64/ WORK_DIR=/var/cicsts/cicsts56/CT56B4A1/work WLP_INSTALL_DIR=/usr/lpp/cicsts/cicsts56/wlp -Dcom.ibm.cics.jvmserver.wlp.autoconfigure=true -Dcom.ibm.cics.jvmserver.wlp.server.host=* -Dcom.ibm.cics.jvmserver.wlp.server.http.port=56441 -Dcom.ibm.cics.jvmserver.wlp.server.https.port=56451 -Xms128M -Xmx256M -Xmso1M -Xgcpolicy:gencon -Xscmx256M -Xshareclasses:name=cicsts%g,groupAccess,nonfatal -Xtune:virtualized -Dcom.ibm.tools.attach.enable=no -Dfile.encoding=ISO-8859-1 _BPXK_DISABLE_SHLIB=YESSIT
上のプロパティーファイルを配置したディレクトリを、SITパラメーター"JVMPROFILEDIR"に指定します。
JVMPROFILEDIR=/var/cicsts/cicsts56/CT56B4A1/JVMProfiles変更反映のためにリージョンを再起動します。
JVMServer定義
JVMSERVER資源定義を準備します。
製品提供のDFH$WLPというグループにあるJVMSERVER定義"DFHWLP"を適当なグループにコピーしてインストールします。OBJECT CHARACTERISTICS CICS RELEASE = 0730 CEDA View JVmserver( DFHWLP ) JVmserver : DFHWLP Group : TAGGRP DEScription : CICS JVM server to run WLP samples Status : Enabled Enabled | Disabled Jvmprofile : DFHWLP (Mixed Case Lerunopts : DFHAXRO Threadlimit : 015 1-256 DEFINITION SIGNATURE DEFinetime : 06/04/20 16:20:21 CHANGETime : 06/04/20 16:20:21 CHANGEUsrid : CICSUSER CHANGEAGEnt : CSDApi CSDApi | CSDBatch CHANGEAGRel : 0730※Jvmprofile: DFHWLPとなっていますが、これはSITのJVMPROFILEDIRに指定されたディレクトリ下のDFHWLP.jvmprofileというファイルがJVMプロパティーファイルとして使用されることを意味します。
CEMT I JVMSERVERで見てEnableになっていればOK。
I JVMS STATUS: RESULTS - OVERTYPE TO MODIFY Jvm(DFHWLP ) Ena Prf(DFHWLP ) Ler(DFHAXRO ) Threadc(005) Threadl( 015 ) Cur(48314096)server.xml変更
今回のサンプル実行手順では、Deployまでを自動でやるのではなく手動でデプロイするような手順になっているので、そのための設定を追加しておきます。
JVMプロファイルで
-Dcom.ibm.cics.jvmserver.wlp.autoconfigure=true
を指定すると、Libertyの構成が自動で行われます。一度JVMSERVER定義をインストールすると、workディレクトリ下にLibertyが構成されます(work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer
)。
このディレクトリ下のserver.xmlを修正して以下のようにします。server.xml... <applicationMonitor dropins="dropins" dropinsEnabled="true" pollingRate="5s" updateTrigger="polled"/> ...このように、dropinsEnabled="true", updateTrigger="polled"を指定します。
これで、dropinsディレクトリに配置されたwarを自動で検知してくれます。
同ディレクトリにdropinsディレクトリを作成しておきます(.../work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/dropins
)。変更したらJVMServerを再起動しておきます。
CICS Bundle Deployment API
CICS TS V5.6から提供されるようになったCICS Bundle Deployment APIのセットアップをしておく必要があります。(サンプル手順の手動デプロイの場合は不要)
この機能は、CMCIと呼ばれるRESTベースの管理APIの一つとしてアプリケーションのデプロイ用に追加されました。
ターゲットのCICSリージョンを管理するWUIサーバー上にCMCIをセットアップし、CMCI JVMサーバーのプロパティーで、CICS Bundle Deployment API用のパラメーターを指定します。
参考: How it works: CICS bundle deployment API最低限必要な設定は以下の通りです。
USS上にBundleファイル配置用のディレクトリを作成します。ここでは/var/cicsts/cicsts56/bundles
とします。
WUIのCMCI JVM Server用のJVMプロファイル(EYUCMCIJ.jvmprofile)に、以下のパラメーターを設定します。
-Dcom.ibm.cics.jvmserver.cmci.bundles.dir=/var/cicsts/cicsts56/bundles
サンプルの稼働確認(1) / 手動デプロイ
まずはgithubに提供されている手順に従って動かしてみます。
参考: cics-java-liberty-springboot-jcicsローカルにクローン作製
適当なディレクトリを作成しローカルのPCに
https://github.com/cicsdev/cics-java-liberty-springboot-jcics.git
のクローンを作成します。c:\y\workspace\cicsts56>git clone https://github.com/cicsdev/cics-java-liberty-springboot-jcics.git Cloning into 'cics-java-liberty-springboot-jcics'... remote: Enumerating objects: 67, done. remote: Counting objects: 100% (67/67), done. remote: Compressing objects: 100% (43/43), done. remote: Total 67 (delta 12), reused 56 (delta 7), pack-reused 0 Unpacking objects: 100% (67/67), done.ファイル構造の理解
ディレクトリ"cics-java-liberty-springboot-jcics"に移動して、ファイルの構造を見てみます。
c:\y\workspace\cicsts56\cics-java-liberty-springboot-jcics>tree /f /a フォルダー パスの一覧: ボリューム Windows ボリューム シリアル番号は 1866-E2FC です C:. | .classpath | .gitignore | .project | build.gradle | gradlew | gradlew.bat | LICENSE | mvnw | mvnw.cmd | pom.xml | README.md | settings.gradle | +---.mvn | \---wrapper | maven-wrapper.jar | maven-wrapper.properties | MavenWrapperDownloader.java | +---.settings | org.eclipse.buildship.core.prefs | org.eclipse.wst.common.component | org.eclipse.wst.common.project.facet.core.xml | +---gradle | \---wrapper | gradle-wrapper.jar | gradle-wrapper.properties | \---src \---main +---java | \---com | \---ibm | \---cicsdev | \---springboot | \---jcics | Application.java | BrowseTSQController.java | DeleteTSQController.java | ServletInitializer.java | TSQInfoController.java | WriteTSQController.java | \---webapp \---WEB-INF ibm-web-ext.xml web.xmlアプリ部分の単発プロジェクトです。
CICS Bundleプロジェクトは含まれていません。
Maven, Gradle両方に対応しているようですが、ここではGradleを使います。中身の確認/編集
いくつかソースがありますが、例えばWriteTSQController.javaを見てみます。これは見るだけ。
WriteTSQController.java/* Licensed Materials - Property of IBM */ /* */ /* SAMPLE */ /* */ /* (c) Copyright IBM Corp. 2020 All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or disclosure */ /* restricted by GSA ADP Schedule Contract with IBM Corp */ /* */ package com.ibm.cicsdev.springboot.jcics; import java.io.IOException; import java.io.UnsupportedEncodingException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.ibm.cics.server.CicsConditionException; import com.ibm.cics.server.TSQ; @RestController public class WriteTSQController { /** * The @GetMapping annotation ensures that HTTP GET requests are mapped to the annotated method. * @throws IOException **/ @GetMapping("/writeTSQs") public String writeTSQs(@RequestParam(value = "tsqName", defaultValue = "ANNE") String tsqName, @RequestParam(value = "tsqContent", defaultValue = "Spring greetings from CICS!") String tsqContent) { String response = ""; // Write to the TSQ try { response = writeTSQ(tsqName, tsqContent); } catch ( CicsConditionException | UnsupportedEncodingException e) { // Print the stack trace e.printStackTrace(); // Return useful information to the user when meeting errors return "Oops! Unexpected CICS condition exception: " + e.getMessage() + ". Please check stderr for details."; } return response; } /** * A method to write a record to a TSQ * * @param tsqName, the name of the TSQ to be written to * @param record, the data to be written to the TSQ * @return, the result of the write * @throws UnsupportedEncodingException * @throws CicsConditionException */ private String writeTSQ(String tsqName, String record) throws CicsConditionException, UnsupportedEncodingException{ // Construct the TSQ object TSQ tsqQ = new TSQ(); tsqQ.setName(tsqName); // the result of writing an item to the TSQ String result = ""; // write the record to the TSQ tsqQ.writeString(record); result = "Record written to TSQ " + tsqName + "."; // return the result to the calling servlet return result; } }JCICSのTSQクラスを使ってTSQにデータを書き込むだけの単純なアプリです。URI
/writeTSQs
のquery parameterでtsqName, tsqContentを受け取り、tsqNameで指定されたTSQにtsqContentで指定された値を書き込むようになっています。ibm-web-ext.xmlで、context-rootを確認しておきます。これも確認のみ。
ibm-web-ext.xml<?xml version="1.0" encoding="UTF-8"?> <web-ext xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-ext_1_0.xsd" version="1.0"> <reload-interval value="3"/> <context-root uri="cics-java-liberty-springboot-jcics-ding" /> <enable-directory-browsing value="false"/> <enable-file-serving value="true"/> <enable-reloading value="true"/> <enable-serving-servlets-by-class-name value="false" /> </web-ext>build.gradleを開いて、依存関係の指定をターゲットのCICSのバージョンに合わせて編集します。ここではCICS TS V5.6をターゲットとするので、以下のように修正します。
build.gradle... compileOnly enforcedPlatform("com.ibm.cics:com.ibm.cics.ts.bom:5.6-20200609123739") ...指定する値は以下から判断することになります。
参考:IBM CICS TS BOMビルド
以下のコマンドでビルドします。
c:\y\workspace\cicsts56\cics-java-liberty-springboot-jcics>gradlew.bat clean bootwar Downloading https://services.gradle.org/distributions/gradle-6.5-bin.zip .........10%..........20%..........30%..........40%.........50%..........60%..........70%..........80%.........90%..........100% Starting a Gradle Daemon (subsequent builds will be faster) BUILD SUCCESSFUL in 1m 35s 3 actionable tasks: 2 executed, 1 up-to-date成功すると、以下のWARが作成されます。
build/libs/cics-java-liberty-springboot-jcics-0.1.0.war
デプロイ
このサンプルの手順では手動でWARをデプロイするようになっているので、一旦それでやってみます。
先に作成しておいた、dropinsディレクトリにバイナリモードで上のWARファイルを転送します。
これで自動でアプリが認識されるはずです。
(この方式の場合、BUNDLE定義は使いません)アプリ稼働確認
ブラウザから、ターゲットのLibertyがListenしているhost:portに対して以下のようなリクエストを投げてみます。
http://etp1:56441/cics-java-liberty-springboot-jcics-ding/writeTSQs?tsqName=SPGJCICS&tsqContent=ILOVECICS
SPGJCICSという名前のTSQにILOVECICSというメッセージを投入することになります。
うまくいけば、TSQにデータが書き込まれるので、CICS端末からCEBRで確認してみます。
きちんとデータが投入されていることが確認できました。サンプルの稼働確認(2) / Gradleによるデプロイ
さて、上の手順だとデプロイが手動になってしまいスマートでは無いので、DeployまでGradleで実施できるようCICS Bundleプロジェクトを追加してみます。
注意!: 上の手順で手動デプロイを試した場合は、アプリがバッティングするのでdropinsディレクトリのwarを削除し、JVMSERVERを再起動しておいてください。
Gradleマルチプロジェクト作成
CICS Bundleプロジェクトを追加し、サンプルで提供されているWARとまとめるための親のプロジェクトを作成します。
親プロジェクト
まず、親となるプロジェクトのディレクトリ
cics-springboot01
というディレクトリを作成します。そこでgradle wrapperを実行しておきます。c:\y\workspace\cicsts56\cics-springboot01>gradle wrapper Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0. Use '--warning-mode all' to show the individual deprecation warnings. See https://docs.gradle.org/6.5/userguide/command_line_interface.html#sec:command_line_warnings BUILD SUCCESSFUL in 6s 1 actionable task: 1 executedc:\y\workspace\cicsts56\cics-springboot01>tree /a /f フォルダー パスの一覧: ボリューム Windows ボリューム シリアル番号は 1866-E2FC です C:. | gradlew | gradlew.bat | +---.gradle | +---6.5 | | | gc.properties | | | | | +---executionHistory | | | executionHistory.bin | | | executionHistory.lock | | | | | +---fileChanges | | | last-build.bin | | | | | +---fileHashes | | | fileHashes.bin | | | fileHashes.lock | | | | | \---vcsMetadata-1 | +---buildOutputCleanup | | buildOutputCleanup.lock | | cache.properties | | outputFiles.bin | | | +---checksums | | checksums.lock | | | \---vcs-1 | gc.properties | \---gradle \---wrapper gradle-wrapper.jar gradle-wrapper.propertiesここに、以下のようにbuild.gradle, setting.gradleを作成します。
build.gradlegroup 'com.ibm.cicsdev.springboot' version '1.0.0'setting.gradlerootProject.name = 'cics-springboot01' include 'cics-java-liberty-springboot-jcics' include 'cics-springboot-bundle04'子プロジェクト(1) / WAR用
これは、サンプルで提供されているものをそのまま使います。
上で示した手順通り、親プロジェクトのディレクトリ下でgit cloneでcics-java-liberty-springboot-jcicsをクローンします。
その後、ターゲットのCICSのバージョンに合わせて、build.gradleのcompileOnlyの行を修正します。子プロジェクト(2) / CICS Bundle用
これは前回の記事を参考に、バンドル用のbuild.gradleを作成してきます。
参考: CICS-Javaアプリケーションを動かす - (3)Gradleによるビルド管理親プロジェクトのディレクトリ下に、
cics-springboot-bundle04
という名前のディレクトリを作成し、そこに以下のようなbuild.gradleを作成します。ディレクトリ名は親のsetting.gradleで指定した名前に合わせます。build.gradleplugins { id 'com.ibm.cics.bundle' version '1.0.0' } group 'com.ibm.cicsdev.springboot' version '1.0.0' repositories { mavenCentral() } cicsBundle { build { defaultJVMServer = 'DFHWLP' // (1)JVMSERVER名 } deploy { cicsplex = 'C73PLX' // (2) ターゲットのCICSリージョンが属しているCICSplex名 region = 'CT56B4A1' // (3) ターゲットのCICSリージョン名 bunddef = 'SPBBUNDL' // (4) ターゲットのCICSリージョン上に定義したバンドル定義資源名 csdgroup = 'TAGGRP' // (5) (4)のバンドル定義が属しているCSDグループ名 url = 'http://etp1:56002' // (6) WUIのCMCIのURL username = 'TAG' // (7) CMCIによるDeployment API発行時に使用するユーザーと password = 'xxxxxxxx' // パスワード //caution: uncomment the line below to disable TLS/SSL checking for certificates //insecure = true } } dependencies { cicsBundlePart project(path:':cics-java-liberty-springboot-jcics', configuration: 'archives') }最終的にはこんな感じの構造になります。
c:\y\workspace\cicsts56\cics-springboot01>tree /a /f フォルダー パスの一覧: ボリューム Windows ボリューム シリアル番号は 1866-E2FC です C:. | build.gradle | gradlew | gradlew.bat | settings.gradle | ... +---cics-java-liberty-springboot-jcics | | .classpath | | .gitignore | | .project | | build.gradle | | build_original.gradle | | gradlew | | gradlew.bat | | LICENSE | | mvnw | | mvnw.cmd | | pom.xml | | README.md | | settings.gradle | | | +---.gradle | | +---6.5 | | | | gc.properties | | | | | | | +---executionHistory | | | | executionHistory.bin | | | | executionHistory.lock | | | | | | | +---fileChanges | | | | last-build.bin | | | | | | | +---fileContent | | | | fileContent.lock | | | | | | | +---fileHashes | | | | fileHashes.bin | | | | fileHashes.lock | | | | | | | +---javaCompile | | | | classAnalysis.bin | | | | javaCompile.lock | | | | taskHistory.bin | | | | | | | \---vcsMetadata-1 | | +---buildOutputCleanup | | | buildOutputCleanup.lock | | | cache.properties | | | outputFiles.bin | | | | | +---checksums | | | checksums.lock | | | md5-checksums.bin | | | sha1-checksums.bin | | | | | \---vcs-1 | | gc.properties | | | +---.mvn | | \---wrapper | | maven-wrapper.jar | | maven-wrapper.properties | | MavenWrapperDownloader.java | | | +---.settings | | org.eclipse.buildship.core.prefs | | org.eclipse.wst.common.component | | org.eclipse.wst.common.project.facet.core.xml | | | +---gradle | | \---wrapper | | gradle-wrapper.jar | | gradle-wrapper.properties | | | \---src | \---main | +---java | | \---com | | \---ibm | | \---cicsdev | | \---springboot | | \---jcics | | Application.java | | BrowseTSQController.java | | DeleteTSQController.java | | ServletInitializer.java | | TSQInfoController.java | | WriteTSQController.java | | | \---webapp | \---WEB-INF | ibm-web-ext.xml | web.xml | +---cics-springboot-bundle04 | build.gradle | \---gradle \---wrapper gradle-wrapper.jar gradle-wrapper.propertiesBUNDLE定義作成
上のbuild.gradleで指定した内容に従って、バンドル定義を作成します。
OBJECT CHARACTERISTICS CICS RELEASE = 0730 CEDA View Bundle( SPBBUNDL ) Bundle : SPBBUNDL Group : TAGGRP DEScription : CICS-SpringBoot-Sample Status : Enabled Enabled | Disabled BUndledir : /var/cicsts/cicsts56/bundles/cics-springboot-bundle04_1.0. (Mixed Case) : 0 : : : BAsescope : (Mixed Case) : : : : DEFINITION SIGNATURE DEFinetime : 07/07/20 17:03:45 CHANGETime : 07/07/20 17:03:57 SYSID=B4A1 APPLID=CT56B4A1 DSN=CICSTS56.CICS.DFHCSDCSDグループは(5)、BUNDLE定義名は(4)、BUNDLEDIRはプロジェクトのディレクトリ名およびバージョン情報の値を元に指定します。
※ここでは、まだインストール操作はしませんビルド/デプロイ実行
以下のようにSpring BootのWARをビルドします。
c:\y\workspace\cicsts56\cics-springboot01>gradlew bootWar BUILD SUCCESSFUL in 6s 2 actionable tasks: 2 executed続いて、CICS Bundleのビルドとデプロイを実行します。
c:\y\workspace\cicsts56\cics-springboot01>gradlew deployCICSBundle > Task :cics-springboot-bundle04:buildCICSBundle Adding Java-based bundle parts from 'cicsBundlePart' dependency configuration Adding Java-based bundle part: 'C:\y\workspace\cicsts56\cics-springboot01\cics-java-liberty-springboot-jcics\build\libs\cics-java-liberty-springboot-jcics-0.1.0.war' Adding non-Java-based bundle parts from 'src/main/resources' > Task :cics-springboot-bundle04:deployCICSBundle Task deployCICSBundle BUILD SUCCESSFUL in 29s 4 actionable tasks: 3 executed, 1 up-to-dateCICS Explorerからバンドル、バンドルパーツがENABLEDになっているのが確認できればOKです。
デプロイまでGradleでできました!
ちなみに、Libertyのmessages.logをみると、SpringBootのアプリが稼働したのが分かります。
[7/7/20 9:20:35:354 GMT] 000000d0 LogService-87-com.ibm.cics.wlp.bundlepart.impl I CWWKE0703I: [com.ibm.cics.wlp.bundlepart.impl] [CICSLibertyBundlepartControllerImpl] @Info : installBundlepart() - cics-java -liberty-springboot-jcics-0.1.0, SPBBUNDL, 2, /var/cicsts/cicsts56/bundles/cics-springboot-bundle04_1.0.0/, 1.0.0, 206F2740000001E9, , , -1, -1, -1, CSD_API [7/7/20 9:20:35:376 GMT] 000000d1 LogService-87-com.ibm.cics.wlp.bundlepart.impl I CWWKE0703I: [com.ibm.cics.wlp.bundlepart.impl] [CICSLibertyBundlepartControllerImpl] @Info : enableBundlepart() - 3549516473 [7/7/20 9:20:36:381 GMT] 00000055 com.ibm.ws.app.manager.AppMessageHelper I CWWKZ0018I: Starting application cics-java-liberty-springboot-jcics-0.1.0. [7/7/20 9:20:36:382 GMT] 00000055 bm.ws.app.manager.war.internal.WARDeployedAppInfoFactoryImpl I CWWKZ0136I: The cics-java-liberty-springboot-jcics-0.1.0 application is using the archive file at the /var/cicsts/cicsts56/C T56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/installedApps/cics-java-liberty-springboot-jcics-0.1.0.war location. [7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.webcontainer.osgi.webapp.WebGroup I SRVE0169I: Loading Web Module: cics-java-liberty-springboot-jcics. [7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.webcontainer I SRVE0250I: Web Module cics-java-liberty-springboot-jcics has been bound to default_host. [7/7/20 9:20:36:723 GMT] 00000055 com.ibm.ws.http.internal.VirtualHostImpl A CWWKT0016I: Web application available (default_host): http://etp1:56441/cics-java-liberty-springboot-jcics-ding/ [7/7/20 9:20:36:725 GMT] 00000055 com.ibm.ws.app.manager.AppMessageHelper A CWWKZ0003I: The application cics-java-liberty-springboot-jcics-0.1.0 updated in 0.344 seconds. [7/7/20 9:20:36:733 GMT] 0000004d com.ibm.ws.webcontainer.osgi.mbeans.PluginGenerator I SRVE9103I: A configuration file for a web server plugin was automatically generated for this server at /var/cicsts/cicsts56/ CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/logs/state/plugin-cfg.xml. [7/7/20 9:20:36:800 GMT] 0000004b com.ibm.ws.session.WASSessionCore I SESN0176I: A new session context will be created for application key default_host/cics-java-liberty-springboot-jcics-ding [7/7/20 9:20:36:801 GMT] 0000004b com.ibm.ws.util I SESN0172I: The session manager is using the Java default SecureRandom implementation for session ID generation. [7/7/20 9:20:37:064 GMT] 0000004b com.ibm.ws.webcontainer.webapp I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.2 Spring WebApplicationInitializers detected on cla sspath [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O . ____ _ __ _ _ [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O \\/ ___)| |_)| | | | | || (_| | ) ) ) ) [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O ' |____| .__|_| |_|_| |_\__, | / / / / [7/7/20 9:20:37:973 GMT] 0000004b SystemOut O =========|_|==============|___/=/_/_/_/ [7/7/20 9:20:37:974 GMT] 0000004b SystemOut O :: Spring Boot :: (v2.3.0.RELEASE) [7/7/20 9:20:38:131 GMT] 0000004b SystemOut O 2020-07-07 09:20:38.128 INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer : Starting ServletInit ializer on etp1.tsc.ibm.com with PID 83952403 (/var/cicsts/cicsts56/CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/defaultServer/installedApps/cics-java-liberty-springboot-jcics-0.1.0.war started by STCUSR in /ETP1/var/cic sts/cicsts56/CT56B4A1/work) [7/7/20 9:20:38:133 GMT] 0000004b SystemOut O 2020-07-07 09:20:38.133 INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer : No active profile se t, falling back to default profiles: default [7/7/20 9:20:38:446 GMT] 00000053 com.ibm.ws.config.xml.internal.ConfigRefresher A CWWKG0016I: Starting server configuration update. [7/7/20 9:20:38:448 GMT] 00000053 com.ibm.ws.config.xml.internal.XMLConfigParser A CWWKG0028A: Processing included configuration resource: /var/cicsts/cicsts56/CT56B4A1/work/CT56B4A1/DFHWLP/wlp/usr/servers/d efaultServer/installedApps.xml [7/7/20 9:20:38:450 GMT] 00000053 com.ibm.ws.config.xml.internal.ConfigRefresher A CWWKG0018I: The server configuration was not updated. No functional changes were detected. [7/7/20 9:20:39:214 GMT] 0000004b com.ibm.ws.webcontainer.webapp I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.Initializing Spring embedded WebApplicationContext [7/7/20 9:20:39:214 GMT] 0000004b SystemOut O 2020-07-07 09:20:39.214 INFO 83952403 --- [RVICE_Thread-28] o.s.web.context.ContextLoader : Root WebApplicationC ontext: initialization completed in 1011 ms [7/7/20 9:20:39:608 GMT] 0000004b SystemOut O 2020-07-07 09:20:39.608 INFO 83952403 --- [RVICE_Thread-28] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing Executo rService 'applicationTaskExecutor' [7/7/20 9:20:39:847 GMT] 0000004b SystemOut O 2020-07-07 09:20:39.846 INFO 83952403 --- [RVICE_Thread-28] c.i.c.s.jcics.ServletInitializer : Started ServletIniti alizer in 2.638 seconds (JVM running for 3347.897) [7/7/20 9:25:53:853 GMT] 00000045 com.ibm.ws.webcontainer.webapp I SRVE0292I: Servlet Message - [cics-java-liberty-springboot-jcics-0.1.0]:.Initializing Spring DispatcherServlet 'dispatcherSe rvlet' [7/7/20 9:25:53:853 GMT] 00000045 SystemOut O 2020-07-07 09:25:53.853 INFO 83952403 --- [HP.TASK205.CJSA] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' [7/7/20 9:25:53:863 GMT] 00000045 SystemOut O 2020-07-07 09:25:53.863 INFO 83952403 --- [HP.TASK205.CJSA] o.s.web.servlet.DispatcherServlet : Completed initializa tion in 10 ms [7/7/20 9:25:53:863 GMT] 00000045 com.ibm.ws.webcontainer.servlet I SRVE0242I: [cics-java-liberty-springboot-jcics-0.1.0] [/cics-java-liberty-springboot-jcics-ding] [dispatcherServlet]: Initia lization successful.アプリ稼働確認
先の例と同様、ブラウザからTSQに書き込むアプリを実行してみます。今度は書き込む文字列を"ILOVECICS2"にしています。
正常に結果が返りました。
CICS端末からCEBRで確認すると、きちんとデータが書き込まれていることが確認できました!
サンプルのカスタマイズ
CICS TS V5.5 + APAR PH14856 or V5.6 base では、Spring Bootアプリを従来のCICSプログラムのように扱うことができるようになるため、EXEC CICS LINKでSpring Bootプログラムを呼び出したり、EXEC CICS STARTで呼び出すことができるようになります。
参考: Linking to a Java EE or Spring Boot application from a CICS programここでは、COBOLなどの言語からEXEC CICS LINK でSpring Bootアプリを呼び出すシナリオを試してみます。
EXEC CICS LINK でSpring Bootアプリを呼び出す際、データの受け渡しはChannel & Containerを使いますが、今回は簡素化のためデータ受け渡しは行わずに単純にプログラム呼び出しの部分のみ追加実装して試してみます。server.xml変更
Liberty上のプログラムを呼び出す構成を行う場合、ランタイムとなるLibertyのフィーチャーとして
cicsts:link-1.0
を追加する必要があります。以下のようにfeatureを追加してJVMServerを再起動(Disabled=>Enabled)しておきます。server.xml... <featureManager> <feature>cicsts:core-1.0</feature> <feature>cicsts:defaultApp-1.0</feature> <feature>jsp-2.3</feature> <feature>wab-1.0</feature> <feature>transportSecurity-1.0</feature> <feature>cicsts:link-1.0</feature> </featureManager> ...サンプルプロジェクトをEclipseへ取り込む
上で取り扱ったGitHubで提供されているサンプルプロジェクトをEclipseに取り込みます。ここではCICS Explorerとして提供されているEclipseを使います。
Eclipse Marketplaceから、Buildship Gradle Integrationをインストールしておきます。
Javaパースペクティブのパッケージ・エクスプローラー・ビューで、右クリック - インポート - フォルダまたはアーカイブからのプロジェクト で、cloneしたプロジェクトのディレクトリを選択して取り込みます。
プロジェクト右クリック - Gradle - Refresh Gradle Project
ロジック追加
まず、build.gradleに依存関係を追加します。dependenciesに以下を追加します。
build.gradle... dependencies { ... // for @CICSProgram annotation compileOnly ("com.ibm.cics:com.ibm.cics.server.invocation.annotations") annotationProcessor ("com.ibm.cics:com.ibm.cics.server.invocation:5.6") }Refresh Gradle Projectを実行しておきます。
WriteTSQController.javaと同じパッケージに、以下のファイルを作成します。
WriteTSQLinked.javapackage com.ibm.cicsdev.springboot.jcics; import org.springframework.stereotype.Component; import com.ibm.cics.server.CicsConditionException; import com.ibm.cics.server.TSQ; import com.ibm.cics.server.invocation.CICSProgram; @Component public class WriteTSQLinked { @CICSProgram("WRTTSQ") public void writeTSQlinked() { String tsqName = "SPGJCICS"; String record = "ILOVECICS3"; // Write to the TSQ try { // Construct the TSQ object TSQ tsqQ = new TSQ(); tsqQ.setName(tsqName); // write the record to the TSQ tsqQ.writeString(record); } catch ( CicsConditionException e) { // Print the stack trace e.printStackTrace(); } } }
@CICSProgram
アノテーションで、直後のメソッドを"WRTTSQ"という名前のCICSプログラムとして認識させています。
CICSプログラムとして認識させる場合、メソッドはpublic指定、引数なしで定義する必要があります。
今回は引数なしで、埋め込みでSPGJCICSというTSQにILOVECICS3という値を書き出すロジックを追加しています。ビルド/デプロイ
C:\y\workspace\cicsts56\cics-springboot02>gradlew bootWar BUILD SUCCESSFUL in 7s 2 actionable tasks: 2 executedC:\y\workspace\cicsts56\cics-springboot02>gradlew deployCICSBundle > Task :cics-springboot-bundle04:buildCICSBundle Adding Java-based bundle parts from 'cicsBundlePart' dependency configuration Adding Java-based bundle part: 'C:\y\workspace\cicsts56\cics-springboot02\cics-java-liberty-springboot-jcics\build\libs\cics-java-liberty-springboot-jcics-0.1.0.war' Adding non-Java-based bundle parts from 'src/main/resources' > Task :cics-springboot-bundle04:deployCICSBundle Task deployCICSBundle BUILD SUCCESSFUL in 1m 31s 4 actionable tasks: 3 executed, 1 up-to-date完了すると、バンドルがインストールされ、WARがバンドルパーツとしてインストールされます。さらに、そこに含まれる
@CICSProgram
で指定したメソッドがCICSプログラムとして認識されるため、CICSプログラム"WRTTSQ"がインストールされた状態になります。インストールされたプログラム定義の詳細はこんな感じ(CICS Explorerで確認)
ターゲットのリージョンのJOBLOGにはこんな感じのメッセージが出ています。
DFHRL0107 I 07/08/2020 15:40:30 CT56B4A1 CICSUSER The CICS resource lifecycle manager has started to create the BUNDLE resource SPBBUNDL. DFHRL0125 I 07/08/2020 15:40:30 CT56B4A1 CICSUSER BUNDLE resource SPBBUNDL is being created with BUNDLEID cics-springboot-bundle04 and version 1.0.0. DFHSJ1105 07/08/2020 15:40:30 CT56B4A1 WAR bundle cics-java-liberty-springboot-jcics-0.1.0 version 1.0.0 from BUNDLE SPBBUNDL has been installed as Disabled. DFHRL0108 I 07/08/2020 15:40:30 CT56B4A1 CONL The CICS resource lifecycle manager is in the process of creating the BUNDLE resource SPBBUNDL and the BUNDLE is in the enabling state. DFHRD0128 I 07/08/2020 15:40:30 CT56B4A1 CICSUSER CONL INSTALL BUNDLE(SPBBUNDL) ???? ??? CONL CICSUSER 07/08/20 15:40:30 INSTALL BUNDLE(SPBBUNDL) GROUP(TAGGRP) DFHFC0961 07/08/2020 15:40:30 CT56B4A1 Calculation of LSR pool 1 parameters incomplete. Filename DFHDBFK has no DSNAME. DFHPG0101 07/08/2020 15:40:34 CT56B4A1 CICSUSER CJSP Resource definition for WRTTSQ has been added. DFHSJ1204 07/08/2020 15:40:34 CT56B4A1 A linkable service has been registered for program WRTTSQ in JVMSERVER DFHWLP with classname com.ibm.cicsdev.springboot.jcics.WriteTSQLinked, method writeTSQlinked. DFHSJ1107 07/08/2020 15:40:34 CT56B4A1 WAR bundle with symbolic name cics-java-liberty-springboot-jcics-0.1.0 version 1.0.0 has bee Enabled. DFHRL0132 I 07/08/2020 15:40:34 CT56B4A1 CJSL All defined resources for BUNDLE SPBBUNDL are now in the enabled state. DFHAP1900 07/08/2020 15:40:40 CT56B4A1 NONE CICSUSER CONL SET BUNDLE(SPBBUNDL) ENABLESTATUS(ENABLED) RESP(NORMAL) RESP2(0).アプリ稼働確認
簡易的にCICS端末から`CECI LINK PROGRAM(WRTTSQ)'発行してみます。
CEBRでTSQ"SPGJCICS"の中身を確認してみます。
期待したメッセージが書き込まれています!
これで、EXEC CICS LINKを使用してSpring Bootアプリを呼び出す流れが確認できました!
- 投稿日:2020-07-07T16:25:12+09:00
例外処理について
例外とは
例外は、プログラム上で想定外の動作が行われ、処理が続行できなくなったことを通知するためのオブジェクトです。
例外を使えば、コードの正常処理と以上処理をある程度分離できるため、コードが読みやすくなります。エラーと例外の違い
Java実行中のトラブルは,エラーと例外の2種類に分けられます。
エラー
実行環境のトラブル等、プログラムから対処不可能な事態。
プログラムが続行できなくなり、強制終了してしまいます。例外
プログラムから対処可能な事態。
エラーとは違い、動作を終わらせることなくプログラムを続行できます。チェック(検査)例外
メソッドを記述する際、例外処理も書かないと怒られるのがチェック例外で、チェック例外は基本的に、正しいプログラムを書いていても避けられない例外です。例えば、参照したいファイルが壊れているとか、DB障害等がこれにあたります。
チェック例外はコンパイラがチェックする例外処理で、Exeptionやそのサブクラス等が対象です。非チェック(検査)例外
例外処理を記述したかをコンパイラがチェックしない例外です。
非チェック例外はプログラマーが任意で記述するもので、RuntimeExcepitonクラスやそのサブクラス等が対象です。非チェック例外は基本的には避けられるエラーで、必ず記載しなければならないものではありません。main.javapublic static void main (String[] args) { int[] ary = {1, 2, 3}; System.out.println(ary[3]); }上記のコードでは、配列aryの要素が3つしか無いのに、4番目を表示するように要求しています。
実行すると以下のようになります。Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3配列の範囲外を見ようとしているというメッセージが出ました。
これに例外処理を追加して実行してみます。
main.javaclass Main{ public static void main(String args[]){ try{ int[] ary = {1, 2, 3}; System.out.println(ary[3]); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("例外です"); } } }実行結果
例外です例外処理が走りました。
try~catch~finaly文
sample.javaclass Sample { public static void main (String[] args) { int ary[] = {1, 2, 3}; System.out.println("開始"); try{ for (int i = 0; i < 4; i++){ System.out.println(n[i]); } } catch(ArrayIndexOutOfBoundsException e){ System.out.println("配列の範囲を超えています"); } finally{ System.out.println("配列を出力"); } System.out.println("処理を終了"); } }tryの部分に例外が発生する可能性のある処理を記載し、catchの部分に例外が発生したときの処理を書きます。例外の種類によってcatchブロックをそれぞれに分けることもできます。finalyの部分で最後に実行される処理を記載します。
throwとthrows
throw
try~catchでの例外処理以外に、自分で例外を起こせるthrowという例外処理もあります。
sample.javavoid test (int num) { if(num == 0) { throw new IllegalArgumentException("引数が不正です"); } }testメソッドではnumという数値型を引数に指定しているにもかかわらず、if分でnumが0だった時に処理をするように書いています。
実行すると以下のようになります。
throw new IllegalArgumentException(“引数が不正です”);throws
throwと名前は似ていますが処理内容は異なります。
throwsは、例外処理をメソッド内ではなく呼び出し元で行いたい時に、呼び出し元に呼ぶことができます。sample.javaimport java.io.FileNotFoundException; import java.io.FileReader; class Sample { public static void main (String[] args) { System.out.println("例外スロー"); try { methodA(); } catch(FileNotFoundException e) { System.err.println(e.getMessage()); } } void methodA() throws FileNotFoundException { FileReader aFile = new FileReader("aFile.txt"); } }実行結果
aFile.txt (No such file or directory) 処理が終わりました
- 投稿日:2020-07-07T16:02:44+09:00
SpringBoot入門ガイドやってみた【Accessing Data with JPA編】
目的
Spring Quickstart Guideを取り組み終えた方、SpringBootを学び始めた方、復習をしたい方に向けて、
公式が人気ガイドだからやってみて!と勧めてくれている、Accessing Data with JPAを実際に取り組み学んだことを共有します。
開発環境OS: macOS Mojave バージョン10.14.6 テキストエディタ: Visual Studio Code(以下VSCode) Java: 11.0.2QuickstartGuideのおさらいはこちらから
Building a RESTful Web Service編のおさらいはこちらから
Consuming a RESTful Web Service編のおさらいはこちらから1.SpringBoot projectを始めよう!
まずは、spring initializrにアクセスします。
1.ADD DEPENDENCIESボタンをクリックして、
Spring Data JPA
とH2 Database
を追加。
Spring Data JPA(Java Persistence API)とは、Javaのオブジェクトをデータベースに保存したり取り出したりするためのAPIです(O/Rマッピングしてくれるもの)。
H2 Databasetohaとは、Javaに標準で用意されているデータベース。ここで追加することによりMySQLなど別途サーバーを立てる必要がないので便利ですね。
2.Artifact, Nameは、
accessing-data-jpa
に変更。
3.Javaを11に変更。そして
GENERATE
ボタンをクリックしてZipファイルをダウンロードします。ダウンロードしたZipファイルを展開したら準備完了です。
2.コードを追加しよう!
先ほどのフォルダをVSCodeで開きます。
拡張機能のJava Extension Packのインストールの推奨します。と言われるのでインストールしておきましょう。(未インスールの方のみ)Customer.javaを作成しよう!
src/main/java/com/example/accessingdatajpa/にCustomer.javaファイルを作成します。
Customer.javaファイル内にコードを追加していきます。
Customer.javapackage com.example.accessingdatajpa; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Customer { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String firstName; private String lastName; protected Customer() {} public Customer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } @Override public String toString() { return String.format( "Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName); } public Long getId() { return id; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } }Customer.javaファイルに追加したコードを深掘りしていきます。
①
@Entity
Customer.java@Entity public class Customer { // 省略 }
@Entity
アノテーションは、DBのテーブルと結びつくクラスとなります(エンティティクラス)。
このエンティティクラスで定義された変数は、DBのカラムと結びつきます。②
@Id
、@GeneratedValue(strategy=GenerationType.AUTO)
、コンストラクタCustomer.java@Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String firstName; private String lastName; protected Customer() {} public Customer(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; }
@Id
アノテーションは、付与されている変数がテーブルの主キーになります。
また、@GeneratedValue(strategy=GenerationType.AUTO)
アノテーションで、idが連番で自動的に生成してくれるようになります。今回のCustomerテーブルは、主キーがid、その他のカラムはfirstNameとlastNameが存在するという事です。
エンティティクラスの要件として、引数のないコンストラクタが必要ですので、引数なしのコンストラクタを定義、
引数があるコンストラクタは、DBに保存するインスタンスを生成する時の為に定義しています。③toStringメソッド、ゲッターメソッドの定義
Customer.java@Override public String toString() { return String.format( "Customer[id=%d, firstName='%s', lastName='%s']", id, firstName, lastName); } public Long getId() { return id; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; }
toStringメソッド
は、java.lang.Objectクラスで定義されている文字列表現を返すメソッド
です。
@Override
アノテーションは、Objectクラスで定義されているtoStringメソッドをこのクラスでオーバーライドしています。
と明示するためのアノテーションです。正しくオーバーライドされていなければエラーになります。
よって、toStrign()
のようにタイプミスをしてしまっていると、コンパイル時にエラーが出て教えてくれます。今回は、idとfirstNameとlastNameを表示するための文字列を返すメソッドにオーバーライドしています。
String.formatというメソッドを使用する際に、第一引数に決められた書式を指定しなければいけないため、
%s
は、文字列、%d
は10進数整数と書式を指定しています。後は、それぞれの変数を取得するためのゲッターメソッドを定義しています。
CustomerRepository.javaを作成しよう!
src/main/java/com/example/accessingdatajpa/にCustomerRepository.javaファイルを作成します。
CustomerRepository.javaファイル内にコードを追加していきます。
CustomerRepository.javapackage com.example.accessingdatajpa; import java.util.List; import org.springframework.data.repository.CrudRepository; public interface CustomerRepository extends CrudRepository<Customer, Long> { List<Customer> findByLastName(String lastName); Customer findById(long id); }CustomerRepository.javaファイルに追加したコードを深掘りしていきます。
①リポジトリインターフェースを作成する
CustomerRepository.javapublic interface CustomerRepository extends CrudRepository<Customer, Long> { // 省略 }CustomerRepositoryというインターフェースを作成しています。その時にCrudRepositoryというインターフェースを継承しています。
CrudRepositoryインターフェースは引数にエンティティの型であるCustomer、IDの型であるLongをジェネリックパラメーターとして指定しています。
CrudRepositoryインターフェースは、Create、Read、Update、Delete(CRUD)という操作が出来るインターフェースです。
よって、CustomerRepositoryインターフェースも上記操作が出来るようになります。②メソッドの実装
CustomerRepository.javaList<Customer> findByLastName(String lastName); Customer findById(long id);
Spring Data JPA
では、findBy〇〇と特定の命名規則を満たすメソッド
はその内容からクエリメソッドとして定義されます。今回は、
findByLastName(String lastName)
が該当します。引数で受け取ったlastNameと一致するデータを全て取得する事が可能なメソッドです。
findById(long id)
は、特定のidと一致するデータを取得する事が可能なメソッドです。AccessingDataJpaApplication.javaを編集しよう!
デフォルトの状態は以下のようになっていると思います。
AccessingDataJpaApplication.javapackage com.example.accessingdatajpa; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AccessingDataJpaApplication { public static void main(String[] args) { SpringApplication.run(AccessingDataJpaApplication.class, args); } }公式を参考にしつつコードを追加します。
AccessingDataJpaApplication.javapackage com.example.accessingdatajpa; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; // 追加したコード import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; @SpringBootApplication public class AccessingDataJpaApplication { // 追加したコード private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class); public static void main(String[] args) { SpringApplication.run(AccessingDataJpaApplication.class); } // 追加したコード @Bean public CommandLineRunner demo(CustomerRepository repository) { return (args) -> { // save a few customers repository.save(new Customer("Jack", "Bauer")); repository.save(new Customer("Chloe", "O'Brian")); repository.save(new Customer("Kim", "Bauer")); repository.save(new Customer("David", "Palmer")); repository.save(new Customer("Michelle", "Dessler")); // fetch all customers log.info("Customers found with findAll():"); log.info("-------------------------------"); for (Customer customer : repository.findAll()) { log.info(customer.toString()); } log.info(""); // fetch an individual customer by ID Customer customer = repository.findById(1L); log.info("Customer found with findById(1L):"); log.info("--------------------------------"); log.info(customer.toString()); log.info(""); // fetch customers by last name log.info("Customer found with findByLastName('Bauer'):"); log.info("--------------------------------------------"); repository.findByLastName("Bauer").forEach(bauer -> { log.info(bauer.toString()); }); // for (Customer bauer : repository.findByLastName("Bauer")) { // log.info(bauer.toString()); // } log.info(""); }; } }AccessingDataJpaApplication.javaファイルに追加したコードを深掘りしていきます。
①ログ出力のためのlog
AccessingDataJpaApplication.java// 追加したコード private static final Logger log = LoggerFactory.getLogger(AccessingDataJpaApplication.class);ターミナルでログを表示するためにLogger、LoggerFactoryを用いています。
LoggerFactory.getLogger()
の引数にクラスを指定してログを取得することが出来ます。②データの登録、取得
AccessingDataJpaApplication.java// 追加したコード @Bean public CommandLineRunner demo(CustomerRepository repository) { return (args) -> { // save a few customers repository.save(new Customer("Jack", "Bauer")); repository.save(new Customer("Chloe", "O'Brian")); repository.save(new Customer("Kim", "Bauer")); repository.save(new Customer("David", "Palmer")); repository.save(new Customer("Michelle", "Dessler")); // fetch all customers log.info("Customers found with findAll():"); log.info("-------------------------------"); for (Customer customer : repository.findAll()) { log.info(customer.toString()); } log.info(""); // fetch an individual customer by ID Customer customer = repository.findById(1L); log.info("Customer found with findById(1L):"); log.info("--------------------------------"); log.info(customer.toString()); log.info(""); // fetch customers by last name log.info("Customer found with findByLastName('Bauer'):"); log.info("--------------------------------------------"); repository.findByLastName("Bauer").forEach(bauer -> { log.info(bauer.toString()); }); // for (Customer bauer : repository.findByLastName("Bauer")) { // log.info(bauer.toString()); // } log.info(""); }; }データの登録、取得を行なっている
CommandLineRunner demo(CustomerRepository repository)
というメソッドは、SpringBootがアプリ実行後に呼び出してくれます。その中でまずは、データの登録を行なっています。
Customerをインスタンス化する際にコンストラクタの引数に文字列(firstName、lastName)を渡しています。
そしてrepositoryのsaveメソッドでその生成されたJavaオブジェクトをCustomerテーブルに登録しています。repository.save(new Customer("Jack", "Bauer"));次に、
findAll()
で全てのデータを取得しています。
拡張for文でループを回して、取得した複数のデータを引数customerで受け取り1つずつ出力しています。
出力する際にオーバーライドしたtoString()
を使用しています。for (Customer customer : repository.findAll()) { log.info(customer.toString()); }次に、
findById(1L)
でIDが1のデータを取得しています。
これは特定の1つのデータしか取得できないので、ループを回さずに出力しています。// fetch an individual customer by ID Customer customer = repository.findById(1L); log.info(customer.toString());最後に、
findByLastName("Bauer")
で、lastNameの値がBauer
のデータを取得しています。
このデータは複数ある可能性があるので、List型で受け取るよう定義されていましたね。取得した複数のデータをforEach文でループを回して、引数bauerで受け取り1つずつ出力しています。
コメントアウトされている拡張for文は、こちらの書き方でも良いですよという事だと思います。// fetch customers by last name repository.findByLastName("Bauer").forEach(bauer -> { log.info(bauer.toString()); }); // for (Customer bauer : repository.findByLastName("Bauer")) { // log.info(bauer.toString()); // }3.実行してみよう!
アプリケーション実行の準備が出来たので確認しましょう。
ターミナルで以下のコマンドを入力してEnterしてください。
ターミナル$ ./mvnw spring-boot:runしばらくすると、ターミナルに以下の文字が出てきます。
ターミナルCustomers found with findAll(): ------------------------------- Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=2, firstName='Chloe', lastName='O'Brian'] Customer[id=3, firstName='Kim', lastName='Bauer'] Customer[id=4, firstName='David', lastName='Palmer'] Customer[id=5, firstName='Michelle', lastName='Dessler'] Customer found with findById(1L): -------------------------------- Customer[id=1, firstName='Jack', lastName='Bauer'] Customer found with findByLastName('Bauer'): -------------------------------------------- Customer[id=1, firstName='Jack', lastName='Bauer'] Customer[id=3, firstName='Kim', lastName='Bauer']
参考サイト
JPA関連アノテーションの基本として-その1-
エンティティークラスの要件
CrudRepository
【Spring Data JPA】自動実装されるメソッドの命名ルール
- 投稿日:2020-07-07T11:44:00+09:00
TDD勉強#1環境構築した&はじめてのテスト駆動開発(July 6th, 2020)
javaの環境構築をした.
動作環境
- visual studio code
- windows10
vscodeのjava環境構築
下のサイトみた
https://qiita.com/takuma-jpn/items/b49785a314fb4db85775早速Hello World!に苦戦
javaで
Hello World!
を表示するプログラム↓Test.javapublic class Test { public static void main(String[] args) { System.out.println("Hello.World!"); } }どうもファイル名とクラス名を一致させる必要があるらしい.沼だった.
あとは,launch.json
をつくる.フォルダを選択してプロジェクト化する(?)maven使ってTDD動いた
下のサイトみた.
https://engineeringnote.hateblo.jp/entry/java/junit_with_maven_in_vscode注意事項
設定からjavahomeでmavenにチェックを入れる必要がある.そもそもjavaが分からない
classの仕組みてきな
class.javaclass AA{ AA(); //コンストラクタ(?) void BB(){ AA C = new AA(); //インスタンス(?) C.BB() } }新しい知識(キーワード)
- new演算子
- assertEquals(引数1,引数2):引数が等しいかどうか調べるメソッド
おわりに
vscodeでpythonでもテスト(javaのテストをpythonに翻訳) しようとしたが,環境構築はうまくいったが,classまわりの書き方が分からず断念.
ひとまず慣れないjavaでTDDを一通り勉強していく.
- 投稿日:2020-07-07T00:40:53+09:00
[Processing×Java] 関数の使いかた
この記事はプログラムの構造をProcessingを通じて理解していくための記事です。
今回は関数について書いていきます。目次
0.関数の使いかた
1.あらかじめ用意されている関数
2.自分で定義してつくる関数
3.関数のモジュール化→再利用化の例0.関数とは
0-0. 関数とは
関数は、出力装置のようなものです。
何かを受け取って、それを変換して出力します。0-1. なぜ関数を使うのか
主な理由は、
①プログラムが読みやすくなるから。
②再利用できるようになるから。
(再利用については後ほど詳しく)0-2. 関数の種類
関数には、"あらかじめ用意されている関数"と、"自分で定義してつくる関数"があります。
あらかじめ用意されている関数は、具体的には、size(),background(),line(),void setup(),void draw()...などです。
1.あらかじめ用意されている関数
Processingでは、たくさんの関数があらかじめ用意されています。
size(),background(),rect(),ellipse()...など。
例えばsize()関数で、size(600,400);とすると横幅600px,縦幅400pxのウィンドウが表示されます。ここで重要なのは、あらかじめ用意されている関数は、決められたルール通りに使う必要があるということです。
例えば、size(600,400,300,200);のようにするとエラーになります。
決められたルールは、ProcessingのReferenceを見ればわかります。(例)size()の決められたルール
2.自分で定義してつくる関数
プログラミングでは自分のオリジナルの関数を作ってプログラムをシンプルにすることができます。
最初は、以下の円を表示するプログラムを簡略化していきます。maru.javavoid setup(){ size(200,200); background(255); } void draw(){ strokeWeight(3); stroke(77,196,224); noFill(); ellipse(100,100,30,30); }プログラムを簡略化するために、
①モジュール化する
②再利用可能にする
ということをしていきます。①モジュール化する
maru_module.javavoid setup(){ size(200,200); background(255); } //何を繰り返すのか一目でわかる! void draw(){ //自分がつくったオリジナルの関数を実行する。 maru(); } //ここにまとめた!! void maru(){ strokeWeight(3); stroke(77,196,224); noFill(); ellipse(100,100,30,30); }Point :
まとめて1つの関数とすることで、draw()関数がすっきりしてプログラムがわかりやすいものになります。②再利用可能にする
再利用が可能とは、複数の出力が可能ということです。
maru_reuse.javavoid setup(){ size(200,200); background(255); } void draw(){ //自分で定義した関数を使う //複数の円を簡単に表示できる! //maru(x座標,y座標,円の大きさ); maru(100,80,100); maru(100,100,50); } //関数の定義 //まず引数に何をとるかを決める void maru(float x,float y,float s){ strokeWeight(3); stroke(77,196,224); noFill(); //引数の値を何に使うかがかいてある ellipse(x,y,s,s); }Point :
再利用可能にするには、引数(パラメータ)の値を決められるようにします。
そうすれば、関数の出力値に変化をつけることができます。そのためには
①どの値に変化をつけたいか決めて、変数で表す。ellipse(x,y,s,s);②データ型 変数という形で引数を定義する。
void maru(float x,float y,float s){ }③自分で定義した関数のルールに従って、関数を使う。
maru(100,80,100);□voidとは何か
関数の実行結果として受け取るデータを返り値といいます。
関数は基本的には、intや、floatなどの値を返します。
float型の数値を返す関数の例↓float_function.javavoid setup(){ //自分で定義したaverage()関数を使って、変数fに平均値を代入する。 float f = average(12.0,6.0); //fの値を表示する。 println(f); } //2つの値の平均値を求めることができる関数average()を定義する。 float average(float num1,float num2){ //変数avに、2つの値の平均値を代入できるように式をつくる float av = (num1 + num2) / 2.0; //返り値にfloat型の数値を返す return av; }9.0しかし、ellipse()など、図形を描く関数は、値を返しません。
このように関数が返り値を返さない場合にvoidを使います。Point :
返り値を返さない関数は通常はそれ自身のみでつかわれます。(つまりvoidは書かれない)
background(),fill(),rect()....など。
{}を使って処理の内容を決める関数には、voidをつけます。
void setup(){},void draw(){}...など。3.関数のモジュール化→再利用化の例
◯桜の花びらを描くプログラム
sakura.javaint x = 300; int y = 300; //回転するはやさを決める変数rを定義する。 float r = 30.0; //桜の透明度を決める変数aを定義する。 int a = 150; void setup(){ size(600,600); } void draw(){ background(255); //popMatrixまでの描写を1つにまとめて出力する。 pushMatrix(); //座標の基準点(原点)を(x,y)に移動する translate(x,y); //どのくらい回転するかを変数rを使って決める。 rotate(frameCount/r); //桜の描写 for(int i = 0;i < 5;i++){ rotate(TWO_PI * 1/5); noStroke(); fill(255,50,80,a); stroke(225,50,80,100); bezier(0,0,35,-20,35,-52,8,-80); bezier(0,0,-35,-20,-35,-52,-8,-80); stroke(225,50,80,30); triangle(0,0,8,-80,0,-75); triangle(0,0,-8,-80,0,-75); } fill(200,50,100,200); ellipse(0,0,15,15); //桜の描写をまとめて出力する。 popMatrix(); }◯桜の花びらを描くプログラム(モジュール化する)
sakura_module.javaint x = 300; int y = 300; float r = 30.0; int a = 150; void setup(){ size(600,600); } //draw()関数の中がすっきりしてみやすくなった。 void draw(){ background(255); //自分で定義した関数を使う! sakura(); } //桜の花びらに関する関数を定義する。 void sakura(){ pushMatrix(); translate(x,y); rotate(frameCount/r); for(int i = 0;i < 5;i++){ rotate(TWO_PI * 1/5); noStroke(); fill(255,50,80,a); stroke(225,50,80,100); bezier(0,0,35,-20,35,-52,8,-80); bezier(0,0,-35,-20,-35,-52,-8,-80); stroke(225,50,80,30); triangle(0,0,8,-80,0,-75); triangle(0,0,-8,-80,0,-75); } fill(200,50,100,200); ellipse(0,0,15,15); popMatrix(); }◯桜の花びらを描くプログラム(再利用可能にする)
sakura_reuse.javavoid setup(){ size(600,600); } void draw(){ background(255); //パラメータを変えた関数を3つ出力する sakura(400,200,30,150); sakura(100,300,-40,100); sakura(380,400,60,50); } //オリジナルの関数を定義する //引数を、データ型と変数の形で定義する。 void sakura(float x,float y,float r,float a){ pushMatrix(); translate(x,y); rotate(frameCount/r); for(int i = 0;i < 5;i++){ rotate(TWO_PI * 1/5); noStroke(); fill(255,50,80,a); stroke(225,50,80,100); bezier(0,0,35,-20,35,-52,8,-80); bezier(0,0,-35,-20,-35,-52,-8,-80); stroke(225,50,80,30); triangle(0,0,8,-80,0,-75); triangle(0,0,-8,-80,0,-75); } fill(200,50,100,200); ellipse(0,0,15,15); popMatrix(); }最後に
読んでいただきありがとうございました。
より良い記事にしていくために御意見、ご指摘のほどよろしくお願いいたします。