今日の役に立たない一言 - Today’s Trifle! -

古い記事ではさまざまなテーマを書いていますが、2007年以降はプログラミング関連の話がほとんどです。

Googleからアカウント確認メールを出す方法

GAEで「承認済みのメール送信者」に設定できるのは、かなり制限されている。

  • 現在ログインしているユーザーの Gmail または Google Apps アカウント
  • anything@[APP_NAME].appspotmail.com または anything@[APP_ALIAS].appspotmail.com の形式のメールアドレス
  • Cloud Platform Console の Email API の承認済み送信者に一覧表示されているメールアドレス

Email API の承認済み送信者リストに含まれているすべてのメールアドレスは、Gmail または Google がホストしているドメインの有効なアカウントである必要があります。アプリ管理者は承認済み送信者のリストに次のアカウントを追加できます。

  • アプリ管理者自身のメールアドレス
  • アプリ管理者がオーナーまたはマネージャーであるグループ
  • noreply@[DOMAIN].com が有効なアカウント(ユーザーまたはグループ)である限り、Google Apps ドメイン noreply@[DOMAIN].com でホストされているアプリケーション。

Mail API の概要  |  Java の App Engine スタンダード環境  |  Google Cloud

GmailまたはGoogle Appsアカウント以外のメールアドレスから出したい場合は、「アプリ管理者自身のメールアドレス」にすればできるのかも、と思ってアドレスを変更してみた。

Googleのサイトで右上のアイコンをクリックして、「プロフィールを表示」の上にある「アカウント」をクリック。
アカウント情報の画面が開くので、「個人情報」→「メール」をクリック。さらに「再設定用のメールアドレス」をクリック。
右側の鉛筆のアイコンをクリックしてメールアドレスを変更してみた。

でも、やっぱり「承認済みのメール送信者」に追加しようとしても「次のメールは存在しません」とエラーになる。

メールアドレスを書き換えたけど確認できてないから?

再設定用のメールアドレスの下にある連絡先メールアドレスから、確認メールを送信できた。

が、これでも「承認済みのメール送信者」に設定できない。

うーむ、Google Appsに登録するしかないのかな?

enctype="multipart/form-data"にするとreqeust.getParameter()がnullを返す問題の対策

というか、slim3だとgetParameter()は取れるけど、getParameterValues()がnullになって困った。

JSPはこんなん。

<form id="form" action="/hoge" enctype="multipart/form-data" method="post" >
  <input type="text" name="name" />
  <input type="file" name="image" accept="image/*" />
  <c:forEach var="o" items="${checks}">
    <span><input id="checks_${o.id}" type="checkbox" name="checks" value="${o.id}" ${o.checked} >
    <label>${o.name}</label></span>
  </c:forEach>
  <input type="submit" value="send" />
</form>

ぐぐるとcommons-fileupload 使えばできるとかあったけど、slim3だと相性のせいなのかできなかった。

ajaxで2回に分けてpostするようにした。
JSPのフォームからenctypeを削除しとく。
Servlet側で区別できるようにhiddenを追加しとく。

<form id="form" action="/hoge" method="post" >
  <input type="text" name="name" />
  <input type="file" name="image" accept="image/*" />
  <c:forEach var="o" items="${checks}">
    <span><input id="checks_${o.id}" type="checkbox" name="checks" value="${o.id}" ${o.checked} >
    <label>${o.name}</label></span>
  </c:forEach>
  <input type="hidden" name="upload" value="no" />
  <input type="button" value="send" onclick="send()" />
</form>

JavaScriptがこんなん。
1回目のpostではfileをdisabledにして無視させる。
2回めのpost前にenctypeを追加する。
しなくてもよさそうだけど、file以外のinputをdisabledにしとく。
hiddenの値も、念のために空文字列にしとく。

function send() {
    $('input[type=file]').prop('disabled', true);
    $.ajax({
        type: 'post',
        data: $('#form').serialize(),
        success: function (data) {
            upload();
        }
    });
}

function upload() {
    $('input').prop('disabled', true);
    $('input[type=file]').prop('disabled', false);
    $('input[type=hidden]').val('');
    $('#form').prop('enctype', 'multipart/form-data');
    $('#form').submit();
}

Servlet側は getParameter("upload") の有無で処理を切り分ける。

    String s = request.getParameter("upload");
    if (s == null || s.isEmpty()) {
        // ファイルを受信
    } else
    if (s.equals("no")) {
        // 入力フォームの値を取得
    }

