IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> springboot+vue搭建后台 -> 正文阅读

[JavaScript知识库]springboot+vue搭建后台

代码地址:https://github.com/hyblist/SpringBoot-Vue2.git

jdk1.8

mysql

node

navicat

idea

SpringBoot + Vue

1、前端环境搭建

1、Vue后台主体搭建

地址:https://element.eleme.cn/#/zh-CN/component/installation

弹窗:https://layuion.com/docs/

docsify动态生成您的文档网站:https://docsify.js.org/#/

安装:

npm i element-ui -S

搭建项目

1、vue-cli安装:

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

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

2、创建一个名为vue的工程

vue create vue

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y75jaYg2-1656746400673)(springboot+vue.assets/image-20220626135443407.png)]

3、测试启动

cd vue
npm run serve

4、项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tCpKvhrY-1656746400675)(springboot+vue.assets/image-20220626135932147.png)]

5、安装element-ui

npm i element-ui -S
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

//{small}指定空间大小
Vue.use(ElementUI,{small})

6、修样式

新建goloable.css,并在main.js导入import ‘./assets/goloable.css’

/*全局去除边框*/
html,body,div{
    margin: 0;
    padding: 0;
}
/*设置高度*/
html,body{
    height: 100%;
}

Home.vue

<!--https://element.eleme.cn/#/zh-CN/component/container#container-bu-ju-rong-qi  搜布局容器,取其中代码,并做修改-->
<template>
<div style="height: 100%">
<!--菜单下面的横线border: 1px solid #eee",去掉-->
  <el-container style="height: 100%">
<!--页面架构-->
<!--el-aside侧边栏-->
<!--el-container有el-header主体 设置颜色:border-bottom: 1px solid #ccc;居中line-height: 60px-->
<!--el-container-->
    <el-aside width="200px" 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>

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

2、Vue后台整体完善(一)

1、设置整体页面100%

goloable.css

/* * 全局元素生效 */
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

App.vue

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

2、调整Home.vue

Home.vue 去除div,并设置<el-container style=“height: 100vh”>;并进行以下设置

<!--https://element.eleme.cn/#/zh-CN/component/container#container-bu-ju-rong-qi  搜布局容器,取其中代码,并做修改-->
<template>
  <!--菜单下面的横线border: 1px solid #eee",去掉-->
  <el-container style="height: 100vh">
    <!--页面架构-->
    <!--el-aside侧边栏-->
    <!--el-container有el-header主体 设置颜色:border-bottom: 1px solid #ccc;居中line-height: 60px-->
    <!--el-container-->
    <!--:width="sideWidth+'px'",绑定,并使其自动更换宽度-->
    <el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246); box-shadow: 2px 0 20px  #888888;" >
      <!--overflow: hidden 多层子菜单菜单超出,设置样式;background-color:颜色;text-color字体颜色-->
      <!--active-text-color="#ffdo4b" 选中菜单的颜色;绑定  :collapse-transition="false"菜单的动漫:
      collapse="isCollapse"菜单收缩根据这个变量来变化  -->
      <el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow: hidden"
      background-color="rgb(48,65,86)"
      text-color="#fff"
      active-text-color="#ffdo4b"
      :collapse-transition="false"
      :collapse="isCollapse"
      >
        <!--设置log,新增一个div;style="height: 60px;line-height: 60px;设置高度text-align: center"位置居中,左(默认),右-->
        <!--style="width: 20px"设置图片大小;position: relative;位置相对 top: 5px 下移动;-->
        <div style="height: 60px;line-height: 60px;text-align: center">
          <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top: 5px;margin-right: 5px">
          <!--是否展示绑定一个变量v-show="logoTextShow"-->
          <b style="color: white" v-show="logoTextShow">后台管理系统</b>
        </div>
        <el-submenu index="1">
          <template slot="title">
            <!--样式有问题调整导航-->
            <i class="el-icon-message"></i>
            <span>导航一</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>导航二</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>导航三</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: 18px">
          <!--绑定点击事件-->
          <span v-bind:class="collapseBtnClass" style="cursor:pointer; " @click="collapse"></span>
        </div>
        <!--el-dropdown下展图标设置,可以通过f12知道其位置-->
        <el-dropdown style="width: 70px; cursor:pointer">
          <!--class="el-icon-caret-bottom"图标样式;style="margin-left: 5px"可以设置与文字距离-->
          <span>王小虎</span><i class="el-icon-caret-bottom" style="margin-left: 5px"></i>
          <el-dropdown-menu slot="dropdown">
            <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>

export default {
  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,
      //logo处理
      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>

3、Vue后台整体完善(二)

1、添加分页

<!--完整版-->
<!--分页:style="padding: 20px(高度) 10px(margin-left[默认隐藏]:10px)[左距离] 设置位置-->
<div style="padding: 20px 10px">
<el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="currentPage4"
      :page-sizes="[100, 200, 300, 400]"
      :page-size="100"
      layout="total, sizes, prev, pager, next, jumper"
      :total="400">
    </el-pagination>
</div>

2、定制样式

/*定制样式*/

/* * 全局元素生效 */
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}


/*可以随意起名字*/
.ml-5{
    margin-left: 10px;
}

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

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

3、调整Home.vue

