Windows環境でNode.JSとPostgreSQLを接続してクエリ発行


前回、Windows上にNode.jsの環境を構築して、Hello,Worldを出力されるところまでおこないました。



今回は、Node.jsとPostgreSQLを接続して、データベースに格納されているデータをブラウザ上に表示させるところまでおこないたいと思います。


やっぱり、データベースに接続してデータを表示するというところまでは、お勉強としておさえておきたいところです。


環境情報


  • OS:Windows10
  • Webサーバ:Node.js 12.16.3
  • DB:PostgreSQL9.6

PostgreSQLとは


PostgreSQL(ぽすとぐれすきゅーえる)は、オープンソースのデータベースになります。
よく、「ぽすぐれ」と言われています。


PostgreSQLはオープンソースなので、気軽に使えるのが良いところです。
かつ、標準SQL にならった実装になっていますので、標準SQLでほぼ全てのクエリを実行することができます。


この記事では、PostgreSQLのダウンロードと環境構築の紹介は省略します。


node-postgres


Node.jsでPostgreSQLと接続をおこなうためには、「node-postgres」を使用する必要があります。
「node-postgres」は、npmでインストールをおこなうことができます。

任意のフォルダを作成して、そのフォルダで以下のコマンドを実行します。


npm install --save pg

インストールが完了すると、インストールしたフォルダに「node_modules」が作成され、インストールが完了します。
このフォルダにプログラムを作成していきます。


PostgreSQLに接続してデータ表示


実際にNode.jsのプログラムを作成して動かしてみます。
データベースにはあらかじめて、以下のデータを格納しておきます。

person_id

name

kana

gender

1

山田太郎

やまだたろう

1

2

山田次郎

やまだじろう

1

3

山田三郎

やまださぶろう

2


上記のデータをクエリで取得し、ブラウザ上に表示するプログラムを作成します。
プログラムとしては以下になります。


// モジュールを準備
var http = require('http')
var {Client} = require('pg'); 

http.createServer(function (req, res) {

    // PostgreSQLに接続
    var client = new Client({
        user: 'postgres',
        host: 'localhost',
        database: 'nodeJsDB',
        password: 'postgres',
        port: 5432
    })
    client.connect()

    // HTTPレスポンスヘッダを出力
    res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'})

    // クエリを実行してTABLEタグで出力
    var query = client.query(
        "select person_id, name, kana, gender from persons;",
         function(err, result) {
        res.write('<html><head></head><body><table>');
        for(lc = 0; lc < result.rows.length; lc++){
            res.write('<tr>');
            res.write("<td>"+result.rows[lc].person_id+"</td>" ); 
            res.write("<td>"+result.rows[lc].name+"</td>" ); 
            res.write("<td>"+result.rows[lc].kana+"</td>" ); 
            res.write("<td>"+result.rows[lc].gender+"</td>" ); 
            res.write('</tr>');
        }
        res.end('</table></body></html>')
    });
}).listen(8989)

プログラムとしては簡単です。
PostgreSQLに接続してクエリを実行し、実行結果をTABLEタグに出力するのみです。
nodeコマンドでNode.jsのサーバを起動します。


node pgConnect.js

URLにアクセスすると実行結果が表示されます。

http://localhost:8989/pgConnect

Node.jsの実行結果

まとめ


いかがでしょうか?
PostgreSQLであっても、Node.jsから簡単に接続がおこなうことができました。

本当はMongoDBとか使ってみたいんですが、しばらくはPostgreSQLでNode.jsの勉強を進めようと思います。



WindowsにNode.jsの環境を構築する-サンプルプログラム実行まで


最近、業務でNode.jsを使ったプロジェクトが増えてきたように思います。
筆者は業務アプリケーションの開発をおこなうSIerなので、実態としては業務アプリケーションではJavaや.NETが主流です。


とはいっても、ポツリポツリと、Node.jsを使ったプロジェクトも出てきています。
時代遅れにならないように、個人的に勉強を始めようかとおもい、まずは環境構築からはじめてみます。


という訳で今回は、Node.jsのダウンロードと環境構築、および、サンプルプログラムを実行するまでを紹介します。


環境情報


  • OS:Windows10
  • Webサーバ:Node.js 12.16.3

Node.jsのダウンロードとインストール


Node.jsは、以下の公式サイトからダウンロードできます。


Node.js
 
Node.js
https://nodejs.org/ja/
Node.js ブログ: リリース

2020/5/3現在では、インストーラはLTS版と最新版の2つがあります。
LTS版とは「Long term support版」の略でして、サポート期間が長く、そのサポート期間の間はバグの修正や主要な機能の保証がされているバージョンのことです。


何かしら最新版を使用しないといけない事情がない限りは、LTS版をダウンロードすることをお勧めします。

という訳で、今回はLTS版をダウンロードします。


「node-v12.16.3-x64.msi」というファイルをダウンロードしたら、そのファイルをダブルクリックしてインストールを開始します。
インストール自体は、ウィザードに沿ってインストールをおこなっていけば、簡単に終了しました。


インストールが完了したら、インストール完了後の確認をおこないます。
インストールが完了すると、Windowsのプログラムメニューに「Node.js command pronpt」というメニューが増えているかと思います。
そのメニューをクリックします。

Node.jsのコマンドプロンプト

コマンドプロンプトがひらきます。
Node.jsのインストールバージョンを確認するために、以下のコマンドを実行します。

node --version

インストールされたNode.jsのバージョンが表示されれば、無事にインストール完了です。


JSファイル単独で実行


JSファイルを作成してコマンドプロンプトで実行してみます。
「helloWorld.js」というサンプルプログラムを作成して実行します。


「helloWorld.js」の中身は、”Hello,World”をコンソールログで出力するだけです。

console.log('Hello, World')

コマンドプロンプトで、nodeコマンドを使用して実行します。

D:\>node helloWorld.js
Hello, World

Webサーバで実行


次は、Webサーバを起動してブラウザ上で”Hello,World”を表示します。
「helloWorldServer.js」というサンプルプログラムを作成します。

こちらも同様に、”Hello,World”を標準出力するだけです。

var http = require('http')

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end(`Hello World \n`)
}).listen(8989)

コマンドプロンプトでWebサーバを起動します。

D:\>node helloWorldServer.js

コマンドを実行した後に、ブラウザで以下のURLにアクセスします。

http://localhost:8989/helloWorldServer

ブラウザ上に”Hello,World”が表示されました。

Node.jsのWebサーバでHelloWorld

まとめ


いかがでしょうか?
簡単に”Hello,World”が表示できました。


開発環境はできたので、これをベースにいろいろ勉強していきたいと思います。



canvasタグを使ってブラウザ上でお絵描きアプリを作る

JavaScript


ブラウザ上でのお絵描きは、HTML5の<canvas>タグを使って描画エリアを準備し、マウス操作をJavaScriptで制御をおこなうことで可能になります。


