2018年8月 8日 (水)

古いプロジェクトを最新のASで開こうとした話

1. ことのはじまり


先日 Google Play から「2018年11月1日までに公開しているすべてのアプリの compileSdkVersion を API 26以上にしてちょうだい」とのメールが。詳しくは今後の Google Play でのアプリのセキュリティおよびパフォーマンスの改善についてというGoogle Developersのブログ記事を参照。


Oh、これ、対応しないと Ban されるやつだわ....。

ということで、GitHubにあげているソースをcloneして改修に入ることに。

2. 最新のAndroid Studioで読めるようにするには


「読めるようにするには」というよりもむしろ、「Gradleビルドが正常終了するようにするには」というほうが正しい。

いまのAndroidはgradleプロジェクトだけど、 build.gradle の設定はざっくりこんな感じ。

minSdkVersion 15
compileSdkVersion 19
targetSdkVersion 19
Gradle Wrapper 1.10
Android Gradle plugin 0.9
buildToolsVersion 19.0.3


注目すべきは Android Gradle plugin のバージョンで、どうやらこのアプリ、Android Studio 1.0がリリースされる前から開発していたようだw

2-1. Gradle Wrapper をアップグレードする


ここから先はASを使わず、エディタとコンソールで対応する。


Android の Gradle プロジェクトは、そのプラグインと Gradle そのもののバージョンに縛りがあり、これは公式で公開されている。


Android Studio 3.x には Gradle 4.4がすでにバンドルされているので、4.4以上にするのだが、たまたまシステムに Gradle 4.6 をセットアップしていたのでこっちの wrapper タスクを利用することにした。


また、 Gradle を 4.6 にするので、 Android Gradle plugin は 3.0.0 以降にする必要があるのだが、公式のAndroid Plugin for Gradle 3.0.0 への移行にあるとおり Google の Maven リポジトリを使う必要がある。

なので、ルートの build.gradle 中の buildscript に Google の Maven リポジトリを追加して Gradle プラグイン 3.1.x を使う設定を書く。

buildscript {
  repositories {
    google()  // 追加、Google Maven Repository を使う設定
    jcenter()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:3.1.4'
  }
}


また、appcompat-v7なども同様に Google Maven リポジトリからの取得になるので、dependencies ブロックにも設定を入れる。

Maven リポジトリの参照先をモジュールごとに変える理由はないので、ルートの build.gradleallprojects ブロックを定義する。

allprojects {
  repositories {
    google()
    jcenter()
    mavenCentral()  // jcenterがあれば普通は大丈夫だが、状況に応じて入れる
  }
}


ここまでできたら wrapper タスクを実行する。

$ gradle wrapper


正常終了したら、 Gradle Wrapper のバージョンは4.6になっているはず。

2-2. Android アプリモジュールの調整


今度は app/build.gradle をいじる。

buildToolsVersion を 27.0.3 以降にすればいいのだが、メジャーバージョンが targetSdkVersion の値と一致していないと警告の対象となるので、 targetSdkVersion は自然と同じ値になる。

また、これに引きずられて compileSdkVersionappcompat-v7 のバージョンも27以降にする必要がある。


今回は API 28 にするので、以下のとおりに変更。

android {
  compileSdkVersion 28
  buildToolsVersion '28.0.2'
  defaultConfig {
    targetSdkVersion 28
  }
}
dependencies {
  implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
}


また、プラグインの仕様変更で、最初の行に書く apply plugin も書き換える必要がある。

apply plugin: 'com.android.application'


この状態で、 assembleDebug タスクが正常終了すれば、ASにインポートしてもビルドが通るはずである。


| | コメント (0) | トラックバック (0)

2018年7月23日 (月)

ぼくのかんがえたさいきょうのドキュメントCIかんきょう

1. 前説:こんな書かれ方をするといやなのだ


みなさん、ソフトウェアの設計書ってどうやって書いてます?

....やっぱExcelですよね、この業界。


僕の周囲でもこれはそうなんだけど、個人的には

  • 自分一人で設計を書き、
  • その設計をもとに自分一人で実装し、
  • 実装内容とは無関係な体裁の修正に、十分な時間がかけられ、
  • 版の管理は気にしなくてよい


場合になら、たぶんExcelを普通に使うと思う。


ただ、実際の現場だとそんな悠長なことを言っていられるわけでもなく、人が書いた設計書をもとに実装、なんてことは普通で、場合によってはこんな設計書()に出くわすこともありうる。

