初めに
本記事は、Dockerを勉強中(2週間ほど)の投稿者のメモとして使用する記事のため、正しい情報とは限りません。ご注意ください。
本記事は、以下を参考にしております。
Spring boot + Vue.js + MySql + VS Code + Docker で開発環境を構築する
上記URLです
https://qiita.com/PoKoPoKoTa2ry/items/2f9b54518b8158809192
今回目指すもの
タイトルの通りDocker、VSCode,SpringBoot,Mybatis,Gradle,MySQL,Vue.jsを連携した簡易アプリ(検索ボタンを押すとDBのデータが表に反映される)の作成を目指す。また、Bootstrap5(見た目)やVue-Router(ルーティング)、axios(FEとBE間の通信)等も使用します。
前提事項
DockerやVSCodeのインストール、VSCodeの拡張機能(Spring Initializrとかlombokなど)がある程度インストールされていること
使用環境について
本記事で、タイトルの通りDocker、VSCode、SpringBoot、Mybatis、Gradle、MySQL、Vue.jsを使用した開発環境となります。以下は使用環境のバージョンになります。
OSは、Macを使用しております。
macOS Montery 12.3.1
Client:
Cloud integration: v1.0.22
Version: 20.10.11
API version: 1.41
Go version: go1.16.10
Git commit: dea9396
Built: Thu Nov 18 00:36:09 2021
OS/Arch: darwin/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.11
API version: 1.41 (minimum version 1.12)
Go version: go1.16.9
Git commit: 847da18
Built: Thu Nov 18 00:35:39 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.12
GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc:
Version: 1.0.2
GitCommit: v1.0.2-0-g52b36a2
docker-init:
Version: 0.19.0
GitCommit: de40ad0
plugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'war'
}
group = 'app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
------------------------------------------------------------
Gradle 7.4
------------------------------------------------------------
Build time: 2022-02-08 09:58:38 UTC
Revision: f0d9291c04b90b59445041eaa75b2ee744162586
Kotlin: 1.5.31
Groovy: 3.0.9
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 16.0.1 (Oracle Corporation 16.0.1+9-24)
OS: Mac OS X 11.3 x86_64
openjdk version "1.8.0_332"
OpenJDK Runtime Environment (build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (build 25.332-b09, mixed mode)
mysql Ver 8.0.29 for Linux on x86_64 (MySQL Community Server - GPL)
app@0.1.0 /usr/src/app
+-- @vue/cli-plugin-babel@5.0.4
| `-- @vue/babel-preset-app@5.0.4
| `-- vue@3.2.33 deduped
+-- bootstrap-vue@2.22.0
| `-- portal-vue@2.1.7
| `-- vue@2.6.14
+-- vue-router@4.0.13
| `-- vue@3.2.33 deduped
`-- vue@3.2.33
`-- @vue/server-renderer@3.2.33
`-- vue@3.2.33 deduped
手順の大まかな流れ
①最低限のフォルダ、ファイル構成の準備 #shを作ったので実行するだけ
②Dockerfileや設定ファイルの作成
③spring_projectの作成 #spring initializrを使用
④コンテナの作成(DockerのBuildを実施)
⑤vue_projectの作成(vue-cliのインストール等の実施)
⑥DBの作成(Tableの作成やデータの挿入)
⑦開発1(Vue.js編)
⑧開発2(Spring編)
⑨動作確認
⑩コンテナの削除
次の見出しから手順です。
手順1:ファイル・フォルダ構成の確認・準備
初めに準備する最低限のファイル・フォルダの構成です。
任意の場所で作成してください。フォルダ名は任意に設定して問題ないですがこの後に作成するDockerfileの指定するパスが変更されるので注意してください。
「*」はファイルです
「-」はフォルダです
・プロジェクト名(名前は任意)
-.devcontainer
*devcontainer.json
-docker
-mysql
-settings
-sql
*init.sql
*Dockerfile
*my.cnf
-spring
*Dockerfile
-vue
*Dockerfile
*docker-compose.yml
-spring_project
-vue_project
*gitkeep
以下のようなシェルを作成し、任意の場所で実行すれば、上記の最低限のフォルダやファイルを作成します。
※spring_projectはSpring Initializrでこの後別途作成するので作りません。
#!/bin/bash
echo -n "任意のプロジェクト名を入力してください:"
read PROJECTNAME
mkdir $PROJECTNAME
#devcontainer関連を作成
mkdir $PROJECTNAME/.devcontainer
touch $PROJECTNAME/.devcontainer/devcontainer.json
mkdir $PROJECTNAME/docker
#mysql関連を作成
mkdir $PROJECTNAME/docker/mysql
mkdir $PROJECTNAME/docker/mysql/settings
mkdir $PROJECTNAME/docker/mysql/sql
touch $PROJECTNAME/docker/mysql/sql/init.sql
touch $PROJECTNAME/docker/mysql/Dockerfile
touch $PROJECTNAME/docker/mysql/my.cnf
#spring関連を作成
mkdir $PROJECTNAME/docker/spring
touch $PROJECTNAME/docker/spring/Dockerfile
#vue関連を作成
mkdir $PROJECTNAME/docker/vue
touch $PROJECTNAME/docker/vue/Dockerfile
#docker-compose.ymlを作成
touch $PROJECTNAME/docker/docker-compose.yml
#vue_project関連を作成
mkdir $PROJECTNAME/vue_project
touch $PROJECTNAME/vue_project/gitkeep
cd $PROJECTNAME
#VSCodeを起動
code .
任意の場所で実行する
sh ./init.sh
プロジェクト名を「Docker_Spring_Vue_MySQL」で作成する
手順2:Dockerfileや設定ファイル等の作成
(1)docker-compose.ymlの作成
version: '3.6'
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
build: ./mysql
environment:
MYSQL_DATABASE: "testdb" #DBの名前は任意に設定してください
MYSQL_ROOT_USER: "root" #root権限のユーザ名は任意に設定してください
MYSQL_ROOT_PASSWORD: "root" #root権限のパスワードは任意に設定してください
MYSQL_USER: "user" #作業ユーザ権限のユーザ名は任意に設定してください
MYSQL_PASSWORD: "user" #作業ユーザ権限のパスワードは任意に設定してください
TZ: "Asia/Tokyo"
ports:
- 3306:3306
volumes:
- ./mysql/sql:/docker-entrypoint-initdb.d # 「:」の左がローカル環境で右がコンテナの環境
- ./mysql/settings/:/var/lib/mysql # 「:」の左がローカル環境で右がコンテナの環境
spring:
image: openjdk:8
container_name: spring
build: ./spring
depends_on:
- mysql
ports:
- "8080:8080"
tty: true
volumes:
- ../spring_project:/srv:cached # 「:」の左がローカル環境で右がコンテナの環境
working_dir: /srv
vue:
container_name: vue
build: ./vue
ports:
- 9000:8080
volumes:
- ../vue_project:/usr/src/app:cached # 「:」の左がローカル環境で右がコンテナの環境
stdin_open: true
tty: true
volumes:
mysql_db:
driver: local
(2)mysqlのDockerfileと設定ファイル等の作成
FROM mysql
EXPOSE 3306
ADD ./my.cnf /etc/mysql/conf.d/my.cnf
CMD ["mysqld"]
[mysqld]
character-set-server=utf8
[mysql]
default-character-set=utf8
[client]
default-character-set=utf8
テーブルの作成とデータを挿入する任意のSQL文を作成してください
CREATE DATABASE IF NOT EXISTS testdb;
CREATE TABLE IF NOT EXISTS user(
id INTEGER not null,
name varchar(20) not null,
PRIMARY KEY (id, name)
);
INSERT INTO user(id, name)VALUES(1, 'Tarou');
(3)springのDockerfileの作成
FROM openjdk:8
VOLUME /tmp
WORKDIR /app
(4)vueのDockerfileの作成
FROM node:14
WORKDIR /usr/src/app/
RUN npm install -g npm && \
npm install -g @vue/cli
手順3:spring_projectの作成
Spring Initializrを使用して、spring_projectを作成します。
本手順では、VSCodeの拡張機能を使用しています。
「Spring Boot Extension Pack」をインストールすれば、自動で必要な拡張機能がインストールされるはずです。
「command + shift + p」を押下し、「Spring Initializr: Create Gradle Project...」を選択
「バージョン2.6.7」を選択
「Java」を選択
デフォルトのパッケージ名を決めます。
何でも良いかと思いますが、今回はシンプルに「app」とします。
プロジェクト名を決めます。
「spring_project」にします。任意のプロジェクト名にしたい場合は、「docker-compose.yml」の「volumes:」の「spring_project」を任意のプロジェクト名と一致させる必要があるので注意してください。
今回、デプロイまでは実施しないのでどちらでも構いません。一応「War」で実施します。
Javaのバージョン8を選択します。変更したい場合は、「docker-compose.yml」と「spring」の「Dockerfile」の修正も必要になります。
依存ライブラリを注入します。
いくつ追加していただいても構いませんが、最低限以下のものを追加してください。
Spring Boot Devtools
Lombok
Spring Web
Mybatis Framework
MySQL Driver
「Generate into this folder」を押下
プロジェクトの作成成功すると以下のように「spring_project」が追加されます。
手順4:コンテナの作成
dockerコマンドを実行して、コンテナの作成を行います。
$ cd docker
$ docker-compose build
(以下のようになればOK)
Building mysql
[+] Building 50.4s (7/7) FINISHED
...
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Building spring
[+] Building 70.9s (6/6) FINISHED
...
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Building vue
[+] Building 214.9s (7/7) FINISHED
...
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
$ docker-compose up -d
(以下のようになればOK)
Creating network "docker_default" with the default driver
Creating vue ... done
Creating mysql ... done
Creating spring ... done
「docker-compose build」実行時に以下のようなエラーが出た場合は、「code ERR_SOCKET_TIMEOUT」とあるようにタイムアウトなので再度実行を試してみてください。
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Building vue
[+] Building 181.0s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 36B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/node:14 2.1s
=> [1/3] FROM docker.io/library/node:14@sha256:2f39686f6d0b2687550659367fa11f56018a0f782b7e30f1a0ea56b11dece124 0.0s
=> CACHED [2/3] WORKDIR /usr/src/app/ 0.0s
=> ERROR [3/3] RUN npm install -g npm && npm install -g @vue/cli 178.7s
------
> [3/3] RUN npm install -g npm && npm install -g @vue/cli:
#6 32.47 /usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js
#6 32.47 /usr/local/bin/npx -> /usr/local/lib/node_modules/npm/bin/npx-cli.js
#6 32.60 + npm@8.9.0
#6 32.60 added 63 packages from 18 contributors, removed 299 packages and updated 138 packages in 30.03s
#6 178.6 npm ERR! code ERR_SOCKET_TIMEOUT
#6 178.6 npm ERR! errno ERR_SOCKET_TIMEOUT
#6 178.6 npm ERR! network Invalid response body while trying to fetch https://registry.npmjs.org/express: Socket timeout
#6 178.6 npm ERR! network This is a problem related to network connectivity.
#6 178.6 npm ERR! network In most cases you are behind a proxy or have bad network settings.
#6 178.6 npm ERR! network
#6 178.6 npm ERR! network If you are behind a proxy, please make sure that the
#6 178.6 npm ERR! network 'proxy' config is set properly. See: 'npm help config'
#6 178.6
#6 178.6 npm ERR! A complete log of this run can be found in:
#6 178.6 npm ERR! /root/.npm/_logs/2022-05-08T14_52_17_816Z-debug-0.log
------
executor failed running [/bin/sh -c npm install -g npm && npm install -g @vue/cli]: exit code: 1
ERROR: Service 'vue' failed to build : Build failed
$ docker exec -it mysql /bin/bash
root@06d477b04065:/# mysql --version
(以下が表示されればMySQLは正常にインストールされる。)
mysql Ver 8.0.29 for Linux on x86_64 (MySQL Community Server - GPL)
root@06d477b04065:/# exit
exit
docker $ docker exec -it spring /bin/bash
root@3fcb4e4b0fe5:/srv# java -version
(以下が表示されればJavaは正常にインストールされる。)
openjdk version "1.8.0_332"
OpenJDK Runtime Environment (build 1.8.0_332-b09)
OpenJDK 64-Bit Server VM (build 25.332-b09, mixed mode)
root@3fcb4e4b0fe5:/srv# exit
exit
docker $ docker exec -it vue /bin/bash
root@8fcff5f29ed5:/usr/src/app# npm -version
(以下が表示されればNode.jsは正常にインストールされる。)
8.9.0
root@8fcff5f29ed5:/usr/src/app# node --version
(以下が表示されればNode.jsは正常にインストールされる。)
v14.19.1
root@8fcff5f29ed5:/usr/src/app# exit
exit
Gitを使用する方は一旦この辺りでpushしましょう。
手順5:vue_projectの作成
$ docker exec -it vue /bin/bash
root@8fcff5f29ed5:/usr/src/app# vue create .
Vue CLI v5.0.4
? Generate project in current directory? (Y/n) Y
Vue CLI v5.0.4
? Please pick a preset: (Use arrow keys)
> Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
Manually select features
Vue CLI v5.0.4
? Please pick a preset: Default ([Vue 3] babel, eslint)
? Pick the package manager to use when installing dependencies:
USE Yarn
> USE NPM
(以下のようになればVueのインストール成功)
...
🎉 Successfully created project app.
👉 Get started with the following commands:
$ npm run serve
Vueの実行をして、正常にインストールされた確認します。
root@b330486c1252:/usr/src/app# npm run serve
(以下のようになれば成功)
> app@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 26011ms 4:24:15 PM
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.0.3:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
ブラウザで以下のURLにアクセスし、以下の画像のように表示されるか確認する。
http://localhost:9000/
手順6:DBの作成(Tableの作成やデータの挿入)
コンテナ作成時に既にデータは挿入されているはずですが、もしない場合は、以下のコマンドを試してください。
$ docker-compose exec mysql /bin/bash
root@5edee7944240:/# mysql -h 127.0.0.1 -P 3306 -uroot -proot
mysql> show databases;
mysql> use testdb;
mysql> show tables;
mysql> select * from user;
(データがあれば問題なし、なかったら以下を実行する)
mysql> source /docker-entrypoint-initdb.d/init.sql;
mysql> select * from user;
(以下のように表示されれば成功)
+----+-------+
| id | name |
+----+-------+
| 1 | Tarou |
+----+-------+
手順7:開発1(Vue.js編)
以下は作成する機能の大まかなイメージです。
(1)ホーム画面(Home.vue):検索画面(Search.vue)にアクセスできる
(2)検索画面(Search.vue):検索ボタンがあり、押下すると表にデータが表示される。ホーム画面(Home.vue)に戻る
(3)ヘッダー(Header.vue):ホーム画面(Home.vue)、検索画面(Search.vue)共通のヘッダー
Vue.jsの開発は以下のものを作成します。
(1)モジュールのインストール(Bootstrap5)
(2)モジュールのインストール(Vue Router)
(3)モジュールのインストール(axios)
(4)main.jsの修正
(5)vue.config.jsの修正
(6)route.jsの作成
(7)Header.vueの作成
(8)Home.vueの作成
(9)Search.vueの作成
(10)App.vueの修正
(11)Vueの動作確認
(1) モジュールのインストール(Bootstrap5)
Vue.jsでBootstrap5を使えるようにします。
$ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm install vue bootstrap-vue bootstrap
npm WARN deprecated popper.js@1.16.1: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
added 16 packages, and audited 940 packages in 1m
100 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
警告メッセージが出るかもしれませんが、一旦無視していただいても問題ないと思います。
(いくつか調べましたがうまくいきませんでした。すみません・・・)
一応調べたことを記載しときます。
$ docker exec -it vue /bin/bash
(1) 警告メッセージのとおり、「popper」のバージョンが古いと言われているので、新しいバージョンにする。
npm uninstall @popperjs/core
npm install @popperjs/core
(2)以下のコマンドを実行
npm audit fix
npm audit fix --force
※もしかしたらvueのバージョンが変更される可能性があるのでその場合は
$ npm uninstall vue
$ npm install vue@3.2.13
動作確認は他のモジュールのインストールが終わった後に行います。
(2)モジュールのインストール(Vue Router)
Vue Routerをインストールします。
$ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm install vue-router@4
added 2 packages, and audited 957 packages in 8s
101 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
(3)モジュールのインストール(axios)
axiosをインストールします。
docker $ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm install axios
added 5 packages, and audited 962 packages in 8s
101 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
(4)main.jsの修正
main.jsを以下のように修正してください。
import App from './App.vue'
import router from './router/router.js'
import { createApp } from 'vue'
import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap/dist/js/bootstrap.js"
createApp(App).use(router).mount('#app')
(5)vue.config.jsの修正
vue.config.jsを以下のように修正してください。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
configureWebpack: {
devtool: 'source-map',
},
})
(6)route.jsの作成
「.Docker_Spring_Vue_MySQL/vue_project/src/」の下に「route」フォルダーを作成し、「route」フォルダー内に「route.js」を新規作成します。
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../pages/Home.vue'
import Search from '../pages/app/Search.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/search',
name: 'Search',
component: Search
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
(7)Header.vueの作成
「GameGenreSelector/vue_project/src/components/」の下に「Header.vue」を新規作成します。
<template>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a class="nav-link active" aria-current="page" href="/">Home</a>
<a class="nav-link" href="/search">search</a>
</div>
</div>
</div>
</nav>
</template>
(8)Home.vueの作成
GameGenreSelector/vue_project/src/の下に「pages」フォルダーを作成し、「pages」フォルダー内に「Home.vue」を新規作成します。
<template>
<h1>Home</h1>
</template>
(9)Search.vueの作成
GameGenreSelector/vue_project/src/の下に「app」フォルダーを作成し、「app」フォルダー内に「Search.vue」を新規作成します。
<template>
<div>
<button @click="search" type="button" class="btn btn-primary">検索</button>
<table class="table">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">ユーザ名</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.message">
<th scope="row">{{item.id}}</th>
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import axios from 'axios';
export default {
data(){
return{
items: []
}
},
methods: {
search (){
axios
.get('http://localhost:8080/search')
.then(
response => {
for (let i=0; i<response.data.length; i++) {
this.items.push(response.data[i]);
}
console.log(this.items);
}
).catch(
error => {
let errorData1 = {id: 2, name: "Jirou"};
let errorData2 = {id: 3, name: "Saburou"};
this.items.push(errorData1);
this.items.push(errorData2);
}
);
}
}
}
</script>
(10)App.vueの修正
vue.config.jsを以下のように修正してください。
<template>
<div id="app">
<Header/>
<router-view name="Header"></router-view>
<router-view></router-view>
</div>
</template>
<script>
import Header from './components/Header'
export default {
name: 'App',
components: {
Header
}
}
</script>
(11)Vueの動作確認
お待たせしました。Vueの動作確認をしましょう。
docker $ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm run serve
> app@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 37356ms 3:48:51 PM
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.0.3:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
もし警告メッセージが出た場合は次のコマンドを実行してください。
docker $ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm run serve
> app@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
WARNING Compiled with 1 warning 3:37:56 PM
warning in ./node_modules/bootstrap/dist/css/bootstrap.min.css
Module Warning (from ./node_modules/postcss-loader/dist/cjs.js):
Warning
(6:29521) autoprefixer: Replace color-adjust to print-color-adjust. The color-adjust shorthand is currently deprecated.
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.0.3:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
####(このコマンドを実行)####
root@b330486c1252:/usr/src/app# npm install autoprefixer@10.4.5 --save-exact
changed 1 package, and audited 962 packages in 11s
101 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
####(再度をサービスを起動する)####
root@b330486c1252:/usr/src/app# npm run serve
> app@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 37356ms 3:48:51 PM
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.0.3:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
ブラウザでアクセスしてください。
http://localhost:9000/
検索画面へアクセス(searchをクリック)してください。
または以下へブラウザでアクセスしてください。
http://localhost:9000/search
・Bootstrap5はナビゲーションバーやボタンのレイアウトが上手くいけば成功です。
・Vue Routerは画面遷移が上手くいっていたら成功です。
・axiosはまだspringと連携していないので、catchで作成したerrorData1,errorData2の内容が反映されていれば成功です。
お疲れ様です。これで、Vueの開発は成功です。
次からSpringの開発を行います。
手順8:開発2(Spring編)
初めにVSCodeで「Remote Development」と「Remote - SSH: Editing Configuration Files」の拡張機能をインストールしましょう。コンテナ内のspringプロジェクトを直接操作したりデバッグ等をするのに使用します。
次に、今まで触れていなかった「.Docker_Spring_Vue_MySQL/.devcontainer/」の「devcontainer.json」を作成しましょう。
{
"name": "spring-vue-mysql",
"workspaceFolder": "/srv",
"dockerComposeFile": "../docker/docker-compose.yml",
"settings": {
// Macの場合
"terminal.integrated.defaultProfile.osx": "/bin/bash"
// Windows(WSL)の場合(おそらく・・・動作確認はしていません。)
// "terminal.integrated.defaultProfile.linux": "/bin/bash",
},
"service": "spring", //attachするコンテナはspringを指定
"extensions": [
"vscjava.vscode-java-pack", // JavaExtensionPack
"pivotal.vscode-boot-dev-pack", // Spring Boot Extension Pack
"gabrielbb.vscode-lombok" //Lombok Annotations Support For VS Code
]
}
作成したら、VSCodeの左下、歯車(設定)の下の「><」のような部分をクリックしましょう。
次に、「Reopen in Container Remote-Containers」を選択します。
すると以下のようにVSCodeが切り替わると思います。
springのプロジェクトが表示されていると思います。
最初はインストール等を行なうので時間がかかるかもしれが、時間がたてば上記のようにspringのプロジェクトが表示されるはずです。
お待たせしました。それでは、Springの開発を始めましょう。
以下は作成する機能の大まかなイメージです。
(1)検索ボタン押下後、DBにアクセスし、user情報を取得する。
(2)取得したDBの情報を画面に返す
Springの開発は以下のものを作成します。
(1)application.propertiesの設定
(2)Accessorの実装
(3)Interfaceの実装
(4)Controllerの実装
(5)Mapper.javaの実装
(6)Mapper.xmlの実装
(7)Serviceの実装
(8)実行
(1)application.propertiesの設定
「application.properties」はMySQLへ接続するための設定を記載します。そのために、VSCodeではないターミナルを開いて、MySQLのコンテナに入り、catコマンドでコンテナのIPアドレスを調べましょう。
$ docker exec -it mysql /bin/bash
root@5edee7944240:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.19.0.3 5edee7944240
catコマンドの最後のIPアドレスが自身のMySQLが存在する環境のIPアドレスです。
今回、投稿者の場合は、「172.19.0.3」ですが、人によってIPアドレスは違うと思うので任意で読み替えてください。
それでは、「application.properties」の設定を行いましょう。
#※localhostを指定すると、springコンテナのIPアドレスを指定していることになるのでエラーになる
#spring.datasource.url=jdbc:mysql://localhost:3306/testdb
#※IPアドレスに注意(localhost:3306はコンテナが違うため)
spring.datasource.url=jdbc:mysql://172.19.0.3:3306/testdb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.configuration.map-underscore-to-camel-case=true
##以下はログ詳細に出してくれるものなのであってもなくても良いです。
# Web関連のロガーのログレベルをDEBUG or TRACEへ
logging.level.web=trace
# Spring MVCへのリクエスト/レスポンスログの詳細情報出力を有効化
spring.mvc.log-request-details=true
ローカル環境だと1行目のようにlocalhostと指定しがちですが、localhostを指定するとspringコンテナのIPアドレスを指定していることになるのでMySQLのコンテナのIPアドレスと異なるので接続できずにエラーになってしまいます。
なので最初に、catコマンドでMySQLのコンテナのIPアドレスを調べてもらいました。
(2)Accessorの実装
DBからデータを取得するときと画面にデータを返すための「UserInfo.java」を実装しましょう。
package app.spring_project.testapp.accessors;
import lombok.Data;
@Data
public class UserInfo {
private int id;
private String name;
}
(3)Interfaceの実装
ControllerクラスとServiceクラスを繋げるためのInterfaceを実装します。
package app.spring_project.testapp.interfaces;
import java.util.List;
import app.spring_project.testapp.accessors.UserInfo;
public interface SearchServiceImpl {
List<UserInfo> callService();
}
(4)Controllerの実装
Controllerの実装をします。今回は検索機能なので「SearchController.java」を実装しましょう。
「Search.vue」のaxiosで「 http://localhost:8080/search 」にリクエストしているのでそれを受け取れるようにします。
package app.spring_project.testapp.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import app.spring_project.testapp.accessors.UserInfo;
import app.spring_project.testapp.interfaces.SearchServiceImpl;
@RestController
@CrossOrigin(origins = {"http://localhost:9000"})
public class SearchController {
@Autowired
private SearchServiceImpl service;
@RequestMapping("/search")
public List<UserInfo> search() {
return service.callService();
}
}
(5)Mapper.javaの実装
検索するSQLを呼び出すためのインターフェース、「SearchMapper.java」を実装しましょう。
package app.spring_project.testapp.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import app.spring_project.testapp.accessors.UserInfo;
@Mapper
public interface SearchMapper {
List<UserInfo> selectUser();
}
(6)Mapper.xmlの実装
「user」テーブルから「id,name」を取得するSQLを作成するために「SearchMapper.xml」を実装しましょう。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="app.spring_project.testapp.mapper.SearchMapper">
<select id="selectUser" resultType="app.spring_project.testapp.accessors.UserInfo">
SELECT id, name FROM user
</select>
</mapper>
(7)Serviceの実装
SQL結果を呼び出す「SearchService.java」クラスを実装しましょう。
package app.spring_project.testapp.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import app.spring_project.testapp.accessors.UserInfo;
import app.spring_project.testapp.interfaces.SearchServiceImpl;
import app.spring_project.testapp.mapper.SearchMapper;
@Service
public class SearchService implements SearchServiceImpl{
@Autowired
private SearchMapper mapper;
@Override
public List<UserInfo> callService() {
return mapper.selectUser();
}
}
(8)spring実行
「/srv/src/main/java/app/spring_project/SpringProjectApplication.java」を開くとmainメソッドの上に「Run | Debug」と表示されていると思うのでどちらでも構いませんがクリックするとspringのプロジェクトがされるのでエラーがないか確認しましょう。
自分は一度以下のエラーに合いました。原因は正確にはわからなかったのですが、最初は「SearchMapper.xml」の2~4行目()の部分を1行にしていたのですが、改行させました。また、「~[/srv/bin/main/app/spring_project/testapp/mapper/SearchMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.」のようなエラーが出ていたので、「SearchMapper.xml」の1~4行目をそのままコピペして、エラーが出るかもしれません。手入力してみると良いかもしれません。
root@e1c653c4dcd1:/srv# cd /srv ; /usr/bin/env /usr/local/openjdk-8/bin/java -cp /tmp/cp_3eelvnh0sq5e0cqtb2r7qdf0l.jar app.spring_project.SpringProjectApplication
12:01:52.636 [Thread-2] DEBUG org.springframework.boot.devtools.restart.classloader.RestartClassLoader - Created RestartClassLoader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@5de3c9de
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.7)
2022-05-10 12:01:59.957 INFO 59857 --- [ restartedMain] a.s.SpringProjectApplication : Starting SpringProjectApplication using Java 1.8.0_332 on e1c653c4dcd1 with PID 59857 (/srv/bin/main started by root in /srv)
2022-05-10 12:01:59.981 INFO 59857 --- [ restartedMain] a.s.SpringProjectApplication : No active profile set, falling back to 1 default profile: "default"
2022-05-10 12:02:01.171 INFO 59857 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2022-05-10 12:02:20.938 INFO 59857 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-05-10 12:02:21.049 INFO 59857 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-05-10 12:02:21.051 INFO 59857 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.62]
2022-05-10 12:02:21.568 INFO 59857 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-05-10 12:02:21.569 INFO 59857 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 20391 ms
2022-05-10 12:02:21.603 TRACE 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Added existing Servlet initializer bean 'dispatcherServletRegistration'; order=2147483647, resource=class path resource [org/springframework/boot/autoconfigure/web/servlet/DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration.class]
2022-05-10 12:02:21.732 TRACE 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'characterEncodingFilter'; order=-2147483648, resource=class path resource [org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.class]
2022-05-10 12:02:21.739 TRACE 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'formContentFilter'; order=-9900, resource=class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]
2022-05-10 12:02:21.742 TRACE 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'requestContextFilter'; order=-105, resource=class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]
2022-05-10 12:02:21.805 DEBUG 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Mapping filters: characterEncodingFilter urls=[/*] order=-2147483648, formContentFilter urls=[/*] order=-9900, requestContextFilter urls=[/*] order=-105
2022-05-10 12:02:21.806 DEBUG 59857 --- [ restartedMain] o.s.b.w.s.ServletContextInitializerBeans : Mapping servlets: dispatcherServlet urls=[/]
2022-05-10 12:02:24.262 ERROR 59857 --- [ restartedMain] o.m.spring.mapper.MapperFactoryBean : Error while adding the mapper 'interface app.spring_project.testapp.mapper.SearchMapper' to configuration.
org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:263) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.parsing.XPathParser.<init>(XPathParser.java:127) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:81) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:76) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.loadXmlResource(MapperAnnotationBuilder.java:178) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:118) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:72) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:864) ~[mybatis-3.5.9.jar:3.5.9]
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:80) ~[mybatis-spring-2.0.7.jar:2.0.7]
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44) [spring-tx-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) [spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.7.jar:2.6.7]
at app.spring_project.SpringProjectApplication.main(SpringProjectApplication.java:10) ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_332]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_332]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_332]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_332]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.6.7.jar:2.6.7]
Caused by: org.xml.sax.SAXParseException: Premature end of file.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:399) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:326) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1466) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:1013) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:601) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:504) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:338) ~[na:1.8.0_332]
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:261) ~[mybatis-3.5.9.jar:3.5.9]
... 60 common frames omitted
2022-05-10 12:02:24.332 WARN 59857 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchController': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchService': Unsatisfied dependency expressed through field 'mapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'searchMapper' defined in file [/srv/bin/main/app/spring_project/testapp/mapper/SearchMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
2022-05-10 12:02:24.488 INFO 59857 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2022-05-10 12:02:24.761 INFO 59857 --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-05-10 12:02:25.476 ERROR 59857 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchController': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchService': Unsatisfied dependency expressed through field 'mapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'searchMapper' defined in file [/srv/bin/main/app/spring_project/testapp/mapper/SearchMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) [spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) [spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) [spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) [spring-boot-2.6.7.jar:2.6.7]
at app.spring_project.SpringProjectApplication.main(SpringProjectApplication.java:10) [main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_332]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_332]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_332]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_332]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.6.7.jar:2.6.7]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'searchService': Unsatisfied dependency expressed through field 'mapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'searchMapper' defined in file [/srv/bin/main/app/spring_project/testapp/mapper/SearchMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:659) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:639) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.19.jar:5.3.19]
... 25 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'searchMapper' defined in file [/srv/bin/main/app/spring_project/testapp/mapper/SearchMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.19.jar:5.3.19]
... 39 common frames omitted
Caused by: java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:83) ~[mybatis-spring-2.0.7.jar:2.0.7]
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44) ~[spring-tx-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.19.jar:5.3.19]
... 49 common frames omitted
Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; Premature end of file.
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:263) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.parsing.XPathParser.<init>(XPathParser.java:127) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:81) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.xml.XMLMapperBuilder.<init>(XMLMapperBuilder.java:76) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.loadXmlResource(MapperAnnotationBuilder.java:178) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.builder.annotation.MapperAnnotationBuilder.parse(MapperAnnotationBuilder.java:118) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:72) ~[mybatis-3.5.9.jar:3.5.9]
at org.apache.ibatis.session.Configuration.addMapper(Configuration.java:864) ~[mybatis-3.5.9.jar:3.5.9]
at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:80) ~[mybatis-spring-2.0.7.jar:2.0.7]
... 52 common frames omitted
Caused by: org.xml.sax.SAXParseException: Premature end of file.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:399) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:326) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLScanner.reportFatalError(XMLScanner.java:1466) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:1013) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:601) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:504) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243) ~[na:1.8.0_332]
at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:338) ~[na:1.8.0_332]
at org.apache.ibatis.parsing.XPathParser.createDocument(XPathParser.java:261) ~[mybatis-3.5.9.jar:3.5.9]
... 60 common frames omitted
...
お疲れ様です。これでspringの開発も完了です。
手順9:動作確認
お待たせしました。これでやっと動作確認ができますね。
springとvueの両方を起動します。springは直前の手順で起動していると思うのでvueを起動します。
docker $ docker exec -it vue /bin/bash
root@b330486c1252:/usr/src/app# npm run serve
> app@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 22511ms 1:21:14 PM
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.0.2:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
以下にブラウザでアクセスします。
http://localhost:9000/
手順10:コンテナの削除
docker $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b7a254a3fe openjdk:8 "bash" 12 seconds ago Up 10 seconds 0.0.0.0:8080->8080/tcp spring
29099a8d550f mysql:8.0 "docker-entrypoint.s…" 15 seconds ago Up 12 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
0224b9a6d45f docker_vue "docker-entrypoint.s…" 15 seconds ago Up 12 seconds 0.0.0.0:9000->8080/tcp vue
docker $ docker-compose down
Stopping spring ... done
Stopping mysql ... done
Stopping vue ... done
Removing spring ... done
Removing mysql ... done
Removing vue ... done
Removing network docker_default
docker $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
次のコマンドで未使用リソースの全削除もあり
docker $ docker system prune -a
これで終わりです。
最後に
大変長い記事になってしまい申し訳ございません。最後にいくつか自分が上手くいかなかった、つまずいた部分についてと解消した方法についてです。
(1) springの実行でエラーになる。
- Mybatisに関するエラーで、SearchMapper.xmlの1~4行目の修正でうまくいった。
- アノテーションのつけ忘れ。@Mapper,@Service, @Controllerなど
(2) springの実行でエラーにならないが、DBアクセスでエラーになる。
- apprication.propertiesの修正(mysqlコンテナのIPアドレスの確認)
(3) なぜか、lombokが読み込めない。
- 何回か、「Reopen in Container Remote-Containers」でspringコンテナに入ったり出たりを繰り返す。
以上、ここまでお読みいただきありがとうございます。もしかしたら誤字やミスがあるかもしれません。その場合はご指摘いただけると助かります。