<!--https://element.eleme.cn/#/zh-CN/component/container#container-bu-ju-rong-qi  搜布局容器,取其中代码,并做修改-->
<template>
  <!--菜单下面的横线border: 1px solid #eee",去掉-->
  <el-container style="height: 100vh">
    <!--页面架构-->
    <!--el-aside侧边栏-->
    <!--el-container有el-header主体 设置颜色:border-bottom: 1px solid #ccc;居中line-height: 60px-->
    <!--el-container-->
    <!--:width="sideWidth+'px'",绑定,并使其自动更换宽度-->
    <el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);  box-shadow: 2px 0 20px  #888888;" >
      <!--overflow: hidden 多层子菜单菜单超出,设置样式;background-color:颜色;text-color字体颜色-->
      <!--active-text-color="#ffdo4b" 选中菜单的颜色;绑定  :collapse-transition="false"菜单的动漫:
      collapse="isCollapse"菜单收缩根据这个变量来变化  -->
      <el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow: hidden"
      background-color="rgb(48,65,86)"
      text-color="#fff"
      active-text-color="#ffdo4b"
      :collapse-transition="false"
      :collapse="isCollapse"
      >
        <!--设置log,新增一个div;style="height: 60px;line-height: 60px;设置高度text-align: center"位置居中,左(默认),右-->
        <!--style="width: 20px"设置图片大小;position: relative;位置相对 top: 5px 下移动;-->
        <div style="height: 60px;line-height: 60px;text-align: center">
          <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top: 5px;margin-right: 5px">
          <!--是否展示绑定一个变量v-show="logoTextShow"-->
          <b style="color: white" v-show="logoTextShow">后台管理系统</b>
        </div>
        <el-submenu index="1">
          <template slot="title">
            <!--样式有问题调整导航-->
            <i class="el-icon-message"></i>
            <span>导航一</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>导航二</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>导航三</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>
      </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: 18px">
          <!--绑定点击事件-->
          <span v-bind:class="collapseBtnClass" style="cursor:pointer; " @click="collapse"></span>
        </div>
        <!--el-dropdown下展图标设置,可以通过f12知道其位置-->
        <el-dropdown style="width: 70px; cursor:pointer">
          <!--class="el-icon-caret-bottom"图标样式;style="margin-left: 5px"可以设置与文字距离-->
          <span>王小虎</span><i class="el-icon-caret-bottom" style="margin-left: 5px"></i>
          <el-dropdown-menu slot="dropdown">
            <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>
        <!--搜索position: relative ; top:-10px连这用的-->
        <div style="position: relative ; top:-10px">
          <!--width英 [w?dθ]宽度;placeholder="请输入名称"提示语,suffix-icon="el-icon-search"嵌套图标-->
          <el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" class="mr-10"></el-input>
          <el-input style="width: 200px" placeholder="邮箱" suffix-icon="el-icon-message" class="mr-10"></el-input>
          <el-input style="width: 200px" placeholder="地址" suffix-icon="el-icon-position" class="mr-10"></el-input>
          <el-button class="ml-5" type="primary">搜索</el-button>
        </div>
        <!--按钮 <i class="el-icon-circle-plus-outline" >嵌套按钮-->
        <div style=" position: relative; top:-6px ">
          <el-button type="primary">新增   <i class="el-icon-circle-plus-outline" ></i></el-button>
          <el-button type="danger">批量删除   <i class="el-icon-circle-close"></i></el-button>
          <el-button type="primary">导入  <i class="el-icon-top"></i></el-button>
          <el-button type="primary">导出  <i class="el-icon-bottom"></i></el-button>
        </div>

        <!--表格设置边框border stripe有线-->
        <!--:header-cell-class-name="headerBg"和下面的<script><script>有联系-->
        <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
          <el-table-column prop="date" label="日期" width="120">
          </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="操作" width="150" >
            <template slot-scope="scope" >
              <el-button >编辑</el-button>
              <el-button type="danger">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!--分页:style="padding: 20px(高度) 10px(margin-left[默认隐藏]:10px)[左距离] 设置位置-->
        <div style="padding: 20px 10px">
          <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>

export default {
  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,
      //logo处理
      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: rgba(204, 204, 204, 0.59) !important;
}
</style>

2、后端环境搭建

1、 创建springboot项目,和配置数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQyXRYtX-1656746400677)(springboot+vue.assets/image-20220626212732545.png)]

2、把vue项目拉到springboot里面,并在springboot配置启动前端的配置[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CJRv56q0-1656746400678)(springboot+vue.assets/image-20220626214628189.png)]

测试前后端是否正常运行

3、搭建/连接数据库

1、创建sys_user表

1-1、一个表要有唯一的主键,勾选自动递增

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QzmMIKAF-1656746400678)(springboot+vue.assets/image-20220627093836101.png)]

1-2、创建时间字段默认值CURRENT_TIMESTAMP

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tv75T5gL-1656746400679)(springboot+vue.assets/image-20220627094426869.png)]

1-3、创建表的sql
CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
  `email` varchar(50) DEFAULT NULL,
  `phone` varchar(50) DEFAULT NULL,
  `address` varchar(50) DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

2、测试查询数据

entity 英 [?ent?ti] 实体:User.java

//entity 英 [?ent?ti] 实体

package com.yebin.springboot.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//实体类。get/set
@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private String email;
    private String phone;
    private String address;
}

mapper(作用:与数据库交互):UserMapper.java

package com.yebin.springboot.mapper;

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

import java.util.List;

//Mapper专门用来与数据库交互的
@Mapper //把UserMapper,注入bean
public interface UserMapper {

    //@Select,mybatis的注解
    @Select("select * from sys_user")
    //泛型方法
    List<User> findAll();
}

controller: UserController.java

package com.yebin.springboot.controller;

import com.yebin.springboot.entity.User;
import com.yebin.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("/")
    private List<User> index(){
        return userMapper.findAll();
    }
}

4、实现增删改查

安装mybatisx插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-depPnMzp-1656746400680)(springboot+vue.assets/image-20220627115620336.png)]

controller: UserController.java

package com.yebin.springboot.controller;

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

import java.util.List;

@RestController
@RequestMapping("/user")//统一加/user,如
public class UserController {

    @Autowired //注入其他类的注解
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

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

    @PostMapping    //post请求
    private Integer save(@RequestBody User user){  //@RequestBody可以把前端传来的对象转成java对象
        //新增或更新
        return userService.save(user);
    }

    @DeleteMapping("/{id}")
    private Integer delete(@PathVariable Integer id){  //@PathVariable接收id
        return userMapper.deleteById(id);
    }
}

mapper(作用:与数据库交互):UserMapper.java

package com.yebin.springboot.mapper;

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

import java.util.List;

//Mapper专门用来与数据库交互的
@Mapper //把UserMapper,注入bean
public interface UserMapper {

    //@Select,mybatis的注解
    @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);

//    //这样写会导致,有些字段我本来不想更新的,但是却给了个null,所有要使用动态sql,在resources里面创建mapper文件夹,并新增User.xml(mybatis的xml)
//    @Update("update sys_user set username = #{username}, password = #{password}, nickname= #{nickname}," +
//            "email = #{email},phone = #{phone},address = #{address} where id = #{id}")
    int update(User user);

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

User.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--从mybatis中文网——入门取来后,需要修改namespace-->
<mapper namespace="com.yebin.springboot.mapper.UserMapper">
    <update id="update">
        -- 判断username是否为空
        -- 密码不在这里修改
        -- 注意要加","符号,要不然会报错
        update sys_user
        <set>

            <if test="username != null">
                username = #{username},
            </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>

mybatis xml格式

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--从mybatis中文网——入门取来后,需要修改namespace-->
<mapper namespace="com.yebinhuang.mapper.UserMapper">
        
</mapper>

配置mybatis application.yaml

# 应用服务 WEB 访问端口
server:
  port: 9090