Revision_of_mislieading_design


この場合の正解は、商品情報.商品カテゴリが104のとき、商品情報.個数を加算する。なんだけど、不要な情報が一緒に目に飛び込んでくるのは、正直勘弁してほしいと思う。個人的には。


それに、設計書がMicrosoft Office(xlsだと特に)だとこんなことが起きうる。

  1. 共有ディスクに設計書がアップされる
  2. 共有ディスクの設計書ファイルをそのまま開くと、反応が悪い上に場合によってはファイルを破壊する可能性もあるので、作業効率を優先してローカルディスクにダウンロード
  3. 実装作業中の設計書がいつの間にか更新される(アナウンスはなし)
  4. 更新を知らないままローカルファイルで実装を終える
  5. 「設計と挙動が違う」とバグ表を切られる


ほかにもいろいろあるが、設計書がMicrosoft Officeだとこんな弊害が起きる、と個人的には考えている。

  • 版の管理にはOneDrive for Businessとかが必要で、ふつうのVCSでやるのは悪夢でしかない
  • (上に関連するが)リビジョン間で「どこがどう変わったか」を把握するのは、容易なことではないので、一つの最終版ドキュメントにすべての情報を押し込めようとする
  • 集中管理されるべき設計書がカジュアルコピーとして拡散するので、どれが本物かわからなくなる
  • 設計とは本質的に関係のない「体裁の修正」に、少なくはない労力を割かなければならない


ここまでで終わらせたらただの文句でしかないので、どうすればましになるかを考える。

2. 設計書作成ツールとしてのMicrosoft Office


オフィススイートであるMicrosoft Officeでもっとも設計書作成で使われるのは、表計算ソフトであるExcelじゃないだろうか。

表計算をほとんど必要としない文書なのに、なぜExcelを使うのか、僕なりに考察してみた。

  • 日本には昔から「方眼紙文化」があるが、Wordだと方眼紙的なインデントが面倒だが、Excelだとセルを狭めることで方眼紙的なレイアウトを容易に再現できる
  • 複数の独立した文書を、「ワークシート」という単位で一つのファイルにまとめることができる
  • 日本のオフィスPCには、原則Microsoft Officeが入っているので、環境を選ばない。これは、設計書を「納品」しても、それを相手先でも読むことができることを意味する


Excelを使うときの利点を考えたら、僕ではこれくらいしか思いつかない。読者諸兄で、これ以外の利点がご存知ならご教示いただきたい。


個人的には、これらは何もExcelでなくても達成できるものだと思う。

そう考える理由は以下のとおり。

  • 方眼紙的なインデントが必要なのは、「一見して文書の意味付けを把握できるようにしたい」という要求の現れなので、要件に合うような文書構造にすればよい
  • 独立した文書を一つのファイルにまとめたいなら、HTMLでもできる
  • 環境を選ばないファイル形式には、Adobe PDFというものがある
  • 版の管理とリビジョン間の更新差分の管理がMicrosoft Officeだと難しいのは、ファイルフォーマットがバイナリが基本なのが原因なので、原稿をプレーンテキストで記述できれば差分管理はVCSが良しなにしてくれる
  • 単一の原稿から複数のフォーマットの成果物を生成できれば、「開発時は開発サーバ上のHTMLを参照」し、「納品にはPDFを使う(必要であれば印刷してもよい)」という方式がとれる
  • ドキュメントビルダを経由すれば、規定のマークアップ仕様のもとで、体裁は統一された仕様として構造化された文書に紐づくので、「文書体裁の修正」と「ソフトウェアの設計」を明示的に分離できる


前置きが長くなったが、これらを一度に解決する(と僕が考える)ソフトウェアがある。Sphinxである。

3. 本題:ぼくのかんがえたさいきょうのドキュメントCIかんきょう


まずは目標とすることを挙げてみる。

  • 文書の意味付けは標準テンプレートでまかなう
  • 版の管理をVCSに分離する
  • VCSにコミットされた原稿からのビルドは、人手を介することなく自動的に行われるようにする
  • 開発中の設計書が拡散しないよう、Webサーバで参照できるようにする
  • 納品用成果物となる設計書は、PDFにして管理する


いろいろ挙げたが、概念的にはこんな図になる。

Document_ci_overview


というわけで、ひとつひとつ書いていく。

3-1. プロジェクトとVCSの設定


