Spring Boot + Vue + MyBatis 实现图书管理系统全栈开发实战

在前后端分离的开发模式盛行的当下,利用 Spring Boot、Vue 和 MyBatis 组合搭建项目,能有效提升开发效率和系统可维护性。本文将以图书管理系统为实战案例,详细介绍从环境搭建到功能实现的全流程,带你深入掌握这一技术栈的应用。​

一、项目概述​

图书管理系统旨在实现对图书信息的高效管理,包括图书的增删改查、分类管理、借阅记录跟踪等功能。后端采用 Spring Boot 构建 RESTful API,MyBatis 负责数据库交互;前端基于 Vue 实现友好的用户界面,通过 Axios 与后端进行数据通信。​

二、后端开发:Spring Boot + MyBatis​

2.1 项目创建与基础配置​

通过Spring Initializr创建项目,添加Spring Web、MyBatis Framework、MySQL Driver和Lombok依赖。在application.yml文件中配置数据库连接:

server:
  port: 8080
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/library?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
  mybatis:
    mapper-locations: classpath:mapper/*.xml
    type-aliases-package: com.example.library.entity

2.2 定义实体类​ 

创建Book实体类,用于映射数据库中的图书表:

import lombok.Data;

@Data
public class Book {
    private Long id;
    private String title;
    private String author;
    private String category;
    private int quantity;
    private boolean isAvailable;
}

2.3 实现 MyBatis 映射层​ 

BookMapper接口继承BaseMapper,利用 MyBatis-Plus 的通用 CRUD 方法简化开发:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.library.entity.Book;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BookMapper extends BaseMapper<Book> {
    // 可自定义扩展方法,如按类别查询图书
    Book[] selectByCategory(String category);
}

同时,在mapper目录下创建BookMapper.xml文件,实现自定义 SQL: 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.library.mapper.BookMapper">
    <select id="selectByCategory" resultType="com.example.library.entity.Book">
        SELECT * FROM book WHERE category = #{category}
    </select>
</mapper>

2.4 服务层与控制器层开发​

服务层BookService接口及其实现类BookServiceImpl:

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.library.entity.Book;

public interface BookService extends IService<Book> {
    Book[] getBooksByCategory(String category);
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.library.entity.Book;
import com.example.library.mapper.BookMapper;
import com.example.library.service.BookService;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {
    @Override
    public Book[] getBooksByCategory(String category) {
        return baseMapper.selectByCategory(category);
    }
}

控制器层BookController提供对外 API: 

import com.example.library.entity.Book;
import com.example.library.service.BookService;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/books")
public class BookController {
    private final BookService bookService;

    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping
    public List<Book> getAllBooks() {
        return bookService.list();
    }

    @GetMapping("/{id}")
    public Book getBookById(@PathVariable Long id) {
        return bookService.getById(id);
    }

    @PostMapping
    public Book createBook(@RequestBody Book book) {
        bookService.save(book);
        return book;
    }

    @PutMapping("/{id}")
    public Book updateBook(@PathVariable Long id, @RequestBody Book book) {
        Book existBook = bookService.getById(id);
        if (existBook != null) {
            existBook.setTitle(book.getTitle());
            existBook.setAuthor(book.getAuthor());
            existBook.setCategory(book.getCategory());
            existBook.setQuantity(book.getQuantity());
            existBook.setIsAvailable(book.isAvailable());
            bookService.updateById(existBook);
        }
        return existBook;
    }

    @DeleteMapping("/{id}")
    public void deleteBook(@PathVariable Long id) {
        bookService.removeById(id);
    }

    @GetMapping("/category/{category}")
    public Book[] getBooksByCategory(@PathVariable String category) {
        return bookService.getBooksByCategory(category);
    }
}

三、前端开发:Vue 3​

3.1 项目初始化与配置​

使用 Vue CLI 创建项目,并安装 Axios:

vue create library-frontend
cd library-frontend
npm install axios

在vue.config.js中配置代理解决跨域问题: 

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
};

3.2 组件开发​

图书列表组件BookList.vue

<template>
  <div class="book-list">
    <h1>图书列表</h1>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>书名</th>
          <th>作者</th>
          <th>类别</th>
          <th>数量</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="book in books" :key="book.id">
          <td>{{ book.id }}</td>
          <td>{{ book.title }}</td>
          <td>{{ book.author }}</td>
          <td>{{ book.category }}</td>
          <td>{{ book.quantity }}</td>
          <td>
            <button @click="editBook(book.id)">编辑</button>
            <button @click="deleteBook(book.id)" style="margin-left: 10px;">删除</button>
          </td>
        </tr>
      </tbody>
    </table>
    <button @click="createBook">添加图书</button>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import request from '../utils/request';
import { useRouter } from 'vue-router';

const router = useRouter();
const books = ref([]);

onMounted(() => {
  loadBooks();
});

const loadBooks = async () => {
  try {
    const res = await request.get('/books');
    books.value = res;
  } catch (error) {
    console.error('加载图书失败:', error);
  }
};

const editBook = (id) => {
  router.push(`/books/${id}/edit`);
};

const deleteBook = async (id) => {
  try {
    await request.delete(`/books/${id}`);
    loadBooks();
  } catch (error) {
    console.error('删除图书失败:', error);
  }
};

const createBook = () => {
  router.push('/books/create');
};
</script>

<style scoped>
/* 样式代码 */
</style>

