TechHotoke’s diary

日々の学びについて記事としてまとめてます。

Vue×SpringでSPA作成①【プロジェクト作成から初期画面表示まで】

f:id:TechHotoke:20211216134840p:plain

目的

VueとSpringで作成したプロジェクトの構築手順の備忘録。

備忘録のため、詳細な説明を省略している部分があります。

前提

基本的なJavaの知識やSpring、Vueの知識があること。

環境

  • Java 11
  • Spring Boot2.5.6
  • Gradle 7.1.1 * Vue3
  • Vue2.6
  • IDESTS

プロジェクト構築手順

  • 新規プロジェクト作成 build.gradleを下記に転載しておきます。 SpringSecurity、MysqlDriverなどもプロジェクト作成時に追加しています。
    plugins {
        id 'org.springframework.boot' version '2.5.6'
        id 'io.spring.dependency-management' version '1.0.11.RELEASE'
        id 'java'
    }
    
    group = 'com.example'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-security'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
        runtimeOnly 'mysql:mysql-connector-java'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testImplementation 'org.springframework.security:spring-security-test'
    }
    
    test {
        useJUnitPlatform()
    }
  • プロジェクトの起動が正常に行われるか確認

適当なDBを作成し(DBの作成方法は割愛します。MySQL8.0を使用しています)設定ファイル(application.propertiesをのちのち本番環境と開発環境で分けたいので、application-dev.propertiesを作成)を下記のように記述してDBとの接続設定を行う application.properties

spring.profiles.active=dev

application-dev.properties

spring.session.store-type=jdbc
spring.datasource.url=jdbc:mysql://127.0.0.1:[任意のポート番号]/[DB名]
spring.datasource.username=${設定した環境変数名}
spring.datasource.password=${設定した環境変数名}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

f:id:TechHotoke:20211114120548p:plain

SpringSecurityを入れているので、添付画像のようにデフォルトログインフォームが表示されれば問題なしです。

Vue CLIのインストール

続いてVueCLIのインストールを行って行きます。

  • パッケージ管理ツールのインストールなどセットアップ手順は省略ます。今回はnpmを使用しています。

  • ターミナルでvue uiの実行

f:id:TechHotoke:20211114120717p:plain

添付画像のようなダッシュボードが表示されます。

  • Vueプロジェクトマネージャで作成をクリック「作成したプロジェクト名/src」を開き、「ここに新しいプロジェクトを作成する」をクリックプロジェクトフォルダに任意のフォルダ名を入力して次へをクリック。今回はfrontendとします。

  • デフォルトプリセットを選択して「プロジェクトを作成する」をクリック。 今回はVueの3系を使用したいのでそちらを選択します。

  • プロジェクト作成後、Vue用のディレクトリに配置したいので、設置→Vue CLI→公開パスに「/frontend」を指定して変更

  • 保存をクリック。設定を完了すると成果物が作成されます。

  • Vue CLIのローカルサーバのポートがSpring Bootと被るため package.jsonのscriptsのserveプロパティを変更。今回は8081を使用します。

**"scripts": {    
    "serve": "vue-cli-service serve --port 8081",    
    "build": "vue-cli-service build",   
    "lint": "vue-cli-service lint"  },**
{
  publicPath: '/frontend',
  outputDir: "../../src/main/resources/static/frontend"
}

SpringBootのビルド時にVueのビルドも行えるようにする

目的

Gitによるソースコード管理は「.vue」ファイルのみにして、ビルドして生成される「.js」は管理せずに将来的にデプロイした際にSpringのビルド時に一緒にVueのソースもビルドされ、配置されることが理想的です。なのでこのような設定が行えるようにbuid.gradleファイルを修正していきます。

build.gradle

task npmRunBuild() {
    doFirst{
        if (!file("${rootDir}/src/frontend/node_modules").exists()) {
            "npm --prefix ${rootDir}/src/frontend install ${rootDir}/src/frontend"
                    .execute()
                    .waitForProcessOutput(System.out, System.err)
        } else {
            "npm --prefix ${rootDir}/src/frontend run build"
                .execute()
                .waitForProcessOutput(System.out, System.err)
        }
    }
}

processResources {
    dependsOn npmRunBuild
}

ここまでで、gradleプロジェクトのリフレッシュを行い、gradle buildコマンドを実行する。 添付画像のようにstaticディレクトリ配下に成果物が生成されていればOKです。

f:id:TechHotoke:20211114120702p:plain

Historyモードの実現

目的

historyモードを実現する場合、API以外のURLに対するアクセスはSPAを返却する必要があるため、存在しないURLへのアクセスは固定でファイルを返すよう指定したい。

実装

添付画像のような階層にBaseController.javaという名称のファイルを作成し f:id:TechHotoke:20211114120630p:plain

固定ファイルにforwardするように実装します。

@Controller
public class BaseController {
    @GetMapping(path = "/")
    public String getSpa() {
        return "forward:frontend/index.html";
    }
}

続いてHtml5HistoryModeResourceConfigという名称のファイルを以下のディレクトリ構成で作成する f:id:TechHotoke:20211114120709p:plain

package jp.co.templeworksystem.config;

import java.io.IOException;

import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;

/**
 * 対応しないURLの場合、固定ページを返す。
 */
@Configuration
public class Html5HistoryModeResourceConfig implements WebMvcConfigurer {
 
    private final Resources resourceProperties = new Resources();
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**") // 全パスをこのリソースハンドラーの処理対象にする
                .addResourceLocations(resourceProperties.getStaticLocations()) // 静的リソース配置先のパスを指定する
                .resourceChain(resourceProperties.getChain().isCache()) // 開発時はfalse、本番はtrueが望ましい。trueにしておくとメモリ上にキャッシュされるためI/Oが軽減される
                .addResolver(new SpaPageResourceResolver()); // 拡張したPathResourceResolverを読み込ませる
    }
 
    public static class SpaPageResourceResolver extends PathResourceResolver {
        @Override
        protected Resource getResource(String resourcePath, Resource location) throws IOException {
            Resource resource = super.getResource(resourcePath, location); // まずはPathResourceResolverで静的リソースを取得する
            return resource != null ? resource : super.getResource("/frontend/index.html", location); // 取得できなかった場合は、index.htmlを返す
        }
    }
}

起動の確認

プロジェクトをクリーンビルドしてアプリケーションを実行する。

ポート番号8080でアクセスした時にログインフォームからログインし、下記画面が表示されれば完了です。

f:id:TechHotoke:20211114120713p:plain

ここまで読んでいただきありがとうございます。