プロジェクトについては、プロジェクトを作るの記事に従って sphinx-quickstart を実行して作るだけなので、特に難しいことはないはず。

VCSも、現状Git以上にベターな選択肢はないので、Gitを選択し、外部のホスティングサービスにおいている。ここでは、プライベート/パブリックの切り替えが簡単なAtlassian BitBucketを使っている。


プロジェクトを作ったら、UTF-8を扱えるエディタでreStructuredTextのマークアップ仕様に基づいて設計書を書いていこう。入門記事もある。

3-2. 面倒なことは有能な執事に任せる


「体裁の修正」や「可読性の高い文書ファイルの生成と配置」といった、本質的に設計と関係ないところで労力を割きたくないので、このテの作業はすべてJenkinsに任せる。

BitBucketがプッシュを受け付けたことをトリガーにしてビルドを始めるのが、反映タイミングとしては最速なのだが、これを実現するためにBitBucketにWebHookを設定する。


まず、Jenkins側にBitBucketからのWebHookを受け付けるためのプラグインを導入する。これにはBitBucket pluginを使った。導入自体は、Jenkinsのプラグインマネージャーから行える。


導入したら、ビルドプロジェクトをつくる。


ソースコード管理はGitにする。BitBucketの仕様に従っていれば特に問題はないはず。

01_source_code_control


次のビルドトリガは Build when a change is pushed to BitBucket を選択する。

02_build_trigger


最後に実際のジョブだが、 make の成果物をディレクトリにコピーするシェルスクリプトを実行する。

Ubuntu の DocumentRoot である /var/www/html 以下に反映する。

#!/bin/bash
HTML_ROOTDIR=/var/www/html/designdoc
UID_TOMCAT=tomcat
UID_WWW=www-data

LANG_CD=ja

HTML_DIST=$HTML_ROOTDIR/$LANG_CD
EPUB_DIST=$HTML_ROOTDIR/epub/$LANG_CD
PDF_DIST=$HTML_ROOTDIR/pdf/$LANG_CD

make clean html epub latexpdf

PS4='+ [${BASH_SOURCE}:${LINENO}] ${FUNCNAME:+$FUNCNAME(): }'
set -vx

if [ ! -e $HTML_ROOTDIR ]; then
mkdir $HTML_ROOTDIR
fi

sudo chown -R $UID_TOMCAT:$UID_TOMCAT $HTML_ROOTDIR

if [ ! -e $HTML_DIST ]; then
mkdir -p $HTML_DIST
fi
rsync -rlDH --delete _build/html $HTML_DIST

if [ ! -e $EPUB_DIST ]; then
mkdir -p $EPUB_DIST
fi
cp -f _build/epub/MySkill.epub $EPUB_DIST

if [ ! -e $PDF_DIST ]; then
mkdir -p $PDF_DIST
fi
cp -f _build/latex/MySkill.pdf $PDF_DIST

sudo chown -R $UID_WWW $HTML_ROOTDIR

set +vx


ただ、 Tomcat の実行ユーザーと Apache の実行ユーザーが違うので、 /etc/sudoers をいじって chown を認証なしで実行できるようにしている。

tomcat	ALL=(ALL:ALL)	NOPASSWD:	/bin/chown


このあたり、もっとましなやりようがないものか。我ながらかなりの力技だ(汗)。


Jenkins側の受け入れ態勢ができたところで、BitBucketのプロジェクトにWebHookを送る設定を書く。

[送信先URL]/bitbucket-hook/を宛先にする。

Webhook_from_bitbucket


ここまでやれば、手元で原稿を書き、それをBitBucketへプッシュするだけで、実装者にも納品担当者にもうれしい設計文書が作られているはずである。


| | コメント (0) | トラックバック (0)

2018年7月20日 (金)

Sphinxの環境を整える

この記事の目標

  • Sphinxの編集環境を作る
  • こぎれいなPDFを出力できる環境をWindowsで作る

Sphinx is 何


SphinxはPythonで書かれたドキュメントビルダで、reStructuredTextというマークアップ言語で書かれたソースをこぎれいなHTMLなんかに変換してくれる優れもの。

Sphinxのインストール


詳しくは公式のSphinxのインストール参照。

以下、かいつまんで書く。

  1. Pythonをインストール、デフォルトでよいが、公式ではPython 3.xを推奨している模様
  2. PIPをインストール
  3. pip install -U Sphinxを実行


編集には、Visual Studio CodeとreStructuredText拡張を使っているが、UTF-8が扱えれば使い慣れたエディタで大丈夫。