今回は、canvasタグを使ってブラウザ上でお絵描きをおこなう方法を紹介します。

JavaScriptでマウスの動きを制御して、canvasタグ上にお絵描きをおこないます。


HTMLとJavaScriptだけで、機能を実現することができます。


環境情報


  • ブラウザ:Chrome81
  • JQuery:JQuery2.2.4

サンプルプログラム


早速ですが、サンプルプログラムを紹介します。

紹介しているHTMLとJavaScriptをそのままコピペして使って頂ければ、基本的な機能をそなえたお絵描きアプリがブラウザ上で実現できます。


サンプルプログラムで動作するお絵描きアプリは、以下のURLから起動できます。


HTMLとJavaScriptは以下になります。


  • HTML
<body>
    <div>
        <canvas id="canvas" style="border:1px solid gray;"></canvas>
    </div>
    <div>
        <input type="button" id="undo" name="undo" value="undo">
        <input type="button" id="redo" name="redo" value="redo">
    </div>
</body>

  • JavaScript
//
// JavaScriptのグローバル変数群
//
var CANVAS_SIZE;
var undoDataStack = [];
var redoDataStack = [];
var mouseDown = false;

$(function() {
    //
    // 画面読み込み時のロード処理
    //
    $(document).ready(function(){

        // キャンバスのサイズを設定
        $('#canvas').css('width', '600px');
        $('#canvas').css('height', '600px');

        // キャンバスの属性を設定
        canvas = document.getElementById('canvas');
        canvas.width = 600;
        canvas.height = 600;
        CANVAS_SIZE = canvas.clientWidth;

        // 描画開始 → 描画中 → 描画終了
        canvas.addEventListener('mousedown', startDraw, false);
        canvas.addEventListener('mousemove', drawing, false);
        canvas.addEventListener('mouseup', endDraw, false);
    });

    //
    // undo
    //
    $("#undo").click(function() {

        if (undoDataStack.length <= 0) {
            return;
        }

        canvas = document.getElementById('canvas');
        context = canvas.getContext('2d');
        redoDataStack.unshift(context.getImageData(0, 0, canvas.width, canvas.height));

        var imageData = undoDataStack.shift();
        context.putImageData(imageData, 0, 0);
    });

    //
    // redo
    //
    $("#redo").click(function() {

        if (redoDataStack.length <= 0) {
            return;
        }

        canvas = document.getElementById('canvas');
        context = canvas.getContext('2d');
        undoDataStack.unshift(context.getImageData(0, 0, canvas.width, canvas.height));

        var imageData = redoDataStack.shift();
        context.putImageData(imageData, 0, 0);
    });
});

//
// 描画開始
//
function startDraw(event){

    // 描画前処理をおこないマウス押下状態にする。
    beforeDraw();
    mouseDown = true;

    // クライアント領域からマウス開始位置座標を取得
    wbound = event.target.getBoundingClientRect() ;
    stX = event.clientX - wbound.left;
    stY = event.clientY - wbound.top;

    // キャンバス情報を取得
    canvas = document.getElementById("canvas");
    context = canvas.getContext("2d");
}

//
// 描画前処理
//
function beforeDraw() {

    // undo領域に描画情報を格納
    redoDataStack = [];
    canvas = document.getElementById('canvas');
    context = canvas.getContext('2d');
    undoDataStack.unshift(context.getImageData(0, 0, canvas.width, canvas.height));
}

//
// 描画中処理
//
function drawing(event){

    // マウスボタンが押されていれば描画中と判断
    if (mouseDown){
        x = event.clientX - wbound.left;
        y = event.clientY - wbound.top;
        draw(x, y);
    }
}

//
// 描画終了
//
function endDraw(event){

    // マウスボタンが押されていれば描画中と判断
    if (mouseDown){
        context.globalCompositeOperation = 'source-over';
        context.setLineDash([]);
        mouseDown = false;
    }
}

//
// 描画
//
function draw(x, y){
    canvas = document.getElementById("canvas");
    context = canvas.getContext("2d");
    context.beginPath();
    context.strokeStyle = "black";
    context.fillStyle = "black";
    context.lineWidth = 2;
    context.lineCap = "round";

    context.globalCompositeOperation = 'source-over';
    context.moveTo(stX,stY);
    context.lineTo(x,y);
    context.stroke();
    stX = x;
    stY = y;
}

HTMLの構成


HTMLはとてもシンプルです。
HTML5の<canvas>タグを定義しているだけ、です。

<canvas id="canvas" style="border:1px solid gray;"></canvas>

<canvas>タグはHTML5から追加されたHTMLタグになります。
2Dのグラフィックを表示することができるので、HTMLとJavaScriptでゲームやグラフィックデザインをおこなうことができます。


ブラウザ上でのゲームは、ほぼ全てこの技術が使われています。


JavaScriptの構成


ポイントは2つありまして、1点目は描画の基本処理。


描画開始 → 描画中 → 描画終了 の3段階で処理をわけています。
イベントの検知は、JQueryのイベントリスナーを使用しています。


// 描画開始 → 描画中 → 描画終了
canvas.addEventListener('mousedown', startDraw, false);
canvas.addEventListener('mousemove', drawing, false);
canvas.addEventListener('mouseup', endDraw, false);

「mousedown(左クリック開始)」のイベントを「startDraw」ファンクションで処理しています。
クリックした位置を算出し、描画開始を認識します。


「mousemove(マウス移動)」のイベントを「drawing」ファンクションで処理しています。
マウス移動に従って、canvas上に線を描画しています。


「mouseup(左クリック終了)」のイベントを「endDraw」ファンクションで処理しています。
左クリックを終了した位置が描画の終了位置と認識します。


もう一つのポイントとしてはUNDO・REDOです。
UNDOはやり直し、REDOはやり直しのやり直し、です。


仕組みは簡単です。
グローバル変数に「undoDataStack」「redoDataStack」を準備し、この領域にデータを格納することでUNDO・REDOを実現しています。


var undoDataStack = [];
var redoDataStack = [];

描画終了したら「undoDataStack」にデータを格納し、UNDOをやったら「redoDataStack」にデータを格納します。
UNDO・REDOの操作をおこなったら、この「undoDataStack」「redoDataStack」領域からデータを取り出し、画面表示をおこないます。


まとめ


いかがでしたでしょうか?


<canvas>タグを使えば、簡単にブラウザ上でお絵描きができることがわかって頂けたかと思います。
今回は紹介しきれませんでしたが、色の指定や図形の指定もおこなうことができます。
ぜひお試しください。



Chrome81へのバージョンアップでシステム管理者がやるべきこと。混合コンテンツ対応。

JavaScript

こんにちは。
さくさくTECHブロガーの「さく」です。


