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

news2025/1/16 2:40:21

首发于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 {
    @Override
    public 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: number
  title: string
  author: string
  createTime: 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?: string
  author?: 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.coloradmin.cn/o/1623209.html

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

相关文章

Spring Boot-基础操作,常用工具,配置文件

lombok工具 首先将lombok的依赖引入 Lombok是一个实用的Java类库,能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,并可以自动化生成日志变量,简化java开发、提高效率。 日志操作 自定义日志打印 有以下两步&#xff1a; 在一个类中先获…

Vue3 实现 Three.js粒子特效

效果 <template><div id"waves" /> </template><script setup> import { ref, onMounted, onUnmounted } from "vue"; import * as THREE from "three";const amountX ref(50); const amountY ref(50); const color …

MySQL统计一个表的行数,使用count(1), count(字段), 还是count(*)?

为什么要使用count函数&#xff1f; 在开发系统的时候&#xff0c;我们经常要计算一个表的行数。比如我最近开发的牛客社区系统&#xff0c;有一个帖子表&#xff0c;其中一个功能就是要统计帖子的数量&#xff0c;便于分页显示计算总页数。 CREATE TABLE discuss_post (id i…

线性模型算法-完结总结篇

简介 该篇文章就是在CSDN上更新的最终版本。 本文章将介绍&#xff1a;机器学习中的线性模型有关内容&#xff0c;我将尽可能做到 详细地介绍线性模型的所有相关内容,模块如下&#xff0c;希望这些将有助于读者了解这种最初步但却强大的算法&#xff1a; 线性回归逻辑回归 S…

【ENSP】VRRP配置方法

VRRP配置步骤 1.配置虚拟ip地址作为网关&#xff0c;进行切换路由器 2.配置vrrp优先级&#xff0c;越大越优先 3.配置延迟抢占时间 4.配置备份组监视接口 AR1路由器配置 u t m #关闭提示 sys …

Zilliz Cloud 助力 AI 在线教育:智慧树的创新之路

在信息技术飞速发展的今天&#xff0c;教育行业正经历着一场深刻的变革。智慧树&#xff0c;作为全球领先的学分课程运营服务平台&#xff0c;始终站在教育创新的前沿。 为了进一步提升教育质量和效率&#xff0c;智慧树携手 Zilliz Cloud&#xff0c;共同开启了一场教育与技术…

Linux——(grep指令及zip/tar压缩指令)

1.grep指令 语法&#xff1a; grep【选项】查找字符串 文件 功能&#xff1a; 在文件中搜索字符串&#xff0c;将找到的行打印出来 常用选项&#xff1a; -i &#xff1a;忽略大小写&#xff0c;所以大小写视为相同 -n &#xff1a; 顺便输出行号 -v &#xff1a;反向选择&…

综合大实验

题目&#xff1a; 1、R4为ISP&#xff0c;其上只配置IP地址&#xff1b;R4与其他所直连设备间均使用公有IP&#xff1b; 2、R3-R5、R6、R7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3、整个OSPF环境IP基于172.16.0.0/16划分&#xff1b;除了R12有两个环回&#xff0c;其…

未来五十年,智能科技将如何改变传统行业格局?

未来五十年内&#xff0c;随着人工智能&#xff08;AI&#xff09;和智能科技的不断发展&#xff0c;许多行业将面临被取代的风险。虽然这种趋势可能会带来一些担忧&#xff0c;但也将为人类社会带来巨大的变革。下面将详细探讨哪些行业可能会在未来被智能科技所取代。 ▶ 制造…

【ruoyi-vue】登录解析(前端)

登录代码 1、登录之后做了什么&#xff1f; 执行登陆方法&#xff0c;成功之后&#xff0c;路由跳转到指定路径或者根目录 2、this.$store.dispatch是什么意思&#xff1f; this.$store.dispatch(‘Login’, this.loginForm) 来调取store里的user.js的login方法3、this.$r…

【Go语言】接口类型(一)接口类型与接口的值

本文是介绍golang接口类型的第一篇&#xff0c;主要介绍接口类型与接口类型的值的相关概念。 1. 静态类型、动态类型、动态值 所谓的静态类型&#xff08;即 static type&#xff09;&#xff0c;就是变量声明的时候的类型。 var age int // int 是静态类型 var name strin…

SSTV音频转图片

SSTV工具有很多&#xff0c;这里使用RX-SSTV慢扫描工具 下载安装 RX-SSTV解码软件 下载地址&#xff1a;https://www.qsl.net/on6mu/rxsstv.htm 一直点下一步&#xff0c;安装成功如下图: 虚拟声卡e2eSoft 由于SSTV工具是根据音频传递图片信息&#xff0c;正常解法需要一…

【动态规划】C++ dp子数组问题(最大/最长:环形/子数组和、乘积最大/为正数、单词拆分、子串)

文章目录 1. 前言 - 理解动态规划算法2. 例题最大子数组和 3. 算法题3.1_环形子数组的最大和3.2_乘积最大子数组3.3_乘积为正数的最长子数组长度3.4_等差数列划分3.5_最长湍流子数组3.6_单词拆分467.环绕字符串中唯一的子字符串 1. 前言 - 理解动态规划算法 关于 动态规划的理…

chrome 浏览器 f12 如何查看 websocket 消息?

1. 打开目标页面 2. f12--》网络--》WS&#xff0c;然后刷新页面( 如果不刷页面&#xff0c;就会看不到 websocket 请求&#xff0c;因为 websocket 是长连接&#xff0c;页面加载后只发出一次连接请求&#xff0c;不像 http 接口&#xff0c;不用刷新页面&#xff0c;待会儿也…

常见UI设计模式有哪些?从小白到资深必学

通过了解如何以及何时使用&#xff0c;每种 UI 设计模式都有其特定的目的&#xff0c;可以创建一个一致高效的界面。UI 设计模式为用户界面设计者提供了一种通用语言&#xff0c;并为网站和应用程序的用户提供了一致性。本指南&#xff0c;即时设计总结了 UI 设计模式和 UI 设计…

百种提权及手段一览系列第5集

特权升级的危险是显而易见的。通过提升权限&#xff0c;攻击者可以绕过网络安全措施&#xff0c;从而损害数据完整性、机密性和系统可用性。对于组织而言&#xff0c;这可能会导致数据泄露、系统停机以及潜在的法律和声誉后果。识别权限升级的迹象并部署预防性网络安全措施对于…

【团体程序设计天梯赛 往年关键真题 详细分析完整AC代码】L2-009 抢红包(排序) L2-010 排座位 (dfs)

【团体程序设计天梯赛 往年关键真题 详细分析&完整AC代码】搞懂了赛场上拿下就稳 【团体程序设计天梯赛 往年关键真题 25分题合集 详细分析&完整AC代码】&#xff08;L2-001 - L2-024&#xff09;搞懂了赛场上拿下就稳了 【团体程序设计天梯赛 往年关键真题 25分题合…

Vue2学习笔记(尚硅谷天禹老师)

目录 一、入门案例 二、模板语法 三、数据绑定 四、el和data的两种写法 五、MVVM模型 六、Object.defineproperty方法 七、Vue中响应式原理 八、数据代理 九、methods配置项 十、Vue中的事件处理 十一、Vue中的键盘事件 十二、计算属性 十三、监视属性watch 十四、绑定Class样式…

《系统架构设计师教程(第2版)》第10章-软件架构的演化和维护-01-软件架构演化概述

文章目录 1. 演化的重要性2. 架构演化示例 教材中&#xff0c;本节名为&#xff1a;“软件架构演化和定义的关系” 1. 演化的重要性 演化目的&#xff1a;维持软件架构自身的有用性 为什么说&#xff0c;软件架构是演化来的&#xff0c;而不是设计来的&#xff1f; 软件架构的…

N元语言模型

第1关&#xff1a;预测句子概率 任务描述 本关任务&#xff1a;利用二元语言模型计算句子的概率 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.条件概率计算方式。 2.二元语言模型相关知识。 条件概率计算公式 条件概率是指事件A在事件B发生的条件下发…