メンチカツには醤油でしょ!!

AWS/Java/Node.js/Spreadsheets/Docker/Jenkins/コミュニティ・勉強会レポを主とした技術系ブログ

npmのメールアドレスが公開な件について #NodeJS

npmとは

Node.jsのパッケージ管理システムであり、Node Package Managerの略です。
また、それらモジュール郡をホスティングしているサイトもnpmです(npmjs.com)
Mavenで言えばセントラルリポジトリ的な役割でしょう。

作成したモジュールをnpmで公開するにはnpmjs.comにサインアップする必要があります。

www.npmjs.com

npmjs.comへのアカウント登録

こちらがサインアップ画面です。

f:id:ryoichi0102:20171005213450p:plain

Public Emailという入力欄があり、登録ボタンの直前には
"Your email address will show on your profile page, but npm will never share or sell it."
とあります。
表示はするけど、引き渡したり売ったりはしないよ、ということですね。

登録後のプロフィール画面でも表示されています。

f:id:ryoichi0102:20171004092302p:plain

いやいやいやいや、これスクレイピングしたら簡単に収集できるじゃないっすか!
全世界にメールアドレスを公開するのはイヤですね。

なぜこうなっているのか調べた感じは以下の通り

・メールアドレスが公開になっているのはユーザー間でモメた時などの連絡に使用するためpublicになっている。
・だが、npmjsにフォーラム機能やサイトを通じて本人にメールが送信されるような仕組みを用意すれば良いだろうと、メールアドレス公開に反発してる人が多いのも事実。(私もそう思う)
・または、画面上にjsでレンダリングしてクローラーの収集を回避するなど。
・そしてGitHubでは、メールアドレスをprivateにしたり、コミット時に使用するメールアドレスはダミーのメールアドレス(noreply)が用意されており それを設定することも推奨されていることにまで言及され、とにかくPublic反対派が大多数。
・結局みんな、npm専用のメールアカウントを作ることになり、そのメールボックスspamでいっぱいに…初期のphp forumの頃のように。

まとめ

解決されなさそうなので、npm用のメールアカウントを作成しましょう。。

参考

github.com

github.com

Adminerが手軽で便利。MySQLなどデータベースに繋ぐ

Adminerとは

Webブラウザから使用するPHP製データベースクライアントです。
サブタイトルにDatabase management in a single PHP fileと記載のある通りphpファイルを置くだけです。
phpMyAdminに似ていますが、MySQL以外にも対応しています。

発音はアドマイナーです。

公式サイト https://www.adminer.org/
GitHub vrana/adminer: Database management in a single PHP file

phpMyAdminよりイイ

インストールは公式サイトからダウンロードして、FTPPHPファイル置くだけですから手軽です。使いにくいレンタルサーバーの管理画面からphpMyAdminを入れてetc...とやらなくて良いのです。
たとえばCakeであればFTP./app/webroot/配下にダウンロードしたadminer-4.3.1-mysql.phpを置くだけで使えます。

何が良いかって、緊急時にサクッと繋げられるのが良いですね。

f:id:ryoichi0102:20170926174522p:plain

上記キャプチャがログイン画面です。
一通りの情報を入力するところがありますね。
ポートの指定は サーバー名:ポート番号 です。(例 127.0.0.1:3306)
3306の場合は省略可能です。

ログイン後はphpMyAdminと同じように、SQLの発行やデータのインポート/エクスポートなど色々出来ます。

※ 緊急時の利用であれば、作業が終わった後にアップしたphpファイルを消しておくことをオススメします。

余談: ファーストサーバーがZenlogicに移行した影響で…

通知から1ヶ月ぐらいでサクッと移行されてしまった気がするのですが、移行前のMySQL環境がポート番号を変更され、localhostからの接続ができないというナカナカの対応をしてくれたようです。

Request URL: /
Stack Trace:
#0 /app/webroot/index.php(108): Dispatcher->dispatch(Object(CakeRequest), Object(CakeResponse))
#1 {main} yyyy-mm-dd hh:mm:ss Error: [MissingConnectionException] Database connection "Mysql" is missing, or could not be created. Exception Attributes: array (
'class' => 'Mysql',
'message' => 'SQLSTATE[28000] [1045] Access denied for user \'mysqluser\'@\'localhost\' (using password: YES)',
'enabled' => true, )

