Spring Boot Ajax/JavaScript連携

Spring BootでHttpヘッダーに値を設定し取得してみた

HTTPは、Webサーバーとクライアント(ブラウザ)の間で、ウェブページを送受信するためのプロトコルで、以下のページに示すように、HTTPメッセージはヘッダーとボディを含んでいる。
http://www.tohoho-web.com/ex/http.htm

今回は、HTTPボディでなくHTTPヘッダーに値を設定し取得するサンプルプログラムを作成してみたので、共有する。

前提条件

下記記事の実装が完了していること。

IntelliJ IDEA上でGradleを使ってWeb画面のSpring Bootプロジェクトを作成してみたSpring Bootのプロジェクトを新規作成を「IntelliJ IDEA」のメニューから実施しようとしたところ、無料の「Commun...

サンプルプログラムの作成

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加/変更したプログラムである。

まず、ログインFormの内容は以下の通りで、ユーザーID・ユーザー名・パスワードをもっている。

package com.example.demo;

import lombok.Data;

@Data
public class LoginForm {

    /** ユーザーID */
    private String userId;

    /** ユーザー名 */
    private String userName;

    /** パスワード */
    private String userPass;

}



次に、ログイン画面のHTMLの内容は以下の通りで、ログインボタンが押下されたタイミングで、JavaScriptのlogin関数を呼び出すようになっている。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" th:src="@{/login.js}"></script>
    <title>index page</title>
</head>
<body>
<p>下記必要事項を記載の上、ログインボタンを押下してください。</p><br/>
<form th:object="${loginForm}">
    ユーザーID: <input type="text" th:value="*{userId}" th:field="*{userId}" />
    <br/>
    ユーザー名: <input type="text" size="40" maxlength="40" th:value="*{userName}" th:field="*{userName}" />
    <br/>
    パスワード: <input type="password" size="40" maxlength="40" th:value="*{userPass}" th:field="*{userPass}" />
    <br/><br/>
    <input type="button" value="ログイン" onclick="login();" />
</form>
</body>
</html>



さらに、メイン画面のHTMLの内容は以下の通りで、ログアウトボタンが押下されたタイミングで、JavaScriptのlogout関数を呼び出すようになっている。

<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" th:src="@{/login.js}"></script>
    <title>index page</title>
</head>
<body>
<p>ユーザーID、ユーザー名は以下の通りです。</p><br/>
<form th:object="${loginForm}">
    <span th:text="'ユーザーID: ' + ${uId}">ここにユーザーIDが表示されます</span>
    <br/>
    <span th:text="'ユーザー名: ' + ${uName}">ここにユーザー名が表示されます</span>
    <br/><br/>
    <input type="button" value="ログアウト" onclick="logout();" />
</form>
</body>
</html>



また、JavaScriptの内容は以下の通りで、ログイン・ログアウト処理が含まれている。ログイン処理では、ユーザー情報をHttpヘッダーに設定した後で、コントローラのsetUserSessionメソッド・toMainメソッドを順に呼び出すようになっていて、ログアウト処理では、コントローラのlogoutメソッドを呼び出すようになっている。

'use strict';

// ログインを行う
function login(){
    // フォームオブジェクトを取得する
    let form = document.getElementsByTagName('form')[0];
    if(!form){
        alert('フォームが取得できませんでした');
        return;
    }
    // ユーザーID、ユーザー名、パスワードを取得する
    let userId = '';
    let userName = '';
    let userPass = '';
    const userIdElem = document.getElementById('userId');
    if(userIdElem){
        userId = userIdElem.value;
    }
    const userNameElem = document.getElementById('userName');
    if(userNameElem){
        userName = userNameElem.value;
    }
    const userPassElem = document.getElementById('userPass');
    if(userPassElem){
        userPass = userPassElem.value;
    }
    // XMLHttpRequestオブジェクトを生成し、
    // ユーザー情報をHttpヘッダーに設定した後で、
    // ユーザー情報をセッションに設定する処理を非同期で呼び出す
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'setUserSession');
    xhr.setRequestHeader('userId', encodeURIComponent(userId));
    xhr.setRequestHeader('userName', encodeURIComponent(userName));
    xhr.setRequestHeader('userPass', encodeURIComponent(userPass));
    xhr.send(null);
    xhr.onreadystatechange = function() {
        // ユーザー情報をセッションに設定後
        // (非同期通信で結果が返ってきた後に下記if文が実行される)
        if(xhr.readyState === 4 && xhr.status === 200) {
            // メイン画面に遷移する
            form.action = 'toMain';
            form.method = 'post';
            form.submit();
        }
    }
}
// ログアウトを行う
function logout(){
    // フォームオブジェクトを取得する
    let form = document.getElementsByTagName('form')[0];
    if(!form){
        alert('フォームが取得できませんでした');
        return;
    }
    // ユーザー情報をセッションから削除し、ログアウトする
    form.action = 'logout';
    form.method = 'post';
    form.submit();
}



