オブジェクト指向とかデザインパターンとか開発プロセスとかツールとか

satoshi's ソフトウェア開発

js






当サイトはアフィリエイト広告を利用してます。

Java node.js Vue.js

vue.js と Spring boot でWebアプリを作ってみる

投稿日:


最近流行りの vue.js を Spring boot と組み合わせてWebアプリを作ってみます。

参考したサイトはこちら。

[Full-stack] Spring Boot + Vue.js: CRUD example

参考にしたサイトでは Tutorial をエンティティにしてますが、ここでは Book をエンティティとする bookshelf アプリケーションにしてみます。

まずは、Spring bootのプロジェクトから作成していきます。

Spring bootのプロジェクトを作成する

ファイルメニューから「新規Springスタータープロジェクト」を選択して、プロジェクトを作成します。

依存関係は、Spring Data JPA と H2 Database と Spring Web を選択しておきます。

依存しているライブラリが自動的にダウンロードされるまで、しばらく待ちます。

プロジェクト・エクスプローラーの表示が以下のように変化したら準備完了です。

src/main/resources にある application.properties ファイルを開き、H2データベースにアクセスするための設定をします。

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true

Bookエンティティを作成する

新規-クラスでBookクラスを作成します。

package jp.bookshelf;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;
	
	@Column
	private String title;
	
	@Column
	private String author;

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}
}

BookRepositoryを作成する

次にリポジトリインタフェースを作ります。

新規-インタフェースでBookRepositoryインタフェースを作成します。
拡張インタフェースで JpaRepository を指定します。

package jp.bookshelf;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

public interface BookRepository extends JpaRepository<Book, Long> {
	List<Book> findByTitle(String title);
	List<Book> findByAuthor(String author);
}

BookControllerを作成する

新規-クラスでBookControllerクラスを作成します。

package jp.bookshelf;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin(origins = "http://localhost:8081")
@RestController
@RequestMapping("/api")
public class BookController {
	@Autowired
	BookRepository bookRepository;
	
	@GetMapping("/books")
	public ResponseEntity<List<Book>> getBooks(@RequestParam(required = false) String title) {
		List<Book> list = bookRepository.findByTitle(title);
		return new ResponseEntity<List<Book>>(list, HttpStatus.OK);
	}
	
	@GetMapping("/books/{id}")
	public ResponseEntity<Book> getBookById(@PathVariable("id") Long id) {
		Optional<Book> data = bookRepository.findById(id);
		if (data.isPresent()) {
			return new ResponseEntity<Book>(data.get(), HttpStatus.OK);
		}
		return new ResponseEntity<Book>(HttpStatus.NOT_FOUND);
	}

	@PostMapping("/books")
	public ResponseEntity<Book> createBook(@RequestBody Book book) {
		Book b = bookRepository.saveAndFlush(book);
		return new ResponseEntity<Book>(b, HttpStatus.OK);
	}
	
	@PutMapping("/books/{id}")
	public ResponseEntity<Book> updateBook(@RequestBody Book book) {
		book = bookRepository.saveAndFlush(book);
		return new ResponseEntity<Book>(book, HttpStatus.OK);
	}
	
	@DeleteMapping("/books")
	public ResponseEntity<HttpStatus> deleteBook(@PathVariable("id") long id) {
		bookRepository.deleteById(id);
		return new ResponseEntity<HttpStatus>(HttpStatus.OK);
	}
}

フロントエンドを vue.js で作成する

次は、フロントエンドを vue.js で作ってみましょう。

参考サイトでは、以下のコマンドで vue プロジェクトを作れと言ってます。

% vue create vue-js-client-crud

これは、vue CLI だそうです。
インストールしないといけないようです。

% npm install -g vue-cli
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated coffee-script@1.12.7: CoffeeScript on NPM has moved to "coffeescript" (no hyphen)
npm WARN deprecated vue-cli@2.9.6: This package has been deprecated in favour of @vue/cli

added 245 packages, and audited 246 packages in 18s

10 packages are looking for funding
  run `npm fund` for details

4 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
npm notice
npm notice New minor version of npm available! 8.3.1 -> 8.4.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.4.1
npm notice Run npm install -g npm@8.4.1 to update!
npm notice

インストールできたか、確認します。

% vue --version
2.9.6

大丈夫みたいです。

vueプロジェクトを作成しましょう。
Spring boot プロジェクトのディレクトリ直下に vjs という名前でプロジェクトを作ります。

