最近流行りの 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クライアントだそうです。
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ボタンで削除ができるようになってます。
試してみたところ、編集も削除も問題なく動作しました。