Spring Boot でCORSを制御

Spring Boot でAPIなどを作っていて、他サイトからアクセスさせると、
Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
が発生する。

これを回避させるためにCORSを制御する。

@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
public class XxxxxxController {

@CrossOrigin アノテーションで許可したいorigin、メソッドなどを設定する。

Vue.js(TypeScript)でvalidation

Vue.js(TypeScript) のプロジェクトで validation を行いたい。
表示はcss フレームワーク Bulma を拡張したUIコンポーネントの Buefy を使う。
validation には VeeValidation を使う。

パッケージのインストール

$ npm install -D buefy node-sass sass-loader vee-validate

buefy を使う

buefyのアイコンを使うので、index.htmlに下記追加。

 <link rel="stylesheet" href="//cdn.materialdesignicons.com/2.0.46/css/materialdesignicons.min.css">

VeeValidate を使う

<template>
  <div>
    <b-field label="メールアドレス"
      :type="errors.has('email') ? 'is-danger': ''"
      :message="errors.has('email') ? errors.first('email') : ''">
        <b-input
            name="email"
            v-model="email"
            v-validate="'required|email'"
            placeholder="メールアドレス">
        </b-input>
    </b-field>
  </div>
</template>
・・・
<script lang="ts">
import Vue from "vue";
import Buefy from "buefy";
import VeeValidate from "vee-validate";

Vue.use(Buefy);
Vue.use(VeeValidate);
・・・

VeeValidate を日本語化

エラーメッセージが英語なので日本語化する。
ローカライズ用のメッセージファイルの読込と、フィールド名の日本語化を行う。

・・・
        <b-input
            name="email"
            v-model="email"
            v-validate="'required'"
            data-vv-as="メールアドレス"
            placeholder="メールアドレス">
・・・
<script lang="ts">
import Vue from "vue";
import Buefy from "buefy";
import VeeValidate, { Validator } from "vee-validate";
// @ts-ignore: implicitly has an 'any' type.
import VeeValidateJa from "vee-validate/dist/locale/ja";

Vue.use(Buefy);
Validator.localize("ja", VeeValidateJa);
Vue.use(VeeValidate);
・・・

フィールド名の日本語化は、data-vv-as を追加してフィールドごとに対応。
attributesファイルを用意しても出来るようです。
https://baianat.github.io/vee-validate/guide/localization.html#aliases

メッセージファイルの読込でエラーが出たので、ts-ignoreで対応、、、

入力チェックのタイミングを変更

メールアドレスのチェックなどで入力を始めるといきなりエラーとなるので、入力チェックを行うタイミングをフォーカスが外れた時にする。

Vue.use(VeeValidate, {
  events: "blur"
});

ボタンクリックなどで入力チェック

ログイン処理など実際にはボタンクリックなどで全体の入力チェックを行うと思うので、その方法。

・・・
<a class="button is-primary is-fullwidth" @click="login()">ログイン</a>
・・・
  methods: {
    login() {
      this.$validator
        .validateAll()
        .then(result => {
          if (!result) {
            console.log(this.$validator.errors.all());
            return;
          }
        })
        .catch(() => {
          console.log(this.$validator.errors.all());
        });
    }
  }

入力チェックでエラーがあってもcatchではなくthenが呼ばれる。入力エラーがあるかはresultで判定する。

vue-cli で作成したプロジェクトの起動時のポートを変更

vue-cli 作成したVue.jsのプロジェクトをnpm run devで起動すると、ポート:8080で起動する。
8080が使われてると、8081で起動したりと賢いのですが、別のポートで起動したい時に下記のように設定する。

config/index.js

module.exports = {
  dev: {
・・・
    host: 'localhost',
    port: 8079, ←コレ

npm でパッケージ管理

npm アップデート

npm 自体をアップデートする

$ npm --version
$ npm install -g npm

npm でインストールされているパッケージの確認

プロジェクト

$ npm ls

グローバル

$ npm ls -g

npm でパッケージをインストール

グローバル

$ npm install -g vue

プロジェクト(package.jsonに書込む)

$ npm install --save-dev grunt
or 
$ npm install --D grunt

AWS の ElasticBeanstalk でログファイルを CloudWatch に転送する

SpringBootで作成したWebアプリケーションをElasticBeanstalkで運用していてAutoScalingなどでEC2が削除されると、EC2上に保存されているログファイルも当然削除されてしまう。
削除される前にログファイルをどこかに保存したいと思うのですが、その一つの方法としてCloudWatchに転送することにする。

ElasticBeanstalkにはCloudWatchにログファイルを連携する機能がありますが、今回はアプリケーション独自のログを連携したいのでこの機能(CloudWatch Logs へのインスタンスログのストリーミング)は使いません。

アプリケーションから出力した独自ログとapacheのログを転送することにします。
CloudWatchへの転送にはawslogsを使用します。
awslogsのインストールなどEC2への操作などはデプロイするWebアプリケーション内に設定ファイルとして追加します。
具体的には、アプリケーションの src/main/webapp/.ebextensions 以下に配置します。

.ebextensions 以下にconfigファイルを配置しますが、awslogsを使う場合は以下のような内容です。

packages:
  yum:
    awslogs: []
container_commands:
  1-cp-awscli_conf:
    command: cp -rf .ebextensions/awscli.conf /etc/awslogs/awscli.conf
  2-cp-awslogs_conf:
    command: cp -rf .ebextensions/awslogs.conf /etc/awslogs/awslogs.conf
  3-chkconfig-awslogs:
    command: /sbin/chkconfig awslogs on
  4-restert-awslogs:
    command: /sbin/service awslogs status; if [ $? -eq 0 ]; then /sbin/service awslogs restart; else /sbin/service awslogs start ; fi;

awslogsの設定ファイルも予め用意しておいて、そのファイルコピーします。
最終的なファイル構成はこんな感じです。

awscli.conf、awslogs.conf の内容も参考までに。

awscli.conf

[plugins]
cwlogs = cwlogs
[default]
region = ap-northeast-1

awslogs.conf

[general]
state_file = /var/lib/awslogs/agent-state

[/var/log/httpd/access_log]
log_group_name = sample_app
log_stream_name = {instance_id}_httpd
file = /var/log/httpd/access_log
datetime_format = %d/%b/%Y:%H:%M:%S
initial_position = start_of_file
buffer_duration = 5000

[/var/log/tomcat8/sample_app.log]
log_group_name = sample_app
log_stream_name = {instance_id}_app
file = /var/log/tomcat8/sample_app.log
datetime_format = %Y-%m-%d %H:%M:%S.
initial_position = start_of_file
buffer_duration = 5000

もちろんログのファイル名や、日付けフォーマットなどを合わせる必要があります。

svg に外部の画像を使う

Webサイトなどのhtmlでsvgを使う際に、svg内にサーバー上の画像などを使う場合、xlink:href 属性で画像を指定する。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="200px" height="200px" viewBox="0 0 200 200" enable-background="new 0 0 200 200" xml:space="preserve">
    <g>
        <image x="0" y="0" width="200" height="100" xlink:href="images/xxxxx.png"></image>
    </g>
</svg>

WordPress(Lightsail)でhttpsを強制

apache設定にリダイレクト設定を追加するので設定ファイルを開き、

sudo vi /opt/bitnami/apache2/conf/bitnami/bitnami.conf

以下のリダイレクト設定を追加。

<VirtualHost _default_:80>
  DocumentRoot "/opt/bitnami/apache2/htdocs"
  # Redirect
  RewriteEngine On
  RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [R=301,L]

追加後にapacheの再起動。

sudo /opt/bitnami/ctlscript.sh restart apache

以下のように条件をつけても良かったが、VirtualHostで80ポートにきたら無条件でリダイレクトにした。

RewriteCond %{HTTPS} off

TypeScript で文字列を一文字ずつスタイルを適用する

ひとまず共通関数を定義

function decorateText(text: string, params: {[index: string]: string}[]): string {
    var result = '';
    var textArr = text.split('');
    var textLen = textArr.length;
    var paramsLen = params.length;
    for (var i = 0; i < textLen; i++) {
        var attr = '';
        let param = params[(i % paramsLen)];
        for (var key in param) {
            attr += ` ${key}="${param[key]}"`
        }
        result += `<span ${attr}>${textArr[i]}</span>`;
    }
    return result;
}

呼び出し側は

var decorateParams = [
    {"style" : "color: #000000;"},
    {"style" : "color: #ff0000;"}
];
decorateText("aaaaaaaaaa", decorateParams);

こんな感じです。