Chrome81のバージョンアップで、やっかいなバージョンアップがおこなわれます。
「混合コンテンツ」に対するChromeの動作が変更になるようです。


本記事では、Chrome81でエラー扱いとなるパターンの検証をおこないます。


環境情報


  • Chrome: 81.0.4044.83(Official Build)beta (64 ビット)

2020/03/29時点では、Chrome81ベータ版しか手に入りません。
なので、このバージョンで検証してみます。


ちなみに、Chrome81正式版のリリースは延期されているようです。
現時点では、延期したリリース日も未定です。


混合コンテンツとは


まず、混合コンテンツとは何か?という事ですが、簡単に説明すると“https化されたサイト内のhttpコンテンツ”です。


“混合コンテンツ”とは、閲覧ページが安全なHTTPS接続で読み込まれているにもかかわらず、そのHTTPSページに含まれる他のリソース(画像、動画、スタイルシート、スクリプトなど)が暗号化されていない、安全ではないHTTP接続で読み込まれている状態、つまりHTTPSページにHTTPサブリソースが混在している状態をいいます。


httpsで常時接続しているサイトにおいて、サイトの中で読み込まれている「画像」「CSS」「スクリプト」がhttpで接続されている場合に”混合コンテンツ”と判断されます。


何がブロックされるのかを検証


Chrome81では、本当に全てのhttpコンテンツがブロックされるのでしょうか?
検証してみました。


まず、混合コンテンツが発生するテストサイトを作成します。
以下のURLのサイトになります。
JavaScript・CSS・画像の3つについて、httpで読み込みをおこなっています。



HTMLは以下になります。

<!DOCTYPE html>
<head>
  <title>混合コンテンツのテストサイト</title>
  <link rel="stylesheet" href="http://sakusaku-techs.com/sample/mixed/css/base.css" />
  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fsakusaku-techs.com%2Fsample%2Fmixed%2Fjs%2Fmixed.js%22%20type%3D%22text%2Fjavascript%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;script&gt;" title="&lt;script&gt;" />
</head>
<body>

混合コンテンツの試験サイト
<img src="http://sakusaku-techs.com/sample/mixed/image/images.png">
</body>
</html>

Chromeのディベロッパーツールでエラーを確認してみます。
CSSとJavaScriptはエラーが発生していますね。
エラーの内容は「Mixed Contents」です。



  • CSSのエラー
Mixed Content: The page at 'https://sakusaku-techs.com/sample/mixed/mixed.html' was loaded over HTTPS, but requested an insecure stylesheet 'http://sakusaku-techs.com/sample/mixed/css/base.css'. This request has been blocked; the content must be served over HTTPS.

  • JavaScriptのエラー
Mixed Content: The page at 'https://sakusaku-techs.com/sample/mixed/mixed.html' was loaded over HTTPS, but requested an insecure script 'http://sakusaku-techs.com/sample/mixed/js/mixed.js'. This request has been blocked; the content must be served over HTTPS.

かしかし、画像だけはエラーではワーニングになりました。

  • 画像のワーニング
Mixed Content: The page at 'https://sakusaku-techs.com/sample/mixed/mixed.html' was loaded over HTTPS, but requested an insecure image 'http://sakusaku-techs.com/sample/mixed/image/images.png'. This content should also be served over HTTPS.

外部コンテンツの読み込み部分は、CSSとJavaScriptはエラー、画像はワーニングになる、という事がわかりました。
画像はワーニングでブラウザ上に画像が表示されるのですが、これはもしかしたらChrome81のベータ版だからかもしれません

もしかしたら、正式版だとエラーになってしまうかも、です。


HTMLのhttp部分をhttpsに変更すれば、エラーは全て解消されました。


まとめ


混合コンテンツが原因でJavaScriptやCSSの読み込みがエラーとなった場合、そのサイトは”まったく動作しない”という可能性があります。
早急に対処した方がよさそうです。



VMWarePlayer上にCentOSをインストールして動かしてみる

Linux

今回は、VMWare上にCentOSをインストールして動かす方法を紹介します。


Linuxに限らず、普段はWindowsを使って作業している人が、他のOS環境も必要な場合があるかと思います。
そういう場合は、VMWareを使う方法が最も簡単です。

Windows上に仮想のHDを割り当てて、別OSの環境を構築できます。


しかも、別サーバに環境を移植したい場合は、VMWareのファイル一式をコピーすれば、簡単に引っ越しも可能です。


今回は、Winodows10上にVMWareをインストールして、CentOSを構築する方法を紹介します。


環境情報


  • ホストマシン:Windows10
  • VMWare:15.5.2 build-15785246
  • CentOS: release 8.1.1911

VMWareをダウンロードしてインストール


以下のURLからダウンロードします。



インストーラを起動すると、いきなり以下のポップアップウィンドウが表示されます。
どうやら、「Microsoft VC」をインストールする必要がありそうです。
とりあえず、ホストとなるインストール端末を再起動します。


VCのインストール

※筆者の場合は自動的にインストールされたようで、再起動してインストールを再開したら再度ダイアログが表示されることはなかったです。


インストール端末を再起動したら、再度インストーラを起動します。
インストールは、画面のウィザードに沿ってインストールしていけば大丈夫です。

最終的に以下のダイアログが表示されればインストール完了です。


VMWareのインストール完了

CentOSをダウンロードしてインストール


CentOSは、以下のURLからダウンロードします。


isoredirect.centos.org
CentOS
http://isoredirect.centos.org/centos/8/isos/x86_64/CentOS-8.1.1911-x86_64-dvd1.iso
In order to conserve the limited bandwidth available, ISO images are not downloadable from mirror.centos.org

ミラーリングサイトを選択し、ISOファイルをダウンロードします。
7GBなので、結構時間がかかります
筆者は5Hくらいかかりました。


VMWare上にインストールするための準備として、まずはCentOSのISOファイルをマウントします。



マウントするとISOファイルがドライブとして認識されます。



この状態でVMWareを起動します。
VMWareが起動したら、「新規マシンの作成」を選択します。



「インストーラディスク」にマウントしたCentOSのドライブを選択し、「次へ」を押下します。



Linuxの情報を入力します。

ここでの「パスワード」は、rootユーザのパスワードになるので忘れないようにしましょう。



次に仮想マシンの名前を入力します。
自分で解りやすい名前をつければいいです。


CentOSのマシン名設定

次にディスク容量の指定をおこないます。
仮想マシンに割り当てる最大のディスクサイズになります。
筆者は、とりあえずデフォルトの20GByteにしました。



最後に確認画面が表示されます。
一応さらっと確認して、「完了」ボタンを押下します。


完了ボタンを押下したらインストールが開始します。
いきなり以下の確認ダイアログが表示されます。



ひとまず必要なさそうなので、「後で通知する」を選択してスキップします。


「Pane is dead」が表示されて画面が固まる


