WindowsPC同士で有線LAN1本直結でリモートデスクトップ接続する
クロスケーブルを買って接続
ストレートケーブルとクロスケーブルを見分ける方法 | バッファロー
通常のLANケーブル(ストレートケーブル)に対して、 端子のピンの並びが端と端同士で鏡のように左右対称に なっているLANケーブルのこと。 PC同士の接続に使う。ルータやハブには使えない。
IPアドレスを手動で設定する
Windows 10でLANケーブルでPC同士を繋いでファイル共有 - キリウ君が読まないノート
WindowsPCを接続しただけでは、DHCP(自動でIPアドレスが 割り振られる仕組み)が働かない。 通常、ブロードバンドルータや企業ネットワークなどでは DHCPサーバーが担当。)
よくわからなければ、サイトの通りに設定すると間違いがない。
なお、元のLANに接続しなおして「IPアドレスが重複しています」 などのエラーが出たら、即時IPアドレスを自動設定に戻すようにする。 (大目玉くらいます)
リモートデスクトップで接続される側のWindowsでリモートデスクトップを有効にする
PC でリモート デスクトップを有効にする | Microsoft Learn
リモートデスクトップで接続される側のWindowsの「パブリックネットワーク」のファイアウォールを切る
直接LANで接続している場合必ずパブリックネットワークになり、 デフォルトではファイル共有およびリモートデスクトップ接続が無効となる。 セキュリティソフトやWindowsファイアウォールの設定を見て、 パブリックネットワークの設定を変える。
Norton Intenet Security リモートデスクトップ許可設定 - KuroNeko666’s blog
リモートデスクトップのWindowsファイアウォール設定 | 日記というほどでも
以上
これで接続できなかったら、pingとかで地道に検証。
謎シチュに至った訳
- VPNの都合上、リモートデスクトップ接続で作業することに
- 突然の有線LAN取り上げ、隣の部屋からの無線オンリーに。レスポンス劇的に劣化。
- リモートデスクトップ接続だけ有線LANに。
初学者がUMLだけやっても意味がないのでは?
身も蓋もない言い方
設計は沼であり、大事な仕事・作業・人間生活にかかることであればちゃんと武装して臨むべき。
UMLは可視化ツール
クラスを中心としたソースコードを書けば、対応するUMLは半ば機械的に生成できる。 UMLは地図であって、極地的な地形であってもとりあえずそのままに書けてしまう。
良い設計は、コンセプトを伴ったパターンを持つことが一種指標に思える。 例えば、クラス図は汎化を表現できるが、以下のように指向するとよい設計につながる。
- あるデスクトップアプリケーションのデータ書き込み処理は、同じデータを固定長レイアウト、JSON形式、CSV形式の3パターンで表現する。
- 3パターンの形式を決定するのは、書き込み時にGUI指定する。それ以外のファイル書き込み時のハンドリングはすべて共通。
- それぞれの派生クラスを「生成」し、後続のファイル書き込み処理に、書き込みデータ供給の共通インタフェースを通じて処理をさせる。
こう言葉で書くとながったらしいことを、UMLは記号化してくれる。 しかし、この複雑さを簡略化はしてくれず、説明を端折ると謎の図になる。
実装パターンを豊富に知っているのであれば、思いつくままパズルの要領でつなぎ合わせて6,7個ぐらいの概念を同時に入れたところで依存性の糸の絡まり具合を可視化し、ここは切れるとかこの概念は相性が悪そうだとかを診断するためのツールになる。
初学者にとってのUML
まだ学生の頃にカリキュラムとしてUMLを触れた当時は価値がわからなかった。 簡単なMVCモデルの1画面をクラス図に書いただけで整理の必要が全くなかったのが一番の原因だが、 複雑なものを表現したとしても、知見不足で書いてみたのでは結局わからずじまいだったかもしれない。
そもそも、UML関連の学習コンテンツは説明が悪いことが多い。 「集約とは、集めて持つことである」「包含とは内部にオブジェクトを隠ぺいして持つことである」「依存はそのクラスを使っていることである」 と定義はわかるのが、なんのために依存するとか、この構造を持つことで特定の処理時にパターン化できるとか、ケーススタディ的な学びがUMLと一緒にできる例についに出会うことはなかった。 「設計とかコーディングのときに気づき内省しものにせよ」と寿司職人さながらのマインドはまだしも、UMLは握ってモチベーションに駆られるかの観点から題材の悪さしか印象にない。
設計とUML
UMLは良くも悪くも可視化ツールだ。 なので、パターンとコンセプトのある設計を表現してみて確からしさを検証するための手遊びの道具であり、 実際の実装や他の図と反復しながら多角的に検証したり、豊富なナレッジベースを並べてみて組み合わせを評価するのが一番道具として生きると考えている。 もし、UMLがしっくりこないとか意味が解らないのであれば、少し仕事や勉強から逸れたことをして、思い切り複雑で新しいことをしたときにでも思い出して無理やり書いてみるとどうだろうか。
【ExcelVBA】VBAはクラス指向より手続き型でFATに作りたい
前置き
VBAでもクラスは作成できる。
しかし、フォルダや階層による小分けができない。 例えば設定ファイルの保持やパースのために作ったConfigクラス、特定ファイルの書き出しのために作ったExternalXXXCSVFileクラスやExternalYYYCSVFile、内部のファイルの保持のために作ったTempFileクラス、その他値の保持用だったりビジネスロジックがぐちゃぐちゃに入り組んだりする実態が同じフォルダに入る。 そこそこの規模のアプリを作ろうとしたとき、違う考え方の領域が10個ぐらい、系3,40個のクラスが並列に並ぶことになる。これはWeb系の言語でやっているようなスケーラブル(脳死で拡張可能)なオブジェクト指向なクラスの管理だろうか?
プロジェクト(=Excelブックやxlamファイル)で分ければできるが、全部読み込むようにするのは手間だし分割も面倒、本末転倒だ。
そこそこ小さい実装ならまあいい感じの実装にはなるだろう、しかし個人としては、VBAでクラス指向*1 で設計するのはアンチパターンと位置付けるに至った。
MVCは、1つの標準モジュール/Excelシート/シートVBAを1つの「M」「V」「C」に見立ててみる
Web系に馴染みのある方であればMVCパターンを適用したくなるだろう。 ここで、それぞれの要素をModel(処理の本体)、View(ユーザーインタフェース)、Contoller(MとVの繋ぎ)で考える。(※Web系実装のMVCは通常、Mはステートフル=DBやデータなどの状態を持ち更新処理などがあるが、ここでは基本的にステートレス=データ保持無しのため、実行時パラメータによって完全に決まるものとする。)
V。Excelシートそのもの。 C。Excelシートをクリックしたときに実行するハンドラ。色々な変換処理がある。Mを呼び出す。 M。Cの結果を受けて、何かしら外部ファイルを出力したり作用したりするメソッドのみの存在。単独テストが可能。
V → Cへの繋ぎは、ExcelのRangeやCellといった各種APIで代用となる。ここら辺が特にツライが、データ化すればこっちのもの。FormやDto、Entity、Recordといった実体が欲しいのであればCreateObject("Dictionary.Scripting")で連想配列を使ったり、そこだけクラスモジュール化してもよい。 C → Mへの繋ぎは、V→Cでデータ化したものをそのまま受け渡すだけでよい。
以上、やりたいことは、引数と戻り値だけの標準モジュールで実装できないだろうか。
モジュールとImmutableを基本に設計・実装する
ローカル変数以外に、メモリ中に状態を持たず、処理結果や確保したリソースを引き続き保持したければすべて引数・戻り値を介して取得・保持し、メンバー変数やグローバル変数は必要時以外排除すると、自然とImmutableな実装は達成される。 細かい項目の受け渡しが面倒であれば、そこだけクラス化や連想配列化によりまとめて処理してしまえばよい。ここまで徹底的にやれば、晴れてクラス実装を手放せる。
代わりに、1つのモジュールの責務が肥大化するが、Excel VBAはそもそもスコープが小さくなる傾向にあるので、よほどの場合を除きコントロール可能な範囲に収まるはず。(そもそも、VBAがコントロール不能なぐらい肥大化している場合、もはやExcel VBA以外の実装を用いたほうがメリットが大きいというような事態に陥ってないだろうか?)
*1:「クラス指向」の言い回しは、オブジェクト指向に造詣の深い方にとって違和感の塊だろう、しかしあえて揶揄している。多態を持たず、静的なプログラム構造によって実際の動作および俯瞰図が完成するのであれば、メモリ上に実態を展開し実行時情報を持つというオブジェクト指向の原典的な利点の1つは別になくても、クラスという書式でカプセル化、レイヤ化、関心や責任の分離は実現できる。そしてその3点はC言語のような純手続き型言語でも設計によって十分可能であり、現実に、1970年代に軍事系のC言語の開発プロジェクトで達成されたという研究もある。クラス名のパターンが設計のすべてなのであれば、関数名+引数にとる構造体のグループでほぼ誤差なく手続き型に落とせる。
【Excel VBA】ファイルの絶対パスを取得する
カレントディレクトリ
Sub 使いないやつ() Debug.Print CreateObject("Scripting.FileSystemObject").GetAbsolutePathName("./") Debug.Print CurDir End Sub
Public Function AbsPath(String RelativePath) As String On Error GoTo HANDLING Dim DirBK As String DirBK = CurDir ChDrive Left(ThisWorkbook.Path, 1) ChDir ThisWorkbook.Path AbsPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(RelativePath) ChDrive Left(DirBK, 1) ChDir DirBK Exit Function HANDLING: Debug.Log ("[ERROR]AbsPath():" & ERR.Description) ERR.Raise ERR.Number, ERR.Source, ERR.Description, ERR.HelpFile, ERR.HelpContext End Function()
- FileSystemObjectやChDirを使わないレシピ
Public Function AbsPath(Path As String) As String On Error GoTo HANDLING If (InStr(Path, ":") <> 2) Then Path = ThisWorkbook.Path & "\" & Path Else Path = Path End If Dim idx As Long Do While InStr(Path, "..\") > 0 idx = InStr(Path, "..\") Dim idxPrevSep As Long idxPrevSep = InStrRev(Path, "\", idx - 2) If (idxPrevSep = 0) Then Exit Do End If Path = Left(Path, idxPrevSep - 1) & Mid(Path, idx + 2) Loop Path = Replace(Path, ".\", "") AbsPath = Path Exit Function HANDLING: Debug.Log ("[ERROR]AbsPath():" & ERR.Description) ERR.Raise ERR.Number, ERR.Source, ERR.Description, ERR.HelpFile, ERR.HelpContext End Function
【Excel VBA】エラー処理(例外処理)をちゃんと書く
概要
- VBAでOn Errorを書くと、どこでエラーになっているのかマジでわからなくなる。
- 付属のデバッガ以外の例外機構/エラーレポーティングが貧弱であるため、全てを手で実装しなければならない。
- ある程度の規模のアプリケーションで実践できたので、共有。
結論(テンプレート)
Worksheet / ThisWorkbook の書き方テンプレート
' ///////////////////////////////////////////////////////////////// ' // 何かのボタンがクリックされたときのイベントハンドラ ' ///////////////////////////////////////////////////////////////// Private Sub BtnA_click() On Error Goto HANDLING ' メソッドに入ったら必ずロギング Call ModuleUtil.Log("Sheet1.BtnA_click() - start") Application.ScreenUpdating = False ' 入力値検証 If Range("A2").Value2 = "" Then ' 注:ここでは安直にRaiseしているけど、やりたい内容によって変えてよい Err.Raise Description:="〇〇が空欄です" End If ' 本処理 call ExecMain() ' メソッド終わったらロギング Call ModuleUtil.Log("Sheet1.BtnA_click() - end") Application.ScreenUpdating = True Exit Sub ' エラーハンドリング ' ------------------------ HANDLING: ' エラー内容をユーザーに通知する。独自のヘルパメソッドを介す。 Call ModuleUtil.MessageBox(Err.Description) ' どこのエラーかしっかり記録する。独自のヘルパメソッドを介す。 Call ModuleUtil.Log("[ERROR] Sheet1.BtnA_click():" & Err.Description) ' 例外は握りつぶす Application.ScreenUpdating = True End Sub ' ///////////////////////////////////////////////////////////////// ' // 本処理 ' ///////////////////////////////////////////////////////////////// Private Sub ExecMain() On Error Goto HANDLING ' メソッドに入ったら必ずロギング Call ModuleUtil.Log("ExecMain() - start") ' 何かのメイン処理をここで行う ' 試しにErrorを起こさせてみる Call Mid("", -1) ' メソッド終わったらロギング Call ModuleUtil.Log("ExecMain() - end") Exit Sub HANDLING: ' どこのエラーかしっかり記録する。独自のヘルパメソッドを介す。 Call ModuleUtil.Log("[ERROR] Sheet1.ExecMain():" & Err.Description) ' Errorを呼び出し上位に伝搬させる Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End Sub
ヘルパメソッドを実装するモジュールのテンプレート
' ///////////////////////////////////////////////////////////////// ' // メッセージボックスを出力する ' // 引数省略時は、なぜか、Call で呼ばないとスタックが壊れる ' ///////////////////////////////////////////////////////////////// Public Function MessageBox(Text As String, Optional buttons As Long = 0, Optional title As String = "-1") As Long On Error GOTO HANDLING If (DisabledMsgBox()) Then Call Log(Text) Exit Function End If Dim argTitle As String If (title = "-1") Then argTitle = ThisWorkbook.Name Else argTitle = title End If MessageBox = MsgBox(Text, buttons, argTitle) Exit Function HANDLING: Call Log("[ERROR]ModuleUtil.MessageBox():" & " " & Err.Description) Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End Function ' ///////////////////////////////////////////////////////////////// ' // ログを出力する ' ///////////////////////////////////////////////////////////////// Public Sub Log(Text As String) Dim StrNow As String StrNow = Format(Now(), "yyyy/mm/dd hh:nn:ss") Debug.Print "[" & StrNow & "] " & Text If (EnabledLog()) Then Dim ts As Object Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile(GetLogFilePath(), 8, True) With ts .WriteLine "[" & StrNow & "] " & Text .Close End With End If End Sub
ヘルパメソッド
Call ModuleUtil.MessageBox(Err.Description) Call ModuleUtil.Log("[ERROR] Sheet1.BtnA_click():" & Err.Description)
- 今回携わったアプリは自動実行モード(CUI)と手動実行モード(GUI)を使い分けるため、それぞれのモードで動作を切り替える必要があった。
そのため、過剰にラップしている。この部分は、要件次第で、MsgBoxやDebug.Print直呼びでも構わない。
ただ、実運用を考えると、ログファイルへの出力機構は用意したほうが追跡性あがる。
- 年月日時分秒の出力はマジで助かる。
開始/終了ログ
Call ModuleUtil.Log("Sheet1.BtnA_click() - start") Call ModuleUtil.Log("Sheet1.BtnA_click() - end")
- 最悪なくてもいいけどあったらうれしい。具体例は記事の最後に。
Errを捕捉したときの処理
最上位呼出階層
HANDLING: Call ModuleUtil.MessageBox(Err.Description) Call ModuleUtil.Log("[ERROR] Sheet1.BtnA_click():" & Err.Description)
それ以外の中間処理
HANDLING: Call Log("[ERROR]ModuleUtil.MessageBox():" & " " & Err.Description) Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
- とりあえずなんでもログに出しておく。本番運用で泣く。
- 余裕があれば、引数に何渡されたか全部出しておいてもよいぐらい。
- VBA標準関数(Mid、MkDirとか)やCreateObjectしたAPI(Scripting.xxxとか)呼ぶようなやつはとりあえず書いていたほうがよい。入力値次第ですぐにErrorを吐くAPIがあまりにも多い。
- Erl() でエラー発生した行番号取れるよって記事を見たけど手元の環境では「0」しか取得できなかった。
以上全盛りしたらどうなるか
- テキストログやイミディエイトウィンドウに以下が出る。
[2022/08/21 00:55:01] -------- [AUTORUN START] 〇〇〇.xlsm --------- [2022/08/21 00:55:01] Sheet1.btnABC_click() - start [2022/08/21 00:55:01] Sheet1.Validate() - start [2022/08/21 00:55:01] Sheet1.Validate() - end [2022/08/21 00:55:01] Sheet1.Generate() - start [2022/08/21 00:55:14] Save: C:\xxx\sample.txt [2022/08/21 00:55:15] Sheet1.Generate() - end [2022/08/21 00:55:15] FIN. [2022/08/21 00:55:15] Sheet1.btnABC_click() - end [2022/08/21 00:55:15] Sheet2.btnABC_click() - start [2022/08/21 00:55:15] Sheet2.Validate() - start [2022/08/21 00:55:15] [ERROR] Sheet2.Validate():引数の数が一致していません [2022/08/21 00:55:15] [ERROR] Sheet2.btnABC_click():引数の数が一致していません [2022/08/21 00:55:16] AUTORUN RESULT: NG [2022/08/21 00:55:16] -------- [AUTORUN END] 〇〇〇.xlsm ---------
- 「引数の数が一致していません」とだけメッセージが出る状況に比べてだいぶマシ。
メモ:システムエンジニアの評価指標
HIGH OUTPUT MANAGEMENTを読み、今の自分がどのような尺度でシステムエンジニアを評価できるかを試し書き。 結論、やや古めのWebアプリケーションエンジニア・アーキテクトに関する評価表になった。 何か本を読むなり手を動かすなりで知識を取り入れて更新していきたい。
設計者(システムエンジニア)としての指標
- 指標(グランドデザイン)
- 業務領域に関する知見の深さ。
- 様々なミドルウェア・ソフトウェアの特性の把握。
- システムを構築する要素の物理(サービス)的・論理(サービス)的観点の知見。(実例を知れば知っているほどよい)
- 運用時、各アクター(ユーザー、特権ユーザー、ヘルプデスク、エンジニア)がそれぞれできることと権限制御を含めたデザインができる能力。
- 外部システムとの依存関係の構築に関する知見。
- 個人情報やシステム監査など、社会的に要求される仕様に関する知見。
- 指標(詳細デザイン)
Webエンジニア(フロント)の指標
- HTML・CSSデザインに関する知見・習熟度。テンプレ的な配色比率やレイアウト(ex:グリッドレイアウト)に関する知見。(鮮度あり。長めに見て直近5年)
- UI・UX視点での知見。(ex:PC向けサイトをスマホで見るとどうなるか?)
- 素材をベースとした画像加工技術やロゴなどの画像制作技術。
- CSSの命名規則など、中長期に渡るCSSの保守に関する知見。(鮮度あり。長めに見て直近5年)
- JavaScriptの習熟度・DOMなどの機構の理解度。
- SPA(Single Page Application)や各フレームワークに関する習熟度。
- WebAPIの呼び出しなどに関する知見。
- 実装が及ぼす性能・処理速度への影響に関する知見。
- デバッグやプロファイルによるアプリケーションの挙動観測技能。
- ほか特定ケースの技能。
Webエンジニア(バック)の指標
- HTTPプロトコルとWebサーバーの仕組みに関するコンピュータ・サイエンス観点の知識。(リクエスト、レスポンスがそれぞれ何なのか。ブラウザはどう受けるのか)
- データストア(データベースなど)の更新特性に関する知見。
- 認可・認証に関する知見。
- トランザクション設計・エラーハンドリングにおける知見。
- 一般的な脆弱性対策に対する知見。(○○インジェクション、認証認可なしでパラメータ次第で不正操作できてしまうかの検出)
- 実装が及ぼす性能・処理速度への影響に関する知見。
- アプリケーション・サーバーが実稼働したときの物理構成に関する知見。(リバースプロキシやロードバランサ、CDNなど)
- デバッグやプロファイルによるアプリケーションの挙動観測技能。
- ほか特定ケースの技能。
テスト計画者・テスターとしての指標
- 一般的なテスト工程に関する知見。(単体テスト、結合テスト、総合(システム)テストはどんな性質の品質を検証するか?)
- テスト工程において期待されていることや作用の理解。(品質確認、ビジネスとしての品質保証、メンバー間の認識統合など)
- 仕様に適合しているかを検証するテストだけでなく、QA(品質保証)観点でのテストに関する知見があるか。
- テスト自動化における前提・弊害の理解。CI(Continuus Integration)実運用の知見。
- 境界値テスト・最大値・ゼロデータなどの一般的なテスト観点の知識。
- 正常系(想定している仕様に適合したケース)、準正常系(想定していない状態だが正常に稼働すると保証するケース)、異常系(処理継続困難となるケース)の理解。
- 状態を持つ実装(JavaScriptを駆使した動的な機能、スタンドアロンexeによる実装など)における検証の知識。(機能を連続して動かした時や、戻ったときに不正な表示や挙動をとるかの検証)
開発作業管理者・リーダーとしての指標
SpringMVC + JSP の環境構築とサンプル実装
前置き
- この記事は、ローカルPCに開発環境構築をすること、サンプルプログラムを実装することを焦点にあてた記事です。
- 実際にアプリケーション開発しサーバーで稼働させるには、セキュリティ観点や開発をスケールさせるための設計のために いくつか留意すべきことがあります。そちらについては、別途文献をご参照ください。
構築する開発環境
ゴール:下記構成のSpringBootを用いたWebアプリケーションの開発環境構築.
なお、できるのであれば lombok も導入するとコーディングが捗ります。
実行構成について
Oracle DB インスタンスについて
Oracleのローカル開発環境構築は割愛。 なお、この環境構築時にはDockerForWindows、およびOracle公式のDockerImageを用いて、ローカルPC上に構築した。
https://itedge.stars.ne.jp/docker_image_oracle_database_19c/
Oracleの単体稼働に2GBのメモリが必要なため、8GBのPCで開発するには若干パワー不足になる。
必要なソフトウェアのダウンロード
JDK 11
Javaの実行ランタイムと開発用のライブラリ・ツールがまとまったセット。 自分の環境用のインストーラを入手。今回は、Windows向けのものを想定する。
https://www.oracle.com/java/technologies/javase-jdk11-downloads.html
STS
統合開発環境。アプリケーション開発に必要。 予めプラグインを組み込んでセットアップ済みのEclipseが配布されている。 自分の環境用のzipファイルを入手。今回は、Windows向けのものを想定する。
Tomcat 9
JavaServlet用のWebサーバー。 自分の環境用のzipファイルを入手。今回は、Windows向けのものを想定する。
https://tomcat.apache.org/download-90.cgi
JDKのインストールとセットアップ
> java -version java version "11.0.6" 2020-01-14 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.6+8-LTS) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.6+8-LTS, mixed mode)
Tomcatのインストールとセットアップ
開発環境の環境変数を変更し「JAVA_HOME」にJDKのインストールパスを設定する。 ここでは、
C:\Program Files\Java\jdk-11.0.6
を設定したとする。 設定は、Windowsであれば設定
>環境変数を編集
を検索し、ユーザー環境変数に設定する。入手したTomcatのバイナリを解凍する。ここでは、解凍し
C:\opt\apache-tomcat-9.0.34
に配置したとする。解凍したディレクトリのbin配下にコマンドプロンプトやターミナルを起動し、 下記コマンドを実行してTomcatをデバッグ用ポートありで起動する。
./catalina jpda start
- ブラウザを起動し、http://localhost:8080 にアクセスしてTomcatの管理画面が表示されるか確認する。
STSのインストールとセットアップ
STSの解凍と起動
STSを解凍し、配置しておきたいフォルダに配置する。
SpringToolSuite4.exe
を実行する。
Note:メモリ不足の場合、 SpringToolSuite4.ini
からJVM引数を編集する。
- workspace(ファイル配置場所)を聞かれたら、とりあえず新しいフォルダ先を指定する。
Eclipseのデフォルトに従うなら、
(SpringToolSuite4.exeがあるフォルダ)/workspace
Gradleプラグインのインストール
- STS上部メニュー
Help
>Eclipse Marketplace...
をクリック - Eclipse MarcketPlaceウィンドウの
Search
タブで、Find:
にGradle
を入力してEnter Gradle ID Pack x.x.x ~
をInstall
。- ライセンスの確認ダイアログが表示されたら、「~Agree All~」みたいなラジオボタンを選択して「Finish」
- STSを再起動する
文字コードの設定
デフォルトのエンコーディングを、Java標準の UTF-8
に設定する。
- STS上部メニュー
Window
>Preferences
をクリック General
>Workspace
をクリックText file encoding
から、Other
: UTF-8 を選択Apply and Close
をクリック
オプション:STSの設定
下記、設定しておくと便利なもの。 もし、開発プロジェクトで標準の環境を作りたい場合、これらを事前設定する手順を追加しておくとよいです。
STS日本語化
保管アクション
- https://lifeinprogram.com/2018/11/25/post-355/
- Javaでは、「Organize imports」(自動インポート)や「Format all lines」 + GoogleStyleフォーマッターによる 自動フォーマットがあればだいたい標準化できる。
- checkStyle は静的解析ツールで、小うるさいことが多い。 新規プロジェクトでレビュー負荷を何がなんでも下げるんだ、という意志を貫きとおす自信がなければ、温かみのある手法に準じるのも一興。
サンプルプロジェクトの作成
サンプルプロジェクト作成
Service URL:任意 Name: プロジェクト名。ここでは「sample」とする Type:「Gradle(Buildship3.x)」 Packaging:「War」 Java Version:「11」 Language:「Java」 Group: mavenがらみの設定。例えば google なら com.google となっている。「org.pack」とする。 Artifact: mavenがらみの設定。通常プロジェクト名をいれる。ここは「sample」とする Version: ビルドスクリプトで参照できる。とりあえず0.0.1-SNAPSHOT でよい。 Description: 説明文。 Package: Javaパッケージの接頭辞。ここでは「org.pack.sample」とする。
- 定番のフレームワーク依存関係の入力し、
Finish
ここでは、下記をチェック。この内容は、 build.gradle
に反映される。
SQL
>MyBatis Framework
SQL
>Oracle Driver
Web
>Spring Web
サンプルアプリケーションの実装(共通部分、Mybatis用設定)
下記に従って、ソースコードを変更、または新規作成する。
編集: src/main/java/org/pack/sample/SampleApplication.java
アプリケーションのエントリーポイント(実行起点)となるソースコード。
- @ComponentScan を追加、サブパッケージをスキャンしてDIできるようにする
- @EnableAutoConfiguration を追加、JavaConfig機能を有効にする。
package org.pack.sample; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.ComponentScan; @ComponentScan @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) @SpringBootApplication public class SampleApplication { public static void main(String[] args) { SpringApplication.run(SampleApplication.class, args); } }
新規: src/main/java/org/pack/sample/config/MyBatisConfiguration.java
DI時にマニュアルでインスタンス作成することでいろいろカスタマイズするため設定コード。 このコードはMyBatisに特化。
- MyBatisの定義クラス Mapper のパッケージを指定
- ついでに色々要求されたので、いい感じのを記述
package org.pack.sample.config; import java.sql.Driver; import java.util.Properties; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.mapper.MapperScannerConfigurer; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.SimpleDriverDataSource; @Configuration public class MyBatisConfiguration { @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer configurer = new MapperScannerConfigurer(); configurer.setBasePackage("org.pack.sample.mapper"); configurer.setSqlSessionFactoryBeanName("sqlSessionFactory"); return configurer; } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); return factoryBean.getObject(); } @SuppressWarnings("unchecked") @Bean public DataSource dataSource(DataSourceProperties properties) throws ClassNotFoundException { SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); dataSource.setDriverClass((Class<? extends Driver>) Class.forName(properties.determineDriverClassName())); dataSource.setUrl(properties.determineUrl()); dataSource.setUsername(properties.determineUsername()); dataSource.setPassword(properties.determinePassword()); Properties connectionProperties = new Properties(); connectionProperties.setProperty("autoCommit", "false"); dataSource.setConnectionProperties(connectionProperties); return dataSource; } }
編集:src/main/resources/application.properties
全体の設定ファイル。
spring.profiles.active=local spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp mybatis.mapper-locations=classpath*:/com/example/demo/mapper/**/*.xml
編集:src/main/resources/application.properties
ローカル環境用の設定ファイル。Tomcatのcontext.xmlの記述で切り替え可能。
参考: https://exceptionblend.wordpress.com/2013/02/11/springframework-profile/
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:orcl spring.datasource.username=system spring.datasource.password=password spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
サンプルアプリケーションの実装(個別実装)
新規:src/main/resources/org/pack/sample/mapper/HealthCheckMapper.xml
MyBatisのMapper向けのSQL定義ファイル。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.pack.sample.mapper.HealthCheckMapper"> <select id="select" resultType="Long"> SELECT 1 FROM dual </select> </mapper>
新規:src/main/resources/org/pack/sample/mapper/HealthCheckMapper.xml
MyBatisのMapper向けのJavaファイル。
package org.pack.sample.mapper; import org.apache.ibatis.annotations.Mapper; @Mapper public interface HealthCheckMapper { long select(); }
新規:src/main/java/org/pack/sample/controller/LoginController.java
Webアプリケーションのリクエストを直接処理する。
package org.pack.sample.controller; import org.jboss.logging.Logger; import org.pack.sample.mapper.HealthCheckMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/login") public class LoginController { Logger logger = Logger.getLogger(LoginController.class); @Autowired private HealthCheckMapper healthCheck; @RequestMapping(value = "", method = RequestMethod.GET) public String index() { long n = healthCheck.select(); logger.info("helthckeck:" + n); return "login"; } @RequestMapping(value = "", method = RequestMethod.POST) public String login(LoginForm form, Model model) { LoginModel loginModel = new LoginModel(); final String loginid = "user"; final String password = "pass"; if (loginid.equals(form.loginid) && password.equals(form.password)) { loginModel.message = "ログインできました."; } else { loginModel.message = "ユーザーまたはパスワードが違います."; } loginModel.loginid = form.loginid; loginModel.password = form.password; model.addAttribute("loginModel", loginModel); return "login"; } /** * ログインフォームのリクエストパラメータ。本当は別ファイルに書くべき */ public class LoginForm { private String loginid; private String password; public String getLoginid() { return loginid; } public void setLoginid(String loginid) { this.loginid = loginid; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } /** * ログインフォームのレンダリングに利用するパラメータ。本当は別ファイルに書くべき */ public class LoginModel { private String message; private String loginid; private String password; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public String getLoginid() { return loginid; } public void setLoginid(String loginid) { this.loginid = loginid; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } }
新規:src/main/webapp/WEB-INF/views/login.jsp
HTMLテンプレート。
webappディレクトリが、WARファイルを配置した時のルートになる。この下に、jsやcssなどを配置する。
また、WEB-INF配下はTomcatの仕様でブラウザから直接アクセスできなくなる。
<%@ page contentType="text/html; charset=UTF-8" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <form action="login" method="POST"> <div>${loginModel.message}</div> <table> <tr> <td>ユーザ</td> <td><input type="text" name="loginid" value="${loginModel.loginid}"></td> </tr> <tr> <td>パスワード</td> <td><input type="password" name="password" value=""></td> </tr> </table> <button type="submit">ログイン</button> </form> </body> </html>
Gradleの依存関係更新
build.gradle または プロジェクト自体 を右クリック > Gradle
> Reflesh Gradle Project
で build.gradle の解析と Maven central リポジトリからの依存ライブラリの取得を実施する。
ビルドスクリプトの修正とTomcatへの配備
- build.gradleを編集し、下記とおりにする
plugins { id 'org.springframework.boot' version '2.2.6.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'java' id 'war' } group = 'org.pack' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' // ▽追加 def warName = 'sample.war' def localTomcatWebapps = 'C:\\opt\\apache-tomcat-9.0.34\\webapps' // △追加 repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.2' runtimeOnly 'com.oracle.ojdbc:ojdbc8' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } } // ▽追加 war { enabled = true archiveName "${warName}" } task deployLocal(type: Copy) { from "build/libs/${warName}" into "${localTomcatWebapps}" } // △追加 test { useJUnitPlatform() }
- コマンドプロンプトまたはターミナルを起動してサンプルプロジェクト直下に移動、下記コマンドを実行する
gradlew war deployLocal
動作確認
- STSでLoginController.java を開き、止めたい場所の行番号をダブルクリックしてブレイクポイントを設定する。
- STSでプロジェクトを右クリック>Debug>Debug Configuration.. を選択。
Remote Java Application
の新しい構成を追加し、Project
sample
、Host
localhost
、Port
8000
で起動。- http://localhost:8080/sample/login にアクセスし動作確認する。
参考委文献
- Spring Boot をはじめてみるよ(Gradle 編) - Multi Vitamin & Mineral https://hiranoon.hatenablog.com/entry/2015/12/30/160215
- Spring Tool Suite インストールと日本語化 for Windows https://qiita.com/andna0410/items/e9cc07c9e2e34a542245
- Mapper の注入 - mybatis-spring https://mybatis.org/spring/ja/mappers.html
- Spring MVC MyBatis - トッカンソフトウェア https://tokkan.net/spring/mybatisweb.html
- springframework profile機能について - Exception Blend https://exceptionblend.wordpress.com/2013/02/11/springframework-profile/
- Spring Boot でjspにページ遷移ができない - teratail https://teratail.com/questions/50904
- Spring MVC + JSP で検索画面の検索条件やページ情報を引き継ぐ方法@yoshikawaa https://qiita.com/yoshikawaa/items/0079c3a6c41e5b3b1fe3
- Tomcatのリモートデバッグの実行方法 - TECHSCHORE BLOG https://www.techscore.com/blog/2012/12/25/tomcat%E3%81%AE%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%81%AE%E5%AE%9F%E8%A1%8C%E6%96%B9%E6%B3%95/
- Eclipseでリモートデバッグする方法 - ラクス エンジニアブログ https://tech-blog.rakus.co.jp/entry/20190930/eclipse
- 第16章 ファイルを取り扱う - Gradle http://gradle.monochromeroad.com/docs/userguide/working_with_files.html