Springboot+vue后台管理系统-前后端分离数据传递

x33g5p2x  于2022-02-07 转载在 Vue.js  
字(18.4k)|赞(0)|评价(0)|浏览(464)

零:最终实现图片展览:

一:前端项目搭建;

1:使用cmd下载vue:

2:npm install -g @vue/cli (如果安装过就不用啦)

3:vue create springboot-vue-demo(自己的名字):

4:

5:将目标移动到第一个选项然后按回车到达下面这个界面,选择一个vue版本,我们这里选择vue3x

6:下一个界面依次按下: y in package.json y 这三个,第三个是是否保存当前配置可以按N

7:

进入:

退出打开idea去开启项目编写

二:前端框架搭建,首先看一下最终的实现效果:

1:首先我们发现这个后台管理系统有三个部分,内容,顶部栏,左边导航栏,所以我们要将顶部和左侧两个不变的地方写在components中:

Header.vue:

<template>
  <div style="height: 50px; line-height: 50px; border-bottom: 1px solid #ccc; display: flex; background-color:#545c64">
    <div style="width: 200px; padding-left: 30px; font-weight: bold; color: white">后台管理</div>
    <div style="flex: 1"></div>
    <div style="width: 100px">
      <el-dropdown style="line-height: 3.5 ;color: white">
        <span class="el-dropdown-link" >
          张三 <el-icon class="el-icon--right"><arrow-down /></el-icon>
        </span>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item>个人信息</el-dropdown-item>
            <el-dropdown-item>退出系统</el-dropdown-item>

          </el-dropdown-menu>
        </template>
      </el-dropdown>
    </div>
    </div>
</template>

<script >
import { ArrowDown } from '@element-plus/icons-vue';
export default {
  components:{ArrowDown},
  name: "Header"

}

</script>

插入一下:新版element引入图标使用的script:import { ArrowDown } from '@element-plus/icons-vue';,项目中加入element是需要手动npm导入的,这里可以通过看官网介绍

Aside.vue:

<template>
  <div>
    <el-menu
        style="width: 200px; min-height: calc(100vh - 50px)"
        :uniqueOpened="true"
        default-active="2"
        class="el-menu-vertical-demo"
        background-color="#545c64"
        text-color="#fff"
        active-text-color="#ffd04b"
    >
      <el-sub-menu index="1">
        <template #title>
          <i class="el-icon-location"></i>
          <span>导航一</span>
        </template>

        <el-menu-item index="1-4">
          <template #title>选项1-1</template>
        </el-menu-item>
      </el-sub-menu>

      <el-menu-item index="2">
        <el-icon><document /></el-icon>
        <template #title>导航二</template>
      </el-menu-item>

      <el-menu-item index="3">
        <el-icon><document /></el-icon>
        <template #title>导航三</template>
      </el-menu-item>

      <el-menu-item index="4">
        <el-icon><setting /></el-icon>
        <template #title>导航四</template>
      </el-menu-item>
    </el-menu>
  </div>
</template>
<script>
import {
  Location,
  Document,
  Menu as IconMenu,
  Setting,
} from '@element-plus/icons-vue'
export default {
  components:{
    Location,
    Document,
    IconMenu,
    Setting
  },

  name: "Aside"
}
</script>

<style scoped>

</style>

Main.js:

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'dayjs/locale/zh-cn'
import locale from 'element-plus/es/locale/lang/zh-cn'

import router from './router'
import store from './store'
import '@/assets/css/global.css'


createApp(App).use(store).use(router).use(ElementPlus,{locale}).mount('#app')

App.vue:

<template>
  <div >
<!--    头部-->
    <Header/>
<!--    主体-->
    <div style="display: flex">
<!--      侧边栏-->
      <Aside />
<!--      内容区域-->
      <router-view style="flex: 1"/>
    </div>
  </div>
<!--  <router-view/>-->
</template>

<style>

</style>

<script>
import Header from "@/components/Header";
import Aside from "@/components/Aside";