こんなん出るしね。
復旧にはDB接続設定を、localhostからループバックアドレス127.0.0.1に変更して、ポートの指定を変更しないといけないという対応。
特に下線の対応がなかなかのノーヒントというか、宝探し的というか、情報が纏まっていないというか…

DBのダンプを取って移行しようにも、外部からの接続が不可だし(これは仕方ないとして)、phpMyAdminが不可になってて、管理画面からのバックアップ機能も停止。
陸の孤島的な。。

そんな時はAdminerですよ!

参考

Adminer / Bugs and Features / #287 Connect to another port

ThymeleafのJava 8 LocalDateTime対応で選択変数式th:objectとth:textの実装方法

Java8のLocalDateTimeをThymeleafで使うには

build.gradleにthymeleaf-extras-java8timeを足して
@Configurationの付いたクラス(ThymeleafConfigとか)にjava8TimeDialect()を実装して
htmlのth:textでは"${#temporals.format(myDatetime}, 'yyyy/MM/dd HH:mm')}"と書く方法が定番かと思われます。

(LocalDateTimeでもLocalDateでもLocalTimeでも同じですね。)

選択式変数と組み合わせて使う場合にはちょっと工夫が必要でした。
選択式変数とはforeachのようなシチュエーションで使う構文で、下記のようにth:objectで指定するとループ内ではアスタリスクで指定できるという利点があります。

<table><tr th:each="record : ${records}" th:object="${record}">
  <td th:text="*{value}">
</tr></table>

環境

* Spring Boot 1.5.6
* Thymeleaf 2.1.5
* Thymeleaf Module for Java 8 Time API compatibility 2.1.0.RELEASE

実装

build.gradle (抜粋)
dependencies {
  compile('org.springframework.boot:spring-boot-starter-web')
  compile('org.springframework.boot:spring-boot-starter-thymeleaf')
  compile('org.thymeleaf.extras:thymeleaf-extras-java8time:2.1.0.RELEASE')
  // 略
}
ShowListController.java (抜粋)
  @RequestMapping(method = RequestMethod.GET)
  public String index(Model model) {

    List<MyBean> myList = query(); // 何かしらの検索処理.

    model.addAttribute("myList", myList);

    return "showList";
  }
MyBean.java (抜粋)
@Data
public class MyBean implements Serializable {
  private int myNumber;
  private int myString;
  private LocalDateTime myDatetime;
}
showList.html (抜粋)
<tr th:each="myBean : ${myList}" th:object="${myBean}">
  <td th:text="*{myNumber}"></td>
  <td th:text="*{myString}"></td>
  <!-- こう書くとダメ -->
  <td th:text="${#temporals.format(*{myDatetime}, 'yyyy/MM/dd HH:mm')}"></td>
  <!-- これはまぁOK -->
  <td th:text="${#temporals.format(myList.myDatetime, 'yyyy/MM/dd HH:mm')}"></td>
  <!-- こう書くと良い -->
  <td th:text="*{#temporals.format(myDateTime, 'yyyy/MM/dd HH:mm')}"></td>
</tr>

ダメな方の実装だと
There was an unexpected error (type=Internal Server Error, status=500).
Exception evaluating SpringEL expression: "#temporals.format(*{myDatetime}, 'yyyy/MM/dd HH:mm')" (showList:46)
ってエラーが出てStacktraceは
org.springframework.expression.spel.SpelParseException: Expression [#temporals.format(*{myDatetime}, 'yyyy/MM/dd HH:mm')] @46: EL1070E: Problem parsing left operand
って感じです。

チュートリアルをちょっと変更する感じだと、こう書きがちなんですが、
これは慣れの問題ですかね。

ちなみに
"#{temporals.format(myDatetime, 'yyyy/MM/dd HH:mm')}"
と書いても表示は
??temporals.format_ja??
とか表示されてダメです。(まぁこれは当然ですね)

間違えて
"${#temporals.format(myDatetime, 'yyyy/MM/dd HH:mm')"
と書くと
java.lang.IllegalArgumentException: Cannot apply format on null
になったり、こねくり回してると
org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method format(null,java.lang.String) on null context object
が出たりしますが、
*{#temporals.format(myDateTime, 'yyyy/MM/dd HH:mm')}"
が正解です。

参考

masatoshitada.hatenadiary.jp

qiita.com