% vue create vjs

  vue create is a Vue CLI 3 only command and you are using Vue CLI 2.9.6.
  You may want to run the following to upgrade to Vue CLI 3:

  npm uninstall -g vue-cli
  npm install -g @vue/cli

なんか、怒られた感じです。

提示されたふたつのコマンドを実行します。

% npm uninstall -g vue-cli

removed 245 packages, and audited 1 package in 2s

found 0 vulnerabilities
% npm install -g @vue/cli
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated apollo-tracing@0.15.0: The `apollo-tracing` package is no longer part of Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#tracing for details
npm WARN deprecated graphql-extensions@0.15.0: The `graphql-extensions` API has been removed from Apollo Server 3. Use the plugin API instead: https://www.apollographql.com/docs/apollo-server/integrations/plugins/
npm WARN deprecated apollo-cache-control@0.14.0: The functionality provided by the `apollo-cache-control` package is built in to `apollo-server-core` starting with Apollo Server 3. See https://www.apollographql.com/docs/apollo-server/migration/#cachecontrol for details.
npm WARN deprecated @hapi/topo@3.1.6: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/hoek@8.5.1: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/bourne@1.3.2: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/address@2.1.4: Moved to 'npm install @sideway/address'
npm WARN deprecated @hapi/joi@15.1.1: Switch to 'npm install joi'
npm WARN deprecated graphql-tools@4.0.8: This package has been deprecated and now it only exports makeExecutableSchema.\nAnd it will no longer receive updates.\nWe recommend you to migrate to scoped packages such as @graphql-tools/schema, @graphql-tools/utils and etc.\nCheck out https://www.graphql-tools.com to learn what package you should use instead

added 945 packages, and audited 946 packages in 1m

68 packages are looking for funding
  run `npm fund` for details

13 vulnerabilities (6 moderate, 7 high)

Some issues need review, and may require choosing
a different dependency.

Run `npm audit` for details.

気を取り直してもう一度createします。

% vue create vjs
Vue CLI v4.5.15
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 2] babel, eslint)
  Default (Vue 3) ([Vue 3] babel, eslint)
  Manually select features

何か選択しろって言われてますので、とりあえず、そのままでEnterしておきます。

Vue CLI v4.5.15
? Please pick a preset: Default ([Vue 2] babel, eslint)


Vue CLI v4.5.15
✨  Creating project in /Users/satoshis/Documents/workspace/bookshelf/vjs.
🗃  Initializing git repository...
⚙️  Installing CLI plugins. This might take a while...


added 1285 packages, and audited 1286 packages in 1m

86 packages are looking for funding
  run `npm fund` for details

