毕设过程记录(web管理系统)

党建管理系统

1、软件版本

  • jdk1.8
  • mysql8.0
  • node14.16.0
  • navicat
  • idea2021.3

##2、准备与创建vue项目

vue-cli安装:npm install -g @vue/cli

npm设置淘宝镜像加速:npm config set registry https://registry.npm.taobao.org

  • 创建vue项目:vue create vue
  • 运行vue项目:
cd vue
npm run serve
  • 安装ElementUI:npm i element-ui -S

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '../src/assets/gloable.css'


Vue.config.productionTip = false

Vue.use(ElementUI,{size:"small"});

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

Home.vue(第一节)

<el-button type="danger">{{ msg }}</el-button>

	export default{
	name:'Home',
	components:{
		Helloworld
	},data(){
		return{
		   msg:"hello world"
		   }
		}
	}

Home.vue(第二节)

<template>
  <div style="height: 100%">
    <el-container style="height: 100%; /*border: 1px solid #eee*/">
      <el-aside width="217px" style="background-color: rgb(238, 241, 246);height: 100%">
        <el-menu :default-openeds="['1', '3']" style="height: 100%">
          <el-submenu index="1">
            <template slot="title"><i class="el-icon-message"></i>导航一</template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
          <el-submenu index="2">
            <template slot="title"><i class="el-icon-menu"></i>导航二</template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
          <el-submenu index="3">
            <template slot="title"><i class="el-icon-setting"></i>导航三</template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="3-1">选项1</el-menu-item>
              <el-menu-item index="3-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="3-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="3-4">
              <template slot="title">选项4</template>
              <el-menu-item index="3-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="text-align: right; font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px">
          <el-dropdown>
            <i class="el-icon-setting" style="margin-right: 15px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>查看</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>删除</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
          <span>王小虎</span>
        </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>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

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

App.vue(第二节)

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style>
#app{
  height: 100%;
}

</style>

package.json

{
  "name": "vue01",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "element-ui": "^2.15.6",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "vue-template-compiler": "^2.6.11"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

gloable.css(第二节)

html,body,div{
    margin: 0;
    padding: 0;
}

html,body{
    height: 100%;
}

在main.js引入:import '../src/assets/gloable.css'

3、Vue后台整体布局完善

gloable.css(第二节)

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="3-1">选项1</el-menu-item>
              <el-menu-item index="3-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="3-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="3-4">
              <template slot="title">选项4</template>
              <el-menu-item index="3-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </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>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

  data(){
    const item = {
      date: '2016-05-02',
      name: '王小虎',
      address: '上海市普陀区金沙江路 1518 弄'
    };
    return {
      tableData: Array(10).fill(item),
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true
    }
  },
  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    }
  }
}
</script>

App.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style>
#app{
  min-height: 100vh;
}

</style>

main.js

保持不变

4、Vue页面主体布局完善

gloable.css(第三节)

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.ml-5{
    margin-left: 5px;
}

.mr-5{
    margin-right: 5px;
}

.pd-10{
    padding: 10px 0;
}

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入查找内容" suffix-icon="el-icon-search"></el-input>
            <el-button class="ml-5" type="primary">搜索</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <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-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                :page-sizes="[5, 10, 15, 20]"
                :page-size="10"
                layout="total, sizes, prev, pager, next, jumper"
                :total="400">
            </el-pagination><!--分页栏-->
          </div>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

  data(){
    const item = {
      date: '2016-05-02',
      name: '王小虎',
      address: '上海市普陀区金沙江路 1518 弄'
    };
    return {
      tableData: Array(10).fill(item),
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },
  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '../src/assets/gloable.css'


Vue.config.productionTip = false

Vue.use(ElementUI,{size:"mini"});

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

App.vue

<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<style>
#app{
  min-height: 100vh;
}

</style>

5、SpringBoot框架搭建

pom里配置阿里云仓库(加速maven下载依赖,放在pom.xml文件最后)

<repositories>
    <repository>
        <id>nexus-aliyun</id>
        <name>nexus-aliyun</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

<pluginRepositories>
    <pluginRepository>
        <id>public</id>
        <name>aliyun nexus</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

配置application.properties

server.port=9090

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8
spring.datasource.username=root
spring.datasource.password=180918

写个测试接口

package com.kep.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

    @GetMapping("/")
    public String index(){
        return "ok";
    }
}

并导入vue项目到springboot文件夹中

6、SpringBoot集成Mybatis实现数据查询

application.properties改进为application.yml

server:
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8
    username: root
    password: 180918

按照数据库三范式创建数据库表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nLyuODru-1647074177441)(软工毕设/image/Snipaste_2022-02-07_11-53-34.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ox2gYV1m-1647074177442)(软工毕设/image/Snipaste_2022-02-07_11-54-02.png)]

用Mybatis来操作数据库

1、首先在java包下创建entity包

2、在entity包里创建实体类User,将数据库表中属性在实体类中声明出来

set和get方法一般是用来给类的成员变量赋值的,由于类的成员变量一般会声明为private的,其他的类是不能直接访问成员变量的,所以为了在类以外给该类的成员变量赋值或者取值,只有用声明为public的set和get方法来实现set和get方法是用于封装的 所以一般只在private中用 当然你如果不是在private中用也没关系 代码也是可以执行的。

public void setA(int a){this.a = a; }是传进去一个int类型的实参a把它赋值给类里的形参a

public void setA(){this.a = a; }相当于执行了一条a=a的代码 都是形参;

public int getA(int a){this.a = a;}

public int get(){this.a = a;}

这两条代码都通不过编译 会提示没有返回值。

package com.kep.springboot.entity;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private String email;
    private String address;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

可使用lombok插件简化代码

package com.kep.springboot.entity;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private String email;
    private String address;
    
}

3、在java包下创建mapper包,在包下创建数据库接口(注解@select由Mybatis提供,注解@Mapper将UserMapper这个bean注入springboot)

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

}

4、在SpringbootApplication.java里查询出所有数据(@RestController注解与@GetMapper组合使用,@RestController标识SpringbootApplication是一个接口,然后@GetMapper用于查询所有数据。)

package com.kep.springboot;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@SpringBootApplication
public class SpringbootApplication {

    @Autowired
    private UserMapper userMapper;

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

    @GetMapping("/")
    public List<User> index(){
        return userMapper.findAll();
    }
}

但是我们并不应该这么写,而是:

4、在java包下com.kep.springboot包里新建controller包,在controller包里新建类UserController.java,再将SpringbootApplication.java内的内容转移到到UserController里。此时:

SpringbootApplication.java

package com.kep.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

UserController.java

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/")
    public List<User> index(){
        return userMapper.findAll();
    }
}

7、SpringBoot实现增删改查

1、接口UserMapper.java中添加插入注解@Insert

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);
}

2、在UserController.java类中添加注解@PostMapper,写上save接口,注解@RequestBody是把前台传来的json对象转成后台的java对象

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

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

    @Autowired
    private UserMapper userMapper;

    @PostMapping
    public Integer save(@RequestBody User user){
        return userMapper.insert(user);
    }

    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }
}

3、下载postman工具,用于测试接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ots5vfLk-1647074177443)(软工毕设/image/Snipaste_2022-02-07_14-48-31.png)]

send成功插入数据后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mkzKLwH3-1647074177444)(软工毕设/image/Snipaste_2022-02-07_14-52-48.png)]

4、在包下添加service包,创建UserService类,加入注解@Service

package com.kep.springboot.service;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public int save(User user){
        if (user.getId()==null){    //user没有id,则表示是新增
            return userMapper.insert(user);
        }else { //否则为更新
            return userMapper.update(user);
        }
    }

}

在UserMapper接口中并用postman测试(静态更新操作)

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);

    @Update("update sys_user set username = #{username},password = #{password},nickname=#{nickname},email=#{email}," +
            "phone=#{phone},address=#{address} where id = #{id}")
    int update(User user);
}

5、改为动态sql更新数据库

先在resources下建文件夹mapper,创建文件User.xml,将原来@update注解删除

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTO Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kep.springboot.mapper.UserMapper">
    <update id="update">
        update sys_user
        <set>
            <if test="username !=null">
                username = #{username},
            </if>
            <!--<if test="password !=null">
                password = #{password}
            </if>-->
            <if test="nickname !=null">
                nickname = #{nickname},
            </if>
            <if test="email !=null">
                email = #{email},
            </if>
            <if test="phone !=null">
                phone = #{phone},
            </if>
            <if test="address !=null">
                address = #{address}
            </if>
        </set>
        <where>
            id = #{id}
        </where>
    </update>

</mapper>

删除后UserMapper.java

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);

    int update(User user);
}

最后在application.yml文件中添加扫描所有mybatis的xml文件

server:
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8
    username: root
    password: 180918
