技术实现


根据 楠哥 项目做得笔记…


Springboot + Vue (用的Mybatis)

使用Springboot进行后端应用开发,使用Vue进行前端应用开发

image-20210306141555706

创建Vue工程

cmd命令行创建vue工程 vue ui

如果没有反应 可以查看 vue -h是否有vue ui命令 如果没有说明版本太低进行脚手架的升级 cnpm i -g @vue/cli

image-20210306141804199

image-20210306141811589

选择目录新建项目

创建项目名–关闭初始化git仓库–手动配置项目–Router、Vuex打开以及Linter/Formatter关闭–Use history mode for router? 打开 – 创建项目,不保存预设

image-20210306142518095

测试

点击任务–server–启动

image-20210306142636165

image-20210306142712261

image-20210306142721173

然后可以把服务停止了

使用IDEA导入工程

打开idea import工程

可以通过命令行运行vue

npm run serve

image-20210306143328778

新建Springboot项目

image-20210306144139651

由测试需要,先从数据库中某表中查询所有数据

image-20210306161935820

image-20210306161911614

然后测试 --成功获得数据

image-20210306162007133

在Vue项目中加入axios

vue add axios

image-20210306162119055

在book.vue页面使用axios获取后台数据

image-20210306164654264

在模板中创建接收数据的地方

<template>
  <div>
      <table>
        <tr>
          <td>编号</td>
          <td>书名</td>
          <td>数量</td>
          <td>鸡汤</td>
        </tr>
        <tr v-for="item in books">
          <td>{{item.bookID}}</td>
          <td>{{item.bookName}}</td>
          <td>{{item.bookCounts}}</td>
          <td>{{item.detail}}</td>
        </tr>

      </table>

  </div>
</template>

以及对应的参数

image-20210306164758635

重点: 后台Controller中需要加入跨域的支持

@CrossOrigin

继承ElementUI

vue ui可视化页面下载ElementUI插件

image-20210306164554908

完成安装

在ElementUI官网使用布局

image-20210306170422881

将对应代码粘贴在App.vue中

Vue + Element UI

Vue继承Element UI

Element UI 后台管理系统主要的标签

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

  • el-aside: 构建左侧菜单栏

  • el-menu: 左侧菜单内容 常用属性

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

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

  • el-submenu: 可展开的菜单.常用属性:

    • index: 菜单的下标,文本类型,不能是数值类型
  • template: 对应el-submenu的菜单名

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

    • el-icon-messae

    • el-icon-menu

    • el-icon-setting

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

    • index: 菜单的下标,文本类型,不能是数值类型

Vue router 来动态构建左侧菜单

  • 导航1
    • 页面1
    • 页面2
  • 导航2
    • 页面3
    • 页面4

在views目录下创建四个页面

image-20210306190310025

配置路由

import PageOne from '../views/PageOne'
import PageTwo from '../views/PageTwo'
import PageThree from '../views/PageThree'
import PageFore from '../views/PageFore'
import APP from '../App'

Vue.use(VueRouter)

const routes = [
  {
    path: "/",
    name: "导航1",
    children: [
      {
        path: "/pageOne",
        name: "页面1",
        component: PageOne
      },
      {
        path: "/pageTwo",
        name: "页面2",
        component: PageTwo
      }
    ]
  },{
    path: "/navigation",
    name: "导航2",
    component: APP,
    children: [
      {
        path: "/pageThree",
        name: "页面3",
        component: PageThree
      },
      {
        path: "/pageFore",
        name: "页面4",
        component: PageFore
      }
    ]
  }
]

在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>
          <el-submenu v-for="(item,index) in $router.options.routes" :index="index">
            <template slot="title"><i class="el-icon-message"></i>{{item.name}}</template>
            <el-menu-item v-for="(item2,index2) in item.children" :index="index+'-'+index2">{{item2.name}}</el-menu-item>
          </el-submenu>
        </el-menu>

      </el-aside>

        <el-main>
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

v-for="(item,index) in $router.options.routes" :index=“index” 是为了让遍历出来的下标不一样,为了获取唯一标识

menu与router的绑定

  1. 标签添加router属性

  2. 在页面中添加标签,它是一个容器,动态渲染你选择的router

  3. 标签中绑定:index="item2.path"

    redirect: "/pageOne"重定向到/pageOne页面

  4. 实现导航栏默认打开以及选中当前页 高亮

    给加上一个判断:class="$route.path==item2.path?'is-active':''"

    $route获取的是浏览器url的当前路径地址

    image-20210306204452290

