1小时学会SpringBoot3+Vue3前后端分离开发

首发于Enaium的个人博客


引言

大家可能刚学会JavaVue之后都会想下一步是什么?那么就先把SpringBootVue结合起来,做一个前后端分离的项目吧。

准备工作

首先你需要懂得JavaVue的基础知识,环境这里就不多说了,直接开始。

创建 SpringBoot 项目

使用IDEA旗舰版的可以直接使用自带Spring Initializr创建项目,其他的可以使用Spring Initializr创建项目。

语言选择Java,类型选择Gradle-KotlinJava选择 21,其他的都随便填。

20240423215241

20240423210415

接下来选择依赖,这里选择weblombok,数据库选择PostgreSQL,如果你使用的是MySQL就选它

20240423210635

20240423210727

之后点击创建自动打开项目,或者点击生成打开下载的项目

20240423210848
20240423210903

之后等待项目的依赖下载完成就好了

如果需要配置镜像那就在repositories中最上面添加腾讯云的镜像

repositories {maven {url = uri("https://mirrors.cloud.tencent.com/nexus/repository/maven-public")}mavenCentral()
}

首先我们需要创建数据库,比如一个图书管理系统,需要有一张图书表,有一些字段,比如标题、作者、创建时间、等等。

我们使用数据库管理工具来创建一个表吧。

20240423225934

注意这里使用的是Postgres,如果是MySQL类型略有不同。

之后我们就可以创建实体类了,这里需要先引入ORM框架依赖,这里我为了方便引入写了一个Gradle插件,把它写入到plugins中,接着在刷新一下项目就可以继续编写代码了。

plugins {// 省略其他插件...id("cn.enaium.jimmer.gradle") version "0.0.11"
}

我们创建一个接口Book添加一个EntityTable注解,之后添加一些方法,名称就是根据数据库中字段名称一样,只不过要把蛇形命名改为小驼峰。

@Entity
@Table(name = "book")
public interface Book {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)int id();String title();String author();LocalDateTime createTime();
}

写完之后,我们按下编译的快捷键(默认是 Ctrl+F9),之后就可以编写接口了。

@RestController
@RequiredArgsConstructor
public class BookController {private final JSqlClient sql;@GetMapping("/book")public List<Book> getBooks() {return sql.createQuery(Tables.BOOK_TABLE).select(Tables.BOOK_TABLE).execute();}@PostMapping("/book")public void saveBook(@RequestBody Book book) {sql.save(book);}
}

使用RequiredArgsConstructor注解可以为被final修饰的字段生成构造方法,这样就不用手动写构造方法了。

getBooks用于获取图书列表,首先使用createQuery创建一个查询,传入一张表,类似于from book,接着使用select选择所有字段,类似于select id, name, author, createTime,最后使用execute执行查询。
saveBook用于保存图书,使用save方法保存图书。

接下来需要配置允许跨域,这里使用CORS,在SpringBoot中配置CORS很简单,只需实现WebMvcConfigurer接口的addCorsMappings方法即可。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedMethods("*").allowedOrigins("*").allowedHeaders("*");}
}

最后我们配置一下数据库链接。

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres?currentSchema=sbv
spring.datasource.username=postgres
spring.datasource.password=postgres
jimmer.dialect=org.babyfish.jimmer.sql.dialect.PostgresDialect

如果是MySQL就把PostgresDialect改为MySqlDialect

这样我们的后端就写完了,接下来我们开始写前端。

创建 Vue 项目

这里使用pnpm create vue来创建,如果没有安装pnpm可以使用npm install -g pnpm来安装。

20240423215715

名称随便,之后使用TypescriptVue Router剩下的选否。

之后使用命令pnpm install安装依赖,并删除src下的所有文件。

编写App.vue

<script setup lang="ts"></script><template><h1>Vue 3 + Vite + TypeScript</h1>
</template>

编写main.ts

import { createApp } from "vue"; import App from "./App.vue"; const app = createApp(App); app.mount("#app");

这里我使用naive ui,使用命令安装pnpm add -D naive-ui,之后使用自动导入配置。

安装这两个插件pnpm add -D unplugin-auto-import unplugin-vue-components

之后修改vite.config.ts文件

import { fileURLToPath, URL } from "node:url"import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import AutoImport from "unplugin-auto-import/vite"
import Components from "unplugin-vue-components/vite"
import { NaiveUiResolver } from "unplugin-vue-components/resolvers"// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(),AutoImport({imports: ["vue",{"naive-ui": ["useDialog", "useMessage", "useNotification", "useLoadingBar"]}]}),Components({resolvers: [NaiveUiResolver()]})],resolve: {alias: {"@": fileURLToPath(new URL("./src", import.meta.url))}}
})

然后就可以继续编写页面了,首先在views中编写两个页面一个用来获取所有的图书,一个用来添加图书。