インストールを開始したと思ったら、何かVMWareのウィンドウが固まっているように見えます。
下の方には「Pane is dead」と表示されています。
日本語では、”画面(ペーン)が死んでいます”ですかね。。。


Pane is deadの表示

原因がよくわからないので、とりあえずもう1回同じ事をしてインストールしてみます。
しかし、それでも同じでした。。。


いろいろ調べたのですが、筆者の場合は以下の方法で回避できました。
とりあえず、VMWareで空のハードディスクを作ります



その後にインストールすると、ひとまずインストールが無事に完了しました。


以下に、空のハードディスクを作ってインストールする方法を紹介します。


空のハードディスクを作ってインストールを継続


インストールが進むと、インストールで使用する言語の選択ウィンドウが表示されます。
日本語を選択します。


CentOSの言語の選択

インストール概要ウィンドウが表示されるので、「インストールの開始」ボタンを押下します。



インストールが始まります。
空のハードディスクからインストールしたので、rootパスワードが設定されいないという表示になっています。
ひとまず、インストールが完了するのをまちます。


CentOSのインストール中

インストールは完了したのですが、設定に必要な項目が残っているので次に進めないです。
まずは、rootパスワードを設定します。


CentOSのrootパスワードの設定

rootのパスワードを設定したら、「設定完了」ボタンを押下します。


インストールが完了したら再起動ボタンを押下して、インストールを完了します。


CentOSの設定完了

再起動後の設定


再起動したら、初期セットアップウィンドウが表示されます。
まず、ライセンス情報を確認します。


CentOSのライセンス設定

「ライセンス契約に同意します」にチェックし、完了ボタンを押下したら完了です。

CentOSライセンスの同意

初期セットアップでの設定は完了です。
設定の完了ボタンを押下して、次に進みます。

最初にウェルカムウィンドウが表示されます。
「次へ」を押下します。

CentOSのインストール完了

位置情報サービスってやつがあるんですね。
これは必要なさそうなので、オフにして次へボタンを押下します。

CentOS位置情報の設定

オンラインアカウントへの接続も今回はおこまいません。
スキップします。

CentOSオンラインアカウント

ユーザ情報を入力します。

CentOSユーザ情報の入力

次にパスワードを入力します。
先ほど入力したユーザのパスワードになります。


これで完了です。
「CentOSを使い始める」を選択します。


先ほど作成したユーザが表示され、ログイン可能な状態になっています。
パスワードを入力して、ログインしてみます。


以下のようなウィンドウが表示されたインストール完了です。

おつかれさまでした。


CUIのウィンドウを開きたい場合は、「アクティビティ」→「端末」を選択します。





JavaMailを使ってメール送受信をおこなう方法

Java

今回は、JavaMailを使ってメールの受信、および送信おこなう方法を紹介します。


JavaMailとは、Javaに標準実装されているメール送信APIです。
簡単な実装で、メールの受信と送信をおこなうことができます。

今回は、Yahooメールを使用した実装サンプルを紹介します。


環境情報


環境の情報は以下になります。

今回は、Yahooメールを使ってメールの送受信をおこなってみます。

メールはYahooのフリーアカウントを使用します。

  • Java1.8.60
  • POP3:Yahooメール
  • SMTP:Yahooメール

Yahooメールを受信する


メール受信プログラムは以下になります。
YahooメールのPOP3サーバに接続し、受信ボックスに存在するメールを取得して標準出力をおこなっています。
22行目のIDとパスワードは、自分のYahooメールのIDをパスワードを使用してください。


import java.util.Properties;

import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Folder;
import javax.mail.Message;

public class MailReceive {

    public static void main(String[] args){
        System.out.print("start: main\r\n");

        try {
            // メール受信のプロパティ設定
            Properties props = new Properties();
            props.put("mail.pop3.host", "pop.mail.yahoo.co.jp");
            props.put("mail.pop3.port", "110");

            // メール受信フォルダをオープン
            Session session = Session.getDefaultInstance(props);
            Store store = session.getStore("pop3");
            store.connect("ID", "PW");
            Folder folderInbox = store.getFolder("INBOX");
            folderInbox.open(Folder.READ_ONLY);

            // メッセージ一覧を取得
            Message[] arrayMessages = folderInbox.getMessages();
            for (int lc = 0; lc < arrayMessages.length; lc++) {

                // メッセージの取得
                Message message = arrayMessages[lc];

                // 件名の取得と表示
                String subject = message.getSubject();
                System.out.print("件名:" + subject + "\r\n");

                // 本文の取得と表示
                String content = message.getContent().toString();
                System.out.print("本文:" + content + "\r\n");

                // 取得の最大件数は10件
                if (lc >= 10) {
                    break;
                }
                System.out.print("\r\n");
            }
        } catch (Exception e) {
            System.out.print("例外が発生!");
            e.printStackTrace();
        } finally {
        }
        System.out.print("end: main\r\n");
    }
}

Javaメールのメール受信をおこなえるようにするためには、Yahooメールでの設定変更が必要です。
Yahooメールの設定画面で、POPサーバについて、Yahoo公式サービス以外からのアクセスを許可します。
送信の場合はSMTPを使うので、POPとSMTPについては許可設定をしておく必要があります。


Yahooメール設定1
Yahooメール設定2

Yahooメールを送信する


次にメール送信です。
メールの送信元がYahooメールで、メールの送信先もYahooメールにしています。
自分自身にメールを送っています。


IDとパスワード、メールアドレスについては、実際に送信する情報にあわせて修正が必要になります。


import java.util.Properties;

import javax.mail.Address;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Transport;
import javax.mail.Multipart;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

public class MailSend {

    public static void main(String[] args){
        System.out.print("start: main\r\n");

        try {
            // メール送信のプロパティ設定
            Properties props = new Properties();
            props.put("mail.smtp.host", "smtp.mail.yahoo.co.jp");
            props.put("mail.smtp.port", "587");
            props.put("mail.smtp.auth", "true");
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.ssl.trust", "*");
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.connectiontimeout", "10000");
            props.put("mail.smtp.timeout", "10000");

            // セッションを作成する
            Session session = Session.getInstance(props,
                new javax.mail.Authenticator() {
                    protected 
                        PasswordAuthentication 
                        getPasswordAuthentication() {
                        return new 
                            PasswordAuthentication("ID", "PW");
                    }
                });

            // メールの送信先はYahooメール。送信元もYahooメール
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(
                "fromAddress", "fromName"));
            message.setReplyTo(new Address[]{
                new InternetAddress("toAddress")});
            message.setRecipients(Message.RecipientType.TO, 
                InternetAddress.parse("toAddress"));
            message.setSubject("テスト");
            MimeBodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setText("テストメール。");

            // メールのメタ情報を作成
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);
            message.setHeader(
                "Content-Transfer-Encoding", "base64");