こぎれいなPDFをWindowsで作る


実はここがこの記事のメイン。


とりあえず、自分で試したWindowsとLinux(Ubuntu)で必要だったパッケージについて、ざっくりまとめた。

ビルダ html epub latex latexpdf
Windows
要TeX Live

要TeX Live, GNU Make, sh
Linux
要TeX Live

要TeX Live


この表のとおり、SphinxでこぎれいなPDFを作るにはTeXの力を借りる必要があるんだが、これにはTeX Liveというパッケージを使うのが一番簡単だ。


インストーラはInstalling TeX Live over the Internetで取得できる。

Windowsの場合、ネットインストール型のインストーラを使うのがお手軽だが、時間はとてもかかる(2時間くらい?)ことを覚悟したほうがいい。

とはいえ、待っているだけで基本終了するので、特に難しいところはないはず。


また、Sphinxのlatexpdfビルダは、WindowsのDOS窓では処理ができない動きをするので、UNIX由来のツールであるGNU Makeとshを入れておく必要がある。

これにはMSYS2を使うことにした。


QiitaにMSYS2 による gcc 開発環境の構築という記事を投稿している方がいるので、そちらを参考にmakeだけを入れる。

入れたら、C:\msys64\usr\binをパスに追加しておくこと。


ここまでできれば、Sphinxのドキュメントプロジェクトのあるディレクトリでmake.exe latexpdfとやればこぎれいなPDFが出力できていることだろう。


なお、「Sphinxのlatexpdfビルダは、WindowsのDOS窓では処理ができない動きをする」件、一応Issueにも挙がっているようで、日本のメーリングリストでも話題になっているんだけど、なかなかfixしないよなぁ....。


| | コメント (0) | トラックバック (0)

2018年1月31日 (水)

買いました報告:Android アプリ設計パターン入門

なんとなーくアプリを作っている身としては、こういう本が出てくるのはありがたい。

Android アプリ設計パターン入門

Android アプリ設計パターン入門

  • 著者:日高 正博,小西裕介,藤原聖,吉岡 毅,今井 智章,
  • 製本版,電子版
  • PEAKSで購入する

| | コメント (0) | トラックバック (0)

2017年12月 6日 (水)

Redmineを入れてみる on CloudGarage

CloudGarageというNHNテコラスさんが展開している定額制パブリッククラウドサービスがあって、こちらのご厚意で開発者ライセンスを発行してもらえるようになった。

で、Ubuntu Serverのインスタンス一つ立てて、前から欲しかった「自分専用BTS」をセットアップしてみることに。自分自身はRedmineが使い慣れているので、がんばってセットアップに挑戦してみた。

手順自体はRedmine.JPさんのブログの手順のとおりで、特にこれといって特別なことはしていないんだが、途中のPassengerのビルドがメモリ不足で止まる。

むぅ、1GBじゃきびしいか、と思っていたんだが、ある日ふと「スワップ拡大すれば何とかならないか?」と考えてスワップを切りなおすことに。

とりあえず現状。

# swapon -s
Filename                                Type            Size    Used    Priority

え? スワップきいてない?

では、ってことでスワップを追加してみることに。さすがにスライス切りなおすわけにもいかないので、Windowsみたいにファイルをスワップにしてみる。伝統的に物理メモリの2倍にしてみる。

# mkdir /swap
# fallocate -l 2G /swap/swapfile
# chmod 600 /swap/swapfile
# mkswap /swap/swapfile
# swapon /swap/swapfile

ここまで出来たら再度確認。

# swapon -s
Filename                                Type            Size    Used    Priority
/swap/swapfile                          file            2097148 360544  -1

うむ、有効になってる。これで作業再開してみると、こんどはちゃんとビルドが通る。これでめでたくRedmineが使えるように。

CloudGarageさんのインスタンスはディスクがSSDなので、スワップアウトしてもさほど気にならない。いいですな。

| | コメント (0) | トラックバック (0)

2017年9月17日 (日)

ログイン失敗時のメッセージを増やしたい on Spring Boot

0. ことのはじまり

先日、ログイン/ログアウト前後でクエリパラメータを保つ on Spring Bootと題して、ログイン/ログアウト時にクエリパラメータを保持する方法について書いたんだけど、こいつの参照実装を後輩君に教えてやったところ、「ログイン失敗時のメッセージが出なくなったんすけど?」とかいうリプライが。