添加表单并实现分页查询

在ElementUI官网粘贴表单代码

<template>
  <div>
  <el-table
      :data="tableData"
      style="width: 100%"
      max-height="250">
    <el-table-column
        fixed
        prop="bookId"
        label="id"
        width="150">
    </el-table-column>
    <el-table-column
        prop="bookName"
        label="书名"
        width="120">
    </el-table-column>
    <el-table-column
        prop="bookCounts"
        label="书本数量"
        width="120">
    </el-table-column>
    <el-table-column
        prop="detail"
        label="鸡汤"
        width="120">
    </el-table-column>

    <el-table-column
        fixed="right"
        label="操作"
        width="120">
      <template slot-scope="scope">
        <el-button
            @click.native.prevent="deleteRow(scope.$index, tableData)"
            type="text"
            size="small">
          移除
        </el-button>
      </template>
    </el-table-column>
  </el-table>

    <el-pagination
        background
        layout="prev, pager, next"
        page-size="4"
        :total="total"
        @current-change="page">
    </el-pagination>
  </div>
</template>

后端使用mybatis插件pagehelper实现分页查询

  1. 添加pagehelper依赖

    <!--mybatis分页插件-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.3.0</version>
    </dependency>
    
  2. 对findAll查询方法进行修改

    修改BookService接口方法

    PageInfo<Book> findAll(Integer pageNum,Integer pageSize);
    

    修改BookServiceImpl实现类

    @Override
    public PageInfo<Book> findAll(Integer pageNum,Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        List<Book> books = bookDao.findAll();
        PageInfo<Book> bookPageInfo = new PageInfo<>(books,pageSize);
        return bookPageInfo;
    }
    

    修改BookController方法

    @RestController
    @RequestMapping("book")
    @CrossOrigin //允许跨域
    public class BookController {
        @Autowired
        private BookService bookService;
    
        @GetMapping("findAll/{page}/{limit}")
        public PageInfo<Book> findAll(@PathVariable("page") Integer page,@PathVariable("limit") Integer limit){
    
            PageInfo<Book> books = bookService.findAll(page, limit);
    
            return books;
        }
    }
    

    测试

    image-20210307093443860

完成前端页面的绑定

  1. 在methods中编写page方法

    page(currentpage){
        const _this = this;
        axios.get('http://localhost:8181/book/findAll/'+ currentpage +'/4').then(res=>{
            _this.tableData = res.data.list;
            _this.total = res.data.total
            console.log(res.data);
        })
    }
    
  2. 在data()中定义接收参数

    data() {
        return {
          total: null,
          tableData: null
        }
    
      }
    
  3. 创建created()方法在页面加载前查询显示数据

    created() {
        const _this = this;
        axios.get('http://localhost:8181/book/findAll/1/4').then(res=>{
          _this.tableData = res.data.list;
          _this.total = res.data.total
          console.log(res.data);
        })
      }
    
  4. 在表单中将接收属性改为后台传来的数据值

    <el-table
          :data="tableData"
          style="width: 100%"
          max-height="250">
        <el-table-column
            fixed
            prop="bookId"
            label="id"
            width="150">
        </el-table-column>
        <el-table-column
            prop="bookName"
            label="书名"
            width="120">
        </el-table-column>
        <el-table-column
            prop="bookCounts"
            label="书本数量"
            width="120">
        </el-table-column>
        <el-table-column
            prop="detail"
            label="鸡汤"
            width="120">
        </el-table-column>
    
        <el-table-column
            fixed="right"
            label="操作"
            width="120">
          <template slot-scope="scope">
            <el-button
                @click.native.prevent="deleteRow(scope.$index, tableData)"
                type="text"
                size="small">
              移除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    
  5. 在后面添加分页代码

    <el-pagination
                   background
                   layout="prev, pager, next"
                   page-size="4"
                   :total="total"
                   @current-change="page">
    </el-pagination>
    
  6. 设置分页代码的total为自己所定义的属性值以及@current-change方法

  7. 测试

    image-20210307094531282

Element UI 表单数据校验

定义rules对象, 在rules对象中设置表单各个校验规则