# 应用名称
spring:
  application:
  name: springboot
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/my_project?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
#下面这些内容是为了让MyBatis映射
mybatis:
  mapper-locations: classpath:mapper/*.xml	#指定Mybatis的Mapper文件
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志



##指定Mybatis的实体目录
#  type-aliases-package: com.yebin.springboot.mybatis.entity

5、实现分页查询(mybatis)

5- 1、不使用插件写分页/带参数分页

后端处理(不带参数):
-- (1-1)*2 = 0
SELECT * FROM sys_user LIMIT 0, 2;-- 第一页
-- (2-1)*2 = 2
SELECT * FROM sys_user LIMIT 2, 2;-- 第二页
-- (2-1)*2 = 4
SELECT * FROM sys_user LIMIT 4, 2;-- 第三页
-- 结论:limit第一个参数 = (pageNum - 1)*pageSize

UserController.java

package com.yebin.springboot.controller;

import com.yebin.springboot.entity.User;
import com.yebin.springboot.mapper.UserMapper;
import com.yebin.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")//统一加/user,如
public class UserController {

    @Autowired //注入其他类的注解
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

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

    @PostMapping    //post请求
    private Integer save(@RequestBody User user){  //@RequestBody可以把前端传来的对象转成java对象
        //新增或更新
        return userService.save(user);
    }

    @DeleteMapping("/{id}")
    private Integer delete(@PathVariable Integer id){  //@PathVariable接收id
        return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page?pageNum=1&pageSize=10
    //@RequestParam接收参数
    //limit第一个参数=pageNum = (pageNum - 1)* pageSize
    @GetMapping("/page")
    private 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.java

package com.yebin.springboot.mapper;

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

import java.util.List;

//Mapper专门用来与数据库交互的
@Mapper //把UserMapper,注入bean
public interface UserMapper {

    //@Select,mybatis的注解
    @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);

//    //这样写会导致,有些字段我本来不想更新的,但是却给了个null,所有要使用动态sql,在resources里面创建mapper文件夹,并新增User.xml(mybatis的xml)
//    @Update("update sys_user set username = #{username}, password = #{password}, nickname= #{nickname}," +
//            "email = #{email},phone = #{phone},address = #{address} where id = #{id}")
    int update(User user);

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


    //@Select,mybatis的注解
    @Select("select * from sys_user limit #{pageNum},#{pageSize}")
    //泛型方法
    List<User> selectPage(@Param("pageNum")Integer pageNum,@Param("pageSize")Integer pageSize);

    //数量,后面需要考虑,逻辑删除情况
    @Select("select count(*) from sys_user")
    Integer selectTotal();
}

User.java 忽略某个字段不展示给前端@JsonIgnore

//entity 英 [?ent?ti] 实体

package com.yebin.springboot.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//实体类。get/set
@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;
}

前端处理:
1、会出现跨域问题:解决方案看“其他——>3、前端跨域问题”
2、elementUi找Pagination 分页——附加功能
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"

然后添加到

<script>
export default {
  data() {
    return {
      pageNum:1,
      pageSize:10,
    }
  },
  created(){
    //分页
    this.load()
    },
  methods:{
    //分页
    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
      })

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

Home.vue 分页的修改

<!--https://element.eleme.cn/#/zh-CN/component/container#container-bu-ju-rong-qi  搜布局容器,取其中代码,并做修改-->
<template>
  <!--菜单下面的横线border: 1px solid #eee",去掉-->
  <el-container style="height: 100vh">
    <!--页面架构-->
    <!--el-aside侧边栏-->
    <!--el-container有el-header主体 设置颜色:border-bottom: 1px solid #ccc;居中line-height: 60px-->
    <!--el-container-->
    <!--:width="sideWidth+'px'",绑定,并使其自动更换宽度-->
    <el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);  box-shadow: 2px 0 20px  #888888;" >
      <!--overflow: hidden 多层子菜单菜单超出,设置样式;background-color:颜色;text-color字体颜色-->
      <!--active-text-color="#ffdo4b" 选中菜单的颜色;绑定  :collapse-transition="false"菜单的动漫:
      collapse="isCollapse"菜单收缩根据这个变量来变化  -->
      <el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow: hidden"
      background-color="rgb(48,65,86)"
      text-color="#fff"
      active-text-color="#ffdo4b"
      :collapse-transition="false"
      :collapse="isCollapse"
      >
        <!--设置log,新增一个div;style="height: 60px;line-height: 60px;设置高度text-align: center"位置居中,左(默认),右-->
        <!--style="width: 20px"设置图片大小;position: relative;位置相对 top: 5px 下移动;-->
        <div style="height: 60px;line-height: 60px;text-align: center">
          <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top: 5px;margin-right: 5px">
          <!--是否展示绑定一个变量v-show="logoTextShow"-->
          <b style="color: white" v-show="logoTextShow">后台管理系统</b>
        </div>
        <el-submenu index="1">
          <template slot="title">
            <!--样式有问题调整导航-->
            <i class="el-icon-message"></i>
            <span>导航一</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>导航二</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>导航三</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>
      </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: 18px">
          <!--绑定点击事件-->
          <span v-bind:class="collapseBtnClass" style="cursor:pointer; " @click="collapse"></span>
        </div>
        <!--el-dropdown下展图标设置,可以通过f12知道其位置-->
        <el-dropdown style="width: 70px; cursor:pointer">
          <!--class="el-icon-caret-bottom"图标样式;style="margin-left: 5px"可以设置与文字距离-->
          <span>王小虎</span><i class="el-icon-caret-bottom" style="margin-left: 5px"></i>
          <el-dropdown-menu slot="dropdown">
            <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>
        <!--搜索position: relative ; top:-10px连这用的-->
        <div style="position: relative ; top:-10px">
          <!--width英 [w?dθ]宽度;placeholder="请输入名称"提示语,suffix-icon="el-icon-search"嵌套图标-->
          <el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" class="mr-10"></el-input>
          <el-input style="width: 200px" placeholder="邮箱" suffix-icon="el-icon-message" class="mr-10"></el-input>
          <el-input style="width: 200px" placeholder="地址" suffix-icon="el-icon-position" class="mr-10"></el-input>
          <el-button class="ml-5" type="primary">搜索</el-button>
        </div>
        <!--按钮 <i class="el-icon-circle-plus-outline" >嵌套按钮-->
        <div style=" position: relative; top:-6px ">
          <el-button type="primary">新增   <i class="el-icon-circle-plus-outline" ></i></el-button>
          <el-button type="danger">批量删除   <i class="el-icon-circle-close"></i></el-button>
          <el-button type="primary">导入  <i class="el-icon-top"></i></el-button>
          <el-button type="primary">导出  <i class="el-icon-bottom"></i></el-button>
        </div>

        <!--表格设置边框border stripe有线-->
        <!--:header-cell-class-name="headerBg"和下面的<script><script>有联系-->
        <!-- :data="tableData" 与下面的<script>中的created()做数据绑定-->
        <el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
          <el-table-column prop="id" label="id" width="50"></el-table-column>
          <el-table-column prop="username" label="用户名" ></el-table-column>
          <el-table-column prop="nickname" label="昵称"   ></el-table-column>
          <el-table-column prop="phone" label="电话"  ></el-table-column>
          <el-table-column prop="email" label="邮箱"   ></el-table-column>
          <el-table-column prop="address" label="地址"></el-table-column>
          <!--添加编辑操作-->
          <el-table-column label="操作" width="150" >
            <template slot-scope="scope" >
              <el-button >编辑</el-button>
              <el-button type="danger">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!--分页:style="padding: 20px(高度) 10px(margin-left[默认隐藏]:10px)[左距离] 设置位置-->
        <div style="padding: 20px 10px">
          <!--@size-change="handleSizeChange"、@current-change="handleCurrentChange"、:current-page="pageNum"
          :page-size="pageSize"、实现动态翻页-->
          <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="pageNum"
              :page-size="pageSize"
              :page-sizes="[10, 20, 50, 100]"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total">
          </el-pagination>
        </div>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>

export default {
  data() {
    return {
      tableData: [],
      total: 0,
      pageNum:1,
      pageSize:10,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      //logo处理
      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(){
      //请求分页查询数据
      //注意:res.json()和res.join()
      // fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res =>res.json()).then(res =>{
      //   console.log(res)
      // 改成动态
      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
      })

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

<style>
.headerBg{
  background: rgba(204, 204, 204, 0.59) !important;
}
</style>

后端处理(带参数):

主要在于改sql

UserMapper.java

package com.yebin.springboot.mapper;

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

import java.util.List;

//Mapper专门用来与数据库交互的
@Mapper //把UserMapper,注入bean
public interface UserMapper {

    //@Select,mybatis的注解
    @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);

//    //这样写会导致,有些字段我本来不想更新的,但是却给了个null,所有要使用动态sql,在resources里面创建mapper文件夹,并新增User.xml(mybatis的xml)
//    @Update("update sys_user set username = #{username}, password = #{password}, nickname= #{nickname}," +
//            "email = #{email},phone = #{phone},address = #{address} where id = #{id}")
    int update(User user);

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



    //只有翻页
    //@Select("select * from sys_user limit  #{pageNum},#{pageSize}")


    //模糊搜索
//    //方式二
//    @Select("select * from sys_user limit like #{username}, #{pageNum},#{pageSize}")
    //@Select,mybatis的注解;方式一
    @Select("select * from sys_user where " +
            "username  like concat('%' , #{username}, '%') " +
            "limit  #{pageNum},#{pageSize}")//在UserMapper也要修改
    List<User> selectPage(
            @Param("username")String username,
            @Param("pageNum")Integer pageNum,
            @Param("pageSize")Integer pageSize);//泛型方法

    //数量,后面需要考虑,逻辑删除情况
    @Select("select count(*) from sys_user where " +
            "username like concat('%' , #{username}, '%')" +
            "")
    Integer selectTotal(
            @Param("username")String username
    );
}

UserController.java

package com.yebin.springboot.controller;

import com.yebin.springboot.entity.User;
import com.yebin.springboot.mapper.UserMapper;
import com.yebin.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")//统一加/user,如
public class UserController {

    @Autowired //注入其他类的注解
    private UserMapper userMapper;

    @Autowired
    private UserService userService;

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

    @PostMapping    //post请求
    private Integer save(@RequestBody User user){  //@RequestBody可以把前端传来的对象转成java对象
        //新增或更新
        return userService.save(user);
    }

    @DeleteMapping("/{id}")
    private Integer delete(@PathVariable Integer id){  //@PathVariable接收id
        return userMapper.deleteById(id);
    }

    //分页查询
    //接口路径:/user/page?pageNum=1&pageSize=10
    //@RequestParam接收参数
    //limit第一个参数=pageNum = (pageNum - 1)* pageSize
    @GetMapping("/page")
    private Map<String,Object> findPage(
            @RequestParam String username,
            @RequestParam Integer pageNum,
            @RequestParam Integer pageSize){
        pageNum = (pageNum - 1)* pageSize;
//        username = "%" + username + "%"; //方式二
        List<User> data = userMapper.selectPage(username,pageNum,pageSize);
        //数量
        Integer total = userMapper.selectTotal(username);
        Map<String,Object> res = new HashMap<>();
        res.put("data",data);
        res.put("total",total);
        return res;
    }

}

前端处理(带参数):

对应Home.vue修改

<el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" class="mr-10" v-model = "username" ></el-input>
<!--@click="load"点击绑定load方法-->
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>


data() {
    return {
	  //带参数
      username:"",
      tableData: [],
      total: 0,
      pageNum:1,
      pageSize:10,
      collapseBtnClass:'el-icon-s-fold',
      isCollapse:false,
      sideWidth:200,
      //logo处理
      logoTextShow:true,
      headerBg:'headerBg'
    }
  }

fetch("http://localhost:9090/user/page?pageNum="+this.pageNum + "&pageSize="+this.pageSize+ "&username="+this.username).
      then(res =>res.json())

3、SpringBoot集成Mybatis-Plus

1、Mybatis-Plus实现分页

快速实现增删改查,但是sql的编写会慢慢忘掉

Mybatis-Plus官网:https://www.baomidou.com/pages/24112f/ (建议多看官网)

1-1、引入依赖依赖和修改配置

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

1-2、mybatis-plus配置(只能留一个)

mybatis和mybatis-plus只能存在一个,要不然会打架,所以导入依赖只能存在其中一个

# 应用服务 WEB 访问端口
server:
  port: 9090
# 应用名称
spring:
  application:
  name: springboot
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/my_project?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456


# mybatis和mybatis-plus只能存在一个,要不然会打架,所以导入依赖只能存在其中一个
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志
    true map-underscore-to-camel-case: true

1-3、在官网→插件主体:copy分页插件代码

MybatisPlusConfig.java

package com.yebin.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.yebin.springboot.mapper") //Mapper由MybatisPlus接手
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//修改成MYSQL
        return interceptor;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ND9tM9On-1656746400681)(springboot+vue.assets/image-20220628133312136.png)]

1-4、mybatis-plus分页查询

//mybatis-plus分页查询
    @GetMapping("/page")
    public IPage<User> findPage(
            @RequestParam Integer pageNum,
            @RequestParam Integer pageSize,
            @RequestParam(defaultValue = "") String username,//(defaultValue = "")设置默认值
            @RequestParam(defaultValue = "") String email,
            @RequestParam(defaultValue = "") String address
            ){
        IPage<User> page = new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)){//if判断空,解决数据库null数据问题
            queryWrapper.like("username",username);
        }
        if (!"".equals(username)){
            queryWrapper.like("email",email);
        }
        if (!"".equals(username)){
            queryWrapper.like("address",address);
        }
        return userService.page(page,queryWrapper);
    }

2、后端代码处理

-----------------------------改得面目全非------------------------

mapper改成MybatisPlus接手,所有UserMapper中得注解@Mapper可以删了,可以看MybatisPlusConfig.java

UserMapper.java 注意要继承extends BaseMapper

package com.yebin.springboot2.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yebin.springboot2.entity.User;
//Mapper专门用来与数据库交互的
//@Mapper //把UserMapper,注入bean,引入mybatis-plus后更换配置注解位置
public interface UserMapper extends BaseMapper<User> {
}

UserController.java

package com.yebin.springboot2.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.yebin.springboot2.entity.User;
import com.yebin.springboot2.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/user")//统一加/user,如
public class UserController {

    @Autowired
    private UserService userService;

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

    @PostMapping    //post请求
    private boolean save(@RequestBody User user) {  //@RequestBody可以把前端传来的对象转成java对象
        //新增或更新
        return userService.saveUser(user);
    }

    //删除
    @DeleteMapping("/{id}")
    private boolean delete(@PathVariable Integer id) {  //@PathVariable接收id
        return userService.removeById(id);
    }

    //批量删除   //有问题暂时不搞
    @PostMapping ("/del/batch")
    private boolean deleteBatch(@RequestBody List<Integer> ids) {  //@RequestBody接收数组
        System.out.println(ids);
        return userService.removeByIds(ids);
    }

    //mybatis-plus分页查询
    @GetMapping("/page")
    public IPage<User> findPage(
            @RequestParam Integer pageNum,
            @RequestParam Integer pageSize,
            @RequestParam(defaultValue = "") String username,//(defaultValue = "")设置默认值
            @RequestParam(defaultValue = "") String email,
            @RequestParam(defaultValue = "") String address
            ){
        IPage<User> page = new Page<>(pageNum,pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (!"".equals(username)){//if判断空,解决数据库null数据问题
            queryWrapper.like("username",username);
        }
        if (!"".equals(username)){
            queryWrapper.like("email",email);
        }
        if (!"".equals(username)){
            queryWrapper.like("address",address);
        }
        queryWrapper.orderByDesc("id");
        return userService.page(page,queryWrapper);
    }

}

User.java 实体类需要注明数据库表名称

//entity 英 [?ent?ti] 实体
package com.yebin.springboot2.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;

//实体类。get/set
@Data
@TableName(value = "sys_user")  //mybatis-plus不表面数据库表会报错
public class User {
    @TableId(type = IdType.AUTO) //mybatis-plus指名为主键,IdType.AUTO:自动增加,可以看官方文档
    private Integer id;
    private String username;
    @JsonIgnore //忽略某个字段不给前端展示
    private String password;
    private String nickname;
    private String email;
    private String phone;
//    @TableField(value = "address") //mybatis-plus可以绑定数据库字段名,然后下面的变量名可以随意改
    private String address; //mybatis-plus可以绑定后,可以随意改
}

UserSevice.java 继承extends ServiceImpl<UserMapper, User>,ServiceImpl继承了IService,IService有些方法名重叠,或者说已经写好,直接调用即可

package com.yebin.springboot2.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yebin.springboot2.entity.User;
import com.yebin.springboot2.mapper.UserMapper;
import org.springframework.stereotype.Service;

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

3、前端代码处理

去除fetch改用axios封装

      fetch("http://localhost:9090/user/page?" +
          "pageNum="+this.pageNum +
          "&pageSize="+this.pageSize+
          "&username="+this.username+
          "&address="+this.address+
          "&email="+this.email
      ).then(res =>res.json())

安装Axios

npm i axios -s

封装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

修改fetch改成Axios,方式

 //修改成Axios,方式
      request.get("http://localhost:9090/user/page",{
        params:{
          pageNum:this.pageNum,
          pageSize:this.pageSize,
          username:this.username,
          address:this.address,
          email:this.email
        }
      }).then(res=>{
        //绑定接口的数据
        this.tableData = res.records
        this.total = res.total
      })
    }

1、新增重置按钮

<el-button type="warning" @click="reset">重置</el-button>
    reset(){
      this.username=""
      this.address=""
      this.email=""
      this.load()
    }

2、添加新增弹窗…(详情看–其他–)

Home.vue

<!--https://element.eleme.cn/#/zh-CN/component/container#container-bu-ju-rong-qi  搜布局容器,取其中代码,并做修改-->
<template>
  <!--菜单下面的横线border: 1px solid #eee",去掉-->
  <el-container style="height: 100vh">
    <!--页面架构-->
    <!--el-aside侧边栏-->
    <!--el-container有el-header主体 设置颜色:border-bottom: 1px solid #ccc;居中line-height: 60px-->
    <!--el-container-->
    <!--:width="sideWidth+'px'",绑定,并使其自动更换宽度-->
    <el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);  box-shadow: 2px 0 20px  #888888;">
      <!--overflow: hidden 多层子菜单菜单超出,设置样式;background-color:颜色;text-color字体颜色-->
      <!--active-text-color="#ffdo4b" 选中菜单的颜色;绑定  :collapse-transition="false"菜单的动漫:
      collapse="isCollapse"菜单收缩根据这个变量来变化  -->
      <el-menu :default-openeds="['1', '3']" style="min-height: 100%; overflow: hidden"
               background-color="rgb(48,65,86)"
               text-color="#fff"
               active-text-color="#ffdo4b"
               :collapse-transition="false"
               :collapse="isCollapse"
      >
        <!--设置log,新增一个div;style="height: 60px;line-height: 60px;设置高度text-align: center"位置居中,左(默认),右-->
        <!--style="width: 20px"设置图片大小;position: relative;位置相对 top: 5px 下移动;-->
        <div style="height: 60px;line-height: 60px;text-align: center">
          <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top: 5px;margin-right: 5px">
          <!--是否展示绑定一个变量v-show="logoTextShow"-->
          <b style="color: white" v-show="logoTextShow">后台管理系统</b>
        </div>
        <el-submenu index="1">
          <template slot="title">
            <!--样式有问题调整导航-->
            <i class="el-icon-message"></i>
            <span>导航一</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>导航二</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>导航三</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>
      </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: 18px">
          <!--绑定点击事件-->
          <span v-bind:class="collapseBtnClass" style="cursor:pointer; " @click="collapse"></span>
        </div>
        <!--el-dropdown下展图标设置,可以通过f12知道其位置-->
        <el-dropdown style="width: 70px; cursor:pointer">
          <!--class="el-icon-caret-bottom"图标样式;style="margin-left: 5px"可以设置与文字距离-->
          <span>黄业斌</span><i class="el-icon-caret-bottom" style="margin-left: 5px"></i>
          <el-dropdown-menu slot="dropdown">
            <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>
        <!--搜索position: relative ; top:-10px连这用的-->
        <div style="position: relative ; top:-10px">
          <!--width英 [w?dθ]宽度;placeholder="请输入名称"提示语,suffix-icon="el-icon-search"嵌套图标-->
          <el-input style="width: 200px" placeholder="请输入名称" suffix-icon="el-icon-search" class="mr-10"
                    v-model="username"></el-input>
          <el-input style="width: 200px" placeholder="邮箱" suffix-icon="el-icon-message" class="mr-10"
                    v-model="email"></el-input>
          <el-input style="width: 200px" placeholder="地址" suffix-icon="el-icon-position" class="mr-10"
                    v-model="address"></el-input>
          <!--@click="load"点击绑定load方法-->
          <el-button class="ml-5" type="primary" @click="load">搜索</el-button>
          <el-button type="warning" @click="reset">重置</el-button>
        </div>
        <!--按钮 <i class="el-icon-circle-plus-outline" >嵌套按钮-->
        <div style=" position: relative; top:-6px ">
          <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-circle-close"></i></el-button>
          <el-button type="primary">导入 <i class="el-icon-top"></i></el-button>
          <el-button type="primary">导出 <i class="el-icon-bottom"></i></el-button>
        </div>

        <!--表格设置边框border stripe有线-->
        <!--:header-cell-class-name="headerBg"和下面的<script><script>有联系-->
        <!-- :data="tableData" 与下面的<script>中的created()做数据绑定-->
        <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="50"></el-table-column>
          <el-table-column prop="username" label="用户名"></el-table-column>
          <el-table-column prop="nickname" label="昵称"></el-table-column>
          <el-table-column prop="phone" label="电话"></el-table-column>
          <el-table-column prop="email" label="邮箱"></el-table-column>
          <el-table-column prop="address" label="地址"></el-table-column>
          <!--添加编辑操作-->
          <el-table-column label="操作" width="150">
            <template slot-scope="scope">
              <el-button @click="handleEdit(scope.row)">编辑</el-button>
              <!--Popconfirm 气泡确认框-->
              <el-popconfirm
                  class="ml-10"
                  title="你要删除吗?"
                  @confirm="delone(scope.row.id)"
              >
                <el-button type="danger" slot="reference" class="ml-5">删除</el-button><!--slot="reference"使按钮显示-->
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <!--分页:style="padding: 20px(高度) 10px(margin-left[默认隐藏]:10px)[左距离] 设置位置-->
        <div style="padding: 20px 10px">
          <!--@size-change="handleSizeChange"、@current-change="handleCurrentChange"、:current-page="pageNum"
          :page-size="pageSize"、实现动态翻页-->
          <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="pageNum"
              :page-size="pageSize"
              :page-sizes="[10, 20, 50, 100]"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total">
          </el-pagination>
        </div>
        <div>
          <!--visible.sync=""控制弹窗是否显示-->
          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px">
              <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.phone" 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.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="saveUser">确 定</el-button>
            </div>
          </el-dialog>
        </div>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>

import request from "@/utils/request";

export default {
  data() {
    return {
      username: "",
      address: "",
      email: "",
      nickname: "",
      tableData: [],
      total: 0,
      pageNum: 1,
      pageSize: 10,
      collapseBtnClass: 'el-icon-s-fold',
      isCollapse: false,
      sideWidth: 200,
      //logo处理
      logoTextShow: true,
      headerBg: 'headerBg',
      dialogFormVisible: false,
      form: {},
      multipleSelection: []
    }
  },
  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
      }
    },
    reset() {
      this.username = ""
      this.address = ""
      this.email = ""
      this.load()
    },
    //分页
    load() {
      //请求分页查询数据
      //注意:res.json()和res.join()
      // fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res =>res.json()).then(res =>{
      //   console.log(res)
      // 改成动态
      // fetch("http://localhost:9090/user/page?" +
      //     "pageNum="+this.pageNum +
      //     "&pageSize="+this.pageSize+
      //     "&username="+this.username+
      //     "&address="+this.address+
      //     "&email="+this.email
      // ).then(res =>res.json()).then(res =>{
      //   console.log(res)
      //   //绑定接口的数据
      //   this.tableData = res.data
      //   this.total = res.total
      // })
      //-----------------------------------------------------------------------------
      //修改成Axios,方式
      request.get("/user/page", {
        params: {
          pageNum: this.pageNum,
          pageSize: this.pageSize,
          username: this.username,
          address: this.address,
          email: this.email
        }
      }).then(res => {
        //绑定接口的数据
        this.tableData = res.records
        this.total = res.total
      })
    },
    rules: {
      username: [
        {required: true, message: '请输入活动名称', trigger: 'blur'},
        {min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur'}
      ]
    },
    //添加用户确认
    handleAdd() {
      this.dialogFormVisible = true
      this.form = {}
    },
    //添加用户
    saveUser() {
      request.post("/user/", this.form).then(res => {
        if (res) {
          this.$message.success("新增成功")
          this.load()
        } else {
          this.$message.error("新增失败")
        }
      });
      this.dialogFormVisible = false
    },
    //编辑用户
    handleEdit(row) {
      console.log(row)
      this.form = row
      this.dialogFormVisible = true
    },
    //删除用户
    delone(id) {
      console.log(id)
      request.delete("/user/" + id, this.form).then(res => {
        if (res) {
          this.$message.success("删除成功")
          this.load()
        } else {
          this.$message.error("删除失败")
        }
      });
      this.dialogFormVisible = false
    },
    //批量删除
    handleSelectionChange(val) {
      console.log(val)
      this.multipleSelection = val
    },
    //批量删除按钮
    delBatch() {
      let ids = this.multipleSelection.map(v =>v.id) //[{},{},{}]=>[1,2,3]对象转换成数组
      console.log(ids)
      request.post("/user/del/batch", ids).then(res => {   //这里的","很关键,不能写成"+",会很刺激
        if (res) {
          this.$message.success("批量删除成功")
          this.load()
        } else {
          this.$message.error("批量删除失败")
        }
        console.log(res)
      });
    },
    //分页
    handleCurrentChange(pageNum) {
      this.pageNum = pageNum
      this.load()
    },
    //分页
    handleSizeChange(pageSize) {
      this.pageSize = pageSize
      this.load()
    }
  }
}
</script>

<style>
.headerBg {
  background: rgba(204, 204, 204, 0.59) !important;
}
</style>

4、MybatisPlus自动生成代码

1、安装依赖

        <!--mybatis-plus代码生成器-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>

2、创建utils包,创建CodeGenerator.java类

package com.yebin.springboot2.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;

/**
 * 代码生成器,使用前记得备份,以防丢失代码,当然可以把.fileOverride()给注释了
 * @author yebin
 * @since 20220629
 */