どうやら、槙 俊明さんのはじめての Spring Boot[改訂版]をもとに(というかほぼそのまんまの模様)Spring Securityの設定をしていたようだが、「ログインに失敗したときに、画面上どうふるまうか」を理解せぬまま、僕が示した参照実装のコードを丸写ししていたようで、あんなリプライを出してきた模様。

このあたり、「自分で考えろ」と突き放してもよかったんだが、後学のために「どうすればいいか」を少々考えてみることにする。

1. 実際どうなっているのか

氏の書籍には、だいたいこんな感じでエラーメッセージ周りの処理が紹介されている。

Viewのhtml(抜粋)



<div th:if="${param.error}>ユーザー名、またはパスワードが違います。</div>

SecurityConfig(抜粋)



protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginProcessingUrl("/login")
.loginPage("/loginForm")
.failureUrl("/loginForm?error")
.defaultSuccessUrl("/", true)
.usernameParameter("username")
.passwordParameter("password")
.permitAll();
}

勘のいい方はお分かりと思うが、


  • 認証に成功したら、「/」にリダイレクト

  • 認証に失敗したら、「/loginForm?error」に移動

と、 URLだけで制御している ことがわかると思う。

それが証拠に、認証に失敗しなくても、「/loginForm?error」をブラウザのアドレスバーに直接入力すると、エラーメッセージが出るはずである。

これ自体は、話を簡単にするための処置なのだろう、と考えているのだが、今回の一件では、認証の成功、失敗で適切にクエリパラメータを加工して流す考慮が必要になるので、アプローチとしては以下の2つがあると考える。


  1. 認証ハンドラで、クエリパラメータを適切に追加、削除する

  2. 失敗時の認証ハンドラで、エラーメッセージをセッションに置く


2. URLだけで制御する場合

Viewの実装をそのままにしたい場合、いままでどおりURLでコントロールするよう、クエリパラメータを適切に追加、削除する処理を書けばよい、ということになる。

たとえば、こんな感じ。

認証成功時(抜粋)



// add whole query parameters to url
String queryParams = request.getQueryString() == null ? "" : "?" + request.getQueryString();

// remove error parameter if present.
if (queryParams.contains("error&")) {
queryParams.replaceAll("error&", "");
} else if (queryParams.contains("&error")) {
queryParams.replaceAll("&error", "");
}

認証失敗時(抜粋)



// add whole query parameters to url
String queryParams = request.getQueryString() == null ? "" : "?" + request.getQueryString();

// add error parameter if not present
if (!queryParams.contains("error")) {
if (queryParams.length() == 0) {
queryParams = queryParams + "?error";
} else {
queryParams = queryParams + "&error";
}
}

汚い実装で恐縮だが、雰囲気は伝わっただろうか。

3. セッションを使う場合

認証失敗時に呼ばれる AuthenticationFailurehandler#onAuthenticationFailure(HttpServletRequest, HttpServletResponse, AuthenticationException) では、認証失敗に至った理由が AuthenticationException のオブジェクトとして受け取ることができるようになっている。(参考

「パスワードが違う」「アカウントが有効期限切れ」「アカウント凍結中」など、詳細に調べることができるので、これを使って流すエラーメッセージを選別すればいい。

たとえば、こんな感じ。

認証失敗時(抜粋)



// Analyze the cause of the error
String errReason = null;
if (exception instanceof BadCredentialsException) {
errReason = "Invalid user name or password.";
} else if (exception instanceof AccountExpiredException) {
errReason = "This account is expired. Please contact administrator.";
} else if (exception instanceof CredentialsExpiredException) {
errReason = "Your password is expired. Please contact administrator.";
} else if (exception instanceof DisabledException) {
errReason = "Your password is disabled. Please contact administrator.";
} else if (exception instanceof LockedException) {
errReason = "Your accouunt is locked. Please contact administrator.";
} else {
errReason = "Unknown problem occured. Please contact administrator.";
}

if (errReason != null && errReason.length() > 0) {
HttpSession session = request.getSession();
session.setAttribute("errReason", errReason);
}

一方Thymeleafには、セッションオブジェクトを扱うための「session」というそのものずばりな予約変数がある。

利用方法は「Spring MVC and Thymeleaf: how to access data from templates - Thymeleaf」という公式ドキュメントに詳しく書かれているので、ひとまずそちらを参照していただくとして、セッションにエラーメッセージを置くなら、セッションから値を取り出して張る処理をViewテンプレートに書く。