<script setup lang="ts">
import type { DataTableColumns } from "naive-ui"
import { ref } from "vue"interface Book {id: numbertitle: stringauthor: stringcreateTime: string
}const columns: DataTableColumns<Book> = [{title: "ID",key: "id"},{title: "Title",key: "title"},{title: "Author",key: "author"},{title: "Create Time",key: "createTime"}
]const books = ref<Book[]>([])fetch("http://localhost:8080/book").then((response) => response.json()).then((data: Book[]) => {books.value = data})
</script><template><n-data-table :columns="columns" :data="books" />
</template>
<script setup lang="ts">
import { ref } from "vue"
import { useMessage, type FormInst } from "naive-ui"interface BookInput {title?: stringauthor?: string
}const message = useMessage()const formRef = ref<FormInst | null>(null)
const bookInput = ref<BookInput>({})const save = () => {formRef.value?.validate().then((valid) => {if (valid) {fetch("http://localhost:8080/book", {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify(bookInput.value)}).then(() => {message.success("Book saved")})}})
}
</script><template><n-form ref="formRef" :model="bookInput"><n-form-item label="Title" path="title" :rule="[{ required: true, message: 'Please input title' }]"><n-input v-model:value="bookInput.title" /></n-form-item><n-form-item label="Author" path="author" :rule="[{ required: true, message: 'Please input author' }]"><n-input v-model:value="bookInput.author" /></n-form-item><n-button type="primary" @click="save">Save</n-button></n-form>
</template>

之后编写布局,在layouts下编写一个,BookLayout.vue,我们使用左侧一栏来选择页面,右侧来展示页面。

<script setup lang="ts"></script><template><n-layout has-sider><n-layout-sider content-style="padding: 24px;"><ul><li><RouterLink to="/book">Book</RouterLink></li><li><RouterLink to="/book/create">Create Book</RouterLink></li></ul></n-layout-sider><n-layout><n-layout-content content-style="padding: 24px;"><RouterView /></n-layout-content></n-layout></n-layout>
</template>

之后创建一个router目录,编写index.ts文件

import BookLayout from "@/layouts/BookLayout.vue"
import Books from "@/views/Books.vue"
import SaveBook from "@/views/SaveBook.vue"
import { createRouter, createWebHistory } from "vue-router"const router = createRouter({history: createWebHistory(),routes: [{path: "/book",component: BookLayout,children: [{path: "",component: Books},{path: "create",component: SaveBook}]}]
})export default router

之后在main.ts中引入router

import router from "./router"// 省略其他代码...app.use(router)

最后在App.vue中使用RouterView

<template><NMessageProvider><RouterView /></NMessageProvider>
</template>

这样我们的前端就写完了,接下来我们启动项目。

源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/3574.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

switch语句深讲

一。功能 1.选择&#xff0c;由case N:完成 2.switch语句本身没有分支功能&#xff0c;分支功能由break完成 二。注意 1.switch语句如果不加break&#xff0c;在一次判断成功后会执行下面全部语句并跳过判断 2.switch的参数必须是整形或者是计算结果为整形的表达式,浮点数会…

JSON Web Tokens攻击漏洞手法

身份验证和授权是任何应用程序的关键组件。人们已经开发了各种标准和框架来促进此类组件的开发并使应用程序更加安全。其中&#xff0c;JSON Web Tokens (JWT) 多年来已成为流行的选择。 JSON Web 令牌是一种开放的行业标准 RFC 7519 方法&#xff0c;用于在两方之间安全地发送…

手机拍照打印出的黑乎乎

1&#xff09;新建word——插入图片——双击图片&#xff0c;在顶部菜单栏中找到校正&#xff0c;选择其中最清晰的图片。 2&#xff09;选中图片——图片另存为。 3&#xff09;自带画图工具打开&#xff0c;ctrla全选——鼠标移动图片&#xff0c;将不需要的边边角角剪切掉。…

科普童话新课堂杂志社科普童话新课堂编辑部2024年第16期目录

作品选 封2,封3-封4 探索新知《科普童话》投稿&#xff1a;cn7kantougao163.com 泱泱国之风 悠悠诗之情 沈灿宇1-3 试论"文化意识"视角下的高中英语阅读教学 董娜4-6 立足小组合作探究优化写作能力培养 时同祥7-9 以"导"促学:全面提升学生的文学核心素养 吴…

平抑风电波动的电-氢混合储能容量优化配置