public class CodeGenerator {

//    //建议谨慎而行
//    public static void main(String[] args) {
//        generate();
//    }
    private static void generate(){
        //在官网取代码:https://www.baomidou.com/ ——>代码生成器
        FastAutoGenerator.create(
                "jdbc:mysql://localhost:3306/my_project?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8",
                "root", "123456") //数据库信息
                .globalConfig(builder -> {
                    builder.author("ye_bin") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
//                            .fileOverride() // 覆盖已生成文件,考虑清楚后就可以开启
                            .outputDir("F:\\Project\\springboot2\\src\\main\\java\\"); // 指定输出目录,一般指java
                })
                .packageConfig(builder -> {
                    builder.parent("com.yebin.springboot2") // 设置父包名
                            .moduleName(null) // 设置父包模块名,这样生成得连接就少一条"\"
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F:\\Project\\springboot2\\src\\main\\resources\\mapper")); // 设置mapperXml生成路径
                })
                .strategyConfig(builder -> {
                    builder.entityBuilder().enableLombok(); //采用Lombok依赖
                    builder.mapperBuilder().enableMapperAnnotation().build();
                    //听说下面两个配置很关键,到时候看
                    builder.controllerBuilder().enableHyphenStyle()  // 开启驼峰转连字符
                            .enableRestStyle();  // 开启生成@RestController 控制器
                    builder.addInclude("sys_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "sys_"); // 设置过滤表前缀
                })
//                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();

    }
}

3、下图位置可以复制模板去修改,也可以修改其他的

image-20220629115714206

controller.java.vm

//自定义controller模板
package ${package.Controller};

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.bind.annotation.*;

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

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

#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);
    }

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

    @GetMapping("/{id}")
    public List<${entity}> findOne(@PathVariable Integer id){
            return ${table.entityPath}Service.list();
    }

    @GetMapping("/page")
    public IPage<${entity}> findPage(
                                @RequestParam Integer pageNum,
                                @RequestParam Integer pageSize
        ){
        QueryWrapper${entity}> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        return ${table.entityPath}Service.page(new Page<>(pageNum,pageSize),queryWrapper);
        }
    }

}

