【Java】Java8で文字列をBase64変換する
java.util.Base64
Base64.Encoder (Java Platform SE 8)
Java8より、Base64によってバイトデータをエンコードできるBase64
クラスが実装されました。
このUtilityクラスを利用することで、Java上で容易にBase64エンコード/デコードが利用できます。
Usage
import java.util.Base64; public class Main { public static void main(String... args) { String message = "Hello, Base64!"; // Base64文字列へエンコード String base64 = Base64.getEncoder().encodeToString(message.getBytes()); // Base64文字列をデコード String decodedMessage = new String(Base64.getDecoder().decode(base64)); } }
参考文献
【Java】Jacksonを使ってJSON文字列←→オブジェクト変換を行う
Jacksonとは
JacksonはJavaで使えるJSONライブラリです。
JSON形式の文字列をJavaのオブジェクトに直接マッピングしたり、逆にJavaオブジェクトをJSON文字列に変換できたりします。
HTTPレスポンスをパースしたりオブジェクトをBase64エンコーディングする時などに便利です。
Usage
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class Main { public static class Obj { private String name; private int value; public Obj(){ } public Obj(String name, int value){ this.name = name; this.value = value; } } public static void main(String... args){ Obj obj = new Obj("apple", 100); String json = getJSONFromObj(obj); Obj newObj = getObjFromJSON(json); } // JavaオブジェクトをJSONに変換 private String getJSONFromObj(Obj obj) { String json = null; ObjectMapper mapper = new ObjectMapper(); try { json = mapper.writeValueAsString(obj); } catch (JsonProcessingException e) { e.printStackTrace(); } return json; } // JSONをJavaオブジェクトに変換 private Obj getObjFromJSON(String json) { ObjectMapper mapper = new ObjectMapper(); Obj obj = null; try { obj = mapper.readValue(json, Obj.class); } catch (Exception e) { e.printStackTrace(); } return obj; } }
パース時の注意
JacksonのObjectMapper
でデシリアライズする際のクラスは、
- 引数なしコンストラクタが定義されていなければならない
- インナークラスはstaticでなければならない(アウタークラスがインスタンス化されないとクラス定義がオンメモリにならないため)
- JSONプロパティはすべて変換後のクラスメンバに存在しなければならない
という制約をクリアしている必要があります。
これらの制約に反していた場合には例外がスローされます。
具体的な注意点は、こちらの方の記事でとてもわかり易くまとめてあったので引用させていただきます。
【OAuth】Google/Facebook/TwitterのOAuth認証APIに設定するリダイレクトURLにパラメータを含める
Google/Facebook/Twitter のOAuth API
Using OAuth 2.0 to Access Google APIs | Google Identity Platform | Google Developers
ウェブ - Facebookログイン - ドキュメンテーション - 開発者向けFacebook
Oauth with the Twitter API — Twitter Developers
SNS認証におけるリダイレクト
GoogleやFacebook、TwitterのOAuth認証用APIを利用して各SNSで認可を行う際、自身が管理するアプリのサーバにリダイレクトさせて認証状況を確認したい場合があります。
このとき、各SNSのOAuth認証用APIを叩く前にリダイレクトしてもらうURLを設定します。
# リダイレクトURL # APIサーバが提供するパスなど https://hoge.net/oauth/callout/google
もし、リダイレクト前の状態をリダイレクト先に渡したい場合、
リクエストパラメータをクエリストリングに追加したい・・・等考えると思いますが、一部のSNSはリダイレクトURLにパラメータを直接指定すると404を返してきます。
# NG(404が返る) https://hoge.net/oauth/callout/google?param=hoge
どうやら、リダイレクト先にパラメータを渡すためにはちょっとした工夫が必要なようです。
リダイレクト先にパラメータを渡す方法:Google
GoogleのOAuthAPIのリダイレクトURLには、直接パラメータを指定することができません。
かわりに、認証サーバへのリクエストURLであるAuthorizationURLにパラメータstate
を介してパラメータを渡すことができます。
Javaで実装する場合こんな感じ。
ServiceBuilder builder = new ServiceBuilder() .apiKey(apiKey) .apiSecret(apiSecret) .scope(scope) .state(state) // リダイレクトURLに含めたいパラメータを指定可能(文字列) .callback(callback) // リダイレクトURL .build(GoogleApi20.instance());
上記コードではScriveJavaというJavaのOAuthクライアントライブラリを使用しています。
OAuthに対する認証リクエストを投げるのに便利です。
リダイレクト先にパラメータを渡す方法:Facebook
Facebookも同様に、AuthorizationURLのパラメータstate
を指定することでリダイレクトURLパラメータを挿入します。
ServiceBuilder builder = new ServiceBuilder() .apiKey(apiKey) .apiSecret(apiSecret) .scope(scope) .state(state) // リダイレクトURLに含めたいパラメータを指定可能(文字列) .callback(callback) // リダイレクトURL .build(FacebookApi.instance());
Googleと大差ありませんね。
リダイレクト先にパラメータを渡す方法:Twitter
一方で、TwitterはリダイレクトURLへのパラメータ指定を許しているみたいです。
# NG(404が返る) String callback = "https://hoge.net/oauth/callout/google?param=hoge"; ServiceBuilder builder = new ServiceBuilder() .apiKey(apiKey) .apiSecret(apiSecret) .scope(scope) .callback(callback) // リダイレクトURL .build(TwitterApi.Authenticate.instance());
逆に、state
にパラメータを設定してもリダイレクトURLにパラメータが挿入されません。
GoogleやFacebookと異なるので注意したいところです。
参考
【AngularJS】未コンパイル状態のHTMLテンプレートが一瞬表示されるのを防ぐ
テンプレートのちらつき
AngularJSのHTMLテンプレートを用いたページを表示したときに、一瞬だけ元のテンプレート表記がちらついてしまう場合があります。
例えば、以下のようなコードでHTML上の{{message}}
に動的に文字列を挿入しようとしたとき、下の画像のように一瞬だけ元の文字列{{message}}
の状態で表示されてしまうことがあります。
<div ng-app="myApp"> <div ng-controller="MyAppCtrl"> {{message}} </div> </div>
let mod = angular.module('myApp',[]); mod.controller('MyAppCtrl', ['$scope', '$timeout', function($scope, $timeout){ $scope.message = "Hello!"; }]);
結果
ng-cloak
このチラツキを防ぐために、ng-cloak
ディレクティブを使用します。
このディレクティブを指定したタグは、テンプレートにデータが挿入されるまで非表示状態になります。テンプレートにデータが挿入されたときタグは表示状態となり、未コンパイル状態のテンプレートが露出されずに済みます。
<div ng-app="myApp"> <div ng-controller="MyAppCtrl" ng-cloak> {{message}} </div> </div>
結果
内部では、画面読み込み時にng-cloak
を指定したタグに対して下記のCSSルールが適用されています。そしてng-cloak
ディレクティブを指定したタグの内側に含むテンプレートがコンパイルされるとき、AngularJSはng-cloak
属性を破棄します。
[ng:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; }
この一連の操作によって、「テンプレートにデータが挿入されるまでタグを表示しない」処理を実現しています。
なおng-cloak
は指定したタグの子要素もすべて非表示にしてしまいます。そのため<body ng-cloak>
とするなど、指定の仕方によってはページの表示が遅延しているように見えてしまうため、ユーザ体験を悪化させる要因になりかねません。
ちらつく可能性のあるテンプレートが特定の領域に限られている場合には、その領域のタグに限定してng-cloak
を付加するのが望ましいです。
参考文献
【AngularJS】$httpによる通信を任意のタイミングで中断する
$httpのタイムアウト
AngularJSではHTTPリクエストを投げるためのサービス$http
が提供されていますが、
引数config
のプロパティtimeout
を設定することで、HTTPリクエストをタイムアウトさせることができます。
timeout – {number|Promise} – timeout in milliseconds, or promise that should abort the request when resolved.
timeout
には整数型とPromise型オブジェクトを設定することができます。
整数型を設定した場合には指定整数ミリ秒後にリクエストをタイムアウトします。
Promise型を設定した場合には、Promise生成元のDefered
オブジェクトに対してDefered.resolve()
がコールされたタイミングでリクエストがタイムアウトされます。
Usage
let mod = angular.module('myApp', []); mod.controller('MyAppCtrl', ['$scope', '$http', '$q', '$timeout', function($scope, $http, $q, $timeout){ $scope.onButtonClick = function onButtonClick() { let defered = $q.defer(); let success = function(response) { $scope.message = "success!"; $scope.response = response; }; let error = function(error) { $timeout(function(){ $scope.message = "error."; $scope.response = error; }); }; // 1) ミリ秒指定 $http({ method: "GET", url : "/hoge/fuga/api", timeout: 3000 }) .then(success) .catch(error); // 2) Promiseオブジェクトを指定 $http({ method: "GET", url : "/hoge/fuga/api", timeout: defered.promise }) .then(success) .catch(error); // Promiseオブジェクトをtimeoutに指定した場合、Defered.resolve()を呼ぶとタイムアウトする // 1) と同じ挙動 $timeout(function(){ defered.resolve(); }, 3000); }; }]);
【AngularJS】プルダウンの一部を動的に選択不可能にする
メモ。
AngularJSではselect
タグにng-options
を指定するとIterableオブジェクトの要素からなるプルダウンを作成できますが、その一部をdisable状態にすることができます。
HTML
<div ng-app="myApp"> <div ng-controller="NgOptionDisableCtrl"> <select ng-model="num" ng-options='number disable when number === 3 for number in numbers'></select> </div> </div>
JS
let mod = angular.module('myApp',[]); mod.controller('NgOptionDisableCtrl', ['$scope', function($scope){ $scope.num = 1; $scope.numbers = [1,2,3,4,5]; }]);
ng-options
に[変数] disable when [条件式] for ...
と指定することで、条件をみたす場合にdisable状態になります。
上記コードでは、プルダウンの3
を選択できないようになっています。
<select ng-model="num" ng-options='number disable when number === 3 for number in numbers'></select>
【JavaScript】反復可能なオブジェクトをArrayとして扱う
Array.from
Array.from
メソッドは、配列型オブジェクトや反復可能なオブジェクトをArray型にキャストするために用います。
// 配列 let ary = Array.from([1,2,3]); console.log(ary);// [1, 2, 3] // Set let set = Array.from(new Set(["a",2,{}])); console.log(set);// ["a", 2, Object {}] // Map let map_ = Array.from(new Map([[1,2], ["a", 3]])); console.log(map_);// [[1, 2], ["a", 3]] // String let str = Array.from("Array"); console.log(str);// ["A", "r", "r", "a", "y]
ちなみに反復可能なオブジェクトなら変換可能なので、前回記事で扱った<input type='file'>
でイベントリスナーを登録したときに取得できるFileListオブジェクトもArray.from
で配列に変換できます。
HTML
<input id="input_file" type="file" multiple/>
JS
function onChange(event) { // 複数選択したファイルをFileList型オブジェクトとして取得->Arrayに変換 let files = Array.from(event.target.files); // ... } document.getElementById("input_file").addEventListener('change', onChange, false);