export default {
  name:"Layout",
  components:{
    Header,
    Aside
  }
}

</script>

Home.vue:

<template>

  <div style="padding: 10px" >

<!--    功能区域-->
    <div style="margin: 10px 0px">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button type="primary">导入</el-button>
      <el-button type="primary">导出</el-button>
    </div>
<!--    搜索区域-->
    <div style="margin: 10px 0px">
      <el-input v-model="search" placeholder="请输入关键字" style="width: 20%"></el-input>
      <el-button type="primary" style="margin-left: 5px">查询</el-button>
    </div>

    <el-table :data="tableData" border style="width: 100%">
      <el-table-column
          prop="id"
          label="ID" sortable="sortable" >
      </el-table-column>
      <el-table-column
          prop="username"
          label="用户名" >
      </el-table-column>
      <el-table-column
          prop="nickName"
          label="昵称">
      </el-table-column>
      <el-table-column
          prop="age"
          label="年龄">
      </el-table-column>
      <el-table-column
          prop="sex"
          label="性别">
      </el-table-column>
      <el-table-column
          prop="address"
          label="地址">
      </el-table-column>

      <el-table-column fixed="right" label="操作" width="100">
        <template #default="scope">
          <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button>
          <el-popconfirm title="确定删除吗?">
            <template #reference>
              <el-button type="text">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <div style="margin: 10px 0">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="currentPage"
          :page-sizes="[5, 10, 20]"
          :page-size="10"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
      >
      </el-pagination>

      <el-dialog title="提示" v-model="dialogVisible" width="30%">
        <el-form :model="form" label-width="120px">
          <el-form-item label="用户名">
            <el-input v-model="form.username" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="昵称">
            <el-input v-model="form.nickName" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="年龄">
            <el-input v-model="form.age" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="性别">
            <el-radio v-model="form.sex" label="男">男</el-radio>
            <el-radio v-model="form.sex" label="女">女</el-radio>
          </el-form-item>
          <el-form-item label="地址">
            <el-input type="textarea" v-model="form.address" style="width: 80%"></el-input>
          </el-form-item>

        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="save" >确 定</el-button>
          </span>
        </template>
      </el-dialog>

    </div>

  </div>
</template>

<script>

import request from "@/util/request";

export default {
  name: 'Home',
  components: {

  },
  data(){
    return{
      form:{},
      dialogVisible:false,
      search:"",
      currentPage:1,
      total:10,
      tableData:[

      ]

    }
  },
  methods:{
    // 新增用户
    add(){
      this.dialogVisible = true
      // 先清空表单域
      this.form = {}
    },
    // 保存用户传送给后台,使用常见的api:axios
    save(){
      request.post("/user",this.form).then(res => {
        console.log(res)
      })

    },
    handleEdit(){

    },
    handleSizeChange(){

    },

    handleCurrentChange(){

    }

  }
}
</script>

全局css:

index.js:(router)

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
]

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

export default router

store:index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

三:后端基本结构:使用springboot+mybatis-plus

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.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</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>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.4.3.1</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.2.2</version>
		</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>
	</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>

实体类:user:

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@TableName("user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)
    private Integer id;

    private String username;
    private String password;
    private String nickName;
    private Integer age;
    private String sex;
    private String address;
    private String avatar;

}

Mapper接口:

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;

public interface UserMapper extends BaseMapper<User> {
}

返回结果封装类:Result:

package com.example.demo.common;

/**
 * 返回结果的包装类
 * @param <T>
 */
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;
    }
}

Mybatis-plus插件:

package com.example.demo.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;

/**
 *  mybatis-plus 分页插件
 */
@Configuration
@MapperScan("com.example.demo.mapper")
public class MybatisPlusConfig {