70 vulnerabilities (2 low, 57 moderate, 11 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
🚀  Invoking generators...
📦  Installing additional dependencies...


added 55 packages, and audited 1341 packages in 5s

91 packages are looking for funding
  run `npm fund` for details

72 vulnerabilities (2 low, 59 moderate, 11 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project vjs.
👉  Get started with the following commands:

 $ cd vjs
 $ npm run serve

Eclipseでプロジェクトをリフレッシュすると、以下のような構成で作られています。

Spring boot 上で動かしてみる

Spring boot 上で Vue を動かすには、vue をビルドしないといけないらしいです。
ただし、ビルドした JavaScript ファイルを Spring boot で動かすためには、src/main/resources/static に配置する必要があります。
package.json を変更します。

[json]
{
"name": "web",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build --dest ../src/main/resources/static/",
"lint": "vue-cli-service lint"
},
[/json]

ビルドしてみます。

% npm run build

> vjs@0.1.0 build /Users/satoshis/Documents/workspace/bookshelf/vjs
> vue-cli-service build --dest ../src/main/resources/static/


⠧  Building for production...

 WARNING  Compiled with 17 warnings                                                                                          19:40:46

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'computed' was not found in 'vue'

 warning  in ./src/router.js

"export 'default' (imported as 'Router') was not found in 'vue-router'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'defineComponent' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'getCurrentInstance' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'h' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'inject' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'nextTick' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'onActivated' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'onDeactivated' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'onUnmounted' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'provide' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'reactive' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'ref' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'shallowRef' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'unref' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'watch' was not found in 'vue'

 warning  in ../node_modules/vue-router/dist/vue-router.esm-bundler.js

"export 'watchEffect' was not found in 'vue'

  File                                                          Size                             Gzipped

  ../src/main/resources/static/js/chunk-vendors.0a90606c.js     100.24 KiB                       35.94 KiB
  ../src/main/resources/static/js/chunk-a020b95a.5f445348.js    23.58 KiB                        8.18 KiB
  ../src/main/resources/static/js/app.3b3d464e.js               3.62 KiB                         1.73 KiB
  ../src/main/resources/static/js/chunk-2d21767c.356128dc.js    2.12 KiB                         0.82 KiB
  ../src/main/resources/static/js/chunk-2d0ba6fb.906a32b7.js    1.89 KiB                         0.85 KiB
  ../src/main/resources/static/js/chunk-2d0bd7a8.7172d8bc.js    1.68 KiB                         0.73 KiB
  ../src/main/resources/static/css/app.d40fc157.css             0.16 KiB                         0.14 KiB

  Images and other types of assets omitted.

 DONE  Build complete. The ../src/main/resources/static directory is ready to be deployed.
 INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html

なんか、いっぱい Warning が出てしまいました。
ぐぐってみると、node.js のバージョンがよろしくないみたいです。

node.js を latest ではなく stable に変えてみます。

% nodebrew install-binary stable
Fetching: https://nodejs.org/dist/v16.13.2/node-v16.13.2-darwin-x64.tar.gz
############################################################################################################################## 100.0%
Installed successfully
% nodebrew ls
v16.13.2
v17.4.0

current: v17.4.0
% nodebrew use 16.13.2
use v16.13.2

ビルドしなおしてみます。

% npm run build

> web@0.1.0 build
> vue-cli-service build


⠙  Building for production...

 DONE  Compiled successfully in 2214ms                                                                                       23:51:49

  File                                 Size                                          Gzipped

  dist/js/chunk-vendors.e4229be5.js    95.12 KiB                                     34.05 KiB
  dist/js/app.6a32d4e9.js              4.58 KiB                                      1.63 KiB
  dist/css/app.fb0c6e1c.css            0.33 KiB                                      0.23 KiB

  Images and other types of assets omitted.

 DONE  Build complete. The dist directory is ready to be deployed.
 INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html

今度は、Warningなど出ないで、正常にビルドできたようです。
Spring boot を起動してアクセスしてみます。

動きました!

動いたところで、次は参考サイトに合わせた感じでカスタマイズしていきましょう。

コンポーネントを作成する

参考サイトでは、唐突に、次のように書かれてます。

After the process is done. We create new folders and files like the following tree:

いきなり、AddTutorial.vue・Tutorial.vue・TutorialList.vue・TutorialDataService.js の4つのファイルが出現します。
しかし、ファイルの内容についてはまったく触れられてないのです。

ぐぐってみたら、Githubにそれっぽいソースコードが出てましたので、そちらを参考にコードを書いていきます。

Github - danielcgithub/vue-getting-started

AddBook.vue

<template>
	<div class="submit-form">
		<div v-if="!submitted">
			<div class="form-group">
				<label for="title">Title</label>
				<input type="text" name="title" class="form-control"
					id="title" required v-model="book.title"
				/>
			</div>
			<div class="form-group">
				<label for="author">Author</label>
				<input type="text" name="author" class="form-control"
					id="author" required v-model="book.author"
				/>
			</div>
			<button @click="saveBook" class="btn btn-success">Submit</button>
		</div>
		<div v-else>
			<p>Submit successed!</p>
			<button class="btn btn-success" @click="newBook">Add</button>
		</div>
	</div>
</template>

<script>
import BookDataService from "../services/BookDataService";

export default {
	name: "add-book",
	data() {
		return {
			book: {
				id: null,
				title: "",
				author: ""
			},
			submitted: false
		};
	},
	methods: {
		saveBook() {
			var data = {
				title: this.book.title,
				author: this.book.author
			};
			BookDataService.create(data)
			.then(response => {
				this.book.id = response.data.id;

			})
			.catch(e => {
				console.log(e);
			});
		},

		newBook() {
			this.submitted = false;
			this.book = {}
		}
	}
};
</script>

Book.vue

<template>
	<div v-if="currentBook" class="edit-form">
		<h4>Book</h4>
		<form>
			<div class="form-group">
				<label for="title">Title</label>
				<input type="text" class="form-control" id="title" v-model="currentBook.title"/>
			</div>
			<div class="form-group">
				<label for="author">Author</label>
				<input type="text" class="form-control" id="author" v-model="currentBook.author" />
			</div>
		</form>
		<button class="badge badge-primary mr-2" @click="deleteBook">Delete</button>
		<button type="submit" class="badge badge-success" @click="updateBook">Update</button>
		<p>{{ message }}</p>
	</div>
	<div v-else>
		<br />
		<p>Click Book</p>
	</div>
</template>

<script>
import BookDataService from "../services/BookDataService";

export default {
	name: "book",
	data() {
		return {
			currentBook: null,
			message: ''
		};
	},
	methods: {
		getBook(id) {
			BookDataService.get(id)
			.then(response => {
				this.currentBook = response.data;
				console.log(response.data);
			})
			.catch(e => {
				console.log(e);
			});
		},

		updateBook() {
			BookDataService.update(this.currentBook.id, this.currentBook)
			.then(response => {
				console.log(response.data);
				this.message = 'The book updated.';
			})
			.catch(e => {
				console.log(e);
			});
		},

		deleteBook() {
			BookDataService.delete(this.currentBook.id)
			.then(response => {
				console.log(response.data);
				this.$router.push({ name: "books" });
			})
			.catch(e => {
				console.log(e);
			});
		}
	},
	mounted() {
		this.message = '';
		this.getBook(this.$route.params.id);
	}
};
</script>

BookList.vue

<template>
	<div class="list row">
		<div class="col-md-8">
			<input type="text" class="form-control" placeholder="Search by title" v-model="title" />
			<div class="input-group-append">
				<button class="btn btn-outline-secondary" type="button" @click="searchTitle">Search</button>
			</div>
		</div>
		<div class="col-md-6">
			<h4>Book List</h4>
			<ul class="list-group">
				<li class="list-group-item" :class="{ active: index == currentIndex }"
					v-for="(book, index) in books" :key="index"
					@click="setActiveBook(book, index)">{{ book.title }}
				</li>
			</ul>
		</div>
		<div class="col-md-6">
			<div v-if="currentBook">
				<h4>Book</h4>
				<div>{{ currentBook.title }}</div>
				<div>{{ currentBook.author }}</div>
				<a class="badge badge-warning" :href="'/books' + currentBook.id">Edit</a>
			</div>
		</div>
	</div>
</template>

<script>
import BookDataService from "../services/BookDataService";

export default {
	name: "books-list",
	data() {
		return {
			books: [],
			currentBook: null,
			currentIndex: -1,
			title: ""
		};
	},
	methods: {
		retrieveBooks() {
			BookDataService.getAll()
			.then(response => {
				this.books = response.data;
				console.log(response.data);
			})
			.catch(e => {
				console.log(e);
			});
		},

		setActiveBook(book, index) {
			this.currentBook = book;
			this.currentIndex = index;
		},

		searchTitle() {
			BookDataService.findByTitle(this.title)
			.then(response => {
				this.books = response.data;
				console.log(response.data);
			})
			.catch(e => {
				console.log(e);
			});
		}
	},
	mounted() {
		this.retrieveBooks();
	}
}
</script>

BookDataService.js

import http from "../http-common";

class BookDataService {
	getAll() {
		return http.get("/books");
	}

	get(id) {
		return http.get(`/books/${id}`);
	}

	create(data) {
		return http.post("/books", data);
	}

	update(id, data) {
		return http.put(`/books/${id}`, data);
	}

	delete(id) {
		return http.delete(`/books/${id}`);
	}

	findByTitle(title) {
		return http.get(`/books?title=${title}`);
	}
}

export default new BookDataService();

Vue Router をインストールする

とりあえず、Vue Router をインストールしないといけないみたいです。
詳しくは調べてないんですが、そうらしいです。
まあ、とりあえずは動かしてみることに専念して、あとで調べてみましょう。

公式ドキュメントには、SPAを構築するためと書かれてますので、SPAでなければ不要なのかも?
よくわからないですが、参考サイトでも使われているので、あまり考えずに使うことにします。

% npm install vue-router

added 23 packages, and audited 24 packages in 6s

1 package is looking for funding
  run `npm fund` for details

found 0 vulnerabilities

router.jsを作成する

vjs/src に、router.js を作ればいいようです。

import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
export default new Router({
  mode: "history",
  routes: [
    {
      path: "/",
      alias: "/books",
      name: "books",
      component: () => import("./components/BooksList")
    },
    {
      path: "/books/:id",
      name: "book-details",
      component: () => import("./components/Book")
    },
    {
      path: "/add",
      name: "add",
      component: () => import("./components/AddBook")
    }
  ]
});

main.js を変更する

main.js に作成した router を追加すればいいみたいです。

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

App.vue を変更する

参考サイトではナビゲーションなどを追加してますが、ここでは省略します。
HelloWorldコンポーネントやstyleは、とりあえず残したままにしてみます。

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
    <div class="container mt-3">
      <router-view />
    </div>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

axiosをインストールする

axiosは、HTTPクライアントだそうです。

Github - axios/axios

Promise based HTTP client for the browser and node.js

% npm install axios

up to date, audited 1342 packages in 21s

91 packages are looking for funding
  run `npm fund` for details

73 vulnerabilities (2 low, 60 moderate, 11 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

73 vulnerabilities (2 low, 60 moderate, 11 high)

えええ?
大丈夫なの?

まあ、テスト的に作って見るだけなので、気にしないことにしましょう。

http-common.jsを作成する

srcの下に、http-common.js を作成します。

import axios from "axios";

export default axios.create({
	baseURL: "http://localhost:8080/api",
	headers: {
		"Content-type": "application/json"
	}
});

ここまで作ればよさそうな雰囲気なので、ビルドしなおしてみます。

% npm run build

> web@0.1.0 build
> vue-cli-service build --dest ../src/main/resources/static/


⠦  Building for production...

 DONE  Compiled successfully in 5084ms                                                                                       16:41:44

  File                                                          Size                             Gzipped

  ../src/main/resources/static/js/chunk-vendors.2909625e.js     121.46 KiB                       43.05 KiB
  ../src/main/resources/static/js/chunk-a020b95a.5f445348.js    23.58 KiB                        8.18 KiB
  ../src/main/resources/static/js/app.9e87135a.js               6.06 KiB                         2.28 KiB
  ../src/main/resources/static/js/chunk-2d21767c.6e9e2cc9.js    2.12 KiB                         0.82 KiB
  ../src/main/resources/static/js/chunk-2d0ba6fb.8c20d7cb.js    1.89 KiB                         0.85 KiB
  ../src/main/resources/static/js/chunk-2d0bd7a8.2c780f7e.js    1.68 KiB                         0.73 KiB
  ../src/main/resources/static/css/app.fb0c6e1c.css             0.33 KiB                         0.23 KiB

  Images and other types of assets omitted.

 DONE  Build complete. The ../src/main/resources/static directory is ready to be deployed.
 INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html

成功しました!

Spring bootを起動してアクセスしてみます。

なんか出ました。

でも、追加するためのリンクが存在しないので、どうすることもできません。

HelloWorldコンポーネントとロゴの画像はなくてもいいので、まずこれを消してみます。

<template>
  <div id="app">
    <div class="container mt-3">
      <router-view />
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

参考サイトではナビゲーションにリンクがありましたが、ここではシンプルにリンクを追加してみます。

<template>
  <div id="app">
    <div>
      <ul>
        <li><a href="/">HOME</a></li>
        <li><a href="/books">Books</a></li>
        <li><a href="/add">Add Book</a></li>
      </ul>
    </div>
    <div class="container mt-3">
      <router-view />
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
ul {
  list-style-type: none;
}
</style>

Books を /books に、Add Book を /add にリンクしているのですが、Spring bootがアクセスを拾って Whitelabel Error Page に飛ばされてしまいます。

Github - danielcgithub/vue-getting-started

こちらを見ても、Vue は npm run serve で動かして、Spring bootは別で動かしているので、Spring boot 内に配置した Vue を動かすことは考えてないみたいです。

Spring boot の Controller にも、@CrossOrigin アノテーションがつけられているので、別ホストで動かす前提のようです。

ぐぐってみたところ、Spring boot 内にまとめるのは簡単にはできなさそうです。
Vue のディレクトリで、npm run serve で Vue を起動すれば、とりあえずは動きます。

% npm run serve

> web@0.1.0 serve
> vue-cli-service serve

 INFO  Starting development server...
98% after emitting CopyPlugin

 DONE  Compiled successfully in 2632ms                                                                                       18:23:17


  App running at:
  - Local:   http://localhost:8081/
  - Network: http://192.168.1.13:8081/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

本を追加してみます。

Submit すると、成功したようです。

HOME または Books のリンクをクリックすると追加されていることがわかります。

もうひとつ追加してみます。

本のタイトルをクリックすると、リストの下に詳細が表示されます。

Editをクリックすると、入力フォームに切り替わって、編集または、Deleteボタンで削除ができるようになってます。

試してみたところ、編集も削除も問題なく動作しました。







-Java, node.js, Vue.js
-, , , ,

Copyright© satoshi's ソフトウェア開発 , 2024 All Rights Reserved Powered by STINGER.