基于SpringBoot和Vue的前后端分离的简单示例(二)

309 阅读6分钟

在第一篇文章我们基本实现了简单的前后端分离,但是展示出来的界面太丑了,今天我使用Element UI来美化页面,同时完善代码,实现简单的增删改查

Element UI的导入

在Vue项目中,控制面板输入以下代码,安装Element UI

npm i element-ui -S

安装成功后在main.js中添加一下代码,导入Element UI组件

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
new Vue({
  el: '#app',
  router,
  render: h => h(App)
});

页面布局

在Element官网上找到页面容器,复制代码到App.vue中,根据自己的需要删除多余的代码

<template>
  <div id="app">
    <el-container style="height: 500px; border: 1px solid #eee">
      <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
        <el-menu :default-openeds="['1', '3']">
          <el-submenu index="1">
            <template slot="title"><i class="el-icon-message"></i>导航一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
              <el-menu-item index="1-3">选项3</el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="text-align: right; font-size: 12px">
        </el-header>

        <el-main>
          <el-table :data="tableData">
            <el-table-column prop="date" label="编号" width="140">
            </el-table-column>
            <el-table-column prop="name" label="姓名" width="120">
            </el-table-column>
            <el-table-column prop="address" label="年龄">
            </el-table-column>
          </el-table>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<style>
  .el-header {
    background-color: #B3C0D1;
    color: #333;
    line-height: 60px;
  }

  .el-aside {
    color: #333;
  }
</style>

<script>
  export default {
    data() {
      const item = {
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      };
      return {
        tableData: Array(20).fill(item)
      }
    }
  };
</script>

主要标签说明:

  • el-container:构建整个页面框架

  • el-aside:构建左侧菜单

  • el-menu:左侧菜单内容

    常用属性:

    ​ :default-openeds 默认展开的菜单,通过菜单的index值来关联

    ​ :default-active 默认选中的菜单,通过菜单的index值来关联

    ​ 以上的参数必须用单引号引起来,否则不生效

  • el-submenu:可展开的菜单

    常用属性:

    ​ index:菜单的下标,文本类型,不能是数值类型,值必须拿双引号引住

  • template:对应el-submenu的菜单名

  • i:设置菜单图标,通过class属性设置

  • el-menu-item-group:设置分组的

  • el-menu-item:菜单的子节点,不可再展开

    ​ 常用属性:

    ​ index:菜单的下标,文本类型,不能是数值类型。值必须拿双引号引住

在控制面板输入npm run dev启动vue项目,查看当前效果

动态生成左侧菜单栏-添加用户预览菜单和添加用户菜单

在components中添加AddUser.vue组件,用来添加用户

<template>
    <h1>添加用户界面</h1>
</template>

配置路由

import Vue from 'vue'
import Router from 'vue-router'
import app from '../App'
import user from '../components/User'
import add from '../components/AddUser'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: '用户管理',
      component: app,
      children:[
        {
          path: '/user',
          name: '查看用户',
          component: user
        },
        {
          path: 'add',
          name: '添加用户',
          component: add
        }
      ]
    }
  ]
})

在App.vue中动态生成左侧菜单

<template>
  <div id="app">
    <el-container style="height: 500px; border: 1px solid #eee">
      <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
        <!--router:实现菜单和路由的绑定,点击菜单,跳转到相应的路由界面-->
        <el-menu router>
          <!--$router.options 获取路由配置文件-->
          <!--$router.options.routes 获取路由配置文件中的routes数据-->
          <!--:index是菜单下标,只能是文本类型,所以加一个单引号,转换为文本类型-->
          <!--:key 不加这个会报错,所以就加上了-->
          <el-submenu v-for="(item,index) in $router.options.routes" :index="index+''" :key="index">
            <template slot="title">{{item.name}}</template>
            <!--:index="item2.path" 菜单与路由进行绑定-->
            <!--:class="$route.path==item2.apth?'is-active':''"  route.path是当前浏览器的地址,若当前浏览器的地址等于菜单的地址,则这个菜单高亮-->
            <el-menu-item v-for="(item2,index2) in item.children" :index="item2.path" :key="index2" :class="$route.path==item2.apth?'is-active':''">{{item2.name}}</el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="text-align: right; font-size: 12px">
        </el-header>

        <el-main>
          <!--展示其他路由界面-->
         <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

此时查看界面发现页面嵌套了

原因分析:

解决方法:

1、在component中新建一个Index.vue,此vue只有一个功能,那就是显示其他路由

<template>
    <router-view></router-view>
</template>

2、在路由中注册Index组件,把主页显示的组件设置为Index

此时查看主界面,发现嵌套消失,显示正常

用户查看界面

在User.vue中添加表格组件和分页组件,限制每页显示5条数据。此时,就需要按照页数来查找数据,而不是一股脑把数据都查出来