Amazon の Cloud9 にGAE開発環境を作る手順

AWSアカウントでログインして「Cloud9」で検索すると出てくるので、そこクリック。
Cloud9のダッシュボードが開くので、オレンジ色の「Create environment」をクリック。
適当に名前をつけて、「Next step」→「Next step」→「Create environment」で環境が作られる。
できた環境の「Open IDE」をクリックするとブラウザ上にIDEが表示される。
shellのところで以下のコマンドを入力。

$ wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-180.0.0-linux-x86_64.tar.gz
$ tar zxvf google-cloud-sdk-180.0.0-linux-x86_64.tar.gz
$ ./google-cloud-sdk/install.sh
$ ./google-cloud-sdk/bin/gcloud init
$ ./google-cloud-sdk/bin/gcloud components update
$ ./google-cloud-sdk/bin/gcloud components install app-engine-java
$ wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u162-b12/0da788060d494f5095bf8624735fa2f1/jdk-8u162-linux-x64.tar.gz
$ tar zxvf jdk-8u162-linux-x64.tar.gz 
$ wget http://www-eu.apache.org/dist/maven/maven-3/3.5.2/binaries/apache-maven-3.5.2-bin.tar.gz
$ tar zxvf apache-maven-3.5.2-bin.tar.gz 
$ wget https://storage.googleapis.com/appengine-sdks/featured/appengine-java-sdk-1.9.54.zip
$ unzip appengine-java-sdk-1.9.54.zip 
$ export JAVA_HOME=/home/ec2-user/jdk1.8.0_162/
$ export PATH=/home/ec2-user/appengine-java-sdk-1.9.54/bin:/home/ec2-user/jdk1.8.0_162/bin:/home/ec2-user/apache-maven-3.5.2/bin:/home/ec2-user/google-cloud-sdk/bin:$PATH

GAEアプリを git clone するなりしてビルドして、

$ dev_appserver.sh <war-directory>

すると、Cloud9上で開発サーバーが起動する。
Cloud9 メニューバーの「Preview」にある「Preview Running Application」で開発サーバーにアクセスできる。

GCSにファイルをアップロードできなくて試行錯誤した話

GAEでファイルをアップロードすると60秒問題があるので、GCSにダイレクトにアップロードする方法を実装しようとして、なかなかできなくてかなり試行錯誤した。

最初、ここに書いてあるやり方で実装してみた。

GAE/jでファイルを扱う Part2 - Qiita

そうすると、GCSにPOSTした時点で、サーバー側でOutOfMemoryErrorが発生してしまう。

こういうときは初心に帰るのが早い。

シンプルなHTMLにformを書いてGCSのURLを指定してsubmitしたら、難なくアップロードできた。

<form id="uploadFiles" action="${url}" method="post" enctype="multipart/form-data">
 <input type="file" name="image"  >
 <input type="submit" value="upload" />
</form>


このformにajaxを叩くボタンを追加して、ajaxで再挑戦。

<script>
function uploadFiles() {
	var formData = new FormData($('#uploadFiles'));
	$.ajax({
		type: $('#uploadFiles').attr('method'),
		url: $('#uploadFiles').attr('action'),
		processData: false,
		contentType: false,
		data: formData
	}).then(
		function(data) {
			console.log(data);
		},
		function(data) {
			console.log("error");
		}
	);
}
</script>

<form id="uploadFiles" action="${url}" method="post" enctype="multipart/form-data">
 <input type="file" name="image"  >
 <input type="submit" value="upload" />
 <input type="button" value="ajaxupload" onclick="uploadFiles();"/>
</form>

なぜかajaxだとOutOfMemoryErrorが発生。submitだとうまくいくのに。

で、実際に動かすサイトのコードをこれに合わせてみた。
すると、なぜかアップロードしてくれない。

コードの差分を調べてみたら、複数ファイルのプレビューを表示するために、data-index属性を追加してあったのがまずいらしい。

<input type="file" name="image0" data-index="0" accept="image/*" />

data-index属性を消したらアップロードが動くようになった。

ウェブサイトURLの正規表現

ぐぐってみると、英数字オンリーばかりなんだけど、最近は日本語ドメインもあるし、パスの中に日本語を含んだりする場合もあるので、日本語も許可したほうがいいと思う。というわけで、"\S"を追加。

    String regex = "^https?(://[-_.!~*\\'()a-zA-Z0-9\\S;\\/?:\\@&=+\\$,%#]+)$";