mybatis:
  mapper-locations: classpath:mapper/*.xml #扫描所有mybatis的xml文件

测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a6JVdYFG-1647074177444)(软工毕设/image/Snipaste_2022-02-07_16-28-48.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7y7Yugc-1647074177444)(软工毕设/image/Snipaste_2022-02-07_16-29-12.png)]

6、删除功能(用注释实现)

在UserController.java中

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public Integer save(@RequestBody User user){
        // 新增或者更新
        return userService.save(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }

    //删除
    @DeleteMapping("/{id}")
    public Integer delete(@PathVariable Integer id) {   //表示url参数
       return userMapper.deleteById(id);
    }
}

在UserMapper.java中

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);

    int update(User user);

    @Delete("delete from sys_user where id = #{id}")
    Integer deleteById(@Param("id") Integer id);

}

测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u8TBLEh2-1647074177445)(软工毕设/image/Snipaste_2022-02-07_16-46-59.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MMmofhUg-1647074177445)(软工毕设/image/Snipaste_2022-02-07_16-47-31.png)]

8、SpringBoot实现分页查询

1、纯手写分页查询

在UserController里

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public Integer save(@RequestBody User user){
        // 新增或者更新
        return userService.save(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }

    //删除
    @DeleteMapping("/{id}")
    public Integer delete(@PathVariable Integer id) {   //表示url参数
       return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
    @GetMapping("/page")
    public Map<String, Object> findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize){
        pageNum = (pageNum -1) * pageSize;
        List<User> data=userMapper.selectPage(pageNum,pageSize);
        Integer total = userMapper.selectTotal();
        Map<String,Object> res = new HashMap<>();
        res.put("data",data);
        res.put("total",total);
        return res;
    }
}

在UserMapper类里

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);

    int update(User user);

    @Delete("delete from sys_user where id = #{id}")
    Integer deleteById(@Param("id") Integer id);

    @Select("select * from sys_user limit #{pageNum},#{pageSize}")
    List<User> selectPage(Integer pageNum, Integer pageSize);

    @Select("select count(*) from sys_user")
    Integer selectTotal();
}

测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZsXjX7hj-1647074177445)(软工毕设/image/Snipaste_2022-02-07_17-34-26.png)]

分页与Home.vue结合

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入查找内容" suffix-icon="el-icon-search"></el-input>
            <el-button class="ml-5" type="primary">搜索</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <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-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                :page-sizes="[5, 10, 15, 20]"
                :page-size="10"
                layout="total, sizes, prev, pager, next, jumper"
                :total="400">
            </el-pagination><!--分页栏-->
          </div>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

  data(){
    const item = {
      date: '2016-05-02',
      name: '王小虎',
      address: '上海市普陀区金沙江路 1518 弄'
    };
    return {
      tableData: Array(10).fill(item),
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res => res.json()).then(res => {
      console.log(res)
    })
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

产生了前端跨域问题

Access to fetch at ‘http://localhost:9090/user/page?pageNum=1&pageSize=2’ from origin ‘http://192.168.10.3:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

跨域是当它请求的一个资源是从一个与它本身提供的第一个资源的不同的域名时,一个资源会发起一个跨域HTTP请求(Cross-site HTTP request)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPCUfR5A-1647074177446)(软工毕设/image/Snipaste_2022-02-07_18-08-35.png)]

因此需要springboot跨域配置

在包下创建config包,包里创建CorsConfig.java

package com.kep.springboot.config;

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 {

    // 当前跨域请求最大有效时长。这里默认1天
    private static final long MAX_AGE = 24 * 60 * 60;

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("http://localhost:8080"); // 1 设置访问源地址
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
        corsConfiguration.setMaxAge(MAX_AGE);
        source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
        return new CorsFilter(source);
    }
}


忽略某个字段,不展示给前端

package com.kep.springboot.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

@Data
public class User {
    private Integer id;
    private String username;
    @JsonIgnore
    private String password;
    private String nickname;
    private String email;
    private String phone;
    private String address;

}

动态sql改变后

对于UserController,用Map封装起来

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public Integer save(@RequestBody User user){
        // 新增或者更新
        return userService.save(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }

    //删除
    @DeleteMapping("/{id}")
    public Integer delete(@PathVariable Integer id) {   //表示url参数
       return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
    @GetMapping("/page")
    public Map<String, Object> findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize){
        pageNum = (pageNum -1) * pageSize;
        List<User> data=userMapper.selectPage(pageNum,pageSize);
        Integer total = userMapper.selectTotal();
        Map<String,Object> res = new HashMap<>();
        res.put("data",data);
        res.put("total",total);
        return res;
    }
}

对于Home.vue,进行修改后

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入查找内容" suffix-icon="el-icon-search"></el-input>
            <el-button class="ml-5" type="primary">搜索</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[2, 5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:2,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      fetch("http://localhost:9090/user/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize).then(res => res.json()).then(res => {
        console.log(res)
        this.tableData = res.data
        this.total = res.total
      })
    },
    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

SpringBoot针对于username进行模糊查询

对于Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入查找内容" suffix-icon="el-icon-search" v-model="username"></el-input>
            <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      fetch("http://localhost:9090/user/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize+"&username="+this.username).then(res => res.json()).then(res => {
        console.log(res)
        this.tableData = res.data
        this.total = res.total
      })
    },
    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

对于UserMapper.java

package com.kep.springboot.mapper;

import com.kep.springboot.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserMapper {

    @Select("SELECT * from sys_user")
    List<User> findAll();

    @Insert("INSERT into sys_user(username,password,nickname,email,phone,address) VALUES (#{username},#{password}," +
            "#{nickname},#{email},#{phone},#{address})")
    int insert(User user);

    int update(User user);

    @Delete("delete from sys_user where id = #{id}")
    Integer deleteById(@Param("id") Integer id);

    @Select("select * from sys_user where username like #{username} limit #{pageNum},#{pageSize}")
    List<User> selectPage(Integer pageNum, Integer pageSize,String username);

    @Select("select count(*) from sys_user where username like #{username}")
    Integer selectTotal(String username);
}

对于UserController.java

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public Integer save(@RequestBody User user){
        // 新增或者更新
        return userService.save(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }

    //删除
    @DeleteMapping("/{id}")
    public Integer delete(@PathVariable Integer id) {   //表示url参数
       return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
    @GetMapping("/page")
    public Map<String, Object> findPage(@RequestParam Integer pageNum,
                                        @RequestParam Integer pageSize,
                                        @RequestParam String username){
        pageNum = (pageNum -1) * pageSize;
        username = "%"+username+"%";
        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
        Integer total = userMapper.selectTotal(username);
        Map<String,Object> res = new HashMap<>();
        res.put("data",data);
        res.put("total",total);
        return res;
    }
}

下节实现多条件查询

9、SpringBoot集成Mybatis-plus和SwaggerUI

依赖引入Mybatis-plus

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

在config包下创建MybatisPlusConfig.java,再加上@MapperScan,而此时UserMapper.java中@Mapper不需要了

package com.kep.springboot.config;

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;

@Configuration
@MapperScan("com.kep.springboot.mapper")
public class MybatisPlusConfig {

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

用Mybatis-plus框架来实现新增与修改

UserService.java

package com.kep.springboot.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService extends ServiceImpl<UserMapper,User> {
    public boolean saveUser(User user) {
//        if (user.getId() ==null){
//            return save(user);  //mybatis-plus提供的方法,表示插入数据
//        }else {
//            return updateById(user);
//        }
//    }
        return saveOrUpdate(user);
//    @Autowired
//    private UserMapper userMapper;

//    public int save(User user){
//        if (user.getId()==null){    //user没有id,则表示是新增
//            return userMapper.insert(user);
//        }else { //否则为更新
//            return userMapper.update(user);
//        }
//    }

    }
}

UserController.java

package com.kep.springboot.controller;

import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        List<User> all= userMapper.findAll();
        return all;
    }

    //删除
    @DeleteMapping("/{id}")
    public Integer delete(@PathVariable Integer id) {   //表示url参数
       return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
    @GetMapping("/page")
    public Map<String, Object> findPage(@RequestParam Integer pageNum,
                                        @RequestParam Integer pageSize,
                                        @RequestParam String username){
        pageNum = (pageNum -1) * pageSize;
        username = "%"+username+"%";
        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
        Integer total = userMapper.selectTotal(username);
        Map<String,Object> res = new HashMap<>();
        res.put("data",data);
        res.put("total",total);
        return res;
    }
}

因为Mybatis-plus无法识别数据库表名称

错误示例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pAYGy5k0-1647074177447)(软工毕设/image/Snipaste_2022-02-07_23-02-26.png)]

因此:

User.java

package com.kep.springboot.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

@Data
@TableName(value = "sys_user")
public class User {

    @TableId(type = IdType.AUTO)    //指定主键是id
    private Integer id;
    private String username;
    @JsonIgnore
    private String password;
    private String nickname;
    private String email;
    private String phone;
    private String address;          //驼峰写法也可以_后面第一个字母大写

}

集成Swagger-UI,用Swagger测试接口,Swagger是一个后台生成的接口文档,在springboot项目中集成swagger-ui

1、Swagger配置类

第一步,需要在pom中引入相应的配置,这里使用2.7.0的版本。需要注意的是2.7.0和2.8.0的版本在界面风格上差异很大,如果感兴趣,可以试试2.8.0以上的版本,我比较青睐使用2.7.0及以下的版本,因为界面比较清爽。

第一步 引入pom

<!--swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

第二步
在代码中加入相应的配置,新建config包,写入swaggerConfig配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    /**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
     * 本例采用指定扫描的包路径来定义指定要建立API的目录。
     *
     * @return
     */
    @Bean
    public Docket restApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("标准接口")
                .apiInfo(apiInfo("Spring Boot中使用Swagger2构建RESTful APIs", "1.0"))
                .useDefaultResponseMessages(true)
                .forCodeGeneration(false)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xqnode.learning.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 创建该API的基本信息(这些基本信息会展现在文档页面中)
     * 访问地址:http://ip:port/swagger-ui.html
     *
     * @return
     */
    private ApiInfo apiInfo(String title, String version) {
        return new ApiInfoBuilder()
                .title(title)
                .description("更多请关注: https://blog.csdn.net/xqnode")
                .termsOfServiceUrl("https://blog.csdn.net/xqnode")
                .contact(new Contact("xqnode", "https://blog.csdn.net/xqnode", "xiaqingweb@163.com"))
                .version(version)
                .build();
    }
}

此时访问http://localhost:9090/swagger-ui.html

若改用Swagger3.0版本,则:

在pom.xml中引入依赖

<!--swagger-->
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

在SwaggerConfig.java中

package com.kep.springboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
@EnableOpenApi
public class SwaggerConfig {

    /**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
     * 本例采用指定扫描的包路径来定义指定要建立API的目录。
     *
     * @return
     */
    @Bean
    public Docket restApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("标准接口")
                .apiInfo(apiInfo("Spring Boot中使用Swagger2构建RESTful APIs", "1.0"))
                .useDefaultResponseMessages(true)
                .forCodeGeneration(false)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.kep.springboot.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * 创建该API的基本信息(这些基本信息会展现在文档页面中)
     * 访问地址:http://ip:port/swagger-ui.html
     *
     * @return
     */
    private ApiInfo apiInfo(String title, String version) {
        return new ApiInfoBuilder()
                .title(title)
                .description("党建管理系统Swagger-UI")
                .termsOfServiceUrl("https://blog.csdn.net/xqnode")
                .contact(new Contact("xqnode", "https://blog.csdn.net/xqnode", "xiaqingweb@163.com"))
                .version(version)
                .build();
    }
}

此时访问http://localhost:9090/swagger-ui/index.html来实现对后台接口测试

用Mybatis-plus的方式实现分页查询

则UserController.java变为:

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam String username){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        IPage<User> userPage = userService.page(page, queryWrapper);
        return userPage;
    }
}

出现错误:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uSxeIeUD-1647074177448)(软工毕设/image/Snipaste_2022-02-08_13-26-01.png)]

原因是与UserMapper.java中的SelectPage重复了,将UserMapper中用注解写的全都注释掉后

将UserMapper.java写成

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam String username){
        IPage<User> page =new Page<>(pageNum,pageSize);
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        IPage<User> userPage = userService.page(page, null);
//        queryWrapper.like("username",username);
        return userPage;
    }
}

postman测试结果为:

{

"records": [
    {
        "id": 1,
        "username": "admin",
        "nickname": "管理员",
        "email": "admin@qq.com",
        "phone": "1388888888",
        "address": "湖北省武汉市"
    },
    {
        "id": 2,
        "username": "ke",
        "nickname": "柯鹏",
        "email": "k180918@163.com",
        "phone": "13872062736",
        "address": "湖北省黄石市"
    }
],
"total": 8,
"size": 2,
"current": 1,
"orders": [],
"optimizeCountSql": true,
"searchCount": true,
"countId": null,
"maxLimit": null,
"pages": 4

}

