ROBOCOPY再び

 Windows端末にインストールする形で提供しているアプリについて、変更都度インストールしなきゃいけないのが面倒という話があり、ファイルサーバからリソースをコピーする形にしようと思います。
 対象のアプリは下記のようなフォルダ構成で、基本的に初期インストール以外はファイルを配置するのみです。

アプリルートフォルダ¥src
アプリルートフォルダ¥img
アプリルートフォルダ¥data
アプリルートフォルダ¥log

 上記フォルダのうち、logとdataのフォルダはコピー対象外となります。
 また、アプリ変更時は数人に先行して使ってもらって評価した後に他の利用者へ配布するという運用なので、端末側に新しいリソースがある場合はコピーしないようにします。

結果こうなりました。

robocopy ファイルサーバの所定フォルダ アプリルートフォルダ /E /XO /XD log data /NDL /NFL /NJH /R:2 /W:3

前回使ったrobocopyコマンドを参考に、/XD でlogとdataのフォルダを対象外にし、/E /XO /XD で端末側が新しければコピーしないという形にします。

Swagger + SpringBoot で APIサイトを作ってみる

既存システムのDBへアクセスしてデータを参照するようなAPIを、って事で、
SwaggerでAPIを定義し、Swaggerから自動生成したソースを使って実装してみました。
なお、今回対象としているのは参照系がメインでRESTって雰囲気ではありません。
対象が既存システムのDBなので。。

とりあえず、ざっくりとした要求と応答の仕様を整理し、Swagger Editorにyamlを書いてみます。

なお、Swagger Editorは、別件で使っていた端末内のxampp/htdocsにGitHubからダウンロードしたZIPを解凍して使ってます。
ある程度、定義を書いた後、Swagger EditorからGenerate ServerでSpringのサーバソースを出力してみます。

自動生成されたJavaソースはこんな構成です。

Controllerとレスポンスエンティティのモデルが揃ってます。全体的なソース構成は、コントローラ層、サービス層、データアクセス層という3構成になりますかね。
コントローラ層は概ねSwaggerで生成したので、データアクセス層も自動生成しようと、Doma2を使ってみます。
doma-gen-build.xmlに接続先DB情報と出力先ソースの設定等を記述し、こちらもGenerate!

結果、ソースを手書きする必要があるのは、

・サービス層全体

・Swaggerで自動生成されたSpringBootApplicationクラスのComponentScanにサービス層のパッケージを追記
  @ComponentScan(basePackages = { “io.swagger”, “io.swagger.api”,”jp.esoro.api” })

・Swaggerで自動生成されたControllerにServiceをコールする箇所を追記

・DAOインターフェースに下記アノテーションを追記
@ConfigAutowireable
@Repository

・自動生成不可能なSQL文の作成し、それに合わせてDAOにメソッド追加

といったところで、とりあえずの動作確認が出来ました。

ただ、実用するには認証やページング等も必要なので、こんな単純な話にはなりませんし、APIの仕様をちゃんと整理してからSwaggerでソースを生成して着手しないと後が面倒ですね。

NTLM認証のサイトからファイルをダウンロードする

SpringBootで作成中のアプリに、企業内のWebサイトよりエクセルファイルをダウンロードする要件があったので、何となくBasic認証のサイトだろうなと思い込んで実装を始めましたが全然繋がりません。

wget ‘http://username:password@filestore.bbb.co.jp/web/download/downloadfile.xlsx’
でファイルは取れます。

でも、
curl ‘http://username:password@filestore.bbb.co.jp/web/download/downloadfile.xlsx’
では動きません。

試しにwgetをデバッグモードでやってみて気が付きました。。

WWW-Authenticate: NTLM

このサイト、NTLM認証ですね。。

下記を参考に認証箇所を変更
http://code-addict.pl/reporting-services-rest-url-client/

また依存が増えてしまいましたが。。

ダウンロードファイルが更新されていた時だけダウンロードするという対応も必要なので、サーバ内にダウンロードしたローカルファイルとサイト上のファイルタイムスタンプをチェックし、一致しなければファイルをダウンロードしタイムスタンプをサイト上と同じ時間に書き換えるという対応になりました。

で、タイムスタンプはどこ?ここに書いてました。

確かにhttpヘッダに
Last-Modified:Tue, 14 Aug 2018 08:53:30 GMT
と書いてあります。

結局、こんな感じのコンポーネントを用意しました。

