2019年2月28日木曜日

SpringBoot 1.3 から 1.5 へのバージョンアップでハマったこと その2


オフィス狛 技術部のJoeです。
今回が初の投稿になります。どうぞよろしくお願いします。

以前、SpringBoot1.31から1.51にバージョンアップを記事にしましたが、その影響がさらに出てきました。
今回は、バージョンアップが原因で発生した事象を追加でご紹介します。

今回の事象が発生したのはファイルのアップロードです。 数MB程度のファイルをmultipart/form-data形式でアップロードしたところ、下記のエラーが出ました。

org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field [xxxxx] exceeds its maximum permitted size of 1048576 bytes.

「最大サイズの1MBを超えています」だそうです。
エラーに出ているファイルサイズ(1MB)はSpringbootのデフォルトのサイズです。

最大サイズはapplication.ymlに定義しているはずなので確認しました。

multipart:
    maxFileSize: 100MB
    maxRequestSize: 100MB

確かに最大100MBと定義しています。
では、何故1MBになってしまうのか・・・・・・
調べてみたところ、バージョンアップによりプロパティーのキー名が変更されていました。

【SpringBoot 1.5】での指定方法
spring:
    http:
        multipart:
            max-file-size: 100MB
            max-request-size: 100MB

デフォルトでは、上記の設定はapplication.ymlには存在しないので、デフォルトのサイズ(1MB)になっていたのですね。
とりあえず、上記のキー名に修正し、無事にアップロードすることができました。

ちなみに、今回のアップロードは1ファイルなので同じ値を設定していますが、
複数ファイルの場合、「max-request-size」はファイル数に応じて変更です。
・max-file-size :1ファイルの最大バイト数
・max-request-size:1リクエストで複数ファイルの最大バイト数

さらに調べてみると、SpringBoot 2.0では、下記の設定方法に変更されていました。

【SpringBoot 2.0】での指定方法
spring:
    servlet:
        multipart:
            max-file-size: 100MB
            max-request-size: 100MB

今回ご紹介した以外にも、バージョンアップでキー名が変更されているものがあるようなので、対応の際は調査が必要ですね。


,

2019年2月27日水曜日

Angular angular.json の scripts は記載する順番が大事、と言う話(bootstrap、popper)


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

Angular の angular.json には、外部のJavaScriptの読み込む為に、「scripts」と言う項目が存在しますが、そこに記載する際は、順番が大事だよ、と言う話です。
まあ、Angularに限った事じゃ無いのですが、毎回ハマるので、備忘録で記載します。

とある新規プロジェクトで、デザイナーが作ったhtmlをせっせとAngularプロジェクトに移植していたのですが、ポップアップ系の表示がエラーになってしまいました。
zone.js:192 Uncaught TypeError: Bootstrap dropdown require Popper.js (https://popper.js.org)
    at c.t.toggle (bootstrap.min.js:6)
    at HTMLAnchorElement. (bootstrap.min.js:6)
    at Function.each (jquery.min.js:2)
    at w.fn.init.each (jquery.min.js:2)
    at w.fn.init.c._jQueryInterface [as dropdown] (bootstrap.min.js:6)
    at HTMLAnchorElement. (bootstrap.min.js:6)
    at HTMLDocument.dispatch (jquery.min.js:2)
    at HTMLDocument.y.handle (jquery.min.js:2)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)

「Bootstrap dropdown require Popper.js」なので、
ああ、「bootstrap.min.js」が「Popper.js」を必要としているのね、と言う事で、まずはインストールしました。
npm install popper.js --save

その後、angular.jsonに「Popper.js」追加しました。
    "scripts": [
        "node_modules/jquery/dist/jquery.min.js",
        "node_modules/bootstrap/dist/js/bootstrap.min.js",
        "node_modules/popper.js/dist/umd/popper.min.js"
    ]
既に、「bootstrap.min.js」は追加していあったので、その直後に追記しました。
(これが良くなかった・・・・)