但我们只需要record与total内容

最后我们将UserController改写为:

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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


    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam String username){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username",username);
        IPage<User> userPage = userService.page(page,queryWrapper);
        return userPage;
    }
}

模糊查询测试结果为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5p5qCbgp-1647074177448)(软工毕设/image/Snipaste_2022-02-08_13-48-33.png)]

并且Mybatis-plus框架可以方便实现多条件模糊查询

在UserController中

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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


    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam String username,
                                @RequestParam String nickname){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username",username);
        queryWrapper.like("nickname",nickname);
        //或者 queryWrapper.and(w -> w.like("nickname",nickname));
        IPage<User> userPage = userService.page(page,queryWrapper);
        return userPage;
    }
}

可实现:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jloBha0b-1647074177448)(软工毕设/image/Snipaste_2022-02-08_14-04-45.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiHhcO5H-1647074177449)(软工毕设/image/Snipaste_2022-02-08_14-05-04.png)]

如果将查询换成查询后(例如将address加为或查询)

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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


    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam String username,
                                @RequestParam String nickname,
                                @RequestParam String address){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username",username);
        queryWrapper.like("nickname",nickname);
        queryWrapper.or().like("address",address);
        //或者 queryWrapper.and(w -> w.like("nickname",nickname));
        IPage<User> userPage = userService.page(page,queryWrapper);
        return userPage;
    }
}

测试结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OyOy1Bld-1647074177449)(软工毕设/image/Snipaste_2022-02-08_14-10-55.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zyxbZThy-1647074177449)(软工毕设/image/Snipaste_2022-02-08_14-11-29.png)]

若并查询,则若username与nickname为空,只按address查询应该可全部查到

因此改进UserController.java(加上默认值与判断语句)

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

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


    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam(defaultValue = "") String username,
                                @RequestParam(defaultValue = "") String nickname,
                                @RequestParam(defaultValue = "") String address){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)) {
            queryWrapper.like("username", username);
        }
        if (!"".equals(nickname)) {
            queryWrapper.like("nickname", nickname);
        }
        if (!"".equals(address)) {
            queryWrapper.like("address", address);
        }
        //或者 queryWrapper.and(w -> w.like("nickname",nickname));
        IPage<User> userPage = userService.page(page,queryWrapper);
        return userPage;
    }
}

实现效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gbQ8Jnzy-1647074177450)(软工毕设/image/Snipaste_2022-02-08_14-37-55.png)]

10、Vue实现增删改查

我们之前用的fetch来实现前端页面显示后台数据,现在用了Mybatis-plus框架后,我们改用axios

下载axios,在idea中前端项目文件中Terminal里写上 npm i axios -S

在前台部分新建文件夹utils,utils下新建文件request.js,request.js封装

import axios from 'axios'

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

在main.js中引入request.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '../src/assets/gloable.css'
import request from "./utils/request";


Vue.config.productionTip = false

Vue.use(ElementUI,{size:"mini"});

Vue.prototype.request=request

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

在Home.vue中修改fetch部分

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入查找内容" suffix-icon="el-icon-search" v-model="username"></el-input>
            <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("http://localhost:9090/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },
    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

此时可实现前后端数据绑定

实现新增功能

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入用户名查找" suffix-icon="el-icon-search" v-model="username"  @keyup.enter.native="triggerClick"></el-input>
            <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
            <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>

          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px" size="small">
              <el-form-item label="用户名">
                <el-input v-model="form.username" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="昵称">
                <el-input v-model="form.nickname" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="邮箱">
                <el-input v-model="form.email" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="电话">
                <el-input v-model="form.phone" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="地址">
                <el-input v-model="form.address" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false">取 消</el-button>
              <el-button type="primary" @click="save">确 定</el-button>
            </div>
          </el-dialog>

        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      nickname:"",
      form:{},
      dialogFormVisible:false,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("http://localhost:9090/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },

    save(){
      request.post("http://localhost:9090/user",this.form).then(res => {
        if (res){
          this.$message.success("保存成功!")
          this.dialogFormVisible = false
        }else {
          this.$message.error("保存失败!")
        }
      })
    },

    reset(){
      this.username = ""
      this.load()
    },

    triggerClick(){ //用于回车键触发搜索功能

  this.$refs.btn.$emit('click')

  this.$refs.select.blur()//解决选择框回车后展示下拉列表问题

},

    handleAdd(){
      this.dialogFormVisible = true //打开弹窗
      this.form = {}  //把form对象置空
    },


    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

此时新增的数据得实时显示,因此需要倒叙排列显示

实现编辑功能

由于新增和修改都是post接口

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入用户名查找" suffix-icon="el-icon-search" v-model="username"  @keyup.enter.native="triggerClick"></el-input>
            <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
            <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
                <el-button type="danger">删除 <i class="el-icon-remove-outline"></i></el-button>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>

          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px" size="small">
              <el-form-item label="用户名">
                <el-input v-model="form.username" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="昵称">
                <el-input v-model="form.nickname" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="邮箱">
                <el-input v-model="form.email" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="电话">
                <el-input v-model="form.phone" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="地址">
                <el-input v-model="form.address" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false">取 消</el-button>
              <el-button type="primary" @click="save">确 定</el-button>
            </div>
          </el-dialog>

        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      nickname:"",
      form:{},
      dialogFormVisible:false,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },

    save(){
      request.post("/user",this.form).then(res => {
        if (res){
          this.$message.success("保存成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("保存失败!")
        }
      })
    },

    reset(){
      this.username = ""
      this.load()
    },

    triggerClick(){ //用于回车键触发搜索功能

  this.$refs.btn.$emit('click')

  this.$refs.select.blur()//解决选择框回车后展示下拉列表问题

},

    handleAdd(){
      this.dialogFormVisible = true //打开弹窗
      this.form = {}  //把form对象置空
    },

    handleEdit(row){
      this.form = row
      this.dialogFormVisible = true

    },


    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

删除功能

用delete接口

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入用户名查找" suffix-icon="el-icon-search" v-model="username"  @keyup.enter.native="triggerClick"></el-input>
            <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
            <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
                <el-popconfirm
                    class="ml-5"
                  confirm-button-text='确定'
                  cancel-button-text='取消'
                  icon="el-icon-info"
                  icon-color="red"
                  title="确定删除吗?"
                  @confirm="del(scope.row.id)">
                <el-button type="danger" slot="reference" >删除 <i class="el-icon-remove-outline"></i></el-button>
              </el-popconfirm>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>

          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px" size="small">
              <el-form-item label="用户名">
                <el-input v-model="form.username" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="昵称">
                <el-input v-model="form.nickname" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="邮箱">
                <el-input v-model="form.email" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="电话">
                <el-input v-model="form.phone" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="地址">
                <el-input v-model="form.address" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false">取 消</el-button>
              <el-button type="primary" @click="save">确 定</el-button>
            </div>
          </el-dialog>

        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      nickname:"",
      form:{},
      dialogFormVisible:false,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },

    save(){
      request.post("/user",this.form).then(res => {
        if (res){
          this.$message.success("保存成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("保存失败!")
        }
      })
    },

    del(id){
      request.delete("/user/"+id).then(res => {
        if (res){
          this.$message.success("删除成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("删除失败!")
        }
      })
    },

    reset(){
      this.username = ""
      this.load()
    },

    triggerClick(){ //用于回车键触发搜索功能

  this.$refs.btn.$emit('click')

  this.$refs.select.blur()//解决选择框回车后展示下拉列表问题

},

    handleAdd(){
      this.dialogFormVisible = true //打开弹窗
      this.form = {}  //把form对象置空
    },

    handleEdit(row){
      this.form = row
      this.dialogFormVisible = true

    },


    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

批量删除功能

用element-ui中Checkbox

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入用户名查找" suffix-icon="el-icon-search" v-model="username"  @keyup.enter.native="triggerClick"></el-input>
            <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
            <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-button type="danger" @click="delBatch">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            <el-button type="primary">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55">
            </el-table-column>
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
                <el-popconfirm
                    class="ml-5"
                  confirm-button-text='确定'
                  cancel-button-text='取消'
                  icon="el-icon-info"
                  icon-color="red"
                  title="确定删除吗?"
                  @confirm="del(scope.row.id)">
                <el-button type="danger" slot="reference" >删除 <i class="el-icon-remove-outline"></i></el-button>
              </el-popconfirm>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>

          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px" size="small">
              <el-form-item label="用户名">
                <el-input v-model="form.username" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="昵称">
                <el-input v-model="form.nickname" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="邮箱">
                <el-input v-model="form.email" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="电话">
                <el-input v-model="form.phone" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="地址">
                <el-input v-model="form.address" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false">取 消</el-button>
              <el-button type="primary" @click="save">确 定</el-button>
            </div>
          </el-dialog>

        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      nickname:"",
      form:{},
      dialogFormVisible:false,
      multipleSelection:[],
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },

    save(){
      request.post("/user",this.form).then(res => {
        if (res){
          this.$message.success("保存成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("保存失败!")
        }
      })
    },

    del(id){
      request.delete("/user/"+id).then(res => {
        if (res){
          this.$message.success("删除成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("删除失败!")
        }
      })
    },

    handleSelectionChange(val){
      console.log(val)
      this.multipleSelection = val
    },

    delBatch(){
      let ids = this.multipleSelection.map(v => v.id) //将多选获取的对象扁平化处理,即[{},{},{}] => [1,2,3]
      request.post("/user/del/batch",ids).then(res => {
        if (res){
          this.$message.success("批量删除成功!")
          this.load()
        }else {
          this.$message.error("批量删除失败!")
        }
      })
    },

    reset(){
      this.username = ""
      this.load()
    },

    triggerClick(){ //用于回车键触发搜索功能

  this.$refs.btn.$emit('click')

  this.$refs.select.blur()//解决选择框回车后展示下拉列表问题

},

    handleAdd(){
      this.dialogFormVisible = true //打开弹窗
      this.form = {}  //把form对象置空
    },

    handleEdit(row){
      this.form = row
      this.dialogFormVisible = true

    },


    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

UserController.java

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

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


    @Autowired
    private UserService userService;


    //新增和修改
    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveUser(user);
    }

    //查询所有数据
    @GetMapping
    public List<User> index(){
        return userService.list();
    }

    //删除
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Integer id) {   //表示url参数
        return userService.removeById(id);
    }
    //批量删除
    @PostMapping("/del/batch")
    public boolean deleteBatch(@RequestBody List<Integer> ids) {   //表示url参数
        return userService.removeBatchByIds(ids);
    }

    //分页查询
    //接口路径:/user/page
    //@RequestParam接收   pageNum=1&pageSize=10
    //limit第一个参数 = (pageNum - 1) * pageSize
    //pageSize
    //selectTotal记录数据总条数
    //用Map封装起来
//    @GetMapping("/page")
//    public Map<String, Object> findPage(@RequestParam Integer pageNum,
//                                        @RequestParam Integer pageSize,
//                                        @RequestParam String username){
//        pageNum = (pageNum -1) * pageSize;
//        username = "%"+username+"%";
//        List<User> data=userMapper.selectPage(pageNum,pageSize,username);
//        Integer total = userMapper.selectTotal(username);
//        Map<String,Object> res = new HashMap<>();
//        res.put("data",data);
//        res.put("total",total);
//        return res;
//    }
    // 分页查询 - mybatis-plus的方式
    @GetMapping("/page")
    public IPage<User> findPage(@RequestParam Integer pageNum,
                                @RequestParam Integer pageSize,
                                @RequestParam(defaultValue = "") String username,
                                @RequestParam(defaultValue = "") String nickname,
                                @RequestParam(defaultValue = "") String address){
        IPage<User> page =new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)) {
            queryWrapper.like("username", username);
        }
        if (!"".equals(nickname)) {
            queryWrapper.like("nickname", nickname);
        }
        if (!"".equals(address)) {
            queryWrapper.like("address", address);
        }
        queryWrapper.orderByDesc("id");//新增数据倒叙排列
        //或者 queryWrapper.and(w -> w.like("nickname",nickname));
        IPage<User> userPage = userService.page(page,queryWrapper);
        return userPage;
    }
}