图书编辑组件BookEdit.vue 

 

<template>
  <div class="book-edit">
    <h2>{{ isEdit ? '编辑图书' : '添加图书' }}</h2>
    <form @submit.prevent="handleSubmit">
      <div>
        <label>书名:</label>
        <input type="text" v-model="form.title" required>
      </div>
      <div>
        <label>作者:</label>
        <input type="text" v-model="form.author" required>
      </div>
      <div>
        <label>类别:</label>
        <input type="text" v-model="form.category" required>
      </div>
      <div>
        <label>数量:</label>
        <input type="number" v-model="form.quantity" min="0">
      </div>
      <div>
        <label>是否可用:</label>
        <input type="checkbox" v-model="form.isAvailable">
      </div>
      <button type="submit">{{ isEdit ? '保存修改' : '添加图书' }}</button>
    </form>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import request from '../utils/request';
import { useRoute, useRouter } from 'vue-router';

const route = useRoute();
const router = useRouter();
const isEdit = route.params.id !== undefined;
const form = ref({
  title: '',
  author: '',
  category: '',
  quantity: 0,
  isAvailable: true
});

onMounted(() => {
  if (isEdit) {
    loadBook(route.params.id);
  }
});

const loadBook = async (id) => {
  try {
    const res = await request.get(`/books/${id}`);
    form.value = res;
  } catch (error) {
    console.error('加载图书失败:', error);
  }
};

const handleSubmit = async () => {
  try {
    if (isEdit) {
      await request.put(`/books/${route.params.id}`, form.value);
    } else {
      await request.post('/books', form.value);
    }
    router.push('/books');
  } catch (error) {
    console.error('提交失败:', error);
  }
};
</script>

四、项目联调与常见问题解决​

4.1 联调测试​

先启动后端 Spring Boot 项目,再启动前端 Vue 项目。在浏览器中访问前端地址,测试图书的增删改查功能。使用浏览器开发者工具的 Network 面板,查看接口请求和响应数据是否正常。​

4.2 常见问题及解决方案​

  • 跨域问题:确保后端配置了 CORS 跨域支持,前端正确配置了代理。若仍有问题,检查请求头和响应头中的跨域相关字段。​
  • 接口返回 404:确认后端接口路径与前端请求路径一致,检查后端控制器方法是否正确映射。​
  • 数据格式错误:检查前后端数据传输的 JSON 格式是否匹配,注意字段名称大小写和数据类型。​

五、项目扩展方向​

  1. 权限管理:引入 Spring Security 实现用户登录、角色权限控制,前端根据用户权限展示不同功能。​
  1. 借阅功能:新增借阅记录表,实现图书借阅、归还逻辑,记录借阅时间和归还状态。​
  1. 数据可视化:使用 ECharts 等图表库,对图书类别分布、借阅统计等数据进行可视化展示。​

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱熬夜的小古

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值