            // メールを送信する
            message.setContent(multipart);
            Transport.send(message);

        } catch (Exception e) {
            System.out.print("例外が発生!\r\n");
            e.printStackTrace();
        } finally {
        }
        System.out.print("end: main\r\n");
    }
}

筆者がちょっとはまったのが、以下の例外が発生した場合です。


javax.mail.NoSuchProviderException: No provider for smtp
        at javax.mail.Session.getProvider(Session.java:464)
        at javax.mail.Session.getTransport(Session.java:659)
        at javax.mail.Session.getTransport(Session.java:640)
        at javax.mail.Session.getTransport(Session.java:697)
        at javax.mail.Transport.send0(Transport.java:192)
        at javax.mail.Transport.send(Transport.java:124)
        at MailSend.main(MailSend.java:55)

“smtpのプロバイダーが存在しないよ”、と言われてしまっています。


この例外が発生する場合は、実行時のクラスパスに「mail.jar」が含まれていないときです。
「mail.jar」がない状態でビルドしてもビルドエラーにならないので、気が付きにくいかもしれません。


最後に


いかがでしたでしょうか?
Javaメールを使った、メール受信とメール送信の方法について紹介しました。


今回はYahooメールを使用したメール送受信方法を紹介しましたが、他メールサービスでも試してみたいと思います。(いつか。。。)
それではまた!




クーロン設定での小技集。設定の基本と、ちょっとしたテクニックを紹介

Linux

今回は、ちょっと特殊なクーロン設定を、まとめる形で紹介していきます
実際の業務でクーロンの設定をおこなう際、“あれ?あの設定でどうやるんだっけ?”というときに役立つTIPS集としてまとめます。


何か思いだしたら都度追記していきます。


クーロン設定の基本


まずは設定の基本を紹介します。
クーロン設定は以下の書式になります。

分  時  日  月  曜日 ユーザ名  コマンド

0分から59分までを定義

0時から23時までを定義

1日から31日までを定義

1月から12月までを定義。英字略形も可(jan,feb…dec)

曜日

0から7までを定義。0が日曜。英字略形も可(sun,mon…sat)


各定義について、リスト定義と範囲体後のどちらも可能です。

リスト

1,5,10

指定した値の場合のみ実行

範囲

1-5

指定した値の範囲内であれば実行

共存

1,5,10-15

リストと範囲の混在定義

間隔

1-5/2

「/」の後に間隔値を定義。左記の例だと「1,3,5」


月末に1回だけ動くクーロン設定


“月末に1回だけ動く”といったクーロン設定について紹介します。

結論を先に言いますと、以下の設定でOKです。


59 23 28-31 * * root   /usr/bin/test `date -d tomorrow +\%d` -eq 1 && sh /home/root/sample.sh

これで、”月末に1回だけ動く”というクーロン設定になります。

各設定の詳細について説明してきます。

前半部分が「月末」の定義です。

59 23 28-31 の部分ですね。


毎月、28日、29日、30日、31日の、23時59分にクーロンを動かせる設定になります。
でもこのままだと、月末に1回だけではなく、最大4回動いてしまいます。

なので、次の日が”1日”だったらという条件を追加します。
つまり、3月だと3月31日の次の日が1日(4月1日)だったら月末、
9月だと9月30日の次の日が1日(10月1日)だったら月末、という事ですね。


その計算が、/usr/bin/test `date -d tomorrow +\%d` -eq 1 &&  です。


testコマンドで条件を記述しています。
「date -d tomorrow +\%d」の返り値が1だったら月末と判定します。


この条件を28日から31日に動かすことによって、月末1回動作します。


標準出力をさせない設定


クーロンで実行したプログラムの実行結果が標準出力されることを防ぐためには、クーロン設定の末尾に標準出力を無しにする記述をおこないます。

55 23 28-31 * * root   /usr/bin/test `date -d tomorrow +\%d` -eq 1 && sh /home/root/sample.sh > /dev/null 2>&1

標準出力をなし(NULL)にします。
これで、標準出力はおこなわれません。



ApacheのログにPOSTで送信された内容をログ出力する方法

apache


Apacheのアクセスログには、デフォルトでGET形式で送信されたきたデータはログ出力されます。
しかし、POST形式で送信されたきたデータはログ出力されません。


実際には、Apacheが受信した時点でのHTTPリクエストにおけるPOSTデータを確認した場合があるかと思います。


というわけで今回は、POST形式のHTTPで送信されたきたデータをApacheのログに出力する方法を紹介します。


Apacheの設定を追加するだけで、ApacheのログにPOST形式で送信されたきたデータをログ出力できるようになります。


環境情報


  • OS:Windows10
  • Apache:Apache 2.4.41

mod_dumpioモジュールの有効化


POST形式で送信されたきたデータをログ出力するためには、「mod_dumpio」というApacheモジュールを有効にする必要があります。
「<Apacheインストールフォルダ>\conf」下の「httpd.conf」について、「mod_dumpio」を検索し、コメントアウトをはずして有効化します。


LoadModule dumpio_module modules/mod_dumpio.so

このモジュールを有効化することにより、HTTPリクエストの内容がログ出力されるようになります。


ログ出力設定の有効化


POST形式で送信されたきたデータをログ出力するためには、mod_dumpioモジュールの有効化以外に、httpd.confに3つの設定をおこなう必要があります。


  • 「DumpIOInput」ディレクティブの追記
  • 「DumpIOOutput」ディレクティブの追記
  • ログレベルを「dumpio:trace7」にする

「DumpIOInput」ディレクティブを追記します。
これを追記することで、HTTPリクエストの内容がログ出力されるようになります。

DumpIOInput On

「DumpIOOutput」ディレクティブを追記します。
これを追記することで、HTTPレスポンスの内容がログ出力されるようになります。

DumpIOOutput On

ログレベルを「dumpio:trace7」にします。

LogLevel dumpio:trace7

最後にApacheを再起動して、ログ出力の準備完了です。


POSTデータのログ出力


POST形式のリクエストがログ出力されるようになったのですが、具体的には「error.log」にログ出力されます。
以下のような感じです。

mod_dumpio:  dumpio_in (data-HEAP): Referer: http://localhost:81/test/post.html?query=1\r\n
mod_dumpio: dumpio_in [getline-blocking] 0 readbytes
mod_dumpio:  dumpio_in (data-HEAP): 36 bytes
mod_dumpio:  dumpio_in (data-HEAP): Accept-Encoding: gzip, deflate, br\r\n
mod_dumpio: dumpio_in [getline-blocking] 0 readbytes
mod_dumpio:  dumpio_in (data-HEAP): 42 bytes
mod_dumpio:  dumpio_in (data-HEAP): Accept-Language: ja,en-US;q=0.9,en;q=0.8\r\n
mod_dumpio: dumpio_in [getline-blocking] 0 readbytes
mod_dumpio:  dumpio_in (data-HEAP): 2 bytes
mod_dumpio:  dumpio_in (data-HEAP): \r\n
mod_dumpio: dumpio_in [readbytes-blocking] 25 readbytes
mod_dumpio:  dumpio_in (data-HEAP): 25 bytes
mod_dumpio:  dumpio_in (data-HEAP): address=address&name=name