新增批量删除接口,并改为@PostMapping

新增删除前询问:

Home.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <el-menu :default-openeds="['1', '3']" style="min-height: 100%;overflow-x: hidden"
                  background-color="rgb(139 71 38)"
                  text-color="#fff"
                  active-text-color="#ffd04b"
                  :collapse-transition="false"
                  :collapse="isCollapse"><!--关掉菜单本身动画-->
          <div style="height: 60px;line-height: 60px;text-align: center">
            <img src="../assets/logo.png" alt="" style="width: 19px;position: relative;top: 5px;margin-right: 3px">
            <b style="color: white" v-show="logoTextShow">后台管理系统</b>

          </div>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-message"></i>
              <span slot="title" >导航一</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="1-1">选项1</el-menu-item>
              <el-menu-item index="1-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="1-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="1-4">
              <template slot="title">选项4</template>
              <el-menu-item index="1-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span slot="title" >导航二</span>
            </template>
            <el-menu-item-group>
              <template slot="title">分组一</template>
              <el-menu-item index="2-1">选项1</el-menu-item>
              <el-menu-item index="2-2">选项2</el-menu-item>
            </el-menu-item-group>
            <el-menu-item-group title="分组2">
              <el-menu-item index="2-3">选项3</el-menu-item>
            </el-menu-item-group>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项4-1</el-menu-item>
            </el-submenu>
          </el-submenu>

          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-setting"></i>
              <span slot="title">导航三</span>
            </template>
          </el-submenu>

        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="font-size: 12px;border-bottom: 1px solid #ccc;line-height: 60px;display: flex">
          <div style="flex: 1;font-size: 20px">
            <span :class="collapseBtnClass" style="cursor: pointer" @click="collapse"></span>
          </div>
          <el-dropdown style="width: 70px;cursor: pointer">
<!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
            <span>王小虎</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>新增</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>

        <el-main>
          <div style="margin-bottom: 30px">
            <el-breadcrumb separator="/">
              <el-breadcrumb-item :to="{path:'/'}">首页</el-breadcrumb-item>
              <el-breadcrumb-item>用户管理</el-breadcrumb-item>
            </el-breadcrumb>
          </div>

          <div style="padding: 10px 0">
            <el-input style="width: 200px" placeholder="请输入用户名查找" suffix-icon="el-icon-search" v-model="username"  @keyup.enter.native="triggerClick"></el-input>
            <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
            <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
          </div><!--搜索框-->

          <div style="margin: 10px 0">
            <el-button type="primary" @click="handleAdd">新增 <i class="el-icon-circle-plus-outline"></i> </el-button>
            <el-popconfirm
                class="ml-5"
                confirm-button-text='确定'
                cancel-button-text='取消'
                icon="el-icon-info"
                icon-color="red"
                title="您确定批量删除这些数据吗?"
                @confirm="delBatch">
            <el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
            </el-popconfirm>
            <el-button type="primary" class="ml-5">导入 <i class="el-icon-bottom"></i> </el-button>
            <el-button type="primary">导出 <i class="el-icon-top"></i> </el-button>
          </div>

          <el-table :data="tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange">
            <el-table-column type="selection" width="55">
            </el-table-column>
            <el-table-column prop="id" label="ID" width="60">
            </el-table-column>
            <el-table-column prop="username" label="用户名" width="140">
            </el-table-column>
            <el-table-column prop="nickname" label="昵称" width="120">
            </el-table-column>
            <el-table-column prop="email" label="邮箱">
            </el-table-column>
            <el-table-column prop="phone" label="电话">
            </el-table-column>
            <el-table-column prop="address" label="地址">
            </el-table-column>
            <el-table-column label="修改操作">
              <template slot-scope="scope">
                <el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
                <el-popconfirm
                    class="ml-5"
                  confirm-button-text='确定'
                  cancel-button-text='取消'
                  icon="el-icon-info"
                  icon-color="red"
                  title="确定删除吗?"
                  @confirm="del(scope.row.id)">
                <el-button type="danger" slot="reference" >删除 <i class="el-icon-remove-outline"></i></el-button>
              </el-popconfirm>
              </template>
            </el-table-column>
          </el-table>
          <div style="padding: 10px 0">
            <el-pagination
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="pageNum"
                :page-sizes="[5, 10, 20]"
                :page-size="pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total">
            </el-pagination><!--分页栏-->
          </div>

          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px" size="small">
              <el-form-item label="用户名">
                <el-input v-model="form.username" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="昵称">
                <el-input v-model="form.nickname" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="邮箱">
                <el-input v-model="form.email" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="电话">
                <el-input v-model="form.phone" autocomplete="off"></el-input>
              </el-form-item>
              <el-form-item label="地址">
                <el-input v-model="form.address" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="dialogFormVisible = false">取 消</el-button>
              <el-button type="primary" @click="save">确 定</el-button>
            </div>
          </el-dialog>

        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import request from "../utils/request";

export default {
  name: 'Home',

  data(){
    return {
      tableData:[],
      total:0,
      pageNum:1,
      pageSize:5,
      phone:"",
      username:"",
      nickname:"",
      form:{},
      dialogFormVisible:false,
      multipleSelection:[],
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      headerBg:'headerBg'
    }
  },

  created() {
    //请求分页查询数据
    this.load()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },
    load(){
      request.get("/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username
        }

          }).then(res =>{
        console.log(res)

        this.tableData = res.records
        this.total = res.total

      })

    },

    save(){
      request.post("/user",this.form).then(res => {
        if (res){
          this.$message.success("保存成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("保存失败!")
        }
      })
    },

    del(id){
      request.delete("/user/"+id).then(res => {
        if (res){
          this.$message.success("删除成功!")
          this.dialogFormVisible = false
          this.load()
        }else {
          this.$message.error("删除失败!")
        }
      })
    },

    handleSelectionChange(val){
      console.log(val)
      this.multipleSelection = val
    },

    delBatch(){
      let ids = this.multipleSelection.map(v => v.id) //将多选获取的对象扁平化处理,即[{},{},{}] => [1,2,3]
      request.post("/user/del/batch",ids).then(res => {
        if (res){
          this.$message.success("批量删除成功!")
          this.load()
        }else {
          this.$message.error("批量删除失败!")
        }
      })
    },

    reset(){
      this.username = ""
      this.load()
    },

    triggerClick(){ //用于回车键触发搜索功能

  this.$refs.btn.$emit('click')

  this.$refs.select.blur()//解决选择框回车后展示下拉列表问题

},

    handleAdd(){
      this.dialogFormVisible = true //打开弹窗
      this.form = {}  //把form对象置空
    },

    handleEdit(row){
      this.form = row
      this.dialogFormVisible = true

    },


    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    }
  }
}
</script>

<style>
.headerBg{
  background-color: #eee!important;
}
</style>

这样一来,增删改查就已经全部实现!💪

11、SpringBoot代码生成器

1、首先引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>

还有一个依赖,因为它是默认 Velocity 为模板引擎

 <!-- 模板引擎Velocity -->
        <!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>

2、创建文件夹utils,在文件夹中创建CodeGenerator.java

package com.kep.springboot.utils;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.Collections;

/**
 * mp代码生成器
 * by kppackage com.kep.springboot.utils;

import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;

import java.util.Collections;

/**
 * mp代码生成器
 * by kp
 * @since 2022-02-09
 */

public class CodeGenerator {
    public static void main(String[] args) {

        generate();
    }