#end

5、Vue使用路由

修改Home.vue文件改成Manage.vue

拆分Manage.vue

导入vuex

npm i vuex@3.6.2 -s

后面再补

6、springboot实现导入导出

Hutool官网:https://www.hutool.cn/docs/#/

导入依赖

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

导出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9RQCQmL3-1656746400682)(springboot+vue.assets/image-20220629224926854.png)]

User

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poIyZxZ4-1656746400683)(springboot+vue.assets/image-20220629224809495.png)]

导入

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9OIlTtXB-1656746400684)(springboot+vue.assets/image-20220629224837014.png)]

7、springboot和Vue实现用户登录

登录页面

其他

div标签

1、div有什么作用

div在html中有着分割的作用,分割与其他样式的作用,去设置页面的布局和样式,主要的作用就是包含一个区块,区块夹在div中,和前后代码隔开,形成一个区块。

2、div用法

是一个块级元素。这意味着它的内容自动地开始一个新行。实际上,换行是固有的特定的格式表现。可以通过的 class style id 应用额外的样式。

java的泛型

1、泛型本质

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,即给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时决定了。这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

//Integer本质:参数数化类型
ArrayList<Integer> intValues = new ArrayList<Integer>()

2、优点:

Java语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了很大的改动,许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:

1、类型安全

