springboot+vue前后端分离项目(后台管理系统)

学习笔记

学习资源来自于B站UP,up他讲的非常详细,对于熟悉两大框架很有用。

我的作业源代码在文章末尾,欢迎有需要的同学,学习参考使用,内置SQL文件,导入后,开启springboot和vue服务即可使用,注意更改自己的数据库信息配置,一起学习,一起进步哦!!

一、所使用的环境配置:

编译器:IDEA
后台框架:SpringBoot
Mybatis-Plus
数据库:Mysql8.0
数据库工具:Navicat premium
前端框架:Vue
Element UI
引用的富文本编辑器:wangEditor

二、项目简介

这是一个基于SpringBoot和Vue的后台管理系统。
主要功能:

1.实现用户信息的CRUD,以及页面的显示。
2.用户权限的分配,不同权限的用户锁能看到的的界面信息和能进行的操作是不同的。
3.实现图片,文件的上传和下载。
4.实现页面富文本编译器的使用与信息的CRUD。
5.跨域配置,MybatisPlus配置。
6.用户的登录注册,拦截器。
7.查询功能。
。。。。
项目展示:(图片)
1.登录界面
在这里插入图片描述
2.注册页面这两个页面可以自由切换
在这里插入图片描述
3.root登录后的默认页面以及高亮显示
在这里插入图片描述
4.几个页面的展示
在这里插入图片描述
在这里插入图片描述
5.root账户所能进行的CRUD操作和能查看的用户信息页面
在这里插入图片描述
修改
在这里插入图片描述
6.个人信息修改,以及退出
在这里插入图片描述
7.普通用户登录
这里只做了图书页面的权限限制和用户信息的限制
在这里插入图片描述

三、知识点总结(代码和配置)

配置文件:
SpringBoot:
1.Mybatis-Plus配置文件,实现分页查询:MybatisPlusConfig
参考官网:MybatisPlus

package com.wen.common;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//Spring boot方式
@Configuration
@MapperScan("com.wen.mapper")//这里所扫描的是项目中mapper文件的位置!
public class MybatisPlusConfig {

    // 旧版,官网的旧版视乎无法使用

    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

2.跨域配置文件:CorsConfig

package com.wen.common;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {
    private static final long Max_AGE = 24*60*60;//连接时间
    private CorsConfiguration buildConfig(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //定义所允许的请求头,方法等。*代表所有
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setMaxAge(Max_AGE);
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",buildConfig());;//允许访问后台的所有接口
        return new CorsFilter(source);
    }
}

3.请求返回类!:Result
这里算是一个重点,解放了我平时后端coding的思维,非常感谢,没有想到get,set这么方便。
将所有的请求放回统一定义,根据项目所规定的code进行再定义与返回,达到项目通用的效果,非常实用!

package com.wen.common;

public class Result<T> {
    private String code;
    private String msg;
    private T data;//定义泛型,用于接受数据。

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
    public Result(){

    }

    public Result(T data) {
        this.data = data;
    }
    public static Result success(){
        Result result = new Result<>();
        result.setCode("0");
        result.setMsg("成功");
        return result;
    }

