JavaEEでのサンプルとしてメモアプリを作成してみた
Javaでの開発は基本的にはほとんどない
ちょっとやってみた
参考情報
Javaエンジニア養成読本 [現場で役立つ最新知識、満載!] (Software Design plus)
- 作者: きしだなおき,のざきひろふみ,吉田真也,菊田洋一,渡辺修司,伊賀敏樹
- 出版社/メーカー: 技術評論社
- 発売日: 2014/11/11
- メディア: 大型本
- この商品を含むブログ (8件) を見る
できたもの
https://github.com/mshige1979/javaee_memoapp
※ちょっとこれじゃない感あるけど
デモ
プロジェクトを作成
問題点・所感など
なんかビルドしても前のものが残ってたりして動かないことが多かった。
一度、glashfishを再起動したり、netbeansを再起動とかすると動くので結構解決しか感じがない。
flashオブジェクトのデータの生成やaction時の挙動などPHPと違ってなかなか手軽に実行できないのがネックかもしれない。
参考
- 作者: 川場隆
- 出版社/メーカー: 秀和システム
- 発売日: 2014/11/13
- メディア: 単行本
- この商品を含むブログを見る
Java EE 7徹底入門 標準Javaフレームワークによる高信頼性Webシステムの構築
- 作者: 寺田佳央,猪瀬淳,加藤田益嗣,羽生田恒永,梶浦美咲,小田圭二
- 出版社/メーカー: 翔泳社
- 発売日: 2015/12/16
- メディア: 大型本
- この商品を含むブログ (7件) を見る
HTMLやcssの情報はリソースファイルはどうするくらいでちょうど良かった気がする
デバッグでどうすんだろ?
途中で変数などを確認したいけどダンプの取り方がわからん。なんかログ出力のやつでもあるのかな…
MacにXamarin Studioをインストールしてみました
特に意味はない
C#とか使えないけどクロスプラットフォームはちょっと便利そうなので入れてみました
インストール
インストーラーを起動してインストールを開始する
↓
↓
↓
↓
↓
↓
起動してサンプルアプリを作成
「New Solution」をクリックする
「Xamarin Forms App」を選択する
アプリ名を設定して次へ
アプリ名を確認して作成
作成した初期はビルドはiOSになっている
実行
※画面がでかいので50%くらいに縮小
CentOS7.xをGUIを有効にしてインストール
インストール
インストール開始
言語を設定
設定画面を確認
ソフトウェアの選択でGUIのアプリを設定する
あとは適当にいれてからインストールする
インストール中の画面
ルートパスワード
ユーザーの作成
インストール完了後は再起動を行う
ライセンス設定
ライセンス設定の確認が表示される
質問に答えて同意するようにする
初期設定
ログインする
言語設定
キーボード設定
オンラインアカウントを設定(スキップ可能)
設定完了
マニュアル
おわり
所感
最小構成の場合は10分〜15分くらいで終わるけどこの場合は30分くらいかかった…
visual studio codeとかlinuxでも動くらしいのでちょっと試してみたいかも…
cakephp3で複数データをインサート
データを登録する際
1件ずつ登録するか、一括で登録するか…
環境
CentOS7.x
php7.0.3
cakephp3.2.3
一括で登録
sample1
src/Shell/Sample1Shell.php
<?php namespace App\Shell; use Cake\Console\Shell; use Cake\ORM\TableRegistry; /** * Sample1 shell command. */ class Sample1Shell extends Shell { /** * main() method. * * @return bool|int Success or error code. */ public function main() { // サンプルデータ準備 $postList = [ [ "title" => "aaa1", "body" => "hogehoge1", "created" => date("Y-m-d H:i:s", strtotime("now")), "modified" => date("Y-m-d H:i:s", strtotime("now")), ], [ "title" => "aaa2", "body" => "hogehoge2", "created" => date("Y-m-d H:i:s", strtotime("now")), "modified" => date("Y-m-d H:i:s", strtotime("now")), ], [ "title" => "aaa3", "body" => "hogehoge3", "created" => date("Y-m-d H:i:s", strtotime("now")), "modified" => date("Y-m-d H:i:s", strtotime("now")), ], ]; // テーブルオブジェクトを取得 $posts = TableRegistry::get("Posts"); // クエリーオブジェクトを取得 $oQuery = $posts->query(); // 配列単位にデータを設定 foreach($postList as $post){ // 1行ずつ設定 $oQuery ->insert(['title', 'body', 'created', 'modified']) // キーを指定 ->values($post); // 明細を設定 } // 実行 $oQuery->execute(); } }
※モデルのsaveではないのでcreatedやmodifiedは任意で設定する必要があります。
SQL
INSERT INTO posts ( title, body, created, modified ) VALUES ('aaa1', 'hogehoge1', '2016-03-08 13:08:31', '2016-03-08 13:08:31'), ('aaa2', 'hogehoge2', '2016-03-08 13:08:31', '2016-03-08 13:08:31'), ('aaa3', 'hogehoge3', '2016-03-08 13:08:31', '2016-03-08 13:08:31')
一括で実行されています
一件ずつ登録
sample2
src/Shell/Sample2Shell.php
<?php namespace App\Shell; use Cake\Console\Shell; use Cake\ORM\TableRegistry; /** * Sample2 shell command. */ class Sample2Shell extends Shell { /** * main() method. * * @return bool|int Success or error code. */ public function main() { // サンプルデータ準備 $postList = [ [ "title" => "bbb1", "body" => "foofoo1", ], [ "title" => "bbb2", "body" => "foofoo2", ], [ "title" => "bbb3", "body" => "foofoo3", ], ]; // テーブルオブジェクトを取得 $posts = TableRegistry::get("Posts"); // データを設定して複数のエンティティを取得 $postsEntities = $posts->newEntities($postList); // データ数分保存する foreach($postsEntities as $entity){ // 保存 $posts->save($entity, ['atomic' => false]); } } }
※createdなどは自動設定してくれる
SQL
INSERT INTO posts (title, body, created, modified) VALUES ('bbb1', 'foofoo1', '2016-03-08 13:23:24', '2016-03-08 13:23:24') INSERT INTO posts (title, body, created, modified) VALUES ('bbb2', 'foofoo2', '2016-03-08 13:23:24', '2016-03-08 13:23:24') INSERT INTO posts (title, body, created, modified) VALUES ('bbb3', 'foofoo3', '2016-03-08 13:23:24', '2016-03-08 13:23:24')
一件ずつ実行
参考
[PHP]CakePHP 3.x でも、複数行INSERTできるよ! - Qiita
Saving Data — CakePHP Cookbook 3.x documentation
Inserting Multiple Rows with CakePHP 3 | Chris Nizzardini
所感
一括で登録できた方が楽なのでそちらを使う事になると思われる。変なデータになっていないかは別の方法でチェックして対応する
ビジネスロジックの場所に困りそうな状況になりつつあるけどまあ最初はコントローラーを困らせていこう(^ ^)
cakephp3でエラー画面
エラー画面を多少はカスタマイズしたい…
エラー内容自体はともかく、デフォルトのフォーマットはマズイし…
環境
CentOS7.x
php7.0.3
cakephp3.2.3
実装
エラー用コントローラーを作成
src/Controller/AppErrorController.php
<?php namespace App\Controller; use Cake\Controller\ErrorController; use Cake\Event\Event; /** * 独自のエラーコントローラー * Class AppErrorController * @package App\Controller */ class AppErrorController extends ErrorController { /** * 描画前処理 * * @param Event $event */ public function beforeRender(Event $event) { // エラーの共通レイアウト名を指定 // src/Template/Layout/error_layout.ctp $this->viewBuilder()->layout('error_layout'); // エラーテンプレートパスを指定 $this->viewBuilder()->templatePath('Error'); } }
※描画前にテンプレートパスやレイアウトを指定する
レンダラーを作成
src/Error/AppExceptionRenderer.php
<?php namespace App\Error; use Cake\Error\ExceptionRenderer; use Exception; use Cake\Log\Log; use App\Controller\AppErrorController; /** * 独自例外用レンダラー * * Class AppExceptionRenderer * @package App\Error */ class AppExceptionRenderer extends ExceptionRenderer { /** * 独自のコントローラーを指定 * @param Exception $exception * @return AppErrorController */ protected function _getController() { // 独自のコントローラーを指定 return new AppErrorController(); } /** * 独自のテンプレート名を指定 * * @param Exception $exception * @param string $method * @param int $code * @return string */ protected function _template(Exception $exception, $method, $code) { // src/Template/Error/error_custom.ctp return $this->template = "error_custom"; } }
※テンプレートを指定
設定ファイルを編集
config/app.php
<?php return [ 'Error' => [ 'errorLevel' => E_ALL & ~E_DEPRECATED, //'exceptionRenderer' => 'Cake\Error\ExceptionRenderer', 'exceptionRenderer' => 'App\Error\AppExceptionRenderer', 'skipLog' => [], 'log' => true, 'trace' => true, ],
※レンダラーを変更
エラー用レイアウトを作成
src/Template/Layout/error_layout.ctp
<!DOCTYPE html> <html> <head> <?= $this->Html->charset() ?> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title> <?= $this->fetch('title') ?> </title> <?= $this->Html->meta('icon') ?> <?= $this->fetch('meta') ?> <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/css/app.css"> <?= $this->fetch('css') ?> </head> <body> <header id="header"> <nav class="navbar navbar-default"> <div class="container"> <a class="navbar-brand" id="logo" href="/"> CakePHP3 Demo </a> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav navbar-right hidden-sm"> </ul> </div> </div> </nav> </header> <div class="container-fluid"> <div class="row"> <div class="col-md-12"> <div style=""> <?= $this->Flash->render() ?> </div> </div> </div> </div> <div class="container-fluid"> <?= $this->fetch('content') ?> </div> <footer> </footer> <script src="/js/jquery-2.2.1.min.js"></script> <script src="/bootstrap/js/bootstrap.min.js"></script> <?= $this->fetch('script') ?> </body> </html>
エラー用テンプレートを作成
<?php use Cake\Core\Configure; use Cake\Error\Debugger; ?> <div class="row"> <div class="col-md-12"> <div style="width: 800px;margin: 0 auto;"> <h2><?= __d('cake', 'An Internal Error Has Occurred') ?></h2> <p class="error"> <strong><?= __d('cake', 'Error') ?>: </strong> <?= h($message) ?> </p> <?php if (!empty($error->queryString)) : ?> <p class="notice"> <strong>SQL Query: </strong> <?= h($error->queryString) ?> </p> <?php endif; ?> <?php if (!empty($error->params)) : ?> <strong>SQL Query Params: </strong> <?= Debugger::dump($error->params) ?> <?php endif; ?> <?php if ($error instanceof Error) : ?> <strong>Error in: </strong> <?= sprintf('%s, line %s', str_replace(ROOT, 'ROOT', $error->getFile()), $error->getLine()) ?> <?php endif; ?> <?php echo $this->element('auto_table_warning'); if (extension_loaded('xdebug')): xdebug_print_function_stack(); endif; $this->end(); ?> </div> </div> </div>
画面
※スタックトレースはおいおい対応する
所感
エラー画面って難しいと思います。よくわからないのでログ吐きまくって調べてしまった。
まだおかしい部分があるのですか今回はこれでなんとかする。
cakephp3でfinderでログイン条件を追加
cakephp3になってからというか少しずつ変化しているものがあります
認証処理とかも…
環境
CensOS7.x
php 7.0.3
cakephp3.2.3
認証処理で条件を付ける際にfinderを使う
以前は"scope"がありましたがそれとは別に"finder"というものがあります。
Usersテーブルとは別にテーブルのチェックなどが必要な場合はこちらがあると便利な感じ
実装
AppController
src/Controller/AppController.php
<?php namespace App\Controller; use Cake\Controller\Controller; use Cake\Event\Event; class AppController extends Controller { public function initialize() { parent::initialize(); $this->loadComponent('RequestHandler'); $this->loadComponent('Flash'); // 認証コンポーネント $this->loadComponent('Auth', [ // ログイン後のリダイレクト 'loginRedirect' => [ 'controller' => 'Posts', 'action' => 'index' ], // ログアウト後のリダイレクト 'logoutRedirect' => [ 'controller' => 'Users', 'action' => 'login', ], // 認証 'authenticate' => [ // フォーム認証 'Form' => [ // 暗号化 'passwordHasher' => [ 'className' => 'Default', ], // 認証フィールド 'fields' => [ 'username' => 'username', 'password' => 'password' ], // モデル 'userModel' => 'Users', // 抽出メソッド 'finder' => 'login' ] ], // データ保存 'storage' => 'Session', // 権限 // isAuthorizedメソッドを実装する必要がある 'authorize' => ['Controller'], ]); } /** * アクション前処理 * @param Event $event */ public function beforeFilter(Event $event) { parent::beforeFilter($event); } /** * Before render callback. * * @param \Cake\Event\Event $event The beforeRender event. * @return void */ public function beforeRender(Event $event) { if (!array_key_exists('_serialize', $this->viewVars) && in_array($this->response->type(), ['application/json', 'application/xml']) ) { $this->set('_serialize', true); } } /** * 認証権限判定処理 * * @param $user * @return bool */ public function isAuthorized($user) { // ユーザーの権限が"admin"の場合は全てを許可する if (isset($user['role']) && $user['role'] === 'admin') { return true; } // Default deny return false; } }
※finderという項目に"login"を指定します。省略時は"all"
UsersTable.php
src/Model/Table/UsersTable.php
<?php namespace App\Model\Table; use App\Model\Entity\User; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; /** * Users Model * */ class UsersTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->table('users'); $this->displayField('id'); $this->primaryKey('id'); $this->addBehavior('Timestamp'); } /** * ログイン用メソッド * * 独自のfindメソッド * @param Query $query * @param array $options * @return Query */ public function findLogin(Query $query, array $options){ // 条件を付与 $query->where([ 'Users.status' => 0, 'Users.deleted' => 0 ]); return $query; } }
SQLのログ
SELECT Users.id AS `Users__id`, Users.username AS `Users__username`, Users.password AS `Users__password`, Users.role AS `Users__role`, Users.status AS `Users__status`, Users.deleted AS `Users__deleted`, Users.created AS `Users__created`, Users.modified AS `Users__modified` FROM users Users WHERE ( Users.username = 'test01' AND Users.status = 0 AND Users.deleted = 0 ) LIMIT 1
所感
HTMLのヘルパーって使いたくない…
生成されるまでどんな形かわからないんですよ…
多少手間がかかってもHTMLで書くべきかと思います…
なんでHTMLヘルパーってあるんだろう…
cakephp3でカスタムバリデーションプロバイダを作成
バリデーションのルールはチェックはいろいろありますが
多少細かいチェックなどがあった場合は対応できません。
各テーブルだけの機能ならともかくいろいろなテーブルクラスで使用する場合はバリデーションを使いまわしたい
対応
ディレクトリを作成
mkdir -p src/Model/Validation
バリデーションインターフェースを実装
src/Model/Validation/CustomValidationInterface.php
<?php namespace App\Model\Validation; interface CustomValidationInterface { // チェックメソッドを定義する public static function sampleCheck1($string); // チェックメソッドを定義する public static function sampleCheck2($string, $len); }
チェック処理を実装
src/Model/Validation/CustomValidation.php
<?php namespace App\Model\Validation; use Cake\Validation; class CustomValidation implements CustomValidationInterface { // チェックメソッドを実装する public static function sampleCheck1($check) { $result = null; if ($check == "check1") { $result = true; } else { $result = false; } return $result; } // チェックメソッドを実装する public static function sampleCheck2($check, $len) { $result = null; if ($check == "1234567890" && strlen($check) == $len) { $result = true; } else { $result = false; } return $result; } }
※サンプルって手抜きの方がわかりやすいと思います
テーブルのバリデーションに実装
<?php namespace App\Model\Table; use App\Model\Entity\Post; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; use App\Model\Validation; /** * Posts Model * */ class PostsTable extends Table { /** * Initialize method * * @param array $config The configuration for the Table. * @return void */ public function initialize(array $config) { parent::initialize($config); $this->table('posts'); $this->displayField('title'); $this->primaryKey('id'); $this->addBehavior('Timestamp'); } /** * Default validation rules. * * @param \Cake\Validation\Validator $validator Validator instance. * @return \Cake\Validation\Validator */ public function validationDefault(Validator $validator) { // プロバイダを追加 $validator->provider('custom', Validation\CustomValidation::class); $validator ->integer('id') ->allowEmpty('id', 'create'); $validator ->requirePresence('title', 'create') ->notEmpty('title') ->add("title", [ "check1" => [ "rule" => ["sampleCheck2", 10], "message" => "カスタムプロバイダーエラー1", "provider" => "custom", // 使用するプロバイダ名を設定 ] ]); $validator ->requirePresence('body', 'create') ->notEmpty('body'); return $validator; } }
こんな感じ
参考
localized/src/Validation at master · cakephp/localized · GitHub
バリデーション — CakePHP Cookbook 3.x ドキュメント
所感
cakephp2の場合はビヘイビアに組み込むという方法で共通化していたので別の場所に配置できるようになるとメンテナンスもやりやすくなるかも…
データだけのチェックの場合とデータベースが絡む場合で難易度が変わるかもしれないので注意する必要があるかもしれないけど…