这篇论文中的EMD分解法在非线性扰动信号分解上优于小波分解法,EMD分解出来的imf各频次信号,继而利用C2F实现信号重构,根据最大波动量限值剔除出需要储能平抑的波动量,继而用超级电容实现平抑(论文中用的碱水电解槽+燃料电池我认为有很多个点可以佐证不合适,但是电制氢是热…

【C++风云录】粒子魔法大全:打造惊艳视觉效果的工具和引擎

从闪光到爆炸&#xff1a;深入了解粒子系统和特效工具 前言 本文将介绍多种用于创建粒子系统和特效的软件开发工具和引擎。这些工具涵盖了从基础到高级的应用&#xff0c;有助于开发人员实现各种视觉效果。 欢迎订阅专栏&#xff1a;C风云录 文章目录 从闪光到爆炸&#xff…

Redis 的持久化机制有哪些??

一、背景&#xff1a; 持久化&#xff0c;就是将数据存入到磁盘中去的过程。虽然redis是基于内存运行的服务&#xff0c;但是也需要做持久化操作的。 二、redis服务等持久化机制流程&#xff1a; Redis是基于内存的非关系型K-V数据库&#xff0c;既然它是基于内存的&#xff0c…

某互联网公司c++笔试题1

1. 画多重继承虚函数表 注&#xff1a;虚函数表是一种编译时构建的数据结构&#xff0c;它用于在运行时解析对虚函数的调用&#xff0c;是一个存储类成员函数指针的数组。每个拥有虚函数的类都有一个对应的虚函数表。当类对象创建时&#xff0c;对象中会包含一个指向相应虚函数…

AI作画算法原理详解:从数据到艺术的自动化之旅

AI作画算法原理详解&#xff1a;从数据到艺术的自动化之旅 在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步渗透到各个领域&#xff0c;其中AI作画技术更是引发了广泛关注。本文将详细解析AI作画算法的原理&#xff0c;带领读者了解从数据收集与处理到…

c# winform 控件皮肤

控件皮肤下载&#xff1a; https://download.csdn.net/download/m0_46973223/89225992 步骤&#xff1a; 第一步 将IrisSkin4.dll文件放在debug文件下&#xff0c;选一个或者多个后缀名为.ssk文件&#xff08;各个皮肤文件&#xff09;放在debug文件下。 第二步 解决方案资…

ocr、人工智能、文字识别接口

人工智能这个词近几年热度颇高&#xff0c;工业上有人称之为“机器代工”&#xff0c;生活中有人称之为“物联网”&#xff0c;而所体现出来的就是智能化&#xff0c;减少人工参与。翔云公有云平台应运而生&#xff0c;提供的OCR API及实名认证API使产品智能化&#xff0c;自动…

华为OD机试真题-剩余银饰的重量-2024年OD统一考试(C卷D卷)

题目描述: 有N块二手市场收集的银饰,每块银饰的重量都是正整数,收集到的银饰会被熔化用于打造新的饰品。 每一回合,从中选出三块 最重的 银饰,然后一起熔掉。假设银饰的重量分别为 x 、y和z,且 x <= y <= z。那么熔掉的可能结果如下: 如果 x == y == z,那么三块银…

全额退款20000,what?

接单的时候有多兴奋&#xff0c;退单的时候就有多落寞。今天我对客户全额退款了&#xff0c;跟踪了10天的项目正式结束。 这是我接单以来项目单价最高的一个项目&#xff0c;本来不太想接的&#xff0c;因为业务领域不擅长&#xff0c;又想挑战一下。兜兜转转找了几个人因为各种…

使用 Python 将 GB2312 和 UTF8 编码的文件转换为带标记的 UTF8 编码

1. 版本、依赖要求 Python 版本要求&#xff1a;Python > 3.6即可 需要安装的包&#xff08;建议使用 conda、miniconda 等 python 环境管理器创建一个 python 环境后运行 chardettkinter 2. 实现功能 对某一文件夹及其子文件夹下的所有txt文件&#xff0c;将原编码为g…

git分支更新

git分支更新 场景&#xff1a; 在本地创建了一个新的分支 test_20240426 后&#xff0c;远端分支更新了内容&#xff0c;需要更新本地的 master 分支和新创建的 test_20240426 分支。 步骤&#xff1a; 更新 master 分支 首先&#xff0c;切换到 master 分支&#xff1a;git …

Neo-reGeorg明文流量

Neo-reGeorg 1 同IP对&#xff0c;同一个URI&#xff0c;第一个TCP流是“GET”请求&#xff0c;随后的TCP流请求为“POST”。&#xff08;jsp\jspx\php&#xff09; 2 第一个TCP流中&#xff0c;GET只有一个会话。&#xff08;jsp\jspx\php&#xff09;&#xff0c;响应body79…

机器学习——过拟合

一、过拟合得表现 模型在训练过程中&#xff0c;除了会出现过拟合现象&#xff0c;还有可能出现欠拟合的情况。相比而言&#xff0c;后者通常发生在建模前期&#xff0c;只要做好特征工程一般可以解决模型欠拟合问题。下图描述了模型在训练数据集上的三种情况&#xff1a; 其…

【LeetCode:2095. 删除链表的中间节点 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

go 环境安装

彻底清楚old version sudo apt-get remove golang-go sudoapt-get remove --auto-remove golang-go rm -rvf /usr/local/go/ 安装方法&#xff1a; 1.下载 Download and install - The Go Programming Language 2. 解压安装 rm -rf /usr/local/go && tar -C /usr/…

BGP的路径属性

路径属性 l每条BGP路由都拥有多个的路径属性&#xff0c;有些是必须携带的&#xff0c;有些是可选添加的 lBGP的路径属性将影响最优路由的选择 lBGP路径属性是描述路由的一组参数&#xff0c;BGP根据路由的属性选择最佳路由&#xff0c;可以人为置值&#xff0c;以便执行路由…