その後も一向にエラーが消えることがありません。
少し考えた後、「これ、もしかして順番かな?」と思い、
    "scripts": [
        "node_modules/jquery/dist/jquery.min.js",
        "node_modules/popper.js/dist/umd/popper.min.js",
        "node_modules/bootstrap/dist/js/bootstrap.min.js"
    ]

順番を入れ替えたらエラーも消えました。
いやー、どハマりする前に気付けて良かったです。

何事も読み込む順番には気を付けようね、と言う話でした。
あまり、Angular関係無かったですね。
次回はもっとAngularっぽい機能を書いていこうと思います。

それでは、良いAngularライフを!


2019年2月26日火曜日

node.jsでインストールしたモジュール(knex、mssql)のバージョンによる問題


オフィス狛 技術部のHammarです。

今回はnode.jsのpackage.jsonに記述したモジュールのインストールバージョンによってハマった事象を書こうと思います。 

環境構築時にDBのテーブルを作成したり、テストデータを登録したりすると思いますが、今回そのテーブル作成(migrate)とテストデータ登録(seed)作業をnode.jsとknex.jsというSQL Query Builderのモジュールで実行させます。
また開発の都合上DBはSQL Serverを利用するので、SQLServerに接続するmssqlというモジュールも利用します。 

■実装環境

・node.js(Express)
・knex、mssqlモジュールを利用 

■npmインストール

まずそれぞれのモジュールの最新バージョン(knex:0.16.3 、mssql:4.3.0)をインストールして使おうとしましたが、そもそもknexとmssqlの最新バージョン互換対応がしておらず、怒られます。
Error: This knex version does not support any other mssql version except 4.1.0 (knex patches bug in its implementation)
このバージョン(knex:0.15.2 、mssql:4.1.0)が最終的に対応しているとのことで、バージョンを指定しインストールします。
 

■テーブル作成(migrate)、テストデータ登録(seed)

次にテーブル作成(migrate)とテストデータ登録(seed)の処理を作成します。
テーブル作成(migrate)ではknexをつかったテーブルcreateを、テーブル毎のファイル別に作成し、その各ファイルを読み込んで実行するというような基本的な流れでテーブルを作成します。
データ登録(seed)も基本的には同じで、insert文が書かれた各ファイルを読み込む感じです。 

このmigrate処理を下記のような感じで記述して実行したのですが
// テーブルcreateファイルの読み込み
const createTableA= require('./createTableA');
const createTableB= require('./createTableB');
const createTableC= require('./createTableC');
const migrationOrder = [
  createTableA,
  createTableB,
  createTableC,
];

// 実行
exports.up = async knex => {
  const results = migrationOrder.map(migration => migration.up(knex));
  return Promise.all(results);
};

 なぜか「Can't acquire connection for the request. There is another request in progress.」というエラーがSQLServerから返ってきてしまいテーブルが作成できませんでした。
記述的には特におかしなところはなさそうなので、なぜうまくいかないのかかなりハマりました。
いろいろ調べていくとmssqlのバージョン4系では単一のトランザクション内で複数のクエリ実行はエラーとなるバグ?のようらしくこのときpromise.allは機能しないようです。
https://github.com/tediousjs/node-mssql/issues/491
https://github.com/Vincit/objection.js/issues/671 

■回避方法

1.mssql、knexのバージョンを下げる

mssqlのバージョンを単純に下げると今度はknexのバージョン互換の関係でつかえなくなるので、
  knex: 0.13.0
  mssql: 3.3.0
が現在の記述でうまくいくバージョンの組み合わせとなるようです。

ただ、やはり最新ではないですが新しいバージョンで開発したほうが今後のためにも良いとはおもうので、できるだけバージョンは下げたくないなーという思いで、個人的にはこの回避方法はやめました。

2.for文を使う

GitHubにも対応策として書かれていた下記のように記述しました。
exports.up = async knex => {
  const results = [];
  for (const migration of migrationOrder) {
    results.push(await migration.up(knex));
  }
  return results;
};

