使用vue3+springboot构建简单Web应用教程
本文将指导你使用Vue3和Spring Boot构建一个简单的Web应用,通过实际操作帮助你理解这两种技术的基本应用和集成方式。Vue3作为前端框架,提供了高效且灵活的开发体验,而Spring Boot则简化了Java应用程序的开发和部署流程。通过具体示例,你将学会如何安装和配置环境、创建Vue3项目和Spring Boot后端服务,以及实现前后端的通信。
引入Vue3和Spring Boot在现代Web开发中,Vue.js 和 Spring Boot 作为前后端开发的流行技术,广泛应用于Web应用构建。本教程将引导你使用Vue3和Spring Boot构建一个简单的Web应用,通过实际操作,帮助你理解这两种技术的基本应用和集成方式。
介绍Vue3和Spring Boot
Vue.js 是一个前端JavaScript框架,它通过代码片段的方式组织视图逻辑,易于上手且维护性高。Vue3 是 Vue.js 的最新稳定版本,它在性能、开发体验和开发者工具方面都有了很大改进。Spring Boot 是一个基于Spring框架的Java库,它简化了Java应用程序的开发和部署,允许开发者快速创建独立的、生产级别的基于Spring的应用程序。
Vue3的特点
- 组合式API:Vue3引入了组合式API,提高了代码的可重用性和可维护性。
- 响应式系统:Vue3的响应式系统进行了重构,性能提升明显。
- Teleports:Vue3新增了Teleports,可以在DOM树的任何位置插入组件,提供了更灵活的布局选项。
- Fragments:Vue3允许组件拥有多个根节点,提高了组件的灵活性。
Spring Boot的特点
- 自动配置:Spring Boot可以自动配置大多数应用程序的常见场景,大大简化了开发流程。
- 独立运行:Spring Boot应用可以独立运行,不需要外部容器,支持嵌入式的Tomcat、Jetty或Undertow。
- 外部配置:支持外部化配置,可以使用properties文件、YAML文件、环境变量、命令行参数来配置应用属性。
安装Node.js和NPM
首先,需要安装Node.js和NPM(Node.js的包管理器)。你可以从官网(Node.js官网)下载最新的长期支持版本(LTS),并按照安装指南进行安装。
# 检查Node.js和NPM是否安装成功
node -v
npm -v
安装Vue CLI
Vue CLI 是一个命令行工具,可以用来快速搭建 Vue.js 项目。通过以下命令安装Vue CLI:
npm install -g @vue/cli
安装Java和Maven
为了使用Spring Boot,你需要Java开发工具包(JDK)和Maven。你可以从Oracle官网下载Java,并从Maven官网下载Maven。
# 检查Java和Maven是否安装成功
java -version
mvn -v
安装IDE
建议使用IDEA或Eclipse进行Java开发。安装完成后,确保IDE已经配置好Java和Maven环境。
创建Vue3项目
我们将使用Vue CLI创建一个新的Vue3项目,并简要介绍项目的基本结构。
使用Vue CLI创建Vue3项目创建项目
在安装了Vue CLI后,你可以使用以下命令来创建一个新项目:
vue create my-vue3-app
在提示选择预设时,选择Manually select features
,然后选择你需要的特性,如Vue3。
进入项目目录
cd my-vue3-app
运行项目
npm run serve
这将启动开发服务器,你可以在浏览器中访问http://localhost:8080查看应用。
项目结构介绍
文件结构
- public:存放静态文件,如index.html、favicon.ico等。
- src:存放应用的主要逻辑文件。
- assets:存放静态资源。
- components:存放可复用的Vue组件。
- views:存放路由视图组件。
- App.vue:根组件。
- main.js:应用入口文件。
- router.js:路由配置文件。
- store.js:状态管理文件。
示例代码
在src/main.js
中,你可以看到默认的入口文件:
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
在src/App.vue
中,你可以看到默认的根组件:
<template>
<div id="app">
<img alt="Vue logo" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style scoped>
#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>
创建组件
创建一个新的Vue组件,例如src/components/MyComponent.vue
。
<template>
<div>
<h1>Hello from MyComponent</h1>
</div>
</template>
<script>
export default {
name: 'MyComponent'
}
</script>
<style scoped>
h1 {
color: red;
}
</style>
使用组件
在App.vue
中引入并使用新创建的组件。
<template>
<div id="app">
<img alt="Vue logo" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<MyComponent />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
import MyComponent from './components/MyComponent.vue';
export default {
name: 'App',
components: {
HelloWorld,
MyComponent
}
}
</script>
状态管理
在src/store.js
中,可以使用vuex
来管理应用的状态。
import { createStore } from 'vuex';
export default createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementCount({ commit }) {
commit('increment');
}
},
getters: {
count: state => state.count
}
});
路由
在src/router.js
中,配置路由规则。
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
静态资源
在src/assets
中存放静态资源,例如图片、字体等。
配置文件
在vue.config.js
中,可以进行一些定制的配置。
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/my-vue3-app/' : '/'
};
创建Spring Boot后端服务
我们将使用Spring Boot创建一个简单的API服务,以便与Vue前端进行通信。
使用Spring Initializr创建Spring Boot项目创建项目
访问Spring Initializr网站(https://start.spring.io/)创建一个新的Spring Boot项目。选择Maven项目,并选择Java版本、项目名称、依赖等。
下载和导入项目
下载创建的项目,解压后导入IDE中。
运行项目
在IDE中,右键项目,选择Run As
-> Spring Boot App
,启动服务。
示例代码
在src/main/java/com/example/myapp
目录下,创建一个简单的Spring Boot应用。
package com.example.myapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyappApplication {
public static void main(String[] args) {
SpringApplication.run(MyappApplication.class, args);
}
}
添加必要的依赖包
在pom.xml
中添加Spring Boot相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
创建RESTful API
在src/main/java/com/example/myapp/controller
目录下,创建一个RESTful API控制器。
package com.example.myapp.controller;
import com.example.myapp.model.Item;
import com.example.myapp.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/items")
public class ItemController {
@Autowired
private ItemService itemService;
@GetMapping
public List<Item> getAllItems() {
return itemService.getAllItems();
}
@PostMapping
public Item createItem(@RequestBody Item item) {
return itemService.createItem(item);
}
@GetMapping("/{id}")
public Item getItemById(@PathVariable Long id) {
return itemService.getItemById(id);
}
@PutMapping("/{id}")
public Item updateItem(@PathVariable Long id, @RequestBody Item item) {
return itemService.updateItem(id, item);
}
@DeleteMapping("/{id}")
public void deleteItem(@PathVariable Long id) {
itemService.deleteItem(id);
}
}
示例数据模型
在src/main/java/com/example/myapp/model
目录下,创建一个简单的数据模型。
package com.example.myapp.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String description;
// getters and setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
示例服务层
在src/main/java/com/example/myapp/service
目录下,创建服务层来处理业务逻辑。
package com.example.myapp.service;
import com.example.myapp.model.Item;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ItemService {
private List<Item> items = new ArrayList<>();
public List<Item> getAllItems() {
return items;
}
public Item createItem(Item item) {
items.add(item);
return item;
}
public Item getItemById(Long id) {
return items.stream()
.filter(item -> item.getId().equals(id))
.findFirst()
.orElse(null);
}
public Item updateItem(Long id, Item item) {
Item existingItem = getItemById(id);
if (existingItem != null) {
existingItem.setName(item.getName());
existingItem.setDescription(item.getDescription());
}
return existingItem;
}
public void deleteItem(Long id) {
Item item = getItemById(id);
if (item != null) {
items.remove(item);
}
}
}
配置数据源
在src/main/resources/application.properties
中配置数据源。
spring.datasource.url=jdbc:mysql://localhost:3306/myapp?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
启动应用
在IDE中运行项目,启动Spring Boot应用。
mvn spring-boot:run
实现前端与后端的通信
我们将在Vue项目中使用axios发送HTTP请求,在Spring Boot项目中创建RESTful API,以实现前后端的通信。
在Vue项目中使用axios发送HTTP请求安装axios
在Vue项目中安装axios。
npm install axios
示例代码
在src/services/ItemService.js
中,创建一个API服务类。
import axios from 'axios';
const API_URL = 'http://localhost:8080/api/items';
export const getAllItems = () => axios.get(API_URL);
export const createItem = (item) => axios.post(API_URL, item);
export const getItemById = (id) => axios.get(`${API_URL}/${id}`);
export const updateItem = (id, item) => axios.put(`${API_URL}/${id}`, item);
export const deleteItem = (id) => axios.delete(`${API_URL}/${id}`);
在src/views/ItemList.vue
中,使用API服务类来操作数据。
<template>
<div>
<h1>Items</h1>
<button @click="addItem">Add Item</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.description }}</td>
<td>
<button @click="editItem(item)">Edit</button>
<button @click="deleteItem(item.id)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { getAllItems, createItem, getItemById, updateItem, deleteItem } from '@/services/ItemService';
export default {
data() {
return {
items: [],
newItem: {
name: '',
description: ''
},
editingItem: null
};
},
methods: {
addItem() {
this.newItem = {
name: '',
description: ''
};
this.editingItem = null;
},
saveItem() {
if (this.editingItem) {
updateItem(this.editingItem.id, this.editingItem).then(() => {
this.getItems();
this.editingItem = null;
});
} else {
createItem(this.newItem).then(() => {
this.getItems();
this.newItem = {
name: '',
description: ''
};
});
}
},
editItem(item) {
this.editingItem = { ...item };
},
deleteItem(id) {
deleteItem(id).then(() => {
this.getItems();
});
},
getItems() {
getAllItems().then((response) => {
this.items = response.data;
});
}
},
mounted() {
this.getItems();
}
};
</script>
使用axios进行请求
在Vue组件中,调用getAllItems
、createItem
、getItemById
、updateItem
、deleteItem
方法来获取和操作数据。
import { getAllItems, createItem, getItemById, updateItem, deleteItem } from '@/services/ItemService';
export default {
data() {
return {
items: [],
newItem: {
name: '',
description: ''
},
editingItem: null
};
},
methods: {
addItem() {
this.newItem = {
name: '',
description: ''
};
this.editingItem = null;
},
saveItem() {
if (this.editingItem) {
updateItem(this.editingItem.id, this.editingItem).then(() => {
this.getItems();
this.editingItem = null;
});
} else {
createItem(this.newItem).then(() => {
this.getItems();
this.newItem = {
name: '',
description: ''
};
});
}
},
editItem(item) {
this.editingItem = { ...item };
},
deleteItem(id) {
deleteItem(id).then(() => {
this.getItems();
});
},
getItems() {
getAllItems().then((response) => {
this.items = response.data;
});
}
},
mounted() {
this.getItems();
}
};
获取数据
在组件的mounted
生命周期钩子中,调用getItems
方法获取数据。
export default {
// ...
mounted() {
this.getItems();
}
};
增加数据
在addItem
方法中,调用createItem
方法增加数据。
addItem() {
this.newItem = {
name: '',
description: ''
};
this.editingItem = null;
},
saveItem() {
if (this.editingItem) {
updateItem(this.editingItem.id, this.editingItem).then(() => {
this.getItems();
this.editingItem = null;
});
} else {
createItem(this.newItem).then(() => {
this.getItems();
this.newItem = {
name: '',
description: ''
};
});
}
},
编辑数据
在editItem
方法中,编辑数据。
editItem(item) {
this.editingItem = { ...item };
},
删除数据
在deleteItem
方法中,调用deleteItem
方法删除数据。
deleteItem(id) {
deleteItem(id).then(() => {
this.getItems();
});
}
在Spring Boot项目中创建RESTful API
在前面的部分,我们已经创建了一个简单的RESTful API。现在,我们将更深入地理解如何创建和测试这些API。
模型层
根据需求,你可能需要创建不同的数据模型。例如,我们创建了一个Item
模型,它代表了商品信息。
package com.example.myapp.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String description;
// getters and setters
}
服务层
服务层负责处理业务逻辑。我们定义了ItemService
类来处理数据相关的操作。
package com.example.myapp.service;
import com.example.myapp.model.Item;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ItemService {
private List<Item> items = new ArrayList<>();
public List<Item> getAllItems() {
return items;
}
public Item createItem(Item item) {
items.add(item);
return item;
}
public Item getItemById(Long id) {
return items.stream()
.filter(item -> item.getId().equals(id))
.findFirst()
.
orElse(null);
}
public Item updateItem(Long id, Item item) {
Item existingItem = getItemById(id);
if (existingItem != null) {
existingItem.setName(item.getName());
existingItem.setDescription(item.getDescription());
}
return existingItem;
}
public void deleteItem(Long id) {
Item item = getItemById(id);
if (item != null) {
items.remove(item);
}
}
}
控制器层
控制器层负责处理HTTP请求,并将请求转发给服务层。
package com.example.myapp.controller;
import com.example.myapp.model.Item;
import com.example.myapp.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/items")
public class ItemController {
@Autowired
private ItemService itemService;
@GetMapping
public List<Item> getAllItems() {
return itemService.getAllItems();
}
@PostMapping
public Item createItem(@RequestBody Item item) {
return itemService.createItem(item);
}
@GetMapping("/{id}")
public Item getItemById(@PathVariable Long id) {
return itemService.getItemById(id);
}
@PutMapping("/{id}")
public Item updateItem(@PathVariable Long id, @RequestBody Item item) {
return itemService.updateItem(id, item);
}
@DeleteMapping("/{id}")
public void deleteItem(@PathVariable Long id) {
itemService.deleteItem(id);
}
}
测试API
你可以使用Postman或curl来测试这些API。
# 获取全部商品
curl -X GET "http://localhost:8080/api/items"
# 创建商品
curl -X POST "http://localhost:8080/api/items" \
-H "Content-Type: application/json" \
-d '{"name": "New Item", "description": "This is a new item"}'
# 获取商品ID为1的商品
curl -X GET "http://localhost:8080/api/items/1"
# 更新商品ID为1的商品
curl -X PUT "http://localhost:8080/api/items/1" \
-H "Content-Type: application/json" \
-d '{"name": "Updated Item", "description": "This is an updated item"}'
# 删除商品ID为1的商品
curl -X DELETE "http://localhost:8080/api/items/1"
通过以上步骤,我们已经实现了前后端的通信,确保了前后端能够顺畅地协作。
部署和运行应用
最后,我们将学习如何打包Vue应用,并部署Spring Boot应用。
打包Vue应用打包命令
使用npm run build
命令,将Vue应用打包成一个静态资源。
npm run build
项目结构
打包后,会在dist
目录下生成一个静态资源文件夹,其中包含包括index.html
和静态资源。
打包Spring Boot应用
使用Maven命令将Spring Boot应用打包成一个可运行的JAR文件。
mvn clean package
项目结构
打包后,可以在target
目录下找到生成的JAR文件。
运行JAR文件
使用以下命令运行生成的JAR文件:
java -jar target/myapp-0.0.1-SNAPSHOT.jar
部署到服务器
你可以将打包后的JAR文件部署到任何支持Java的服务器上,如Linux服务器、Docker容器等。
# 在Linux服务器上运行
java -jar myapp-0.0.1-SNAPSHOT.jar
部署到云服务器
使用云服务商提供的服务,如AWS、阿里云等,可以将JAR文件部署到云服务器上。
# 使用阿里云ECS部署
scp myapp-0.0.1-SNAPSHOT.jar root@your_ecs_ip:/path/to/deploy
ssh root@your_ecs_ip
java -jar /path/to/deploy/myapp-0.0.1-SNAPSHOT.jar
部署到Docker容器
使用Docker,可以将Spring Boot应用容器化部署。
# Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/myapp-0.0.1-SNAPSHOT.jar myapp.jar
ENTRYPOINT ["java","-jar","/myapp.jar"]
# 构建Docker镜像
docker build -t myapp .
# 运行Docker容器
docker run -p 8080:8080 myapp
通过以上步骤,你已经将Vue应用和Spring Boot应用分别打包,并部署到相应的服务器上。
常见问题与解决办法
在开发过程中,你可能会遇到各种各样的问题,下面是一些常见的问题及其解决方法。
常见错误与解决方法Vue项目错误
1. Module not found
错误信息:
Module not found: Error: Can't resolve 'module-name' in 'path'
解决方法:
确保模块已正确安装,检查路径是否正确。
npm install module-name
2. Property 'xxx' is missing in type
错误信息:
Type '{ yyy: string; }' is not assignable to type '{ xxx: string; yyy: number; }'
解决方法:
检查类型定义是否正确,确保属性类型一致。
interface MyType {
xxx: string;
yyy: number;
}
const myObject: MyType = {
xxx: 'string',
yyy: 123
};
Spring Boot项目错误
1. DataSource not configured
错误信息:
org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException: Invalid property 'url' of type 'java.lang.String' in class 'com.example.demo.DataSourceProperties'
解决方法:
检查配置文件中数据源是否正确配置。
spring.datasource.url=jdbc:mysql://localhost:3306/myapp
spring.datasource.username=root
spring.datasource.password=root
2. No qualifying bean of type 'XXXX' available
错误信息:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.XXXX' available
解决方法:
确保对应的类已经添加了@Component
或@Service
注解。
package com.example.demo;
import org.springframework.stereotype.Component;
@Component
public class XXXX {
//...
}
运行时问题排查
Vue项目运行时问题
1. Failed to mount app: template or render function not defined
错误信息:
TypeError: Cannot read properties of undefined (reading 'data')
解决方法:
确保组件的template
或render
函数已被定义。
export default {
template: `<div>Hello World</div>`
};
2. Vue warn: Error in render function
错误信息:
[Vue warn]: Error in render function: "TypeError: Cannot read properties of undefined (reading 'name')"
解决方法:
检查数据绑定是否正确。
<template>
<div>{{ item.name }}</div>
</template>
<script>
export default {
data() {
return {
item: {
name: ''
}
};
}
};
</script>
Spring Boot项目运行时问题
1. No qualifying bean of type 'XXXX' available
错误信息:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.XXXX' available
解决方法:
检查是否已经导入了对应类的包。
package com.example.demo;
import org.springframework.stereotype.Component;
@Component
public class XXXX {
//...
}
2. Cannot create inner bean
错误信息:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'XXXX': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.YYYY' available
解决方法:
确保依赖的类已添加@Component
或@Service
注解。
package com.example.demo;
import org.springframework.stereotype.Component;
@Component
public class YYYYY {
//...
}
@Component
public class XXXX {
public XXXX(YYYYY yyyyy) {
//...
}
}
通过以上方法,你可以在遇到问题时快速找到解决方案。希望这些信息对你有所帮助。
共同学习,写下你的评论
评论加载中...
作者其他优质文章