更新 [1] 画面操作に準じた制御
最終更新日: 2020年6月9日
R8 | R9
指定したデータのロックを行います。
http://localhost:8921/wagby/rest/customer/edit/1000
STATUS=200 OK
STATUS=404 Not Found
STATUS=409 Conflict
指定したデータのロックを行います。
http://localhost:8921/wagby/rest/customer/edit?customerid=1000
「更新開始(主キーURL指定)」と同様です。
ロックを解除します。更新は行われません。
http://localhost:8921/wagby/rest/customer/edit/cancel
返戻の内容例を示します。
更新画面にてデータを入力し、リロードした際のデータを返します。更新の前に入力した値を使って、(サーバ側で)計算処理を行い、その結果を受け取るという目的で利用します。
http://localhost:8921/wagby/rest/customer/edit/refresh
フォーム画面と同様のパラメータを指定します。
入力した値に対して、計算処理などが行われたあとの値が返ります。
「更新キャンセル」と同様です。
http://localhost:8921/wagby/rest/customer/edit/refresh
Content-Type:application/json
プレゼンテーションオブジェクトのJSON表現を指定します。
「requestパラメータによる更新リフレッシュ」と同様です。
「requestパラメータによる更新リフレッシュ」と同様です。
「requestパラメータによる更新リフレッシュ」と同様です。ただしレスポンスに含まれる entity は更新用の入力値と同じものが返されます。
更新後にデータベースに格納された値を返戻させるように動作を変えることもできます。
STATUS=409 Conflict
「JSONオブジェクトによる更新リフレッシュ」と同様です。
「requestパラメータによる更新実行」と同様です。
マルチパート形式で送信することで、ファイル型項目を含む新規登録を行うことができます。詳細は "ファイルの扱い" をお読みください。
requestパラメータまたはJSONオブジェクトによる登録、更新処理後に返戻される(レスポンスに含まれる)entity, entityp は登録、更新時に渡した入力値と同じものが返されます。すなわち、entity, entityp はデータベースに格納された値と同一ではありません。具体的には次のような違いがあります。
このルールはパフォーマンスを優先したものです。一方で登録、更新後に改めてデータを取得して最新の値を利用したいという場合もあります。この場合はもう一度、データ取得のための API 呼び出しを行います。
この手間をなくすため、登録、更新後にデータベースの値を改めて取得した値を entity, entityp として返戻させることができます。つまり登録更新と取得という二回の REST API 呼び出しを一回にまとめます。
呼び出し時にリクエストヘッダ "x-wagby-reload-entity" に
x-wagby-reload-entity をセットすることでデータベースアクセスのための処理が加わるようになります。参照連動や計算式の処理をすべて終えた状態の値を返戻してほしいという要件の場合、x-wagby-reload-entity を指定してください。
ここでは juser モデルを JSON 形式で更新するときの JSON オブジェクトの扱いを説明します。モデル参照項目 jprincipalId に注目します。
1. 更新開始(主キーパラメータ指定)の手順に従ってプレゼンテーションモデルを取得します。例えばアカウント test1 について、次のURLにGETでアクセスします。
次のJSONオブジェクトを取得できます。
ここで "entityp" に格納されているのがプレゼンテーションモデルです。entityp内のjprincipalIdは、content(内容部)だけでなく、idやchooseといった情報も含まれています。詳細はプレゼンテーションモデルの説明をお読みください。
2. 得られた値を修正し、更新します。次のURLのREST APIをPUTで呼び出します。
リクエストには次に示すJSONオブジェクトを指定した、とします。これは 1. で取得したJSONオブジェクトの "entityp" の部分です。また、設定したいjprincipalIdのchooseをtrueとします。(今回はjprincipalIdが "0","1","2","9" の選択肢を設定した、としています。)
1. で得られたモデルの項目の値を全て設定します。(設定しない項目は null 扱いで更新されます。)
上では jprincipalId の choose と id だけを指定しましたが、他の値を含めて送信しても問題ありません。
モデルの項目の値を全て設定してください。設定しない項目は null 扱いで更新されます。
上の説明から、その項目自体を送信情報から除くことで null 扱いで更新されます。ただしその項目が必須項目の場合は null となりません。(文字列型なら空文字、数値型なら0という値が自動的にセットされます。)
本方式は更新開始時に更新対象のデータを取得し、セッションに格納します。また、悲観ロックの場合はロックを行います。
更新実行にてセッションに格納されたデータを用いて、更新を実行します。悲観ロックの場合はロックの解放を行います。
ここで自動ログオン機能にて更新開始を行った場合、更新対象のデータをセッションに格納しても、ログオフ時に解放されることになります。そのため自動ログオン機能には対応していません。自動ログオン機能を用いる場合は「簡易制御」方式をご利用ください。
楽観ロックを利用する場合は、バージョン管理用カラムの設定が必要です。異なる値を指定した場合は 409 Conflictを返します。この場合は更新されません。
/wagby/rest/[modelid]/entry/[pkey] GETにて、下記のような値が取得されたとします。項目 "optilock" は楽観ロックのためのバージョン管理カラムとします。
このとき、下記のようにバージョン管理用カラムに、取得時のentityに格納されている値をセットしたJSONデータを送信してください。
もし取得と更新の間に、別の利用者から更新があった場合、バージョン管理用カラムの番号が進むことになります。この場合は 409 Conflict を返し、データの更新が失敗します。
失敗時のJSONオブジェクトには、下記のようなエラーメッセージが格納されます。
更新開始(主キーURL指定)
@RequestMapping(value="/rest/[modelid]/edit/{pkey}", method=GET)
URL例
レスポンス - データ取得成功
返戻の内容例を示します。
{
"entityp": {
"customerid": {
"content":"1000",
"formatted": null,
"errorcode":""
},
"name": {
"content":"Satou",
"formatted": null,
"errorcode":""
},
"email": [
{
"id": 1,
"priority": null,
"content": null,
"errorcode":""
}
]
},
"errors": {
"jfcinfo": [],
"jfcwarn": [],
"jfcdebug": [],
"jfcerror": []
},
"status":"updateCustomer.input",
"pkey": null,
"entity": {
"customerid": 1000,
"name": "Satou",
"email": []
}
}
レスポンス - データが見つからない
レスポンス - ロック取得失敗
更新開始(主キーパラメータ指定)
@RequestMapping(value="/rest/[modelid]/edit", method=GET)
URL例
レスポンス
更新キャンセル
@RequestMapping(value="/rest/[modelid]/edit/cancel", method=GET)
URL例
レスポンス
{
"entityp": null,
"errors": {
"jfcinfo": [],
"jfcwarn": [],
"jfcdebug": [],
"jfcerror": []
},
"status":"showCustomer",
"pkey": "1000",
"entity": null
}
requestパラメータによる更新リフレッシュ
@RequestMapping(value="/rest/[modelid]/edit/refresh", method=POST, headers="Content-Type=application/x-www-form-urlencoded")
URL例
リクエスト
例:
customer_p$002fcustomerid=1000
customer_p$002fname=Satou
レスポンス
{
"entityp": {
"customerid": {
"content":"1000",
"formatted": null,
"errorcode":""
},
"name": {
"content":"Satou",
"formatted": null,
"errorcode":""
},
"email": [
{
"id": 1,
"priority": null,
"content": null,
"errorcode":""
}
]
},
"errors": {
"jfcinfo": [],
"jfcwarn": [],
"jfcdebug": [],
"jfcerror": []
},
"status":"updateCustomer.input",
"pkey": null,
"entity": {
"customerid": 1000,
"name": "Satou",
"email": []
}
}
レスポンス
JSONオブジェクトによる更新リフレッシュ
@RequestMapping(value="/rest/[modelid]/edit/refresh", method=POST, headers="Content-Type=application/json")
URL例
HTTPヘッダ
リクエスト
{
"customerid": {
"content":"1000"
}
"name": {
"content":"Satou"
}
}
レスポンス
requestパラメータによる更新実行
@RequestMapping(value="/rest/[modelid]/edit", method=PUT, headers="Content-Type=application/x-www-form-urlencoded")
リクエスト
レスポンス
レスポンス - ロックエラー
JSONオブジェクトによる更新実行
@RequestMapping(value="/rest/[modelid]/edit", method=PUT, headers="Content-Type=application/json")
リクエスト
レスポンス
ファイル項目を含める
データベースに保存された値を返戻する8.3.0
方法
true
を指定します。
例 モデル参照の値をJSON形式で更新する
http://localhost:8921/wagby/rest/juser/edit/test1
{
"entityp": {
"userid": {
"content": "test1",
"formatted": null,
"errorcode": ""
},
"passwdNow": null,
"passwd2": null,
"jgroupid": [],
"passwd": {
"content": null,
"formatted": null,
"errorcode": ""
},
"compulsoryChange": [
{
"noId": false,
"priority": 0,
"content": "次回ログオン時にパスワードを強制変更させる",
"choose": false,
"invalid": false,
"errorcode": "",
"label": "",
"id": 1
}
],
"name": {
"content": "",
"formatted": null,
"errorcode": ""
},
"valid": {
"content": "",
"formatted": null,
"errorcode": ""
},
"level": {
"content": "",
"formatted": "",
"errorcode": ""
},
"passwdChangeDate": {
"content": "2019-08-27",
"formatted": null,
"errorcode": ""
},
"passwdChangeFlag": {
"content": null,
"formatted": null,
"errorcode": ""
},
"passwdErrCount": {
"content": "",
"formatted": "",
"errorcode": ""
},
"oldPasswds": [
{
"id": 1,
"priority": null,
"content": null,
"errorcode": ""
}
],
"jprincipalId": [
{
"noId": false,
"priority": 0,
"content": "共通処理",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 0
},
{
"noId": false,
"priority": 0,
"content": "パスワード変更",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 1
},
...(中略)...
{
"noId": false,
"priority": 0,
"content": "ジョブ専用アカウント",
"choose": false,
"invalid": false,
"errorcode": "",
"label": "",
"id": 21
}
],
"lastLogonDate": {
"content": null,
"formatted": null,
"errorcode": ""
},
"avatarImage": {
"content": "",
"formatted": null,
"errorcode": ""
},
"avatarImage_jshfilename": {
"content": "",
"formatted": null,
"errorcode": ""
},
"rule": []
},
"pkey": null,
"errors": {
"jfcerror": [],
"jfcinfo": [],
"jfcwarn": [],
"jfcdebug": []
},
"entity": {
...(中略)...
},
"status": "updateJuser.input"
}
http://localhost:8921/wagby/rest/juser/edit
{
"userid": {
"content": "test1",
"formatted": null,
"errorcode": ""
},
"passwdNow": null,
"passwd2": null,
"jgroupid": [],
"passwd": {
"content": null,
"formatted": null,
"errorcode": ""
},
"compulsoryChange": [
{
"noId": false,
"priority": 0,
"content": "次回ログオン時にパスワードを強制変更させる",
"choose": false,
"invalid": false,
"errorcode": "",
"label": "",
"id": 1
}
],
"name": {
"content": "",
"formatted": null,
"errorcode": ""
},
"valid": {
"content": "",
"formatted": null,
"errorcode": ""
},
"level": {
"content": "",
"formatted": "",
"errorcode": ""
},
"passwdChangeDate": {
"content": "2019-08-27",
"formatted": null,
"errorcode": ""
},
"passwdChangeFlag": {
"content": null,
"formatted": null,
"errorcode": ""
},
"passwdErrCount": {
"content": "",
"formatted": "",
"errorcode": ""
},
"oldPasswds": [
{
"id": 1,
"priority": null,
"content": null,
"errorcode": ""
}
],
"jprincipalId": [
{
"choose": true,
"id": 0
},
{
"choose": true,
"id": 1
},
{
"choose": true,
"id": 2
},
{
"choose": true,
"id": 9
}
],
"lastLogonDate": {
"content": null,
"formatted": null,
"errorcode": ""
},
"avatarImage": {
"content": "",
"formatted": null,
"errorcode": ""
},
"avatarImage_jshfilename": {
"content": "",
"formatted": null,
"errorcode": ""
},
"rule": []
}
モデル参照部の表記についての詳細
...
"jprincipalId": [
{
"noId": false,
"priority": 0,
"content": "共通処理",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 0
},
{
"noId": false,
"priority": 0,
"content": "パスワード変更",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 1
},
{
"noId": false,
"priority": 0,
"content": "システム管理者",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 2
},
...
{
"noId": false,
"priority": 0,
"content": "一般ユーザ",
"choose": true,
"invalid": false,
"errorcode": "",
"label": "",
"id": 9
},
...
仕様・制約
すべての項目を設定する
特定の項目の値を null(未設定)としたい
自動ログオンには未対応
楽観ロックを利用する場合
詳細
{
"entityp": {
"pkey": {
"content": "1008",
"formatted": null,
"errorcode": ""
},
"item1": {
"content": "aaaa1",
"formatted": null,
"errorcode": ""
},
"optilock": null
},
...
"entity": {
"pkey": 1008,
"item1": "aaaa1",
"optilock": 3
},
...
}
{
"pkey": {
"content": "1008",
"formatted": null,
"errorcode": ""
},
"item1": {
"content": "aaaa1a",
"formatted": null,
"errorcode": ""
},
"optilock": {
"content": "3"
}
}
"errors": {
"jfcwarn": [],
"jfcdebug": [],
"jfcinfo": [],
"jfcerror": [
{
"name": null,
"content": "データベースの更新処理に失敗しました。このデータは他のユーザーによって更新されているので、そのままでは保存できません。キャンセルボタンをクリックして、再度更新処理をやり直してください。",
"sanitizeAsBoolean": false,
"code": "model1.error.dbaccess.update.OptimisticLockingFailure",
"sanitize": false
}
]
},