promise.allをつかわずに上記のようにfor文でテーブル作成を行うとうまくいきました。
ただ自分の開発環境ではこれにも1つ問題点がありました。 

ESlintをインストールしていて、for文の記述がこのESlintのチェックにひっかかってしまいました。
error   iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations no-restricted-syntax

現在の開発環境ではgitのcommit時にESlintチェックしていて、もしチェックに引っかかる場合はcommitできないようにしているのでこのままではcommitできません。
うーんこれは困った。。。
このチェックだけESlintから外したりすることも可能ですが、それだと今後開発のときのチェックとしてはすべて外れてしまうしー、
ということで、一旦ここの記述だけをチェックしないようにする、というちょっと強引な感じでひとまず切り抜けることにしました。

記述はこんな感じです。
exports.up = async knex => {
/* eslint-disable */
  const results = [];
  for (const migration of migrationOrder) {
    results.push(await migration.up(knex));
  }
  return results;
/* eslint-enable */
};

れでこの記述だけはチェック除外となるので、ひとまずは切り抜けられました。
データ登録(seed)も同じようなながれで記述することで回避できます。

結局やってみるとちょっと強引な形なので、回避方法1にしてもいい気もしますが、ご参考までに。

ということで、まだ他にもこのようなモジュールのバージョンでなにか事象があるかと思いますが、ハマり次第記載していけたらと思います。

, ,

2019年2月22日金曜日

StackViewの優先度 Content Hugging PriorityとContent Compression Resistance Priority


こんにちは、オフィス狛 モバイル開発担当 Aika-yuy です。
今回の投稿は、 StackViewにつけるAutoLayoutの優先度について書いてみたいと思います。


サイズが曖昧だと怒られる

動的なサイズ変更や、デバイスサイズにも柔軟に対応してくれるStackViewですが、サイズが曖昧だと怒られることがあります。固定サイズを指定するという方法もありますが、iPad対応で文字のサイズを動的に変更したい場合は、あらかじめ優先度を設定しましょう。

まず、StackViewに2つのLabelを配置し、StackViewのサイド20、Y軸の中心になるように制約をつけます。











そうすると、こんなエラーが出ます。







『どっちをLabelサイズを優先すればいいかわからないよーー 』ということです。
こまちゃんのLabelの優先度を低くするようにアドバイスしてくれています。

優先度を指定する

優先度を変更するときはAutoLayoutで設定できます。
優先度は、高くしたい方のpriorityを高くするのではなく、低くしたい方のpriorityを低くするようです。

いろんな解釈の仕方があると思いますが、私が覚えやすい方法使い分けをで書いてみました。

・Content Hugging Priority・・・・・・・・・・  子Viewが親Viewより小さい時 

・Content Compression Resistance Priority・・・  子Viewが親Viewより大きい時 


子Viewが小さい時

2つのLabelどちらともの文章が短い時、どちらのサイズを大きくしてViewいっぱいに表示するかを指定しなければいけません。
その場合は、優先順位が低い方の(固有のサイズを保持しなくてもいい方、大きくなってもいい方)
Content Hugging Priorityを1小さく設定します。

下の画像では、nameは動的にサイズが変更する予定がないので元々のサイズを維持。こまちゃん部分は動的にサイズ変更したいというような場合です。
こまちゃんのLabelのContent Hugging Priorityを下げることにより、長くなってしまった場合省略表示され、nameのラベルを親Viewから押し出すこともなくなります。











子Viewのどちらかが大きい時

2つのLabel合わせたサイズが親Viewよりも大きくなってしまう場合、どちらを優先して表示するか指定します。
省略して表示してもいい方の優先度を1小さくします。










子Viewどちらとも親Viewより大きい時(どちらかを優先すると、どちらかが消えてしまう場合)

この場合は、設定次第ですがどちらも表示したい場合は親のStackViewの比率から固定サイズで指定した方がいいかもしれません。

AutoLayoutマスターになるべく、少しづつブログも更新していけるよう頑張ります。



,