テストしてみます。

とりえあず、動いたので整理してから実装します。

カテゴリー: Java

SpringBootでWebアプリが動かない

 作りかけのSpringBootのRestアプリを別端末の開発環境(Windows+EclipseSTS+Maven)へ移行して動かしてみたところ、ブラウザからURLを打ち込んでも、RestControllerがうんともすんともいいません。元々の環境では普通に動作していたのですが。。
 困ったな・・と別環境への移行を諦めようかと思っていたところ、よく見るとSpring実行時のログ出力に下記を発見


[ERROR] C:\Users\admin\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\8.5.31\tomcat-embed-core-8.5.31.jarの読込みエラーです。invalid LOC header (bad signature)

 とりあえず該当のC:\Users\admin\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\8.5.31 内のファイルを全て消して再度、プロジェクト→実行→Maven install実施。
すると何事も無く動き始めました。。


2018-07-30 15:18:55.806 INFO 14844 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8090 (http) with context path ''

こういった問題はあまり深く考えても詮無き事。。
なお、デフォルトの8080ポートは他アプリと被ってたので、application.ymlに

server:
port: 8090

と書いています。

SpringBootのCacheにCSVを入れてみた

 別のところで開発してもらったSpringBootのソースを引き取って機能追加の対応をしているのですが、毎日定時に更新されるCSVファイルをマスターデータとして使用するという要件が含まれてました。
 CSVをそのまま処理の都度読み込むのもイマイチだし、今回はSpringBootのアプリケーションなんで、SpringBootCacheを使ってみる事にしました。

今回の要件的にCacheとしてはConcurrentMapCacheでこと足りそうなので、実装前に下記サイトの住所CSV関東版を使って試してみます。
住所データのダウンロードサイト【住所.jp】

まず適当にエンティティを・・

キャッシュ設定のevictスケジュールについては、ここではテストなので1分でクリアし、クリアした事がわかるように出力してます。実際には日次CSVファイル更新処理が終わった後くらいに動作するようにします。

で、サービスを作りますが、ここでCSVのデータを全部キャッシュに突っ込みます。CSV読み込みについてはこちらを参考にさせて頂きました。

事前にapplication.ymlに下記を書いておきます。

依存しているものです

最後にテストを書いて効果を確認します。

テスト結果です。

CSVを読んだ場合500ms程度ですが、キャッシュが効いてると殆ど1ms以内の世界です。
こりゃいい感じですね!

google-http-clientを使ってみた

 とあるWebAPIサービスを提供しているサイトへアクセスするクライアントをjavaで書こうかと、最初はjerseyを試してみたのですが、これがなかなか厄介で、次から次と依存が判明して動作するまで一苦労。。
最終的には、とあるサイト側の認証における制約により、jerseyの仕様ではどうやってもアクセスが出来ない事が判明。。

 失敗の原因は概ね当たりが付いていたので、その辺りに問題が無さそうなライブラリとしてgoogle-http-clientを使うことにしました。
 jerseyで途中まで実装していたものをそのままgoogle-http-clientを使う形に置き換えて疎通確認レベルまでやってみます。

 google-http-clientは依存が無く構成がとてもシンプルで置き換えた途端に、サックリとAPIアクセスに成功しました。proxy経由でもJVM引数で指定してあっさり通りました。

 細かいところでは、どうも指定したタイムアウトは効いてないような気がしますが、まあ、今回の実務上問題無さそうなので、利用しやすいように整理して実装しようと思います。

 だいぶ経って2019年1月現在、久しぶりに使ってみると、当時のバージョン1.23と現在の1.28では仕様が変わっており上記のままでは動かなくなりました。。

ADOでCSVファイルを読み込むと255文字以上でエラーになる

 ちょっと前にVBScriptで作られたツールがあるのですが、最近になってエラーが出るとの連絡。
エラーになるケースは、CSVファイルを読み込んで255Byteを超えている値を扱う時と判明。
対象のツールは実装上ADOが使われており、下記のようにCSVへアクセスしてます。

対象のCSVファイルが改行を含む値を扱う都合でADOを使ったようなのですが、どうやら、CSVテキストドライバとしての仕様上、255を超える項目数だったり、255を超えるサイズといった、昔ながらの壁がある模様。
回避策としては、Schema.iniで逃げるのが定番らしいのですが、試したところエラーにはならないが、255文字超が勝手に切られる形に・・・