    public static <T> Result<T> success(T data){
        Result<T> result = new Result<>(data);
        result.setCode("0");
        result.setMsg("成功");
        return result;
    }
    public static Result error(String code,String msg){
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

4.pom.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wen</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--spring mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
<!--        mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3.1</version>
        </dependency>
<!--一个后端工具库-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.7</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Vue:
1.这里为解决未登录用户页面拦截的问题,同时封装了axios便于请求使用,在Vue中创建了一工具类/utils/:request.js

import axios from 'axios'
import router from "@/router";

const request = axios.create({
    //baseUrl:'/api'
    timeout: 5000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    // config.headers['token'] = user.token;  // 设置请求头
    //取出sessionStorage里面的用户信息
    let userJson = sessionStorage.getItem("user");
    if (!userJson){
        router.push("/login");
    }
    return config
}, error => {
    return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
        let res = response.data;
        // 如果是返回的文件
        if (response.config.responseType === 'blob') {
            return res
        }
        // 兼容服务端返回的字符串数据
        if (typeof res === 'string') {
            res = res ? JSON.parse(res) : res
        }
        return res;
    },
    error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)
export default request

2.为解决跨域问题:在vue文件下新建vue.config.js文件

// 跨域配置
module.exports = {
    devServer: {                //记住,别写错了devServer//设置本地默认端口  选填
        port: 9876,//设置的本项目端口
        proxy: {                 //设置代理,必须填
            '/api': {              //设置拦截器  拦截器格式   斜杠+拦截器名字,名字可以自己定
                target: 'http://localhost:9090/',     //代理的目标地址
                changeOrigin: true,              //是否设置同源,输入是的
                pathRewrite: {                   //路径重写
                    '/api': ''                     //选择忽略拦截器里面的单词
                }
            }
        }
    }
}

其余知识点总结:
SpringBoot后端文件上传和下载的Controller:FileController

package com.wen.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.wen.common.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

@RestController
@RequestMapping("/files")
public class FileController {
    @Value("${server.port}")
    private String port;

    private static final String ip = "http://localhost";

    /**
     * 上传接口
     * @param file
     * @return
     */

    @PostMapping("/upload")
    public Result<?> upload(MultipartFile file){
        String originalFilename = file.getOriginalFilename();//获取源文件的名称
//        定义文件的唯一标识(前缀)
        String flag = IdUtil.fastSimpleUUID();

        String rootFilePath = System.getProperty("user.dir")+"/springboot/src/main/resources/files/"+flag+"_"+originalFilename;//获取文件上传的路径
        try {
            FileUtil.writeBytes(file.getBytes(),rootFilePath);//把文件写入该路径
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = ip+":"+port+"/files/"+flag;
        return Result.success(url);//返回结果url
    }

    /**
     * 下载接口
     * @param flag
     * @param response
     */
    @GetMapping("/{flag}")
    public void getFiles(@PathVariable String flag, HttpServletResponse response){
        OutputStream os;//新建一个输出对象
        String basePath = System.getProperty("user.dir")+"/springboot/src/main/resources/files/";//文件路径
        List<String> fileNames = FileUtil.listFileNames((basePath));//获取所有的文件名称
        String fileName = fileNames.stream().filter(name -> name.contains(flag)).findAny().orElse("");//找到根参数一致的文件

        try {
            if (StrUtil.isNotEmpty(fileName)){
                response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
                response.setContentType("application/octet-stream");
                byte[] bytes = FileUtil.readBytes(basePath + fileName);//通过文件路径读取文字节流
                os = response.getOutputStream();//通过输出流返回文件
                os.write(bytes);
                os.flush();
                os.close();
            }
        }catch (Exception e){
            System.out.println("文件下载失败");
        }
    }
    /**
     * 富文本上传接口
     * @param file
     * @return
     */

    @PostMapping("editor/upload")
    public JSON editorUpload(MultipartFile file){
        String originalFilename = file.getOriginalFilename();//获取源文件的名称
//        定义文件的唯一标识(前缀)
        String flag = IdUtil.fastSimpleUUID();

        String rootFilePath = System.getProperty("user.dir")+"/springboot/src/main/resources/files/"+flag+"_"+originalFilename;//获取文件上传的路径
        try {
            FileUtil.writeBytes(file.getBytes(),rootFilePath);//把文件写入该路径
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = ip+":"+port+"/files/"+flag;
        JSONObject jsonObject = new JSONObject();
        jsonObject.set("errno",0);
        JSONArray arr = new JSONArray();
        JSONObject data = new JSONObject();
        arr.add(data);
        data.set("url",url);
        jsonObject.set("data",arr);
        return jsonObject;//返回结果url
    }
}

总结:

  • @Value:获取配置文件中指定的数据(这里的server.port存在于项目文件中application.yaml文件中),存入下方定义的变量中。
  • MultipartFile:用于接收上传文件的类,推荐文章,其中包含了该类的许多用法,很详细。
  • IdUtil.fastSimpleUUID():使用的是hutool中的方法,用于生成唯一标识的UUID,加在上传图片的前面,用于唯一区别,避免了相同文件名上传后覆盖的问题。
  • System.getProperty(“user.dir”):获取当前项目的根目录,在本项目中也就是springboot-vue-demo目录了。在这里插入图片描述
  • HttpServletResponse:http请求的响应。(学习重点,自己也不是很熟啦,加强学习!)
  • response.addHeader(“Content-Disposition”,“attachment;filename=”+ URLEncoder.encode(fileName,“UTF-8”));:添加相应头,定义文件下载后的名字。
  • response.setContentType(“application/octet-stream”);:定义文件下载的格式,二进制流。

关于Mybatis-Plus: 总之就是非常方便,结合lombok进行开发极大的简化了后端的实体定义和数据库相关的操作问题。
SpringBoot中:

  • SpringBoot通过maven引入MybatisPlus
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>mybatis-plus-latest-version</version>//这里记得更改成版本号,这样是无法导入的!
</dependency>
  • 配置只需要通过@MapperScan注解即可使用
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")//这里是项目中mapper存放的文件路径。
  • 需要使用的注解:官网
    例如:在实体上使用@TableName(“user”),即是将实体与数据库中相应的表格相对应,@TableId,即是数据库中的主键。
  • 定义接口,即是mapper层或者service层:继承BaseMapper<相应的实体名>即可使用BaseMapper中的方法,包括各种CRUD操作,如果有定义自身的XXmapper.xml文件的话,就会使用xml文件中相应的CRUD方法。官方中的所有接口
public interface BookMapper extends BaseMapper<Book> {
}

关于wangEditor:
哈哈哈,解决了重复创建编辑器的问题!
学习时错误如下:
问题描述:由于编辑器的节点只有在弹窗创建之后才能生成,也就是才能获取,在项目中,原本的代码会导致新增和修改弹窗重复创建编辑器。
在这里插入图片描述
解决办法:

let editor;
method:{
creatDom(){
      editor = new E('#div1');//富文本编辑器创建,获取节点
      // 配置 server 接口地址
      editor.config.uploadImgServer = 'http://localhost:9090/files/editor/upload';
      editor.config.uploadFileName = 'file';//设置文件上传的名字
      editor.create();//创建。
    },
    //这里是新增弹窗
    add(){
      this.dialogVisible = true;
      this.form = {};
      //由于只有在弹窗启动之后,div节点才会被创建,那么创建富文本编辑器也只能在其之后。
      this.$nextTick(()=>{
        if (editor==null){
          this.creatDom();
        }else {
          editor.destroy();//这里做了一次判断,判断编辑器是否被创建,如果创建了就先销毁。
          this.creatDom();
        }
      });
    },
    //这里是修改弹窗
    handleEdit(row){
      this.form = JSON.parse((JSON.stringify(row)));
      this.dialogVisible = true;
      this.$nextTick(()=>{
        if (editor==null){
          this.creatDom();
          editor.txt.html(row.content);
        }else {
          editor.destroy();//这里做了一次判断,判断编辑器是否被创建,如果创建了就先销毁。
          this.creatDom();
          editor.txt.html(row.content);
        }
      });
    },
}

关于Vue中:
使用sessionStorage获取登录用户的信息,用于判断用户是否登录,以及从中获取用户的权限、昵称、年龄等信息用于页面的显示,若用户为进行登录则重定向转到登录界面。
所需用的代码如下:非同一页面使用

sessionStorage.removeItem("user");//登录界面加载前先清楚已有的用户信息(若有)
sessionStorage.setItem("user",JSON.stringify(res.data));//缓存用户信息

let userStr =sessionStorage.getItem("user") || '{}';//从sessionStorage中获取用户信息
this.user = JSON.parse(userStr);//将JSON转为JavaScript对象,再赋值给user对象

Vue的路由:

import { createRouter, createWebHistory } from 'vue-router'
import Layout from '../layout/Layout.vue'

const routes = [
  {
    path: '/',
    name: 'Layout',
    component: Layout,
    redirect: "/news",
    children: [
      {
        path: 'user',
        name: 'User',
        component: () => import("@/views/User"),
      },
      {
        path: '/book',
        name: 'Book',
        component: ()=>import("@/views/Book")
      },
      {
        path: '/person',
        name: 'Person',
        component: ()=>import("@/views/Person")
      },
      {
        path: '/news',
        name: 'News',
        component: ()=>import("@/views/News")
      },
    ]
  },
  {
    path: '/login',
    name: 'Login',
    component: ()=>import("@/views/Login")
  },
  {
    path: '/register',
    name: 'Register',
    component: ()=>import("@/views/Register")
  },

]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

其中: 主路由为/,访问时重定向到/news页面,在主路由下有许多子路由,及children中的数组对象,即是同一页面,不同子页面。

项目源代码Github仓库

Talk is cheap,show me the code!—— 薪火工作室!

  • 199
    点赞
  • 1798
    收藏
    觉得还不错? 一键收藏
  • 43
    评论
1.项目概况 ​ 提到宿舍,现在无论是学校,还是工厂,都是在熟悉不过的了,学生宿舍楼,职工教员工,职工宿舍楼等等,每一栋楼房都有很多的房间,每个宿舍分配了多少个床位,住着什么人,那些床位是空的,那些房间是空的,这些都需要人员去维护,曾经的我们,通过纸张登记,查看房间信息,房间床位信息,房间少的情况下还好,我们可以一个个进行比对,看登记信息去查看房间信息,床位信息,但是房间多,登记信息多的情况下,或者有人员进行变动,退房,换房的情况下,可就麻烦了我们的宿舍管理员了,我们的宿舍管理员,需要慢慢的进行查找,浪费了时间成本不说,还容易出错,新来的学生或员工需要等待很长时间才能进去入住,在加上现在楼层在逐渐的向高层发展,人员手动管理已经不能满足社会的需要,因而,社会需要更好的工具去管理这些枯燥的的宿舍管理工作,从而宿舍管理系统应用而生。 ​ 宿舍管理系统,解决了当前人力成本,时间成本问题,可以快速的定位到房间号,宿舍床位号,通过宿舍管理系统,我们只要根据系统的要求去操作,就可以分分钟的时间解决某个宿舍是否满员,可以方便的把人员和宿舍,床位进行绑定,就像我们的身份号似的,都是唯一的,查询起来很方便,相比较起传统的宿舍纸张登记来说,现代化的宿舍管理系统更快捷,更高效,更适应人们快捷化的生活。 ​ 现在高校的发展和体制不断的进行了完善,所以学校的服务也逐渐有了变化,对于学校宿舍的管理有了新形势的管理模式。学校根据自身的实际情况,对于学生宿舍生活管理的服务进行改善。有些学校因为管理工作的错误,影响了学校里学生的现况,甚至给整个学校造成了负面的影响,而且现在学校管理问题普遍存在。所以现在学校也在建设信息化管理系统,这种管理系统,可以为学校的管理工作和宿舍管理工作带来很好的效果。
"ruoyi-基于springboot vue前后端分离权限管理系统.zip" 是一个基于SpringBootVue前后端分离的权限管理系统。以下是对该系统的详细说明: 这个系统是一个完全分离前后端的架构,使用了现代化的前端技术Vue.js和后端框架SpringBoot。它的设计目标是实现一个可靠、安全、易用的权限管理系统。 系统的前端部分使用Vue.js库进行开发,它充分利用了Vue.js的组件化和响应式特性,从而提供了一个良好的用户界面和交互体验。前端页面可以动态地响应用户的操作,并与后端进行数据交互。通过Vue-router插件,系统实现了页面的路由功能,使用户能够方便地在不同的页面之间进行切换和导航。此外,系统还使用了Element UI库,该库提供了丰富的组件和样式,可以大大提高开发效率。 系统的后端部分使用了SpringBoot框架,它是一种快速开发Java应用程序的框架。SpringBoot具有自动配置、快速启动、约定大于配置等特点,可以让开发人员更专注于业务逻辑的实现。后端部分负责处理前端发送的请求,并进行权限验证、数据查询和操作等后端逻辑。同时,系统还使用了MyBatis框架来操作数据库,它是一种简化了数据库访问的框架,能够有效地提高数据库操作的效率。 此外,系统还具有权限管理的功能。它能够根据不同的角色对用户进行权限控制,实现用户的分级管理和权限的授权。系统管理员可以在后台管理界面对用户进行管理,并配置他们的角色和权限。通过这种方式,可以保护系统的安全性,并限制用户对敏感数据的访问。 总之,ruoyi-基于springboot vue前后端分离权限管理系统.zip 是一个功能强大且易于使用的权限管理系统,它综合运用了SpringBootVue.js的优势,提供了一个完整的前后端分离架构,可以满足不同应用场景下的权限管理需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值