    private static void generate(){
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8", "root", "180918")
                .globalConfig(builder -> {
                    builder.author("kp") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D:\\Intellij IDEA\\dangjian\\src\\main\\java\\"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.kep.springboot") // 设置父包名
                            .moduleName(null) // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\Intellij IDEA\\dangjian\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("sys_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

 * @since 2022-02-09
 */

public class CodeGenerator {
    public static void main(String[] args) {

        generate();
    }

    private static void generate(){
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8", "root", "180918")
                .globalConfig(builder -> {
                    builder.author("kp") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("D:\\Intellij IDEA\\dangjian\\src\\main\\java\\"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.kep.springboot") // 设置父包名
                            .moduleName("") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D:\\Intellij IDEA\\dangjian\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.addInclude("sys_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

执行main函数后,自动生成代码

之后在External libraries中的controller.java.vm复制到resources中的templates中修改代码加入crud功能

package ${package.Controller};

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;

import $!{package.Service}.${table.serviceName};
import ${package.Entity}.${entity};

#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end

/**
 * <p>
 * $!{table.comment} 前端控制器
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end

#else
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end

    @Resource
    private ${table.serviceName} ${table.entityPath}Service;

    @PostMapping
    public boolean save(@RequestBody ${entity} ${table.entityPath}){
        // 新增或者更新
        return ${table.entityPath}Service.saveOrUpdate(${table.entityPath});
        }


        //删除
    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable Integer id) {
        return ${table.entityPath}Service.removeById(id);
        }   /*${table.entityPath}==user*/

        //批量删除
    @PostMapping("/del/batch")
    public boolean deleteBatch(@RequestBody List<Integer> ids) {   //表示url参数
        return ${table.entityPath}Service.removeBatchByIds(ids);
        }

        //查询
    @GetMapping
    public List<${entity}> findAll() {
        return ${table.entityPath}Service.list();
        }

        //根据id查询
    @GetMapping("/{id}")
    public ${entity} findOne(@PathVariable Integer id) {
        return ${table.entityPath}Service.getById(id);
        }

        //分页查询
    @GetMapping("/page")
    public Page<${entity}> findPage(@RequestParam Integer pageNum,
                        @RequestParam Integer pageSize) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");//新增数据倒叙排列
        return ${table.entityPath}Service.page(new Page<>(pageNum, pageSize),queryWrapper);
        }

}

#end

由代码生成器生成的UserController.java为

package com.kep.springboot.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kep.springboot.entity.User;
import com.kep.springboot.service.IUserService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author kp
 * @since 2022-02-09
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @PostMapping
    public boolean save(@RequestBody User user){
        // 新增或者更新
        return userService.saveOrUpdate(user);
        }


        //删除
    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable Integer id) {
        return userService.removeById(id);
        }   /*user==user*/

        //批量删除
    @PostMapping("/del/batch")
    public boolean deleteBatch(@RequestBody List<Integer> ids) {   //表示url参数
        return userService.removeBatchByIds(ids);
        }

        //查询
    @GetMapping
    public List<User> findAll() {
        return userService.list();
        }

        //根据id查询
    @GetMapping("/{id}")
    public User findOne(@PathVariable Integer id) {
        return userService.getById(id);
        }

        //分页查询
    @GetMapping("/page")
    public Page<User> findPage(@RequestParam Integer pageNum,
                        @RequestParam Integer pageSize,
                               @RequestParam(defaultValue = "") String username,
                               @RequestParam(defaultValue = "") String nickname,
                               @RequestParam(defaultValue = "") String address) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)) {
            queryWrapper.like("username", username);
        }
        if (!"".equals(nickname)) {
            queryWrapper.like("nickname", nickname);
        }
        if (!"".equals(address)) {
            queryWrapper.like("address", address);
        }
        queryWrapper.orderByDesc("id");//新增数据倒叙排列
        return userService.page(new Page<>(pageNum, pageSize),queryWrapper);
        }

}

在前台测试后功能正常👍

12、Vue使用路由

我们将Home.vue改名为Manage.vue,管理界面,将界面分为导航栏和主体,而导航栏应不变,只变主体部分,把里面的视图作为子路由,根据子路由更换主界面

下载vuex,在terminal写npm i vuex -S

版本要是3.6.2

在src下创建文件夹store,文件夹内创建index.js

import Vue from 'vue';
import Vuex from 'vuex'

Vue.use(Vuex)

const  store = new Vuex.Store({
    state:{
        currentPathName:''
    },
    mutations:{
        setPath(state){
            state.currentPathName = localStorage.getItem("currentPathName")
        }
    }
})

export default store

引入vuex,在main.js中

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from "./store"
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '../src/assets/gloable.css'
import request from "./utils/request";


Vue.config.productionTip = false

Vue.use(ElementUI,{size:"mini"});

Vue.prototype.request=request

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Manage.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    component: () => import('../views/Manage.vue'),
    redirect:'/home',
    children:[
      {
        path:'home', name:'首页', component: () =>import('../views/Home.vue')},
      {path:'user',name:'用户管理',component: () => import('../views/User.vue')}
    ]
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

/*路由守卫*/
router.beforeEach((to, from, next) => {
  localStorage.setItem("currentPathName",to.name) //设置当前的路由名称,为了在header组件中去使用
  store.commit("setPath") //触发store的数据更新
  next()  //放行路由
})

export default router

Header.vue

 computed:{
    currentPathName(){
      return this.$store.state.currentPathName; //需要监听的数据
    }
  },

  watch:{ // 百度搜出的结果,监听路由变化
    currentPathName(newVal,oldVal){
      console.log(newVal)
    }
  },

// 使用
<el-breadcrumb separator="/" style="display: inline-block;margin-left: 10px">
        <el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
        <el-breadcrumb-item>{{ currentPathName }}</el-breadcrumb-item>
      </el-breadcrumb>

13、SpringBoot和Vue实现导入导出

1、首先在pom.xml中导入hutool依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.20</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

2、在UserController.java中加入导出部分,在实体类中要加上注解@ToString

/**
 * 导出接口
 */
@GetMapping("/export")
public void export(HttpServletResponse response) throws Exception{
    //从数据库查询出所有的数据
    List<User> list = userService.list();
    //通过工具类创建writer 写出到磁盘路径,我们就不导出到磁盘路径
    //ExcelWriter writer = ExcelUtil.getWriter(fileUploadPath+"/用户信息.xlsx")
    //在内存操作,写出到浏览器
    ExcelWriter writer = ExcelUtil.getWriter(true);
    //自定义标题别名,根据实体类User
    writer.addHeaderAlias("username","用户名");
    writer.addHeaderAlias("password","密码");
    writer.addHeaderAlias("nickname","昵称");
    writer.addHeaderAlias("email","邮箱");
    writer.addHeaderAlias("phone","电话");
    writer.addHeaderAlias("address","地址");
    writer.addHeaderAlias("createTime","创建时间");
    writer.addHeaderAlias("avatarUrl","头像");

    //一次性写出list内的对象到excel,使用默认样式,强制输出标题
    writer.write(list,true);

    //设置浏览器响应的格式
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
    String fileName = URLEncoder.encode("用户信息","UTF-8");
    response.setHeader("Content-Disposition","attachment;filename="+ fileName +".xlsx");

    //通过response获取到输出流,把writer里面的东西刷新到输出流里面去,最后通过输出流返回到浏览器
    ServletOutputStream out = response.getOutputStream();
    writer.flush(out,true);
    out.close();
    writer.close();
}

加入导入部分

/**
     * excel 导入
     * @param file
     * @throws Exception
     */
    @PostMapping("/import")
    public Boolean imp(MultipartFile file) throws Exception{
        InputStream inputStream =file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //方式一:通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来
//        List<User> list = reader.readAll(User.class);

        //方式二:忽略表头的中文,直接读取表的内容
        List<List<Object>> list = reader.read(1);
        List<User> users = CollUtil.newArrayList();
        for (List<Object> row : list){
            User user = new User();
            user.setUsername(row.get(0).toString());
            user.setPassword(row.get(1).toString());
            user.setNickname(row.get(2).toString());
            user.setEmail(row.get(3).toString());
            user.setPhone(row.get(4).toString());
            user.setAddress(row.get(5).toString());
            users.add(user);
        }
        userService.saveBatch(users);
        return true;
    }

14、SpringBoot和Vue实现用户登录

1、在views文件夹内新增文件Login.vue

<template>
<div class="wrapper">
  <div style="margin: 200px auto;background-color: #fff;width: 350px;height: 300px;padding: 20px;border-radius: 10px">
    <div style="margin: 20px 0;text-align: center;font-size: 24px">
      <b>用户登录</b></div>
      <el-form :model="user" :rules="rules" ref="userForm">
        <el-form-item prop="username" >
          <el-input size="medium" style="margin: 10px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input size="medium" style="margin: 10px 0" prefix-icon="el-icon-lock" show-password v-model="user.password"></el-input>
        </el-form-item>

      <el-form-item style="margin: 10px 0;text-align: center;">
        <el-button type="primary" size="small" autocomplete="off" @click="login"style="margin-right: 20px">登录</el-button>
        <el-button type="warning" size="small" autocomplete="off">注册</el-button>
      </el-form-item>
      </el-form>
  </div>
</div>
</template>

<script>
export default {
  name: "Login",
  data(){
    return{
      user:{},
      rules:{
        username:[
          {required:true,message:'请输入用户名',trigger:'blur'},
          {min:3,max:8,message: '长度在 3 到 8 个字符',trigger: 'blur'}
        ],
        password:[
          {required:true,message:'请输入密码',trigger:'blur'},
          {min:5,max:12,message: '长度在 5 到 12 个字符',trigger: 'blur'}
        ]
      }
    }
  },
  methods:{
    login(){
      this.$refs['userForm'].validate((valid) =>{
        if (valid){ //表单校验合法,合法才发送请求
          this.request.post("/user/login",this.user).then(res =>{
            if (!res){
              this.$message.error("用户名或密码错误!")
            }else {
              this.$router.push("/")
            }
          })
        }else {
          return false;
        }
      })
    }
  }
}
</script>

<style>
  .wrapper{
    height: 100vh;
    background-image: linear-gradient(to bottom right,#FC4668,#3F5EF8); /*从左上角到右上角渐变色*/
    overflow: hidden;
  }

</style>

2、在文件夹router里新建index.js,加上登录界面路由

{
  path: '/login',
  name:'Login',
  component:() => import('../views/Login.vue')
}

3、在UserServiceImpl中加入登录验证功能

package com.kep.springboot.service.impl;

import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kep.springboot.controller.dto.UserDTo;
import com.kep.springboot.entity.User;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kp
 * @since 2022-02-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private static final Log LOG = Log.get();

    @Override
    public boolean login(UserDTo userDTo) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",userDTo.getUsername());
        queryWrapper.eq("password",userDTo.getPassword());
//        第一种方式,后台查询出多条相同的账号
//        List<User> list = list(queryWrapper);
//        return list.size()!=0;
//        第二种方式
        try{
            User one = getOne(queryWrapper);
            return one !=null;
        }catch (Exception e){
            LOG.error(e);
            return false;
        }

    }
}

4、在UserController中加入登陆验证

@PostMapping("/login")
public boolean login(@RequestBody UserDTo userDTo){
    String username = userDTo.getUsername();
    String password = userDTo.getPassword();
    if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
        return false;
    }
    return userService.login(userDTo);
}

15、SpringBoot和Vue实现注册和异常处理

1、异常处理

设置不同的异常来进行不同的报错

1、创建文件夹common,文件夹下创建Result.java

package com.kep.springboot.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 接口返回包装类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {

    private String code;
    private String msg; //返回请求失败的原因
    private Object data;    //后台需要携带的数据

    public static Result success(){
        return new Result(Constants.CODE_200,"",null);
    }

    public static Result success(Object data){
        return new Result(Constants.CODE_200,"",data);
    }

    public static Result error(String code,String msg){
        return new Result(code,msg,null);
    }

    public static Result error(){
        return new Result(Constants.CODE_500,"系统错误",null);
    }
}

2、创建Constants.java接口

package com.kep.springboot.common;

public interface Constants {
    String CODE_200 = "200";    //成功
    String CODE_401 = "401";    //权限不足
    String CODE_400 = "400";    //参数错误
    String CODE_500 = "500";    //系统错误
    String CODE_600 = "600";    //其他业务异常

}

3、创建异常处理的文件夹exception,里面创建两个类GlobalExceptionHandler

package com.kep.springboot.exception;