Apache+Tomcatのインストールと連携設定

apache

こんにちは。

さくさくTECHブロガーの「さく」です。


今回は、ApacheとTomcatをインストールし、連携をおこなうまでの方法を紹介します。


ApacheはHTTPサーバで、TomcatはWEBサーバになります。
どちらも単独で動かすことができますが、ちょっとしたWEBアプリケーションでは、連携して環境を構築するパターンが多いです。

その場合、フロント側にApache、バック側にTomcatを設置します。
WEBアプリケーションはTomcat上に乗せた場合、Apacheで受けたHTTPリクエストをTomcatに連携する必要があります。


環境情報


  • OS:Windows10
  • Apache:Apache 2.4.41
  • Tomcat:Tomcat 8.5.51

Apacheのダウンロードとインストール


今回は、Windows(64Bit)の「Apache 2.4.41」をダウンロードします。

Apacheのダウンロードは、以下のサイトから可能です。



Apacheのダウンロード

ZIPファイルを解凍すると、「httpd-2.4.41-win64-VC14」というフォルダが解凍されます。
「httpd-2.4.41-win64-VC14」フォルダ配下の「Apache24」を、Cドライブ直下に格納します。


次のDOSプロンプトを起動し、インストールの準備をおこないます。
DOSプロンプトを管理者権限で起動します。

管理者として実行

ユーザアカウント制御の確認ダイアログが表示されますが、「はい」を押下して先に進みます。

管理者としての実行

DOSプロンプトが開いたら、先ほどダウンロードした「Apache24」配下に存在する「\bin」フォルダに移動します。

コマンドプロンプト

以下コマンドを実行し、インストールを開始します。

httpd.exe -k install

インストールコマンドを実行していますが、実態はサービス化とサービスの起動をおこなっているようです。
なので、サービスの起動に失敗した場合は以下ようなメッセージが表示されます。

c:\Apache24\bin>httpd.exe -k install
Installing the 'Apache2.4' service
The 'Apache2.4' service is successfully installed.
Testing httpd.conf....
Errors reported here must be corrected before the service can be started.
(OS 10013)アクセス許可で禁じられた方法でソケットにアクセスしようとしました。  : AH00072: make_sock: could not bind to address [::]:80
(OS 10013)アクセス許可で禁じられた方法でソケットにアクセスしようとしました。  : AH00072: make_sock: could not bind to address 0.0.0.0:80
AH00451: no listening sockets available, shutting down
AH00015: Unable to open logs

「Errors reported・・・」以降がエラーの内容です。
筆者の場合は上記のようなエラーになりましたが、インストールしようとするマシンによってエラーの内容は異なるかと思います。


今回は、上記エラーの原因を探ります。
エラーメッセージの内容から、Apacheが使用する80ポートが既に使用されているようです。
「netstat -oab」コマンドを実行し、80ポートを使用しているアプリケーションを探します。

c:\Apache24\bin>netstat -oab
アクティブな接続
  プロトコル  ローカル アドレス      外部アドレス           状態            PID
  TCP         0.0.0.0:80             DESKTOP-U7JE3FQ:0      LISTENING       4

PID=4のアプリケーションが80ポートを使用しているようです。
PID=4のアプリケーションを特定します。


「tasklist」コマンドを実行して確認してみます。

c:\Apache24\bin>tasklist
イメージ名                     PID セッション名     セッション# メモリ使用量
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0          8 K
System                           4 Services                   0      1,492 K

「System」ってあるけど。。。なに?って感じです。


いろいろググりましたが、特定するのが面倒になってきたので、Apacheのデフォルトポートを変更することにします。
Apacheのデフォルトポートは、「C:\Apache24\conf\httpd.conf」に定義されています。
『Listen』で検索すると80と定義されている箇所があるので、アプリケーションが使用していないポートに変更します。
筆者は81に変更してみました。

# Change this to Listen on specific IP addresses as shown below to 
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80
#80→81
Listen 81

再度、Apacheを起動してみます。
「コントロールパネル」→「サービス」からApacheを指定し、サービスの開始をおこないます。
状態が「実行中」になったら起動成功になります。

サービスでのApache起動確認

最後にブラウザからアクセスして、Apacheが起動したかを確認します。
「http://localhost:81/」をブラウザのURLバーに入力し、起動確認します。

Apacheの起動確認

WEB画面上に「It works!」が表示されていれば、Apacheがきちんと起動していることになります。


これで、Apacheのインストールと起動確認は完了です。


Tomcatのダウンロードとインストール


今回は、Windows(64Bit)の「Tomcat 8.5.51」をダウンロードします。
バイナリ版をダウンロードします。



Tomcatのダウンロード

ZIPファイルを解凍すると、「apache-tomcat-8.5.51」というフォルダが解凍されます。
そのフォルダをCドライブ直下に格納します。


ここから、Tomcat起動のための準備をおこないます。


最初に「CATALINA_HOME」の設定をおこないます。

「CATALINA_HOME」の設定

次に、tomcatのbin下に「パス」を設定します。

tomcatのパス設定

最後に「JAVA_HOME」です。

「JAVA_HOME」の設定

環境変数の設定は完了したらので、Tomcatを起動してみます。
Apacheのインストール時と同様に、管理者権限でDOSプロンプトをひらきます。
「c:\apache-tomcat-8.5.51\bin」に移動したら、「startup.bat」を実行します。

c:\apache-tomcat-8.5.51\bin>startup.bat

別ウィンドウでログが表示されれば起動成功です。
以下のようなログがウィンドウに表示されます。
以下のログは、Tomcatのログフォルダにも出力されます。