Boot项目中编写根据页数查询数据的持久层接口、映射语句、控制层方法

public List<User> findByPages(Integer page);
<select id="findByPages" resultType="user" parameterType="int">
    select * from user limit #{pages},5;
</select>
@GetMapping("/findByPages/{pages}")
public List<User> findByPages(@PathVariable("pages") Integer pages){
    //开始索引=(当前页码数-1)*每页显示的数量
    return dao.findByPages((pages-1)*5);
}

User.vue在初始化完成后加载第一页的数据

 //页面初始化完成后要加载的东西
        created() {
          //this指的是当前的vue对象,把vue对象赋给_this
          const _this=this
          this.axios.get('http://localhost:8081/user/findByPages/1').then(function (resp) {
            //回调函数中的this指的是回调
            //把data数据赋给_this,即vue对象
            _this.users=resp.data
          })
        }

给分页组件绑定事件方法,动态的查询每页的数据

<template>
  <div>
    <el-table
      :data="users"
      border
      style="width: 100%">
      <el-table-column
        fixed
        prop="id"
        label="编号"
        width="200">
      </el-table-column>
      <el-table-column
        prop="name"
        label="姓名"
        width="150">
      </el-table-column>
      <el-table-column
        prop="age"
        label="年龄"
        width="150">
      </el-table-column>

      <el-table-column
        label="操作"
        width="200">
        <template slot-scope="scope">
          <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
          <el-button type="text" size="small">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      background
      layout="prev, pager, next"
      :page-size="5"
      :total="50"
      @current-change="page"
    ><!--绑定page方法-->
      <!--current-change 页码改变时触发,返回当前页码-->

    </el-pagination>
  </div>

</template>

<script>
    export default {
        methods: {
          page(currentPage){
            const _this=this
            this.axios.get('http://localhost:8081/user/findByPages/'+currentPage).then(function (resp) {
              _this.users=resp.data
            })
          },
          handleClick(row) {
            console.log(row);
          }
        },
        data(){
          return {
            users:[

            ]
          }
        },
        //页面初始化完成后要加载的东西
        created() {
          //this指的是当前的vue对象,把vue对象赋给_this
          const _this=this
          this.axios.get('http://localhost:8081/user/findByPages/1').then(function (resp) {
            //回调函数中的this指的是回调
            //把data数据赋给_this,即vue对象
            _this.users=resp.data
          })
        }
    }
</script>

<style scoped>

</style>

添加用户页面

在Boot项目中编写添加用户的持久层接口、映射代码、控制层方法

 public int addUser(User user);