import com.kep.springboot.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 如果抛出的是ServiceException,则调用该方法
     * @param se 业务异常
     * @return Result
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Result handle(ServiceException se){
        return Result.error(se.getCode(),se.getMessage());
    }
}

4、创建类ServiceException

package com.kep.springboot.exception;

import lombok.Getter;

/**
 * 自定义异常
 */

@Getter
public class ServiceException extends RuntimeException{
    private String code;

    public ServiceException(String code,String msg){
        super(msg);
        this.code = code;
    }
}

5、UserServiceImpl

package com.kep.springboot.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.log.Log;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kep.springboot.common.Constants;
import com.kep.springboot.controller.dto.UserDTO;
import com.kep.springboot.entity.User;
import com.kep.springboot.exception.ServiceException;
import com.kep.springboot.mapper.UserMapper;
import com.kep.springboot.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kp
 * @since 2022-02-09
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private static final Log LOG = Log.get();

    @Override
    public UserDTO login(UserDTO userDTO) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",userDTO.getUsername());
        queryWrapper.eq("password",userDTO.getPassword());
        User one;
//        第一种方式,后台查询出多条相同的账号
//        List<User> list = list(queryWrapper);
//        return list.size()!=0;
//        第二种方式
        try{
            one = getOne(queryWrapper);    //从数据库查询用户信息

        }catch (Exception e){
            LOG.error(e);
            throw new ServiceException(Constants.CODE_500,"系统错误");
        }
        if (one !=null) {
            BeanUtil.copyProperties(one,userDTO,true);
            return userDTO;
        }else {
            throw new ServiceException(Constants.CODE_600,"用户名或密码错误");
        }

    }
}

6、IUserService接口

package com.kep.springboot.service;

import com.kep.springboot.controller.dto.UserDTO;
import com.kep.springboot.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author kp
 * @since 2022-02-09
 */
public interface IUserService extends IService<User> {

    UserDTO login(UserDTO userDTO);
}

7、在Login.vue中加入

methods:{
  login(){
    this.$refs['userForm'].validate((valid) =>{
      if (valid){ //表单校验合法,合法才发送请求
        this.request.post("/user/login",this.user).then(res =>{
          if (res.code === '200' ){
            localStorage.setItem("user",JSON.stringify(res.data)) //存储用户信息到浏览器
            this.$router.push("/")
            this.$message.success("登录成功!")
          }else {
            this.$message.error(res.msg)
          }
        })
      }
    });

8、在UserController.java中

@PostMapping("/login")
public Result login(@RequestBody UserDTO userDTO){
    String username = userDTO.getUsername();
    String password = userDTO.getPassword();
    if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
        return Result.error(Constants.CODE_400,"参数错误");
    }
    UserDTO dto = userService.login(userDTO);
    return Result.success(dto);
}

9、在Header.vue中加上退出时的方法

<el-dropdown style="width: 120px;cursor: pointer">
    <div style="display: inline-block">
      <img src="../assets/IMG_0955(20220212-201455).png" alt="" style="width: 30px;border-radius: 50%;position: relative;top: 10px;right: 8px">
    <!--            <i class="el-icon-setting" style="margin-right: 15px"></i>-->
    <span>{{ user.nickname }}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
    </div>
    <el-dropdown-menu slot="dropdown" style="width: 100px;text-align: center">
      <el-dropdown-item style="font-size: 14px;padding: 5px 0">个人信息</el-dropdown-item>
<!--      <el-dropdown-item style="font-size: 14px;padding: 5px">——</el-dropdown-item>-->
      <el-dropdown-item style="font-size: 14px;padding: 5px 0">
        <span style="text-decoration: none" @click="logout">退出</span>
      </el-dropdown-item>
    </el-dropdown-menu>
  </el-dropdown>
data(){
    return{
      user:localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")):{}
    }
  },
 logout(){ //退出时的方法:清除数据,导向登录界面
      this.$router.push("/login")
      localStorage.removeItem("user")
      this.$message.success("退出成功!")
    }

2、实现注册功能

1、首先创建Register.vue,可直接从Login.vue复制

<template>
<div class="wrapper">
  <div style="margin: 80px auto;background-color: #fff;width: 350px;height: 550px;padding: 20px;border-radius: 10px">
    <div style="margin: 20px 0;text-align: center;font-size: 24px">
      <b>注 册</b></div>
      <el-form :model="user" :rules="rules" ref="userForm">
        <el-form-item prop="username" >
          <el-input placeholder="请输入注册用户名" size="medium" style="margin: 6px 0" prefix-icon="el-icon-user" v-model="user.username"></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input placeholder="请输入注册密码" size="medium" style="margin: 6px 0" prefix-icon="el-icon-lock" show-password v-model="user.password"></el-input>
        </el-form-item>
        <el-form-item prop="confirmPassword">
          <el-input placeholder="请确认注册密码" size="medium" style="margin: 6px 0" prefix-icon="el-icon-finished" show-password v-model="user.confirmPassword"></el-input>
        </el-form-item>
        <el-form-item prop="nickname">
          <el-input placeholder="请输入注册昵称" size="medium" style="margin: 6px 0" prefix-icon="el-icon-info" v-model="user.nickname"></el-input>
        </el-form-item>
        <el-form-item prop="email">
          <el-input placeholder="请输入注册邮箱" size="medium" style="margin: 6px 0" prefix-icon="el-icon-message" v-model="user.email"></el-input>
        </el-form-item>
        <el-form-item prop="phone">
          <el-input placeholder="请输入注册电话" size="medium" style="margin: 6px 0" prefix-icon="el-icon-phone" v-model="user.phone"></el-input>
        </el-form-item>

        <el-form-item style="margin: 10px 0;text-align: center;">
        <el-button type="primary" size="small" autocomplete="off" @click="login"style="margin-right: 20px">注册</el-button>
        <el-button type="warning" size="small" autocomplete="off" @click="$router.push('/login')">返回登录</el-button>
      </el-form-item>
      </el-form>
  </div>
</div>
</template>

<script>
export default {
  name: "Login",
  data(){
    return{
      user:{},
      rules:{
        username:[
          {required:true,message:'请输入用户名',trigger:'blur'},
          {min:2,max:8,message: '长度在 2 到 8 个字符',trigger: 'blur'}
        ],
        password:[
          {required:true,message:'请输入密码',trigger:'blur'},
          {min:5,max:12,message: '长度在 5 到 12 个字符',trigger: 'blur'}
        ],
        confirmPassword:[
          {required:true,message:'请确认密码',trigger:'blur'},
          {min:5,max:12,message: '长度在 5 到 12 个字符',trigger: 'blur'}
        ],
        nickname:[
          {required:true,message:'请输入昵称',trigger:'blur'},
          {min:2,max:8,message: '长度在 2 到 8 个字符',trigger: 'blur'}
        ],
        email:[
          {required:true,message:'请输入邮箱',trigger:'blur'},
          {min:8,max:25,message: '长度在 8 到 25 个字符',trigger: 'blur'}
        ],
        phone:[
          {required:true,message:'请输入电话',trigger:'blur'},
          {min:11,max:11,message: '长度为11个字符',trigger: 'blur'}
        ]
      }
    }
  },
  methods:{
    login(){
      this.$refs['userForm'].validate((valid) =>{
        if (valid){ //表单校验合法,合法才发送请求
          if (this.user.password !== this.user.confirmPassword){
            this.$message.error("两次输入的密码不一致")
            return false;
          }
          this.request.post("/user/register",this.user).then(res =>{
            if (res.code === '200' ){
              this.$message.success("注册成功!")
            }else {
              this.$message.error(res.msg)
            }
          })
        }
      });
    }
  }
}
</script>

<style>
  .wrapper{
    height: 100vh;
    background-image: linear-gradient(to bottom left,#FC4668,#3F5EF8); /*从左下角到右上角渐变色*/
    overflow: hidden;
  }

</style>

2、在路由中加入注册界面路由

{
  path: '/register',
  name:'Register',
  component:() => import('../views/Register.vue')
},

3、在Login.vue的注册按钮中写上

 <el-button type="warning" size="small" autocomplete="off" @click="$router.push('/register')">注册</el-button>

4、在UserController.java中加入注册接口

@PostMapping("/register")
public Result register(@RequestBody UserDTO userDTO){
    String username = userDTO.getUsername();
    String password = userDTO.getPassword();
    String nickname = userDTO.getNickname();
    String email = userDTO.getEmail();
    String phone = userDTO.getPhone();
    if (StrUtil.isBlank(username)||StrUtil.isBlank(password)||StrUtil.isBlank(nickname)||StrUtil.isBlank(email)||StrUtil.isBlank(phone)){
        return Result.error(Constants.CODE_400,"参数错误");
    }
    return Result.success(userService.register(userDTO));
}

5、在IUserService.java接口中加上

User register(UserDTO userDTO);

6、在实现类UserServiceImpl.java中加上

 @Override
    public User register(UserDTO userDTO) {
        User one = getUserInfo(userDTO);
        if (one == null){
            one = new User();
            BeanUtil.copyProperties(userDTO,one,true);
            save(one);  //把copy之后的用户对象存储到数据库
        }else {
            throw new ServiceException(Constants.CODE_600,"用户已存在!");
        }
        return one;
    }

    private User getUserInfo(UserDTO userDTO){  //封装一个查询检测方法
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",userDTO.getUsername());
        queryWrapper.eq("password",userDTO.getPassword());
        User one;
//        第一种方式,后台查询出多条相同的账号
//        List<User> list = list(queryWrapper);
//        return list.size()!=0;
//        第二种方式
        try{
            one = getOne(queryWrapper);    //从数据库查询用户信息

        }catch (Exception e){
            LOG.error(e);
            throw new ServiceException(Constants.CODE_500,"系统错误");
        }
        return one;
    }

7、在UserDTO中加上

package com.kep.springboot.controller.dto;

import lombok.Data;

/**
 * 接收前端登录请求的参数
 */
@Data
public class UserDTO {
    private String username;
    private String password;
    private String nickname;
    private String email;
    private String phone;
}

3、实现个人信息展示和修改界面

1、在views中创建Person.vue

<template>
<el-card style="width: 500px">
  <el-form label-width="80px" size="small">
    <el-form-item label="用户名">
      <el-input v-model="form.username" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="昵称">
      <el-input v-model="form.nickname" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="邮箱">
      <el-input v-model="form.email" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="电话">
      <el-input v-model="form.phone" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="地址">
      <el-input v-model="form.address" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="save">确 定</el-button>
      <el-button type="warning" @click="reBack" style="margin-left: 180px">返 回</el-button>
    </el-form-item>
  </el-form>
</el-card>
</template>

<script>
export default {
  name: "Person",
  data(){
    return{
      form:{},
      user:localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
    this.request.get("/user/username/" + this.user.username).then(res => {
      if (res.code === '200'){
        this.form = res.data
      }
    })
  },

  methods:{
    save(){
      this.request.post("/user",this.form).then(res => {
        if (res.data){
          this.$message.success("保存成功!")
        }else {
          this.$message.error("保存失败!")
        }
      })
    },
    reBack(){
      this.$router.push("/user")
    }
  }
}
</script>

<style scoped>

</style>

2、加上路由

{
  path: '/',
  component: () => import('../views/Manage.vue'),
  redirect:'/home',
  children:[
    {path:'home', name:'首页', component: () =>import('../views/Home.vue')},
    {path:'user',name:'用户管理',component: () => import('../views/User.vue')},
    {path:'person',name:'个人信息',component: () => import('../views/Person.vue')}
  ]
},

3、在Header.vue中写上

<el-dropdown-item style="font-size: 14px;padding: 5px 0">
  <span style="text-decoration: none" @click="personInfo">个人信息</span>
</el-dropdown-item>
personInfo(){
  this.$router.push("/person")
}

4、将UserController.java中的接口返回值全部修改为Result

package com.kep.springboot.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kep.springboot.common.Constants;
import com.kep.springboot.common.Result;
import com.kep.springboot.controller.dto.UserDTO;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

import com.kep.springboot.service.IUserService;
import com.kep.springboot.entity.User;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author kp
 * @since 2022-02-09
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @PostMapping("/login")
    public Result login(@RequestBody UserDTO userDTO){
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();
        if (StrUtil.isBlank(username)||StrUtil.isBlank(password)){
            return Result.error(Constants.CODE_400,"参数错误");
        }
        UserDTO dto = userService.login(userDTO);
        return Result.success(dto);
    }

    @PostMapping("/register")
    public Result register(@RequestBody UserDTO userDTO){
        String username = userDTO.getUsername();
        String password = userDTO.getPassword();
        String nickname = userDTO.getNickname();
        String email = userDTO.getEmail();
        String phone = userDTO.getPhone();
        if (StrUtil.isBlank(username)||StrUtil.isBlank(password)||StrUtil.isBlank(nickname)||StrUtil.isBlank(email)||StrUtil.isBlank(phone)){
            return Result.error(Constants.CODE_400,"参数错误");
        }
        return Result.success(userService.register(userDTO));
    }

    @PostMapping
    public Result save(@RequestBody User user){
        // 新增或者更新
        return Result.success(userService.saveOrUpdate(user));
        }


        //删除
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        return Result.success(userService.removeById(id));
        }   /*user==user*/

        //批量删除
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {   //表示url参数
        return Result.success(userService.removeBatchByIds(ids));
        }

        //查询
    @GetMapping
    public Result findAll() {
        return Result.success(userService.list());
        }

        //根据id查询
    @GetMapping("/{id}")
    public Result findOne(@PathVariable Integer id) {
        return Result.success(userService.getById(id));
        }

    @GetMapping("/username/{username}")
    public Result findPerson(@PathVariable String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username",username);
        return Result.success(userService.getOne(queryWrapper));
    }

        //分页查询
    @GetMapping("/page")
    public Result findPage(@RequestParam Integer pageNum,
                        @RequestParam Integer pageSize,
                               @RequestParam(defaultValue = "") String username,
                               @RequestParam(defaultValue = "") String nickname,
                               @RequestParam(defaultValue = "") String address) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)) {
            queryWrapper.like("username", username);
        }
        if (!"".equals(nickname)) {
            queryWrapper.like("nickname", nickname);
        }
        if (!"".equals(address)) {
            queryWrapper.like("address", address);
        }
        queryWrapper.orderByDesc("id");//新增数据倒叙排列
        return Result.success(userService.page(new Page<>(pageNum, pageSize),queryWrapper));
        }

    /**
     * 导出接口
     */
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws Exception{
        //从数据库查询出所有的数据
        List<User> list = userService.list();
        //通过工具类创建writer 写出到磁盘路径,我们就不导出到磁盘路径
        //ExcelWriter writer = ExcelUtil.getWriter(fileUploadPath+"/用户信息.xlsx")
        //在内存操作,写出到浏览器
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //自定义标题别名,根据实体类User
        writer.addHeaderAlias("username","用户名");
        writer.addHeaderAlias("password","密码");
        writer.addHeaderAlias("nickname","昵称");
        writer.addHeaderAlias("email","邮箱");
        writer.addHeaderAlias("phone","电话");
        writer.addHeaderAlias("address","地址");
        writer.addHeaderAlias("createTime","创建时间");
        writer.addHeaderAlias("avatarUrl","头像");

        //一次性写出list内的对象到excel,使用默认样式,强制输出标题
        writer.write(list,true);

        //设置浏览器响应的格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息","UTF-8");
        response.setHeader("Content-Disposition","attachment;filename="+ fileName +".xlsx");

        //通过response获取到输出流,把writer里面的东西刷新到输出流里面去,最后通过输出流返回到浏览器
        ServletOutputStream out = response.getOutputStream();
        writer.flush(out,true);
        out.close();
        writer.close();
    }

    /**
     * excel 导入
     * @param file
     * @throws Exception
     */
    @PostMapping("/import")
    public Result imp(MultipartFile file) throws Exception{
        InputStream inputStream =file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //方式一:通过 javabean的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来
//        List<User> list = reader.readAll(User.class);

        //方式二:忽略表头的中文,直接读取表的内容
        List<List<Object>> list = reader.read(1);
        List<User> users = CollUtil.newArrayList();
        for (List<Object> row : list){
            User user = new User();
            user.setUsername(row.get(0).toString());
            user.setPassword(row.get(1).toString());
            user.setNickname(row.get(2).toString());
            user.setEmail(row.get(3).toString());
            user.setPhone(row.get(4).toString());
            user.setAddress(row.get(5).toString());
            users.add(user);
        }
        userService.saveBatch(users);
        return Result.success(true);
    }

}