15-Feb-2020 16:59:55.242 情報 [main] org.apache.catalina.core.StandardService.startInternal サービス [Catalina] を起動します
15-Feb-2020 16:59:55.242 情報 [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.51
15-Feb-2020 16:59:55.253 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Webアプリケーションディレクトリ [C:\apache-tomcat-8.5.51\webapps\docs] を配備します
15-Feb-2020 16:59:55.583 警告 [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom セッション ID を生成するための SecureRandom インスタンスの作成に [147] ミリ秒かかりました。アルゴリズムは [147] です。
15-Feb-2020 16:59:55.599 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory ディレクトリ [C:\apache-tomcat-8.5.51\webapps\docs] の Web アプリケーションの配置は [346] ms で完了しました。
15-Feb-2020 16:59:55.599 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Webアプリケーションディレクトリ [C:\apache-tomcat-8.5.51\webapps\examples] を配備します
15-Feb-2020 16:59:55.898 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory ディレクトリ [C:\apache-tomcat-8.5.51\webapps\examples] の Web アプリケーションの配置は [299] ms で完了しました。
15-Feb-2020 16:59:55.898 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Webアプリケーションディレクトリ [C:\apache-tomcat-8.5.51\webapps\host-manager] を配備します
15-Feb-2020 16:59:55.944 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory ディレクトリ [C:\apache-tomcat-8.5.51\webapps\host-manager] の Web アプリケーションの配置は [46] ms で完了しました。
15-Feb-2020 16:59:55.945 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Webアプリケーションディレクトリ [C:\apache-tomcat-8.5.51\webapps\manager] を配備します
15-Feb-2020 16:59:55.972 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory ディレクトリ [C:\apache-tomcat-8.5.51\webapps\manager] の Web アプリケーションの配置は [27] ms で完了しました。
15-Feb-2020 16:59:55.972 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Webアプリケーションディレクトリ [C:\apache-tomcat-8.5.51\webapps\ROOT] を配備します
15-Feb-2020 16:59:55.995 情報 [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory ディレクトリ [C:\apache-tomcat-8.5.51\webapps\ROOT] の Web アプリケーションの配置は [23] ms で完了しました。
15-Feb-2020 16:59:56.000 情報 [main] org.apache.coyote.AbstractProtocol.start プロトコルハンドラー ["http-nio-8080"] を開始しました。
15-Feb-2020 16:59:56.011 情報 [main] org.apache.catalina.startup.Catalina.start Server startup in 797 ms

最後にブラウザからアクセスして、Tomcatが起動したかを確認します。
「http://localhost:8080/」をブラウザのURLバーに入力し、起動確認します。

Tomcatの起動確認

上記のTomcat画面が表示されれば、Tomcatの起動成功です。


ちなみに、起動は「startup.bat」ですが、終了は「shutdown.bat」になります。
「shutdown.bat」を実行すると、Tomcatは停止されます。


ApacheとTomcatのバージョン確認


インストールしたApacheとTomcatのバージョンを確認しておきます。

Apacheのバージョンは、DOSプロンプトで以下のコマンドを実行します。

c:\Apache24\bin>httpd -v
Server version: Apache/2.4.41 (Win64)
Apache Lounge VC14 Server built:   Aug 12 2019 10:48:01

インストールしたApacheのバージョンが「2.4.41」であることがわります。


次にTomcatのバージョンを確認します。
Tomcatのバージョンは、インストールされた「version.bat」を実行します。

C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin>version.bat
Using CATALINA_BASE:   "C:\Program Files\Apache Software Foundation\Tomcat 8.5"
Using CATALINA_HOME:   "C:\Program Files\Apache Software Foundation\Tomcat 8.5"
Using CATALINA_TMPDIR: "C:\Program Files\Apache Software Foundation\Tomcat 8.5\temp"
Using JRE_HOME:        "C:\Program Files\Java\jdk1.8.0_60"
Using CLASSPATH:       "C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\bootstrap.jar;C:\Program Files\Apache Software Foundation\Tomcat 8.5\bin\tomcat-juli.jar"
Server version: Apache Tomcat/8.0.41.0
Server built:   Sep 28 2017 10:30:11 UTC
Server number:  8.0.41.0
OS Name:        Windows 10
OS Version:     10.0
Architecture:   amd64
JVM Version:    1.8.0_60-b27
JVM Vendor:     Oracle Corporation

インストールしたTomcatのバージョンが「8.0.41」であることがわります。



ApacheとTomcatの連携設定


最後に、ApacheとTomcatの連携をおこないます。
Apacheでリクエストを受け付け、受け付けたリクエストをTomcatに転送します。


Tomcatに連携するドキュメントルートを準備


Tomcatに新たなドキュメントルートを設けます。
最終的に、ここで作成するドキュメントルートについて、Apacheと連携します。


今回は、Tomcatのドキュメントルートに「test」というフォルダを作成し、HelloWorldを表示するHTMLを準備します。


Tomcatにアクセスし、配置した「helloWorld.html」がブラウザで表示されることを確認します。
ブラウザで「http://localhost:8080/test/helloWorld.html」を入力して確認します。

ドキュメントルートの設定

この時点では、まだApacheとTomcatの接続はおこなわれていません。
8080ポートでアクセスしているので、現時点ではまだTomcat直接アクセスになっています。


8080ポートを停止し、AJPプロトコルでの接続準備


現時点では8080ポートで直接接続が可能な状態ですが、Apache経由での接続に切り替えるため、8080ポートでの直接接続を出来ないようにします。


Tomcatインストールディレクトリの「\conf\server.xml」をひらき、8080ポートでの接続設定をコメントアウトします。

    <!--					
    <Connector port="8080" protocol="HTTP/1.1"					
               connectionTimeout="20000"					
               redirectPort="8443" />					
    -->					

server.xmlの修正が完了したらTomcatを再起動します。

再起動が完了したら、再度、8080ポートへのアクセスをおこない、アクセスできなかったら設定変更は成功です。

server.xmlの設定変更

次に、「AJP/1.3」を使用してApacheとの接続準備をおこないます。
インストール時点でserver.xmlに設定が入っている場合もあれば、設定が入っているがコメントアウトされている場合もあります。
筆者のTomcatインストール時点ではコメントアウトされていたので、Apacheとの接続設定部分についてコメントアウトをはずしておきます。

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               redirectPort="8443" />

server.xmlの修正が完了したらTomcatを再起動します。
しかし、上記の設定(デフォルト)では、エラーが出てしまい起動に失敗してしまいました。

15-Feb-2020 17:50:18.727 重大 [main] org.apache.catalina.core.StandardService.startInternal Failed to start connector [Connector[AJP/1.3-8009]]		
	org.apache.catalina.LifecycleException: プロトコルハンドラの起動に失敗しました	
		at org.apache.catalina.connector.Connector.startInternal(Connector.java:1057)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		at org.apache.catalina.core.StandardService.startInternal(StandardService.java:440)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:766)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		at org.apache.catalina.startup.Catalina.start(Catalina.java:688)
		at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
		at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
		at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
		at java.lang.reflect.Method.invoke(Method.java:497)
		at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343)
		at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:474)
	Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.	
		at org.apache.coyote.ajp.AbstractAjpProtocol.start(AbstractAjpProtocol.java:274)
		at org.apache.catalina.connector.Connector.startInternal(Connector.java:1055)
		... 12 more

どうやら「secretRequired」というオプションの設定が必須のようです。
この設定は、AJPコネクタを信頼できないサイトと接続する際に使用するオプションのようです。
Tomcatのマニュアルに「信頼できるサイトと接続する場合にのみfalseを設定すること」とあるので、今回は「false」を設定します。


    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               secretRequired="false"
               redirectPort="8443" />