<insert id="addUser" parameterType="user">
    insert into user(id,name,age) values(null,#{name},#{age});
</insert>
@PostMapping("/addUser")
    //@RequestBody 将前端传过来的json字符串转换为User对象
    public String addUser(@RequestBody User user){
        int count = dao.addUser(user);//返回受影响的行数
        if(count>0){
            return "success";//插入成功
        }else{
            return "error";//插入失败
        }
    }

AddUser.vue中的代码

<template>
  <!--:model="ruleForm" 数据绑定,和下边的ruleForm进行绑定-->
  <!--:rules="rules" 进行数据校验-->
  <!-- ref="ruleForm" 设置一个名字,将来click事件要用到-->
  <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <!--prop="name" 校验规则取的是rules中的name-->
    <el-form-item label="姓名" prop="name">
      <!--v-model="ruleForm.name" 与ruleForm中的name进行绑定-->
      <el-input v-model="ruleForm.name"></el-input>
    </el-form-item>
    <el-form-item label="年龄" prop="age">
      <el-input v-model="ruleForm.age"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
      <el-button @click="resetForm('ruleForm')">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
  export default {
    data() {
      return {
        ruleForm: {
          name: '',
          age: ''
        },
        rules: {
          name: [
            //required 是否为必填项
            //message 输出信息
            //trigger 触发事件
            { required: true, message: '请输入名字', trigger: 'blur' },
          ],
          age: [
            { required: true, message: '请输入年龄', trigger: 'blur' },
          ],

        }
      };
    },
    methods: {
      submitForm(formName) {
        const _this=this
        this.$refs[formName].validate((valid) => {
          if (valid) {//校验通过
            this.axios.post('http://localhost:8081/user/addUser',this.ruleForm).then(function (resp) {
              if(resp.data=='success'){
                //插入成功,跳转到查看用户界面
                _this.$router.push('/user')
              }
            })
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    }
  }
</script>

修改用户信息

思路分析:

1、在用户列表中点击某一用户的修改按钮后,则会携带当前用户的信息跳转到用户更新界面

2、用户修改完成之后,跳转到用户列表

在User.vue中编写携带用户编号跳转页面的方法

edit(row) {
        //点击修改按钮之后,带参数跳到修改界面
        this.$router.push({
          path: '/update',
          //query是固定的,必须写
          //参数写在query里边
          query: {
            id: row.id
          }
        })
      }

新建UpdateUser.vue项目,并在路由配置文件中注册

UpdateUser页面初始化完成之后,应该将要更新的数据显示在表单上

先在Boot项目中写一套根据Id查询用户的方法

public User findById(Integer id);
<select id="findById" resultType="user" parameterType="int">
    select * from user where id=#{id};
</select>
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") Integer id){
    return dao.findById(id);
}

在UpdateUser.vue项目的created()方法中调用根据id查询用户的方法,获得数据

//页面初始化完成后,应该根据id查出用户信息,显示在表单中
//拿参数,选择route
//跳转,选择router
created() {
  const _this=this
  this.axios.get('http://localhost:8081/user/findById/'+this.$route.query.id).then(function (resp) {
    _this.ruleForm=resp.data
  })
}

在Boot项目中编写更新用户数据的接口,修改完毕后调用此接口进行数据更新

public int updateUser(User user);
<update id="updateUser" parameterType="user">
    update user set name=#{name},age=#{age} where id=#{id};
</update>
@PostMapping("/updateUser")
public String updateUser(@RequestBody User user){
    int count = dao.updateUser(user);
    if(count>0){
        return "success";
    }else{
        return "error";
    }
}

UpdateUser.vue的总代码

<template>
  <!--:model="ruleForm" 数据绑定,和下边的ruleForm进行绑定-->
  <!--:rules="rules" 进行数据校验-->
  <!-- ref="ruleForm" 设置一个名字,将来click事件要用到-->
  <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <el-form-item label="编号">
      <el-input v-model="ruleForm.id" readonly></el-input>
    </el-form-item>
    <!--prop="name" 校验规则取的是rules中的name-->
    <el-form-item label="姓名" prop="name">
      <!--v-model="ruleForm.name" 与ruleForm中的name进行绑定-->
      <el-input v-model="ruleForm.name"></el-input>
    </el-form-item>
    <el-form-item label="年龄" prop="age">
      <el-input v-model="ruleForm.age"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
      <el-button @click="resetForm('ruleForm')">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
  export default {
    data() {
      return {
        ruleForm: {
          id: '',
          name: '',
          age: ''
        },
        rules: {
          name: [
            //required 是否为必填项
            //message 输出信息
            //trigger 触发事件
            { required: true, message: '请输入名字', trigger: 'blur' },
          ],
          age: [
            { required: true, message: '请输入年龄', trigger: 'blur' },
          ],

        }
      };
    },
    methods: {
      submitForm(formName) {
        const _this=this
        this.$refs[formName].validate((valid) => {
          if (valid) {//校验通过
            this.axios.post('http://localhost:8081/user/updateUser',this.ruleForm).then(function (resp) {
              if(resp.data=='success'){
                //插入成功,跳转到查看用户界面
                _this.$router.push('/user')
              }
            })
          }
        });
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      }
    },
    //页面初始化完成后,应该根据id查出用户信息,显示在表单中
    //拿参数,选择route
    //跳转,选择router
    created() {
      const _this=this
      this.axios.get('http://localhost:8081/user/findById/'+this.$route.query.id).then(function (resp) {
        _this.ruleForm=resp.data
      })
    }
  }
</script>

删除用户信息

给删除按钮绑定事件

@click="del(scope.row)"

在Boot项目中编写根据id删除的方法

public int deleteUser(Integer id);
<delete id="deleteUser" parameterType="int">
    delete from user where id=#{id};
</delete>
@GetMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id") Integer id){
    int count = dao.deleteUser(id);
    if(count>0){
        return "success";
    }else{
        return "error";
    }
}

在User.vue中编写删除方法

del(row) {
        this.axios.get('http://localhost:8081/user/deleteUser/'+row.id).then(function (resp) {
          if(resp.data=='success'){
            //删除成功,刷新此页面
            window.location.reload()
          }
        })
      }

最后还有一个小问题,左侧菜单栏多了一个无名的一级菜单

这是在动态生成菜单时,把更新用户的路由也生成了菜单。但实际上我们并不想要这个菜单。我们可以在路由中添加一个show属性,来设置此路由是否会生成菜单

在App.vue的el-submenu标签中添加v-if属性,即

v-if="item.show"

若路由的show属性为true,则生成菜单;否则不生成。

总结

到这里,一个简单的SpringBoot+Vue的前后端分离的简单示例就完成了。其中还有不完善的地方,请大家多多批评指教,我们一起进步。

源码链接:

链接:pan.baidu.com/s/1rMMejxxR… 提取码:ycph