5、最后将vue文件中所有res判断改为res.data,重启java部分便可成功📑

16、SpringBoot集成JWT

Jwt全称是:json web token。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。

一个token分3部分,按顺序为

  1. 头部(header)
  2. 载荷(payload)
  3. 签证(signature)

优点

简洁: 可以通过URL、POST参数或者在HTTP header发送,因为数据量小,传输速度也很快;
自包含:负载中可以包含用户所需要的信息,避免了多次查询数据库;
因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持;
不需要在服务端保存会话信息,特别适用于分布式微服务。

缺点

无法作废已颁布的令牌;
不易应对数据过期。
1、项目依赖pom.xml

	<dependency>
		<groupId>com.auth0</groupId>
		<artifactId>java-jwt</artifactId>
		<version>3.10.3</version>
	</dependency>

2、JWT集成,记得要在UserDTO中设置参数token

package com.kep.springboot.utils;

import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.Date;

public class TokenUtils {
    /**
     * 生成token
     * @return
     */
    public static String genToken(String userId,String sign){
       return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetHour(new Date(),2)) //2小时后token过期
                .sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
    }
}

token示例

{“username”:“admin”,“password”:“admin”,“nickname”:“管理员01”,“email”:“admin@qq.com”,“phone”:“1388888888”,“token”:“eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwiZXhwIjoxNjQ0NzQwNDM0fQ.lEoUI7kS2I8qdm8WVDiwqVq3y8Wk9U7pX-6pAUPBAvU”}

3、在config文件下创建文件InterceptorConfig.java

package com.kep.springboot.config;

import com.kep.springboot.config.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**") // 拦截所有请求,通过判断token是否合法来决定是否需要登录
                .excludePathPatterns("/user/login", "/user/register","/**/export","/**/import");
    }
    @Bean
    public JwtInterceptor jwtInterceptor(){
        return new JwtInterceptor();
    }

}

4、创建文件夹interceptor,文件夹下创建JwtInterceptor.java

package com.kep.springboot.config.interceptor;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.kep.springboot.common.Constants;
import com.kep.springboot.entity.User;
import com.kep.springboot.exception.ServiceException;
import com.kep.springboot.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    private IUserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("token");
        //如果不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        //执行认证
        if (StrUtil.isBlank(token)){
            throw new ServiceException(Constants.CODE_401,"无token,请重新登录");
        }
        //获取 token 中的 user id
        String userId;
        try{
            userId = JWT.decode(token).getAudience().get(0);
        }catch (JWTDecodeException j){
            throw new ServiceException(Constants.CODE_401,"token验证失败,请重新登录");
        }
        //根据token中的userid查询数据库
        User user = userService.getById(userId);
        if (user == null){
            throw new ServiceException(Constants.CODE_401,"用户不存在,请重新登录");
        }
        //用户密码加签验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try{
            jwtVerifier.verify(token);  //验证token
        }catch (JWTVerificationException e){
            throw new ServiceException(Constants.CODE_401,"token验证失败,请重新登录");
        }
        return true;
    }
}

5、在utils中的request.js中加上

// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    let user=localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : null
    if (user){
        config.headers['token'] = user.token;  // 设置请求头
    }

###后台获取用户信息

1、在UserController中加上

//获取当前用户信息
User currentUser = TokenUtils.getCurrentUser();
System.out.println("获取当前用户信息==============="+currentUser.getNickname());

2、在TokenUtils.java中加入

/**
 * 获取当前登录的用户信息
 * @return user对象
 */
public static User getCurrentUser() {
    try {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        if (StrUtil.isNotBlank(token)) {
            String userId = JWT.decode(token).getAudience().get(0);
            return staticUserService.getById(Integer.valueOf(userId));
        }
    }catch (Exception e) {
            return null;
    }
    return null;
}

17、SpringBoot文件上传+用户信息修改同步

1、File.vue