たとえば、こんな感じ。

Viewのテンプレート(抜粋)



<div th:unless="${session == null}" th:text="${session.errReason}">Hoge</div>

この方法のメリットは、クエリパラメータをこねくり回す必要がなくなる点で、おそらくこういう方法のほうがフレームワークの設計思想に沿ったものなんじゃないだろうか、と個人的に考えている。

4. とりあえず動く参照実装

URLだけでコントロールしたい場合こちらを、セッションを使う場合こちらを、それぞれご参照ください。

| | コメント (0) | トラックバック (0)

2017年9月10日 (日)

ログイン/ログアウト前後でクエリパラメータを保つ on Spring Boot

0. ことのはじまり

僕は現在、都合により外に出されているんだけど、先日22:00くらいに自宅で自社のグループウェアを開いてみると、弊社内にいる後輩君から「助けてくださ~い(´;ω;`)」とかいうメールが。

いわく、「Spring Bootを使っているアプリがあり、認証にSpring Securityを使っているが、ログイン/ログアウトの際にクエリパラメータ(※ページのアドレスの後ろについている「?」以降のアレ)を保つ必要があり、どうやったらいいのか自分ではわからない」とのことらしい。

まぁ、自分で調べる際の検索キーワードの選定がまずいだけ、のような気もしないでもないのだが、とりあえず参照実装作成までを目標にして、どうやったらいいかを調べてみた。

ということなので、どういう想定でいくかの整理をしてみる。

  • Spring Bootの最新安定版(現時点では1.5.6.RELEASE)を使用
  • 依存ライブラリは、Thymeleaf、Spring Securityと、JS処理用にjQuery 2.1.4を追加
  • 認証には、データアクセスではなくインメモリ認証を使う
  • クエリパラメータはpだけを認識する

というわけなので、やってみる。

1. やること

いろいろググってみたところ、やらなければならないことは以下の3つだということが判明。

  1. 認証ハンドラを実装したクラスを用意し、その中でクエリパラメータを右から左にリレーする処理を書く。
  2. WebSecurityConfigurerAdapter の継承クラスで、1.で作成した認証ハンドラを使う設定を書く。
  3. Viewからのアクセスは、単純なsubmitやaタグのhrefで処理するのではなく、JSでaction属性やhref属性を直接操作する。

2. 実際には

2-1. カスタム認証ハンドラの実装

必要なカスタム認証ハンドラは、以下のとおり。

処理されるタイミング 実装するinterface
ログイン成功時 org.springframework.security.web.authentication.AuthenticationSuccessHandler
ログイン失敗時 org.springframework.security.web.authentication.AuthenticationFailureHandler
ログアウト時 org.springframework.security.web.authentication.logout.LogoutHandler

とりあえずログイン成功時だけ乗せるけど、HttpSevletRequestからクエリパラメータの文字列をとって、リダイレクトURLにぶら下げなおす、というのが基本。

public class AuthSuccess implements AuthenticationSuccessHandler {

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
      Authentication authentication) throws IOException, ServletException {
    
    // add whole query parameters to url 
    String queryParams = request.getQueryString() == null ? "" : "?" + request.getQueryString();

    RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    redirectStrategy.sendRedirect(request, response, "/menu" + queryParams );
  }

}

2-2. WebSecurityConfigurerAdapterに認証ハンドラをセット

Spring Securityを入れていると、その構成を行うJavaConfigがあるはずだが、そこをこんな感じに書き換える。

http.formLogin()
    .loginProcessingUrl("/login")
    .loginPage("/login")
    .successHandler(new AuthSuccess())  // ログイン成功時のカスタムハンドラ
    .failureHandler(new AuthFailure())  // ログイン失敗時のカスタムハンドラ
    .permitAll();

http.logout()
    .logoutRequestMatcher(new AntPathRequestMatcher("/logout**"))
    .addLogoutHandler(new LogoutPostProcess())  // ログアウト時のカスタムハンドラ
    .deleteCookies("JSESSIONID")
    .invalidateHttpSession(true);

それぞれカスタム認証ハンドラを設定するためのメソッドが用意されているので、そこにオブジェクトを放り込めばOK。

2-3. JSでURLをたたく

フロント系中心にやってる人にはどうということはないんだけど、通常 <input type="submit"> とか <a href="hogehoge"> とかで書いている処理を、JavaScriptでクエリパラメータを取得してURLをたたくようにすればOK。

/**
 * URLについているクエリパラメータを取得して、Formのaction属性を書き換えてsubmitする処理。
 */
function sendReq() {
  var arg = getQueryParam();
  
  var url = $('#loginForm').attr('action');
  if (arg.p != null) {
    url += '?p=' + arg.p;
  }

  $('#loginForm').attr('action', url);
  $('#loginForm').submit();
}

/**
 * URLについているクエリパラメータを取得する処理。
 */
function getQueryParam() {
  var arg = new Object;
  var pair = location.search.substring(1).split('&');
  for (var i = 0; pair[i]; i++) {
    var kv = pair[i].split('=');
    arg[kv[0]] = kv[1];
  }
  
  return arg;
}

/**
 * URLについているクエリパラメータを取得して特定ページへ遷移する処理。
 */
function doLogout() {
  var proto = location.protocol;
  var host = location.host;

  var url = proto + '//' + host + '/logout';
  
  var arg = getQueryParam();
  if (arg.p != null) {
    url += '?p=' + arg.p;
  }
  
  location.href = url;
}

3. とりあえず動かせる参照実装

GitHubに上げました。ご参照あれ。
f97one/AddingQueryParamsDemo

| | コメント (0) | トラックバック (0)

2016年8月28日 (日)

液晶割れ

久しぶりの更新。

開発機を兼ねている僕のケータイ(auSHL25/SHARP)は、ときどき子供のおもちゃになるときがあるんだけど、今日はいつもよりぞんざいに扱われたらしく、初の液晶割れを経験した。

保険に入っていたこともあり、とりあえず近所のauショップに行って代替機の借用と交換機種の取り寄せ手続きをしてきたんだけど、自力でデータ移行をやるのは久しぶり、しかも片方は液晶割れでまったく操作できないというおまけ付き。

「そういえば以前、姉が液晶割れを経験して、USBホストケーブルでマウスをつないで急場をしのいだとか言ってたっけ」ということで、その時の状況を聞いてみると「USBホストケーブル+マウスで1500円くらいだった。そんなに高いものじゃない」とのこと。

さっき調べたら、USBホストケーブル自体は100均でも売っているらしいので、ダメ元で買ってみるか....。

| | コメント (0) | トラックバック (0)

2014年4月12日 (土)

AndroidAnnotationsを使ってみる 〜Android Studio編〜

0. イントロダクション

 以前、こんなエントリを書いていたけど、今度はAndroid Studioで同じことをしてみよう、というお話。
# ネタの更新に1年もかけているのはどうなんだ、という話は置いといて(汗)

1. Android Studioのプロジェクトに導入してみる

 Android Studioの場合、導入のキモはbuild.gradleに書くことがわかっていること、これに尽きる。

 一応、ライブラリ検索はMaven Central Repository Search EngineGradle, pleaseを使えばdependencyに書く内容はわかるんだけど、AndroidAnnotationsはその名のとおりアノテーションプロセッサ。
 なので、Gradle Android Pluginsにアノテーションプロセッサを理解させる必要がある。

 幸い前回のネタから1年経過している現在では、そのあたりの事情もよくなって来ていて、公式にもGradleプロジェクト向けの設定方法も書かれている。今回はこいつを元に、Android Studioで作ったプロジェクトに適用してみた。

  1. プロジェクトを作ったら、プロジェクトのルートにあるbuild.gradleをひらき、depondenciesにAndroid-APTを追加する。
  2. dependencies {
          classpath 'com.android.tools.build:gradle:0.9.+'
        // AndroidAnnotationsの使用宣言
        //   Android-APTプラグイン(依存)
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.2'
    }
  3. 次に、実際のJavaソースがあるモジュールディレクトリへ降り、そこのbuild.gradleにプラグイン適用とAndroidAnnotationsの依存設定を書く。
  4. apply plugin: 'android-apt'
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        apt 'org.androidannotations:androidannotations:3.0.1'
        compile 'org.androidannotations:androidannotations:3.0.1'
    }
    
    apt {
        arguments {
            androidManifestFile variant.processResources.manifestFile
            resourcePackageName 'net.formula97.aaex.app'
        }
    }
  5. build.gradleを2つ編集し終えたら、プロジェクトのルートで ./gradlew build を実行してやると、依存設定に追加したプラグインたちがMaven Central Repositoryから落ちてきてビルドが通る(はず)。

 あとはアノテーションを使ってActivityを拡張し、AndroidManifest.xmlの設定をいじるだけで使えるようになっているはず。

 ちなみに、僕のGitHubにこの手順で作ったプロジェクトを上げておいたので、よろしかったらご参考にしてください。

 あ、いい忘れてたけど、signingConfigsブロックにある大文字の部分は環境変数で、こいつはそれぞれこんな意味を持っている。

DEBUG_KEYSTORE : デバッグ証明書ストアのパス
RELEASE_KEYSTORE : リリース証明書ストアのパス
RELEASE_KEYSTORE_PASSWORD : リリース証明書ストアのパスワード
RELEASE_KEY_ALIAS : リリース証明書のキーエイリアス
RELEASE_KEY_PASSWORD : リリース証明書のパスワード

 こいつらの設定をしていないと、ビルドが通らないのでご注意を。

| | コメント (0) | トラックバック (0)

2014年1月12日 (日)

Android Support Librariesを使う

0. イントロダクション

 Androidで新規プロジェクトを作ると、libs/以下にandroid-support-v4というライブラリが追加されるようになっているのは、ずいぶん前からの話。
 で、実はこれ、ちょっと前まで「Fragmentを2.xデバイスでも使えるようにするためのもの」くらいの認識でしかなかったことと、僕自身Fragmentの仕組みをよく理解できていないこともあって、まったく使ったことがなかった。

 ということなので、自分向けメモとしてちょっと書いてみる。

1. システム要件

 条件としては、 Android SDKを最新に更新しており、Extrasの下にある「Android Support Libraries」をインストールしていることである。

2. セットアップ

 実際のセットアップは、以下のとおりとした。
 元ネタはSupport Libraries Setup | Android Developersなのだが、ActionBarで標準添付リソースが使いたかったので、リソース付きでセットアップする手順としている。

  1. メニューのFile -> Importで、Existing Android Code into Workspaceを選ぶ。
  2. {SDKのディレクトリ}//extras/android/support/v7/appcompat/をインポートする。
  3. Finishを押してインポートを完了する。名称はわかれば何でもよいが、僕はデフォのandroid-support-v7-appcompatとしている。
  4. インポートしたライブラリプロジェクトのlibs/を開くと、android-support-v4.jarとandroid-support-v7-appcompat.jarの二つがあるはずなので、この両方を右クリックからBuild Path -> Add to Build Pathを選んでJava Build Pathに追加する。
    この操作で、ライブラリプロジェクトのReferenced LibrariesにJarファイルが二つ追加されているはずである。
  5. ライブラリプロジェクトを右クリックし、Build Path -> Configure Build Pathを開くと、プロジェクトのJava Build Path設定のOrder and Exportタブが開いているはずなので、設定を以下のとおりとする。
    • android-support-v4.jarとandroid-support-v7-appcompat.jarの両方に、チェックを入れる。
    • Android Dependenciesのチェックを外す
  6. この状態で[OK]を押すと、ライブラリプロジェクトがビルドされ、使用可能になる。

 あとは、こいつを使いたいAndroidプロジェクトのプロパティを開き、Android -> Libraryに先ほど追加したライブラリプロジェクトをAddで追加してやればよい。

3. 注意点

 作業中に、Androidプロジェクトに最初から存在するandroid-support-v4.jarと、v7-appcompatに含まれるandroid-support-v4.jarが一致しない、という事象が起きた。

 比較したところ、Androidプロジェクトのほうがファイルサイズが小さかったため、おそらく元のAndroidプロジェクトを作成した時期のリビジョンと、SDKの現在のリビジョンが異なる(プロジェクトのほうが古い)ためと思われる。

 とりあえず、Androidプロジェクトのほうのandroid-support-v4.jarをBuild Pathから除去した後、libs/にあるandroid-support-v4.jarを物理的に削除することで、これを回避した。

 なおこのライブラリプロジェクトは、API Level 7(=Android 2.1)以上のアプリケーションプロジェクトが対象なので、もしAndroidManifest.xmlのminSdkVersionが6以下の場合は、7に変更しておくこと。
 大勢にはほとんど影響はないだろうけど。
# いまどき、API Level 4(=Android 1.6)を新規にサポートする意味はないだろうし、API Level 8(=Android 2.2)以下のデバイスはほとんど駆逐されているだろうし....。

| | コメント (0) | トラックバック (0)

«書籍購入:Jenkins実践入門 ~ビルド・テスト・デプロイを自動化する技術