rules: {
        name: [
          { required: true, message: '请输入活动名称', trigger: 'blur' },
          { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
        ],
  • required: true, 是否为必填项
  • message: '请输入活动名称' 提示信息
  • trigger: 'blur' 触发事件

添加数据表

在Element UI官网找到合适的表单

<template>
  <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">

    <el-form-item label="图书名称" prop="bookName">
      <el-input style="width: 60%" v-model="ruleForm.bookName"></el-input>
    </el-form-item>

    <el-form-item label="图书数量" prop="bookCounts">
      <el-input style="width: 60%" v-model="ruleForm.bookCounts"></el-input>
    </el-form-item>

    <el-form-item label="图书鸡汤" prop="detail">
      <el-input style="width: 60%" v-model="ruleForm.detail"></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: {
        bookName: '',
        bookCounts: '',
        detail: '',
      },
      //校验的规则
      rules: {
        bookName: [
          { required: true, message: '图书名称不能为空', trigger: 'blur' },
          { min: 3, max: 15, message: '长度在 3 到 5 个字符', trigger: 'blur' }
        ],
        bookCounts: [
          { required: true, message: '图书数量不能为空(若没有请填写0)', trigger: 'change' }
        ],
        detail: [
          { required: true, message: '图书鸡汤不能为空', trigger: 'change' }
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
      const _this = this;
      this.$refs[formName].validate((valid) => {
        if (valid) {
          axios.post("http://localhost:8181/book/save",this.ruleForm).then(res=>{
            if (res.data == "success"){
              _this.$message({
                message: '恭喜你,上传成功',
                type: 'success'
              });
              _this.$router.push('/pageOne')
            }
          });
        } else {
          return false;
        }
      });
    },
    test(){
      console.log(this.ruleForm);
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  }
}
</script>

<style scoped>

</style>
  • <el-form>中定义ref标签与所定义的方法和提交按钮绑定所定义的数据

  • 在提交按钮添加点击事件@click="submitForm('ruleForm')"

  • 定义submitForm方法

    submitForm(formName) {
          const _this = this;
          this.$refs[formName].validate((valid) => {
            if (valid) {
              axios.post("http://localhost:8181/book/save",this.ruleForm).then(res=>{
                if (res.data == "success"){
                  _this.$message({
                    message: '恭喜你,上传成功',
                    type: 'success'
                  });
                  _this.$router.push('/pageOne')
                }
              });
            } else {
              return false;
            }
          });
        },
    

    其中axios中post路径是调用后台数据插入的url

  • 后台创建插入方法

    • 依次创建bookDao、bookDaoMapper.xml

      void save(Book book);
      
      ---------------------
          
       <insert id="save" parameterType="Book">
              insert into ssmbuild.books values (#{bookId},#{bookName},#{bookCounts},#{detail});
          </insert>
      
    • 创建bookService、bookServiceImpl实现类

      Book save(Book book);
      
      --------------------------
      
          @Override
          public Book save(Book book) {
          bookDao.save(book);
          return book;
      }
      
    • 创建bookController方法

      @PostMapping("save")
          //由于前段传来的是json对象需要加@RequestBody才能变成java对象
          public String save(@RequestBody Book book){
              Book result = bookService.save(book);
              if (result != null){
                  return "success";
              }else {
                  return "error";
              }
          }
      
  • 测试

    image-20210307141358594

修改数据

首先让选中的图书在修改页面显示信息

创建BookUpdate.vue

添加表单

<template>
  <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">

    <el-form-item label="图书id">
      <el-input style="width: 60%" v-model="ruleForm.bookId" readonly></el-input>
    </el-form-item>

    <el-form-item label="图书名称" prop="bookName">
      <el-input style="width: 60%" v-model="ruleForm.bookName"></el-input>
    </el-form-item>

    <el-form-item label="图书数量" prop="bookCounts">
      <el-input style="width: 60%" v-model="ruleForm.bookCounts"></el-input>
    </el-form-item>

    <el-form-item label="图书鸡汤" prop="detail">
      <el-input style="width: 60%" v-model="ruleForm.detail"></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: {
        bookId: '',
        bookName: '',
        bookCounts: '',
        detail: '',
      },
      //校验的规则
      rules: {
        bookName: [
          { required: true, message: '图书名称不能为空', trigger: 'blur' },
          { min: 3, max: 15, message: '长度在 3 到 15 个字符', trigger: 'blur' }
        ],
        bookCounts: [
          { required: true, message: '图书数量不能为空(若没有请填写0)', trigger: 'change' }
        ],
        detail: [
          { required: true, message: '图书鸡汤不能为空', trigger: 'change' }
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
      const _this = this;
      this.$refs[formName].validate((valid) => {

        if (valid) {
          axios.put("http://localhost:8181/book/bookUpdate",this.ruleForm).then(res=>{
            if (res.data == "success"){
              _this.$message({
                message: '恭喜你,修改成功',
                type: 'success'
              });
              _this.$router.push('/BookManage')
            }
          });
        } else {
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  },
  created() {
    const _this = this;

    axios.get("http://localhost:8181/book/findId/" + this.$route.query.bookId).then(res=>{
      _this.ruleForm = res.data;
    })
  }
}
</script>
  • 在BookMange页面中修改添加绑定事件@click="edit()"

    edit(row) {
          this.$router.push({
            path: '/BookUpdate',
            query: {
              bookId:row.bookId
            }
          })
          //console.log(row.bookId);
          //rows.splice(index, 1);
        }
    

    点击按钮后将所选id传递

  • 在后台创建update方法

    BookDao、BookDaoMapper

    void updateBook(Book book);
    
    ----------------------------
        
    <update id="updateBook" parameterType="Book">
            update ssmbuild.books set bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail}
            where bookID = #{bookId};
        </update>
    
  • BookService、BookServiceImpl

  Book updateBook(Book book);
-------------------------------
      
  @Override
  public Book updateBook(Book book) {
  	bookDao.updateBook(book);
  	return book;
  }
  • BookController

    //根据id修改数据
        @PutMapping("bookUpdate")
        public String updateBook(@RequestBody Book book){
            Book result = bookService.updateBook(book);
            if (result != null){
                return "success";
            }else {
                return "error";
            }
        }
    
  • 在Vue前台BookUpdate.vue中创建created函数

    created() {
        const _this = this;
    
        axios.get("http://localhost:8181/book/findId/" + this.$route.query.bookId).then(res=>{
          _this.ruleForm = res.data;
        })
      }
    

    并在文中使用v-model进行绑定

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chiizNv5-1615121535629)(C:\Users\MengFei\AppData\Roaming\Typora\typora-user-images\image-20210307192329214.png)]

  • image-20210307192348656

进行修改操作

步骤类似添加书籍

给提交按钮添加点击事件@click="submitForm('ruleForm')

定义方法

submitForm(formName) {
      const _this = this;
      this.$refs[formName].validate((valid) => {

        if (valid) {
          axios.put("http://localhost:8181/book/bookUpdate",this.ruleForm).then(res=>{
            if (res.data == "success"){
              _this.$message({
                message: '恭喜你,修改成功',
                type: 'success'
              });
              _this.$router.push('/BookManage')
            }
          });
        } else {
          return false;
        }
      });
    }

image-20210307192616221

删除数据

步骤同修改数据

  • 给删除按钮添加点击事件deleteBook(scope.row)

  • 后台依次创建dao、daoMaper、Service、ServiceImpl、Controller

  • 在BookMange.vue页面创建deleteBook方法

    deleteBook(row){
          const _this = this;
    
          axios.delete("http://localhost:8181/book/deleteBook/" + row.bookId).then(res=>{
            _this.$alert('(' + row.bookName + ') 删除成功', '消息', {
              confirmButtonText: '确定',
              callback: action => {
                window.location.reload();
              }
            });
          })
        }
    

res.data == “success”){
_this. m e s s a g e ( m e s s a g e : ′ 恭 喜 你 , 修 改 成 功 ′ , t y p e : ′ s u c c e s s ′ ) ; t h i s . message({ message: '恭喜你,修改成功', type: 'success' }); _this. message(message:,type:success);this.router.push(’/BookManage’)
}
});
} else {
return false;
}
});
}


[外链图片转存中...(img-nlImZzDT-1615121535631)]

##   删除数据

步骤同修改数据

- 给删除按钮添加点击事件`deleteBook(scope.row)`

- 后台依次创建dao、daoMaper、Service、ServiceImpl、Controller

- 在BookMange.vue页面创建deleteBook方法

  ```javascript
  deleteBook(row){
        const _this = this;
  
        axios.delete("http://localhost:8181/book/deleteBook/" + row.bookId).then(res=>{
          _this.$alert('(' + row.bookName + ') 删除成功', '消息', {
            confirmButtonText: '确定',
            callback: action => {
              window.location.reload();
            }
          });
        })
      }
Logo

前往低代码交流专区

更多推荐