server.xmlの修正が完了したらTomcatを再起動し、エラーが発生せずに起動が完了したら変更完了です。


Apacheの設定


最後にApacheの設定をおこないます。
Apache側でproxy_ajpを使用するようにします。


proxy_ajpを使用するためには、Apacheのproxy_ajpモジュールを使用するようにします。
使用するモジュールは以下の2つです。


  • mod_proxy.so
  • mod_proxy_ajp.so

Apacheのhttpd.conf内をモジュール名で検索し、以下のようにコメントアウトをはずします。

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so

一応、Apacheを再起動して無事に起動すること(モジュールを使えるようになったこと)を確認します。

Apacheの起動確認

最後に、ApacheにTomcatとの接続設定をおこないます。
以下の設定を追加します。

<Location /test/>					
    ProxyPass ajp://localhost:8009/test/					
</Location>					

この設定を「httpd.conf」に追加すればよいのですが、Apacheの記述ルールに従って記述を追加します。
「httpd-proxy.conf」を作成し、上記の記述を追加し、「httpd.conf」の中に「httpd-proxy.conf」の読み込み設定をおこなえば設定完了です。


Include conf/extra/httpd-proxy.conf

最後にApacheを再起動して無事に起動が完了したら設定完了です。


これで、ApacheとTomcatがAJPを使用して接続されました。
以下のURLをブラウザに入力して、最終確認します。


http://localhost:81/test/helloWorld.html

ApacheとTomcatの接続設定

Apacheのデフォルトポートに設定した「81」を経由して、Tomcat上に格納したHelloWorldを表示するHTMLの表示がおこなわれました。




cpコマンド(コピー)の使い方。覚えておくと便利なオプションも解説。

Linux

前回、lsコマンドの使い方、覚えておくと便利なオプションについて紹介させてもらいました。



今回は、コピーコマンドについて紹介していきます。
コピーコマンドについても、Linuxで作業をおこなう上では必須のコマンドになります。
こちらもまた、使わない人はいないでしょう。


メジャーなオプションからマイナーなオプションまで、いろいろ説明していきます。


頻繁に使うコマンドなのであまり忘れることはないオプションが多いかもしれませんが、参考にしてください。


同名ファイルが存在する場合はバックアップ作成(-b)


コピー先に同名ファイルが存在する場合、バックアップファイルを作成します。
「-b」オプションを使用します。


$ ls -la
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:31 .
drwxr-xr-x 5 xxx yyy 4096 2019-07-28 23:49 ..
-rw-r--r-- 1 xxx yyy    5 2020-01-29 01:31 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:31 src.txt
$ cp -b src.txt dest.txt
$ ls -la
total 20
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:31 .
drwxr-xr-x 5 xxx yyy 4096 2019-07-28 23:49 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:31 dest.txt
-rw-r--r-- 1 xxx yyy    5 2020-01-29 01:31 dest.txt~
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:31 src.txt

上記コマンド結果のようになります。
コピー先に既に「dest.txt」というファイルが既に存在するので、コピー先に存在していた「dest.txt」をバックアップファイルとして退避しています。


強制上書き(-f)


OS自体の設定にもよりますが、ファイルをコピーすると上書きになる場合、「上書きします。よろしいですか?」のメッセージが表示されます。
「-f」オプション、または、「–force」オプションを使用すると、この上書き確認メッセージを表示しません。


$ ls -la
total 12
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:34 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    0 2020-01-29 01:36 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:34 src.txt
$ cp -f src.txt dest.txt
$ ls -la
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:34 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:34 src.txt

上記コマンド結果のように、同じファイル名でコピーしたとしても、上書き確認メッセージは表示されません。


必ず上書き確認メッセージを表示(-i)


先ほどの強制上書きでも記載しましたが、「上書きします。よろしいですか?」のメッセージが表示されるかどうかは、OS自体の設定に依存します。
「-i」オプション、または、「–interactive」オプションを使用すると、上書き確認メッセージを必ず表示することができます。


$ ls -la
total 12
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:49 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    0 2020-01-29 01:49 src.txt
$ cp -i dest.txt src.txt
cp: overwrite `src.txt'? yes
$ ls -la
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 01:49 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:49 src.txt

上記コマンド結果のように、上書きコピー時に「 overwrite `src.txt’?」という確認メッセージを表示しています。
yesと入力すると、ファイルが上書き更新されます。


同名ファイルの場合は上書きしない(-n)


同名ファイルを上書きしたくない場合は、「-n」オプション、または、「–no-clobber」オプションを指定すると、上書きは行われません。


$ ls -la
total 12
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 02:08 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    0 2020-01-29 02:04 src.txt
$ cp -n dest.txt src.txt
$ ls -la
total 12
drwxr-xr-x 2 xxx yyy 4096 2020-01-29 02:08 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    0 2020-01-29 02:04 src.txt

属性情報(タイムスタンプなど)をそのままにしてコピー(-p)


タイムスタンプ・グループ・所有者といった属性情報はそのままにしてコピーする場合は「-p」オプション、または、「–preserve」オプションを指定します。


$ ls -la
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:35 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-02-05 00:38 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 src.txt
$ cp -p src.txt dest.txt
$ ls -la
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:35 .
drwxr-xr-x 5 xxx yyy 4096 2020-01-29 01:36 ..
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 src.txt

フォルダをコピー/再帰的にコピー(-r)


フォルダをコピーする場合は「-r」オプションを指定します。

このオプションを指定すれば、フォルダの中身がそのまま表示されます。

フォルダをコピーというよりも、フォルダの中身を再帰的にコピーするという動きになります。


$ ls -la
total 12
drwxr-xr-x 3 xxx yyy 4096 2020-02-05 00:49 .
drwxr-xr-x 8 xxx yyy 4096 2019-09-10 01:01 ..
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:35 dir
$
$
$ ls -la ./dir/
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:35 .
drwxr-xr-x 3 xxx yyy 4096 2020-02-05 00:49 ..
-rw-r--r-- 1 xxx yyy    4 2020-02-05 00:40 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-01-29 01:43 src.txt
$ cp -r dir dir2
$ ls -la
total 16
drwxr-xr-x 4 xxx yyy 4096 2020-02-05 00:50 .
drwxr-xr-x 8 xxx yyy 4096 2019-09-10 01:01 ..
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:35 dir
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:50 dir2
$ ls -la ./dir2/
total 16
drwxr-xr-x 2 xxx yyy 4096 2020-02-05 00:50 .
drwxr-xr-x 4 xxx yyy 4096 2020-02-05 00:50 ..
-rw-r--r-- 1 xxx yyy    4 2020-02-05 00:50 dest.txt
-rw-r--r-- 1 xxx yyy    4 2020-02-05 00:50 src.txt