    /**
     * 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

控制层:controller:

package com.example.demo.controller;

import com.example.demo.common.Result;
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

/**
 * @RestController:返回数据
 * @Controller:渲染界面
 */

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    UserMapper userMapper;
    /**
     * 新增  @RequestBody:前台传过来的json转换为java对象
     * @return
     */
    @PostMapping
    public Result<?> save(@RequestBody User user){
        userMapper.insert(user);
        return Result.success();
    }



}

三:数据交互:

这里首先说前端我们怎样将home.vue里面的数据传输给后端?答案是使用axios!

配置axios:

import axios from 'axios'

const request = axios.create({
    // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!!
    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;  // 设置请求头
    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

配好这个以后在数据交互的home.vue界面就可以使用了:

浏览器还有一个跨域访问的问题:配置vue.config.js:

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

现在就可以测试了:

最新的home.vue:

<template>

  <div style="padding: 10px" >

<!--    功能区域-->
    <div style="margin: 10px 0px">
      <el-button type="primary" @click="add">新增</el-button>
      <el-button type="primary">导入</el-button>
      <el-button type="primary">导出</el-button>
    </div>
<!--    搜索区域-->
    <div style="margin: 10px 0px">
      <el-input v-model="search" placeholder="请输入关键字" style="width: 20%"></el-input>
      <el-button type="primary" style="margin-left: 5px">查询</el-button>
    </div>

    <el-table :data="tableData" border style="width: 100%">
      <el-table-column
          prop="id"
          label="ID" sortable="sortable" >
      </el-table-column>
      <el-table-column
          prop="username"
          label="用户名" >
      </el-table-column>
      <el-table-column
          prop="nickName"
          label="昵称">
      </el-table-column>
      <el-table-column
          prop="age"
          label="年龄">
      </el-table-column>
      <el-table-column
          prop="sex"
          label="性别">
      </el-table-column>
      <el-table-column
          prop="address"
          label="地址">
      </el-table-column>

      <el-table-column fixed="right" label="操作" width="100">
        <template #default="scope">
          <el-button @click="handleEdit(scope.row)" type="text" size="small">编辑</el-button>
          <el-popconfirm title="确定删除吗?">
            <template #reference>
              <el-button type="text">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <div style="margin: 10px 0">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="currentPage"
          :page-sizes="[5, 10, 20]"
          :page-size="10"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
      >
      </el-pagination>

      <el-dialog title="提示" v-model="dialogVisible" width="30%">
        <el-form :model="form" label-width="120px">
          <el-form-item label="用户名">
            <el-input v-model="form.username" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="昵称">
            <el-input v-model="form.nickName" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="年龄">
            <el-input v-model="form.age" style="width: 80%"></el-input>
          </el-form-item>
          <el-form-item label="性别">
            <el-radio v-model="form.sex" label="男">男</el-radio>
            <el-radio v-model="form.sex" label="女">女</el-radio>
          </el-form-item>
          <el-form-item label="地址">
            <el-input type="textarea" v-model="form.address" style="width: 80%"></el-input>
          </el-form-item>

        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="dialogVisible = false">取 消</el-button>
            <el-button type="primary" @click="save" >确 定</el-button>
          </span>
        </template>
      </el-dialog>

    </div>

  </div>
</template>

<script>

import request from "@/util/request";

export default {
  name: 'Home',
  components: {

  },
  data(){
    return{
      form:{},
      dialogVisible:false,
      search:"",
      currentPage:1,
      total:10,
      tableData:[

      ]

    }
  },
  methods:{
    // 新增用户
    add(){
      this.dialogVisible = true
      // 先清空表单域
      this.form = {}
    },
    // 保存用户传送给后台,使用常见的api:axios
    save(){
      request.post("/user",this.form).then(res => {
        console.log(res)
      })
      this.dialogVisible=false

    },
    handleEdit(){

    },
    handleSizeChange(){

    },

    handleCurrentChange(){

    }

  }
}
</script>

这就是一个简单的前后端交互数据,接下来我们完善这个项目…未完…

加急更新…

相关文章

微信公众号

最新文章

更多

目录