というか、これ以上ADODBについて調べる時間が無駄!!なので、テキストファイル読み込みとして作り直しました。。

こちらを少し参考にして、さらにダブルクォーテーション内のカンマも考慮し(ここではカンマは削除してます)、ADOのレコードセットっぽく1レコード毎に配列へ列の値をセットしてから処理を行っていきます。

redmine plugin DMSFを入れてみた

文書管理をしたいという話があがり、redmineプラグインにDMSFってのがあるよ!
って事で、対象のredmineが3.3なので、DSMFは現時点の最新より一つ古い 1.5.9 を入れてみました。

redmine/pluginsにダウンロードしたソースを置き、redmineのルートディレクトリに移動。
最初
bundle install –without development test
とした後に
bundle execでインストールしようとしたが、redmineローカル内のGemとして入ってないと怒られた。
また、xapian-full-alaveteliというgemがどうも入らないので、こちらはGemfileの該当箇所をコメントアウト。

結果、
bundle install –without development test –path vendor/bundle
とした後に
bundle exec rake redmine:plugins:migrate NAME=redmine_dmsf RAILS_ENV=production
でとりあえず入った。

プラグイン設定画面はこんな感じ
一番下のテキスト検索の箇所が、入らなかったgemと関係している模様。文書検索できるならさらに素晴らしいが日本語は選択対象に無いので、とりあえずOFF。

利用対象とするプロジェクトの設定から、「文書管理」ってモジュールにチェックを入れて使用開始。

wikiの隣あたりから「文書管理」が開くようになり、ファイルをドラッグアンドドロップでアップロードできるようになりました。
同じファイル名はアップロードするごとに自動的にマイナーバージョン番号がアップされ、メジャーにするときはアップロード時に画面で指定します。

文書の更新履歴はこんな感じ。

他に承認ワークフロー機能があるようなので試したところ、承認ワークフローの設定で新規ステップと押しても反応しないのでログを見たら、DBエラーが出てました。
該当ソースのgithub履歴をみるとバグフィックスしたコミットがあったので、ステップが登録できるようになりました!承認者をORかANDで設定していく形です。

で、該当文書の右端チェックを押すとワークフローを適用できます。
今回試しに「ソフトウェア資料」というワークフローを作りレビュアー3名をOR設定、承認者1名をセットするとこんな感じで履歴が見れます。

とは言え、1.5.9は他にもバグがあるのでパッチをあてないとredmineの動きがちょっとおかしくなります。最新バージョンを入れてみれば良かったと後悔。。

DMSFによる文書管理をこれからどう運用していくかは、既存のファイルサーバ管理からの移行方針とか、プロジェクトの切り方といったredmine運用も考えた上でやらないといけませんね。

Windows10でHTAの画面フォントが崩れる

 少し前にHTAで作られたツールのWindows10対応をしていましたが、一部の画面で文字が巨大化したりで表示が崩れて目も当てられない状況。。

 でも全ての端末で起きる事象では無いらしく、特にパナのLet’s Note の場合に発生しているらしい。どうも、Win10のデスクトップ右クリックでディスプレイの設定を開き、「拡大縮小とレイアウト」が100%でないと崩れる模様。
 パナのLet’s Noteは、ディスプレイの解像度が高い為、文字を大きく表示したいと設定を変更する人が多いようです。

「拡大縮小とレイアウト」より設定を変更しながら対応結果の確認をしますが、HTAは「一部のアプリは、サインアウトするまで、拡大縮小の設定に応答しません」の対象なので、設定を変更してはサインアウトの繰り返しが必要。

 結局、HTAに書かれているCSSを確認したところ、%指定とかem指定とか結構適当になっていた事に起因している事が判明。
 フォントサイズを全てピクセル指定にして一件落着。

今どきはXCOPYでなくROBOCOPY

ファイルサーバからWindows端末にディレクトリ毎ファイルを同期させたいような話があり、昔ながらXCOPYのオプションなんだっけ?とググっていたところ、今はROBOCOPYなる便利なコマンドがある模様。

今回は、完全にディレクトリを同期させ、うざい出力も消したいので下記のコマンドで対応

robocopy \\fileserver\targetdir %USERPROFILE%\targetdir /mir /NDL /NFL /NJH

スタートアップにバッチを仕込んで、Windowsローカルアプリ更新時の同期とか簡単に出来ますね。