在没有泛型之前,从集合中读取到的每一个对象都必须进行类型转换,如果不小心插入了错误的类型对象,在运行时的转换处理就会出错。

//比如:没有泛型的情况下使用集合:
public static void noGeneric() {
ArrayList names = new ArrayList();
names.add("mikechen的互联网架构");
names.add(123); //编译正常
}

//有泛型的情况下使用集合:
public static void useGeneric() {
ArrayList<String> names = new ArrayList<>();
names.add("mikechen的互联网架构");
names.add(123); //编译不通过
}

//有了泛型后,定义好的集合names在编译的时候add(123)就会编译不通过。
//相当于告诉编译器每个集合接收的对象类型是什么,编译器在编译期就会做类型检查,告知是否插入了错误类型的对象,使得程序更加安全,增强了程序的健壮性
2、消除强制类型转换

泛型的一个附带好处是,消除源代码中的许多强制类型转换,这使得代码更加可读,并且减少了出错机会。

//没有泛型的代码段需要强制转换:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);

//当重写为使用泛型时,代码不需要强制转换:
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
3、更高的运行效率

在非泛型编程中,将筒单类型作为Object传递时会引起Boxing(装箱)和Unboxing(拆箱)操作,这两个过程都是具有很大开销的。引入泛型后,就不必进行Boxing和Unboxing操作了,所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。

泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱、拆箱操作

//未使用泛型
object a=1;//由于是object类型,会自动进行装箱操作。
int b=(int)a;//强制转换,拆箱操作。这样一去一来,当次数多了以后会影响程序的运行效率。

//使用泛型之后
    public static T GetValue<T>(T a){ 
        return a; 
    }
    public static void Main(){ 
        int b=GetValue<int>(1);//使用这个方法的时候已经指定了类型是int,所以不会有装箱和拆箱的操作。
    }
4、潜在的性能收益

3、如何使用泛型

泛型有三种使用方式,分别为:泛型类、泛型接口和泛型方法。

1、泛型类
public class 类名 <泛型类型1,...> {
    
}

注意事项:泛型类型必须是引用类型(非基本数据类型)

定义泛型类,在类名后添加一对尖括号,并在尖括号中填写类型参数,参数可以有多个,多个参数使用逗号分隔:

public class GenericClass<ab,a,c> {}

当然,这个后面的参数类型也是有规范的,不能像上面一样随意,通常类型参数我们都使用大写的单个字母表示:

T:任意类型 type
E:集合中元素的类型 element
K:key-value形式 key
V: key-value形式 value

示例代码:

public class GenericClass<T> {
    private T value;
 
 
    public GenericClass(T value) {
        this.value = value;
    }
    public T getValue() {
        return value;
    }
    public void setValue(T value) {
        this.value = value;
    }
}
2、泛型接口
//格式
public interface interfaceName<T>

注意:

方法声明中定义的形参只能在该方法里使用,而接口、类声明中定义的类型形参则可以在整个接口、类中使用。当调用fun()方法时,根据传入的实际对象,编译器就会判断出类型形参T所代表的实际类型。

public interface GenericInterface<T> {
void show(T value);}
}
public class StringShowImpl implements GenericInterface<String> {
@Override
public void show(String value) {
System.out.println(value);
}}
 
public class NumberShowImpl implements GenericInterface<Integer> {
@Override
public void show(Integer value) {
System.out.println(value);
}}

注意:

//使用泛型的时候,前后定义的泛型类型必须保持一致,否则会出现编译异常:
GenericInterface<String> genericInterface = new NumberShowImpl();//编译异常
//或者干脆不指定类型,那么 new 什么类型都是可以的:
GenericInterface g1 = new NumberShowImpl();
GenericInterface g2 = new StringShowImpl();
3、泛型方法

泛型方法,是在调用方法的时候指明泛型的具体类型 。

//格式
public <T>T method Tt

示例

/**
     *
     * @param t 传入泛型的参数
     * @param <T> 泛型的类型
     * @return T 返回值为T类型
     * 说明:
     *   1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
     *   2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
     *   3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
     *   4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E等形式的参数常用于表示泛型。
     */
    public <T> T genercMethod(T t){
        System.out.println(t.getClass());
        System.out.println(t);
        return t;
    }
 
 
public static void main(String[] args) {
    GenericsClassDemo<String> genericString  = new GenericsClassDemo("helloGeneric"); //这里的泛型跟下面调用的泛型方法可以不一样。
    String str = genericString.genercMethod("hello");//传入的是String类型,返回的也是String类型
    Integer i = genericString.genercMethod(123);//传入的是Integer类型,返回的也是Integer类型
}
 
//打印结果
//class java.lang.String
//hello
 
//class java.lang.Integer
//123

数据库三大范式是什么?

第一范式:每个列都不可以在拆分。
第二范式:在第一范式的基础上,非主键列完全依赖于逐渐,而不能是依赖于主键的一部分。
第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。
在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。

mybatis xml格式

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--从mybatis中文网——入门取来后,需要修改namespace-->
<mapper namespace="com.yebinhuang.mapper.UserMapper">
    
</mapper>

@JsonIgnore

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

前端与后端做数据绑定

后端提供一个接口:http://localhost:9090/user/page?pageNum=1&pageSize=2"

数据类型如下:

{
    "total": 8,
    "data": [
        {
            "id": 1,
            "username": "admin",
            "nickname": "管理员",
            "email": "hyblist@163.com",
            "phone": "17324070785",
            "address": "广东茂名"
        },
        {
            "id": 2,
            "username": "xiaoming",
            "nickname": "小明",
            "email": "xiaoming@163.com",
            "phone": "10086",
            "address": "小明的家"
        }
    ]
}

前端操作

<template>
</div>
<!--表格设置边框border stripe有线-->
<!--:header-cell-class-name="headerBg"和下面的<script><script>有联系-->
<!-- :data="tableData" 与下面的<script>中的created()做数据绑定-->
<el-table :data="tableData" border stripe :header-cell-class-name="headerBg">
  <el-table-column prop="id" label="id" width="50"></el-table-column>
  <el-table-column prop="username" label="用户名" ></el-table-column>
  <el-table-column prop="nickname" label="昵称"   ></el-table-column>
  <el-table-column prop="phone" label="电话"  ></el-table-column>
  <el-table-column prop="email" label="邮箱"   ></el-table-column>
  <el-table-column prop="address" label="地址"></el-table-column>
  <!--添加编辑操作-->
  <el-table-column label="操作" width="150" >
    <template slot-scope="scope" >
      <el-button >编辑</el-button>
      <el-button type="danger">删除</el-button>
    </template>
  </el-table-column>