<template>
  <div>
    <div style="padding: 10px 0">
      <el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" v-model="name"  @keyup.enter.native="triggerClick"></el-input>
      <el-button class="ml-5" type="primary" @click="load" ref="btn">搜索</el-button>
      <el-button class="ml-5" type="warning" @click="reset">重置</el-button>
    </div>
    <div style="margin: 10px 0">
      <el-upload action="http://localhost:9090/file/upload" :show-file-list="false" :on-success="handleFileUploadSuccess" style="display: inline-block">
        <el-button type="primary" class="ml-5">上传文件 <i class="el-icon-top"></i> </el-button>
      </el-upload>
      <el-popconfirm
          class="ml-5"
          confirm-button-text='确定'
          cancel-button-text='取消'
          icon="el-icon-info"
          icon-color="red"
          title="您确定批量删除这些数据吗?"
          @confirm="delBatch">
        <el-button type="danger" slot="reference">批量删除 <i class="el-icon-remove-outline"></i> </el-button>
      </el-popconfirm>
    </div>

    <el-table :data="tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55"></el-table-column>
      <el-table-column prop="id" label="ID" width="80"></el-table-column>
      <el-table-column prop="name" label="文件名称"></el-table-column>
      <el-table-column prop="type" label="文件类型"></el-table-column>
      <el-table-column prop="size" label="文件大小(kb)"></el-table-column>
      <el-table-column label="下载">
        <template slot-scope="scope">
          <el-button type="primary" @click="download(scope.row.url)">下载</el-button>
        </template>
      </el-table-column>
      <el-table-column label="启用">
        <template slot-scope="scope">
          <el-switch v-model="scope.row.enable" active-color="#13ce66" inactive-color="#ccc" @change="changeEnable(scope.row)"></el-switch>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="200" align="center">
        <template slot-scope="scope">
          <el-popconfirm
              class="ml-5"
              confirm-button-text='确定'
              cancel-button-text='取消'
              icon="el-icon-info"
              icon-color="red"
              title="确定删除吗?"
              @confirm="del(scope.row.id)">
            <el-button type="danger" slot="reference" >删除 <i class="el-icon-remove-outline"></i></el-button>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <div style="padding: 10px 0">
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageNum"
          :page-sizes="[5, 10, 20]"
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total">
      </el-pagination><!--分页栏-->
    </div>
  </div>
</template>

<script>
export default {
  name: "File",
  data(){
    return {
      tableData:[],
      name:'',
      multipleSelection:[],
      headerBg:'headerBg',
      pageNum:1,
      pageSize:5,
      total:0
    }
  },
  created() {
    this.load()
  },
  methods:{
    load(){
      this.request.get("/file/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          name:this.name,
        }

      }).then(res =>{

        this.tableData = res.data.records
        this.total = res.data.total

      })
    },

    triggerClick(){ //用于回车键触发搜索功能

      this.$refs.btn.$emit('click')

    },

    changeEnable(row){
      this.request.post("/file/update",row).then(res =>{
        if (res.code === '200'){
          this.$message.success("操作成功!")
        }
      })
    },

    del(id){
      this.request.delete("/file/"+id).then(res => {
        if (res.code === '200'){
          this.$message.success("删除成功!")
          this.load()
        }else {
          this.$message.error("删除失败!")
        }
      })
    },

    handleSelectionChange(val){
      console.log(val)
      this.multipleSelection = val
    },

    delBatch(){
      let ids = this.multipleSelection.map(v => v.id) //将多选获取的对象扁平化处理,即[{},{},{}] => [1,2,3]
      this.request.post("/file/del/batch",ids).then(res => {
        if (res.code === '200'){
          this.$message.success("批量删除成功!")
          this.load()
        }else {
          this.$message.error("批量删除失败!")
        }
      })
    },

    reset(){
      this.name = ""
      this.load()
    },

    handleSizeChange(pageSize){
      console.log(pageSize)
      this.pageSize=pageSize
      this.load()
    },
    handleCurrentChange(pageNum){
      console.log(pageNum)
      this.pageNum=pageNum
      this.load()
    },
    handleFileUploadSuccess(res){
      console.log(res)
      this.load()
    },
    download(url){
      window.open(url)
    }
  }

}
</script>

<style scoped>

</style>

Person.vue

<template>
<el-card style="width: 500px">
  <el-form label-width="80px" size="small">
    <el-upload
      action="https://localhost:9090/file/upload"
      :show-file-list="false">
    </el-upload>

    <el-form-item label="用户名">
      <el-input v-model="form.username" disabled autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="昵称">
      <el-input v-model="form.nickname" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="邮箱">
      <el-input v-model="form.email" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="电话">
      <el-input v-model="form.phone" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="地址">
      <el-input type="textarea" v-model="form.address" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="save">确 定</el-button>
      <el-button type="warning" @click="reBack" style="margin-left: 180px">返 回</el-button>
    </el-form-item>
  </el-form>
</el-card>
</template>

<script>
export default {
  name: "Person",
  data(){
    return{
      form:{},
      user:localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
    this.getUser().then(res => {
      console.log(res)
      this.form = res
    })
  },

  methods:{
    async getUser(){
      return (await this.request.get("/user/username/"+this.user.username)).data
    },
    save(){
      this.request.post("/user",this.form).then(res => {
        if (res.code === '200'){
          this.$message.success("保存成功!")

          //触发父级更新User的方法
          this.$emit("refreshUser")

          //更新浏览器存储用户信息
          this.getUser().then(res => {
            res.token = JSON.parse(localStorage.getItem("user")).token
            localStorage.setItem("user",JSON.stringify(res))
          })

        }else {
          this.$message.error("保存失败!")
        }
      })
    },
    reBack(){
      this.$router.push("/user")
    }
  }
}
</script>

<style scoped>

</style>

3、router中的index.js

const routes = [
  {
    path: '/',
    component: () => import('../views/Manage.vue'),
    redirect:'/home',
    children:[
      {path:'home', name:'首页', component: () =>import('../views/Home.vue')},
      {path:'user',name:'用户管理',component: () => import('../views/User.vue')},
      {path:'person',name:'个人信息',component: () => import('../views/Person.vue')},
      {path:'file',name:'文件管理',component: () => import('../views/File.vue')},
    ]
  },

4、Manage.vue

<template>
    <el-container style="min-height:100vh /*border: 1px solid #eee*/">
      <el-aside width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246);box-shadow: 1px 0 6px rgb(205 133 63)">
        <Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow"/>  <!--给组件传值-->
      </el-aside>

      <el-container>
        <el-header style="border-bottom: 1px solid #ccc">
        <Header :collapse-btn-class="collapseBtnClass" v-on:click="collapse" :user="user"/>
        </el-header>

        <el-main>
<!--          表示当前页面的子路由会在 <router-view /> 里面显示-->
          <router-view @refreshUser="getUser"/>
        </el-main>

      </el-container>
    </el-container>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
// import request from "../utils/request";

import Aside from "../components/Aside";
import Header from "../components/Header";

export default {
  name: 'Home',

  data(){
    return {
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      logoTextShow:true,
      user:{}
    }
  },


  components:{
    Header,
    Aside
  },

  created() {
    //从后台获取最新的User数据
    this.getUser()
  },

  methods:{
    collapse(){   //点击收缩按钮触发
      this.isCollapse = !this.isCollapse
      if (this.isCollapse){
        this.sideWidth = 64
        this.collapseBtnClass='el-icon-s-unfold'
        this.logoTextShow = false
      }else{  //展开
        this.sideWidth = 200
        this.collapseBtnClass = 'el-icon-s-fold'
        this.logoTextShow = true
      }
    },

    getUser() {
      let username =localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")).username : ""
      //从后台获取user数据
      this.request.get("/user/username/" + username).then(res => {
        //重新赋值后台的最新User数据
        this.user=res.data
      })
    }
  }
}
</script>

5、实体类File.java

package com.kep.springboot.entity;

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

@Data
@TableName("sys_file")
public class Files {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    private String type;
    private Long size;
    private String url;
    private String md5;
    private Boolean isDelete;
    private Boolean enable;
}

6、FileMapper.java

package com.kep.springboot.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kep.springboot.entity.Files;

public interface FileMapper extends BaseMapper<Files> {

}

7、application.yml

server:
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/dangjian?serverTimezone=GMT%2b8
    username: root
    password: 180918
mybatis:
  mapper-locations: classpath:mapper/*.xml #扫描所有mybatis的xml文件
  #configuration:
   # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

files:
  upload:
    path: D:/Intellij IDEA/files/

18、整合Echarts

下载Echarts:terminal中npm i echarts -S

在主页中引入echarts:import * as echarts from 'echarts'

官网:https://echarts.apache.org/zh/index.html

使用:

1、折线图

2、柱状图

3、饼图

示例:Home.vue

<template>
  <div>
    <div id="main" style="width: 500px;height: 400px"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts'

export default {
  name: "Home",
  data(){
    return{

    }
  },
  mounted() { //页面元素渲染之后再触发
    var chartDom = document.getElementById('main');
    var myChart = echarts.init(chartDom);
    var option;

    let base = +new Date(1968, 9, 3);
    let oneDay = 24 * 3600 * 1000;
    let date = [];
    let data = [Math.random() * 300];
    for (let i = 1; i < 20000; i++) {
      var now = new Date((base += oneDay));
      date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));
      data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));
    }
    option = {
      tooltip: {
        trigger: 'axis',
        position: function (pt) {
          return [pt[0], '10%'];
        }
      },
      title: {
        left: 'center',
        text: 'Large Area Chart'
      },
      toolbox: {
        feature: {
          dataZoom: {
            yAxisIndex: 'none'
          },
          restore: {},
          saveAsImage: {}
        }
      },
      xAxis: {
        type: 'category',
        boundaryGap: false,
        data: date
      },
      yAxis: {
        type: 'value',
        boundaryGap: [0, '100%']
      },
      dataZoom: [
        {
          type: 'inside',
          start: 0,
          end: 10
        },
        {
          start: 0,
          end: 10
        }
      ],
      series: [
        {
          name: 'Fake Data',
          type: 'line',
          symbol: 'none',
          sampling: 'lttb',
          itemStyle: {
            color: 'rgb(255, 70, 131)'
          },
          areaStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              {
                offset: 0,
                color: 'rgb(255, 158, 68)'
              },
              {
                offset: 1,
                color: 'rgb(255, 70, 131)'
              }
            ])
          },
          data: data
        }
      ]
    };
    option && myChart.setOption(option);

  }
}
</script>

<style scoped>

</style>

19、权限菜单

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设计划是基于web的系统的设计和开发,通过使用web技术来搭建一个功能完善的系统。 首先,我会进行需求分析,与项目组成员和用户讨论,确定系统的功能和特性。然后,我将进行系统的设计,包括数据库设计、系统架构设计和用户界面设计。在设计阶段,我会考虑系统的安全性和性能,确保用户数据的保密性和系统的响应速度。 接下来,我会使用适当的编程语言和框架来实现系统的核心功能。我会编写前端代码,包括HTML、CSS和JavaScript,来创建用户友好的界面。同时,我会使用后端技术,如PHP、Python或Java,来处理用户请求,与数据库交互并生成动态内容。 在开发过程中,我会进行测试来确保系统的稳定性和正确性。我会进行单元测试和集成测试,模拟用户操作和各种情况,并修复发现的问题。 一旦开发完成,我会部署系统到web服务器上,并进行性能优化和安全加固。我会配置服务器和数据库,确保系统的可用性和可靠性。同时,我会采取适当的措施来防止恶意攻击和数据泄露。 最后,我会编写系统的用户手册以及技术文档,以便用户和其他开发者了解系统的功能和使用方法。 通过毕设的这个项目,我可以提高我的web开发技能和系统设计能力。这个基于web的系统有助于满足用户的需求,并提供便捷的功能和友好的用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值