さらに、コントローラクラスの内容は以下の通りで、setUserSessionメソッドでHttpヘッダーからユーザー情報を取得するようになっている。

package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

@Controller
public class LoginController {

    /**
     * Formオブジェクトを初期化して返却する
     * @return Formオブジェクト
     */
    @ModelAttribute("loginForm")
    public LoginForm createLoginForm(){
        LoginForm loginForm = new LoginForm();
        return loginForm;
    }

    /**
     * ログイン画面に遷移する
     * @return ログイン画面へのパス
     */
    @GetMapping("/")
    public String toLogin(){
        return "login";
    }

    /**
     * ユーザー情報を取得し、セッションに設定する
     * @param request HttpServletRequestオブジェクト
     * @param session HttpSessionオブジェクト
     * @return ログイン画面へのパス
     */
    @GetMapping("/setUserSession")
    public String setUserSession(HttpServletRequest request, HttpSession session){
        // ユーザーID・ユーザー名・パスワードをHttpヘッダーから取得し、コンソールに出力
        String userId = decodeByUTF8(request.getHeader("userId"));
        String userName = decodeByUTF8(request.getHeader("userName"));
        String userPass = decodeByUTF8(request.getHeader("userPass"));
        System.out.println("userId : " + userId
                + ", userName : " + userName + ", userPass : " + userPass);

        // ユーザーID・ユーザー名をセッションに設定し、ログイン画面に遷移
        session.setAttribute("userId", userId);
        session.setAttribute("userName", userName);
        return "login";
    }

    /**
     * ユーザー情報をセッションから取得し、メイン画面に遷移する
     * @param session HttpSessionオブジェクト
     * @param model Modelオブジェクト
     * @return メイン画面へのパス
     */
    @PostMapping("/toMain")
    public String toMain(HttpSession session, Model model){
        // ユーザーID・ユーザー名をセッションから取得
        String userId = (String)session.getAttribute("userId");
        String userName = (String)session.getAttribute("userName");

        // 取得したユーザーID・ユーザー名をModelオブジェクトに設定し、メイン画面に遷移
        model.addAttribute("uId", userId);
        model.addAttribute("uName", userName);
        return "main";
    }

    /**
     * ユーザー情報をセッションから破棄し、ログイン画面に遷移する
     * @param session HttpSessionオブジェクト
     * @return ログイン画面へのパス
     */
    @PostMapping("/logout")
    public String logout(HttpSession session){
        // セッションからユーザーID・ユーザー名を破棄し、ログイン画面に遷移
        session.removeAttribute("userId");
        session.removeAttribute("userName");
        return "login";
    }

    /**
     * 指定された文字列をUTF-8でデコードする
     * @param str デコード前文字列
     * @return デコード後文字列
     */
    private String decodeByUTF8(String str){
        String afterStr = null;
        try{
            afterStr = URLDecoder.decode(str, "UTF-8");
        }catch(UnsupportedEncodingException ex){
            System.err.println(ex);
        }
        return afterStr;
    }
}



その他、build.gradleの内容は以下の通りで、lombokを利用するための設定が追加されている。

plugins {
	id 'org.springframework.boot' version '2.1.7.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//lombokを利用するための設定
	compileOnly 'org.projectlombok:lombok:1.18.10'
	annotationProcessor 'org.projectlombok:lombok:1.18.10'
}

サンプルプログラムの実行結果

サンプルプログラムの実行結果は、以下の通り。

1) Spring Bootアプリケーションを起動し、「http://(サーバー名):(ポート番号)/」とアクセスすると、以下の画面が表示される。
サンプルプログラムの実行結果_1

2) ユーザーID、ユーザー名、パスワードを入力し「ログイン」ボタンを押下する。なお、パスワードには「pass」と入力するものとする。
サンプルプログラムの実行結果_2

3) 下記メイン画面に遷移することが確認できる。
サンプルプログラムの実行結果_3_1

また、コンソールログには、以下の赤枠のように、ユーザーID・ユーザー名・パスワードが出力されていることが確認できる。
サンプルプログラムの実行結果_3_2

4) メイン画面で「ログアウト」ボタンを押下すると、以下のように、ログアウトすることが確認できる。
サンプルプログラムの実行結果_4_1

サンプルプログラムの実行結果_4_2

要点まとめ

  • Httpヘッダーに値を設定するには、JavaScript内でXMLHttpRequestオブジェクトを利用すればよい。
  • Httpヘッダーから値を取得するには、JavaでHttpServletRequestクラスのgetHeaderメソッドを利用すればよい。