</el-table>
<!--分页:style="padding: 20px(高度) 10px(margin-left[默认隐藏]:10px)[左距离] 设置位置-->
<div style="padding: 20px 10px">
    
</template>    
 
<script>

export default {    
  created(){
    //请求分页查询数据
    //注意:res.json()和res.join()
    fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res =>res.json()).then(res =>{
      console.log(res)
      //绑定接口的数据
      this.tableData = res.data
      this.total = res.total
    })
  }
    
</script>    

复制地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9HWlzC9S-1656746400685)(springboot+vue.assets/image-20220627221548676.png)]

前端一些功能实现

1、按钮弹窗(Dialog 对话框)

关键:visible.sync=""控制弹窗是否显示,官方采用dialogFormVisible控制

<div>
          <!--visible.sync=""控制弹窗是否显示,官方采用dialogFormVisible控制-->
          <el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
            <el-form label-width="80px">
              <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.phone" 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.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="saveUser">确 定</el-button>
            </div>
          </el-dialog>
        </div>

2、二次确认弹窗(Popconfirm 气泡确认框)

<template slot-scope="scope">
<el-button @click="handleEdit(scope.row)">编辑</el-button>
<!--Popconfirm 气泡确认框-->
<el-popconfirm
               class="ml-10"
               title="你要删除吗?"
               @confirm="delone(scope.row.id)"
               >
    <el-button type="danger" slot="reference" class="ml-5">删除</el-button><!--slot="reference"使按钮显示-->
    </el-popconfirm>
</template>

3、新增(绑定按钮弹窗)

新增按钮绑定handleAdd()方法

<div style=" position: relative; top:-6px ">
    <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-circle-close"></i></el-button>
    <el-button type="primary">导入 <i class="el-icon-top"></i></el-button>
    <el-button type="primary">导出 <i class="el-icon-bottom"></i></el-button>
</div>

handleAdd()方法

    //添加用户确认
    handleAdd() {
      this.dialogFormVisible = true
      this.form = {}
    },

弹窗的确认按钮绑定@click="saveUser"完成接口请求

//添加用户
    saveUser() {
      request.post("/user/", this.form).then(res => {
        if (res) {
          this.$message.success("新增成功")
          this.load()
        } else {
          this.$message.error("新增失败")
        }
      });
      this.dialogFormVisible = false
    },

4、列表编辑(调用)

列表取row中数据:row打印出来是一个对象

<el-table-column label="操作" width="150">
  <template slot-scope="scope">
    <el-button @click="handleEdit(scope.row)">编辑</el-button>
  </template>
</el-table-column>

绑定了@click="handleEdit(scope.row)"方法

    //编辑用户
    handleEdit(row) {
      console.log(row)
      this.form = row
      this.dialogFormVisible = true //使新增的弹窗打开,数据是取编辑的
    },

5、删除(调用二次弹窗的方法/或者不调用,如过不调用可以直接用@click=“delone(scope.row.id)”)

@confirm=“delone(scope.row.id)”

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

6、批量删除

在data()里面添加字段

multipleSelection: []

使<el-table></el-table>绑定@selection-change="handleSelectionChange"这个方法

<el-table :data="tableData" border stripe :header-cell-class-name="headerBg"
                  @selection-change="handleSelectionChange">
          <el-table-column type="selection" width="55"></el-table-column>

handleSelectionChange()

,
    //批量删除
    handleSelectionChange(val) {
      console.log(val)
      this.multipleSelection = val
    }

批量删除按钮绑定@click="delBatch"方法

<div style=" position: relative; top:-6px ">
    <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-circle-close"></i></el-button>
    <el-button type="primary">导入 <i class="el-icon-top"></i></el-button>
    <el-button type="primary">导出 <i class="el-icon-bottom"></i></el-button>
</div>

@click="delBatch"方法

    //批量删除按钮
    delBatch() {
      let ids = this.multipleSelection.map(v =>v.id) //[{},{},{}]=>[1,2,3]对象转换成数组
      console.log(ids)
      request.post("/user/del/batch", ids).then(res => {   //这里的","很关键,不能写成"+",会很刺激
        if (res) {
          this.$message.success("批量删除成功")
          this.load()
        } else {
          this.$message.error("批量删除失败")
        }
        console.log(res)
      });

全选(Table 表格)

<el-table-column type="selection" width="55"></el-table-column>

Exception

1、Invalid bound statement (not found): com.yebin.springboot.mapper.UserMapper.update

原因:没有配置mybatis的配置

#指定Mybatis的Mapper文件
mybatis:
  mapper-locations: classpath:mapper/*xml

2、org.apache.ibatis.binding.BindingException: Parameter ‘pageNum’ not found. A

原因:@Param(“pageNum”)没有加@Param接收pageNum

    @Select("select * from sys_user limit #{pageNum},#{pageSize}")
    //泛型方法
    List<User> selectPage(@Param("pageNum")Integer pageNum,@Param("pageSize")Integer pageSize);

3、前端跨域问题

Access to fetch at ‘http://localhost:9090/user/page?pageNum=1&pageSize=2’ from origin ‘http://localhost: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.

后端做调整:springboot跨域设置

package com.yebin.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);
    }
}

4、The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

原因:mysql服务没有启动

5、mybatis和mybatis-plus只能存在一个

mybatis和mybatis-plus只能存在一个,要不然会打架,所以导入依赖只能存在其中一个

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志
    true map-underscore-to-camel-case: true

6、 Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

原因缺少一个<div></div>

7、Uncaught TypeError: (0 , vue__WEBPACK_IMPORTED_MODULE_2__.reactive) is not a function

原因vuex版本太高

npm i vuex@3.6.2 -s

    if (res) {
      this.$message.success("批量删除成功")
      this.load()
    } else {
      this.$message.error("批量删除失败")
    }
    console.log(res)
  });

全选(Table 表格)

```vue
<el-table-column type="selection" width="55"></el-table-column>

Exception

1、Invalid bound statement (not found): com.yebin.springboot.mapper.UserMapper.update

原因:没有配置mybatis的配置

#指定Mybatis的Mapper文件
mybatis:
  mapper-locations: classpath:mapper/*xml

2、org.apache.ibatis.binding.BindingException: Parameter ‘pageNum’ not found. A

原因:@Param(“pageNum”)没有加@Param接收pageNum

    @Select("select * from sys_user limit #{pageNum},#{pageSize}")
    //泛型方法
    List<User> selectPage(@Param("pageNum")Integer pageNum,@Param("pageSize")Integer pageSize);

3、前端跨域问题

Access to fetch at ‘http://localhost:9090/user/page?pageNum=1&pageSize=2’ from origin ‘http://localhost: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.

后端做调整:springboot跨域设置

package com.yebin.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);
    }
}

4、The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

原因:mysql服务没有启动

5、mybatis和mybatis-plus只能存在一个

mybatis和mybatis-plus只能存在一个,要不然会打架,所以导入依赖只能存在其中一个

mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志
    true map-underscore-to-camel-case: true

6、 Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

原因缺少一个<div></div>

7、Uncaught TypeError: (0 , vue__WEBPACK_IMPORTED_MODULE_2__.reactive) is not a function

原因vuex版本太高

npm i vuex@3.6.2 -s

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 22:45:33  更:2022-07-04 22:47:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 11:03:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码