0


springboot+vue

视频链接
代码链接

一、前端环境搭建

1.创建一个文件夹,在文件加内输入cmd打开命令行窗口,然后检查node.js和npm的版本用命令:

node -v 
npm -v

2.全局安装一个vue cli插件用命令

npm install -g  @vue/cli

3.然后创建一个名字为springboot-vue-demo的项目
(在创建过程中遇到一个代理相关的问题,最后通过更换镜像源,切换代理最终解决问题)

vue create springboot-vue-demo

二、在idea中启动

1.把创建好的项目拖进idea中,设置启动自动跳转页面在如下位置

在这里插入图片描述
然后出现以下问题:
网址为http://0.0.0.0:8080/ 的页面可能存在问题,或者已永久移动到新的网址
通过在编辑里边全局查找0.0.0.0 然后修改为localhost,最后成功在idea里边启动,如下图;
在这里插入图片描述

三、前端布局以及页面的制作

1.删除不要的组件

1.删除掉多余的Helloworld组件,以及相关的配置,然后自己创建一个Header(头部)组件,然后在HomeView.vue中引入Header组件,代码如下;

<template>
<!--  引入Header组件-->
<div> <Header/> </div>
  <router-view/>
</template>

<style>

</style>

<!--导入Header组件-->
<script >

import Header from "@/components/Header";

export default{
  name:"Layout",
  components:{
    //光标对着Header然后alt+enter,进行引入
    Header
  }
}
</script>

在Header.vue中创建一个大盒子然后再在其中创建三个小盒子的代码如下;

<template >
  <div style="height:50px; line-height:50px; border-bottom: 1px solid #ccc; display: flex">
    <div style="width: 200px">后台管理</div>
    <div style="flex:1">时间</div>
    <div style="width: 100px">下拉框</div>
  </div>

</template>

<script>
export default {
  name: "Header"
}
</script>

<style scoped>

</style>

2.设置全局样式

2.再创建一个全局的css样式管理命名为global.css,代码如下

/*设置全局样式*/
*{
    margin: 0;
    padding: 0;
    box-sizing:border-box ;
}

运行之后结果图为
在这里插入图片描述
3.在main.js中引入elementPlus组件
以下实在elementplus中的源码

// main.ts
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

需要引入的内容(蓝色部分和我标红的)
在这里插入图片描述

3.引入elementplus组件

1.引入下拉框

把文字部分改为自己需要的

<el-dropdown>
    <span class="el-dropdown-link" style="padding:  18px">
      用户
      <el-icon class="el-icon--right">
        <arrow-down />
      </el-icon>
    </span>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>退出系统</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>

2.引入侧边栏

1.再定义一个vue组件Aside.vue,然后再App.vue中引入Aside.vue组件
App.vue中的代码为:

<template>
<!--  引入Header组件-->
<div>
<!--  头部-->
  <Header/>
<!--  主体 侧边栏再定义一个div flex布局-->
  <div style="display: flex">
<!--    侧边栏-->
    <Aside/>
<!--    内容区域-->
    <router-view style="flex: 1"/>
  </div>
</div>
</template>

<style>

</style>

<!--导入Header组件-->
<script >

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

export default{
  name:"Layout",
  components:{
    //光标对着Header然后alt+enter,进行引入
    Header,
    //引入侧边栏vue组件
    Aside
  }
}
</script>

2.然后引入侧边栏导航,为App.vue设置样式

<template>
<div>
  <el-menu
      default-active="2"
      class="el-menu-vertical-demo"
      style="width: 200px; min-height: calc(100vh - 50px)"
  >
    <el-sub-menu index="1">
      <template #title>
        <el-icon><location /></el-icon>
        <span>导航一</span>
      </template>
        <el-menu-item index="1-3">选项一</el-menu-item>
        <el-menu-item index="1-3">选项二</el-menu-item>
        <el-menu-item index="1-3">选项三</el-menu-item>
    </el-sub-menu>
    <el-sub-menu index="2">
      <template #title>
        <el-icon><location /></el-icon>
        <span>导航二</span>
      </template>
      <el-menu-item index="2-3">选项一</el-menu-item>
      <el-menu-item index="2-3">选项二</el-menu-item>
      <el-menu-item index="2-3">选项三</el-menu-item>
    </el-sub-menu>
    <el-sub-menu index="3">
      <template #title>
        <el-icon><location /></el-icon>
        <span>导航三</span>
      </template>
      <el-menu-item index="3-3">选项一</el-menu-item>
      <el-menu-item index="3-3">选项二</el-menu-item>
      <el-menu-item index="3-3">选项三</el-menu-item>
    </el-sub-menu>
  </el-menu>
</div>
</template>

<script>
export default {
  name: "Aside"
}
</script>

<style scoped>

</style>

宽度长度
在这里插入图片描述

3.引入主体表格等内容

在Home.vue主体组件中引入主体table以及新增、导入、导出、搜索等按钮
基本都是从elementplus上边复制过来的,只是做了一些加外边距、改点样式的工作

<template>
  <div style="padding: 10px">
<!--    功能区-->
    <div style="margin: 10px 0">
      <el-button type="primary">新增</el-button>
      <el-button type="primary">导入</el-button>
      <el-button type="primary">导出</el-button>
    </div>
<!--    搜索区-->
    <div style="margin:10px 0">
      <el-input v-model="search" placeholder="请输入..." style="width: 20%"/>
      <el-button type="primary" style="margin-left: 5px">查询</el-button>
    </div>
<!--    表格-->
    <el-table :data="tableData"
              border
              stripe
              style="width: 100%">
<!--      sortable是为时间加上排序-->
      <el-table-column prop="date" label="日期" sortable/>
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="address" label="地址" />
      <el-table-column fixed="right" label="操作" width="120">
<!--        操作部分的按钮-->
        <template #default>
          <el-button link type="primary"  @click="handleEdit"
          >编辑</el-button>
          <el-popconfirm title="确认删除吗?">
            <template #reference>
              <el-button type="text">删除</el-button>
            </template>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
<!--    分页组件-->
    <div style="margin: 10px 0">
      <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="[5, 10, 20]"
          :small="small"
          :disabled="disabled"
          :background="background"
          layout="total, sizes, prev, pager, next, jumper"
          :total="10"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: 'HomeView',
  components: {
  },

  //先为表格填入假数据
  data(){
    return{
      search:'',
      pageSize:10,
      currentPage:1,
      tableData:[{
        date: '2016-05-03',
        name: 'Tom',
        address: 'No. 189, Grove St, Los Angeles',
      },
        {
          date: '2016-05-02',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
        },
        {
          date: '2016-05-04',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
        },
        {
          date: '2016-05-01',
          name: 'Tom',
          address: 'No. 189, Grove St, Los Angeles',
        },]
    }
  },
  methods:{
    handleEdit(){

    },
    handleSizeChange(){

    },
    handleCurrentChange(){}
  },

}
</script>

做完以上工作得到如下界面:

在这里插入图片描述
问题:放大缩小界面后下边会有一个不能自适应屏幕大小的问题
在这里插入图片描述
以上问题解决方案:

<template #default="scope">
          <el-button link type="primary" size="mini"  @click="handleEdit(scope.$index,scope.row)"
          >编辑</el-button>
          <el-popconfirm title="确认删除吗?">
            <template #reference>
              <el-button size="mini" type="danger" @click="handleDelete(scope.$index,scope.row)">删除</el-button>
            </template>
          </el-popconfirm>
        </template>

4.细节完善

按钮太大看着别扭,设置小号,可以让它看起来更舒服
如下如所示;
在这里插入图片描述

5.加新增弹出框

点击新增的时候弹出添加数据的显示框,用户可以在其中输入数据,需要为新增按钮绑定一个方法:

在这里插入图片描述

方法区:

methods:{
    add(){
      //表单其实一直都在,只是把它设置成为不可见得了
      this.dialogVisible=true
    //  新增的时候一定要清空一下表单域,不会影响下一次操作
      this.form={}
    },
    handleEdit(){

    },
    handleSizeChange(){

    },
    handleCurrentChange(){}
  }

再添加elementPlus组件(对话框设置了一个dialogVisible的模型,在数据区设置为默认不可见,在add方法内写入逻辑,当点击确认按钮触发add方法后,对话框就显示出来了):

<!--    弹出对话框  -->
      <el-dialog
          v-model="dialogVisible"
          title="提示"
          width="30%">
<!--     表单组件   -->
        <el-form :model="form" label-width="120px">
          <el-form-item label="用户名">
            <el-input v-model="form.username" style="width:80%"/>
          </el-form-item>
          <el-form-item label="昵称">
            <el-input v-model="form.nickName" style="width:80%"/>
          </el-form-item>
          <el-form-item label="性别">
              <el-radio v-model="form.sex" label="1" size="large">男</el-radio>
              <el-radio v-model="form.sex" label="2" size="large">女</el-radio>
          </el-form-item>
          <el-form-item label="年龄">
            <el-input v-model="form.age" style="width:80%"/>
          </el-form-item>
          <el-form-item label="地址">
            <el-input v-model="form.address"  style="width:80%"/>
          </el-form-item>
          </el-form>

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

      </el-dialog>

四、后端架子以及新增功能

1.创建一个springboot工程

很简单直接在idea里边创建,记得要添加web、mybatis、mysql、lombok(用来简化开发,少写一些东西)

2.配置application.properties文件

1.这是用properties写的比较老的东西了

server.port=9090
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username= root
spring.datasource.password= root

2.pom文件引入mybatisPlus依赖,目的是为了能够使用mybatisPlus提供的分页插件

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

3.引入一些通用类

通用返回类

package com.example.common;

public class Result<T> {
    private String code;
    private String msg;
    private T data;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public Result() {
    }

    public Result(T data) {
        this.data = data;
    }

    public static Result success() {
        Result result = new Result<>();
        result.setCode("0");
        result.setMsg("成功");
        return result;
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>(data);
        result.setCode("0");
        result.setMsg("成功");
        return result;
    }

    public static Result error(String code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }
}

分页插件

package com.example.common;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

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

}

实体类:

package com.example.entity;

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

//引入lombok之后,用这个注解可以将这个实体类和数据库名字为user1的表关联起来
@TableName("user1")
//使用这个注解可以不用写get set方法
@Data
public class User {
//    设置主键自增,下边的id其实可以不用写,如果主键名字不是id的话,就需要写value ="id"
    @TableId(value ="id",  type = IdType.AUTO)
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String sex;
    private String address;

}

4.写接口

因为这个项目比较简单,所以就没有写service层,只写了mapper和controller
mapper层:

package com.example.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

controller层:

package com.example.controller;

import com.example.common.Result;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
    @Resource
    UserMapper userMapper;
//    @RequestBody 的作用就是从前台拿过来的数据把它给封装成User实体类型的数据
    @PostMapping
    public Result<?> save(@RequestBody User user){
            userMapper.insert(user);
            return Result.success();
    }
}

5.实现前后端交互

在新增表单输入数据,点击确认后前端发送axios请求(要引入一个js文件),写上请求路径(这里涉及一个跨域限制的问题针对本项目实际就是前端的8080端口不能访问后端的9090端口,可以在查到跨域问题的解决方案,就是在前端文件夹里引入一个vue.config.js文件),能够在后端数据库中看到新增的数据
如图;

1.引入axios相关的配置文件
在这里插入图片描述
代码:

import axios from 'axios'
import router from "@/router";
const request = axios.create({
    baseURL: "/api",
    timeout: 5000
})

// 请求白名单,如果请求在白名单里面,将不会被拦截校验权限
const whiteUrls = ["/user/login", '/user/register']

// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';

    // 取出sessionStorage里面缓存的用户信息
    let userJson = sessionStorage.getItem("user")
    if (!whiteUrls.includes(config.url)) {  // 校验请求白名单
        if(!userJson) {
            router.push("/login")
        } else {
            let user = JSON.parse(userJson);
            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
        }
        // 验证token
        if (res.code === '401') {
            console.error("token过期,重新登录")
            router.push("/login")
        }
        return res;
    },
    error => {
        console.log('err' + error) // for debug
        return Promise.reject(error)
    }
)

export default request

2.设置访问的请求路径

确认按钮添加上save方法
在这里插入图片描述
在save方法内设置请求路径
在这里插入图片描述

3.涉及一个跨域限制的问题针对本项目实际就是前端的8080端口不能访问后端的9090端口,可以在查到跨域问题的解决方案,就是在前端文件夹里引入一个vue.config.js文件(注意要在前端的工程的那个文件夹下)

在这里插入图片描述
代码:

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

6.测试是否能从前端接收到数据

在UserController里边打一个断点,用debug模式启动
在这里插入图片描述
在输入框输入数据

此时idea响应并且成功接收到数据
在这里插入图片描述
放开断点,让程序启动
在这里插入图片描述
在数据库看到新添加的数据
在这里插入图片描述

7.至此完成自己第一个前后台交互的功能

以前自己也偷偷学过相关的内容,但是一遇到一点问题自己就坚持不下去,然后就放弃了,这一次真的不错,虽然还是遇到许多问题,但是都通过自己的努力都得到了解决,感谢自己一点一滴的坚持,加油!
对每一位正在学习的朋友们说一句,问题肯定会有的,但是只要你肯坚持,那么就一定可以战胜,最难不过坚持!

五、将数据在页面显示

前端

分页组件:

<!--    分页组件--><div style="margin: 10px 0"><el-pagination
          @size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[5, 10, 20]":page-size="pageSize":small="small":disabled="disabled":background="background"
          layout="total, sizes, prev, pager, next, jumper":total="total"/>

后端

hutool的工具类:官网上搜索,然后引入依赖,可以用来判断某个字段是否为空

//    TODO 差点死在这,草 要长记性呀,对于这种查询某个字段一定要看他是不是为空,要对他进行一个判断,不然会出问题的if(StrUtil.isNotBlank(search)){
            queryWrapper.like(User::getNickName,search);}Page<User>  userPage= userMapper.selectPage(newPage<>(pageNum,pageSize),queryWrapper);returnResult.success(userPage);

分页插件:

packagecom.example.common;importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;/**
 *  mybatis-plus 分页插件
 */@Configuration@MapperScan("com.example.mapper")publicclassMybatisPlusConfig{/**
     * 分页插件
     */@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptor interceptor =newMybatisPlusInterceptor();
        interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}

注意:对某一个字段进行查询的时候一定要判断它是否为空,不然可能查不出来

/**
     * 查询的方法
     * @param pageNum
     * @param pageSize
     * @param search
     * @return
     */@GetMapping//    defaultValue就是设置默认访问值,publicResult<?>findPage(@RequestParam(defaultValue ="1")Integer pageNum,@RequestParam(defaultValue ="5")Integer pageSize,@RequestParam(defaultValue ="")String search){LambdaQueryWrapper<User> queryWrapper=newLambdaQueryWrapper<>();//    TODO 差点死在这,草 要长记性呀,对于这种查询某个字段一定要看他是不是为空,要对他进行一个判断,不然会出问题的if(StrUtil.isNotBlank(search)){
            queryWrapper.like(User::getNickName,search);}Page<User>  userPage= userMapper.selectPage(newPage<>(pageNum,pageSize),queryWrapper);returnResult.success(userPage);}

六、查询功能

前端

查询按钮处:

<!--    搜索区--><div style="margin:10px 0"><el-input v-model="search" placeholder="请输入..." style="width: 20%"  clearable ></el-input><el-button type="primary" style="margin-left: 5px"@click="load">查询</el-button></div>

对应的方法:

// 加载的方法,在加载的时候调用created(){this.load()},
  methods:{load(){
      request.get("/user",{params:{
          pageNum:this.currentPage,
          pageSize:this.pageSize,
          search:this.search,}}).then(res=>{
        console.log(res)this.tableData = res.data.records
        this.total=res.data.total
      })}

后端

七、编辑功能

前端

点击编辑的时候弹出一个可以编辑的对话框(和新增时候弹出来的是一个,不同的是它会有数据的回显)
在这里插入图片描述
代码:

<!--      操作框-->
      <el-table-column fixed="right" label="操作" >
        <template #default="scope">
          <el-popconfirm title="确认删除吗?">
            <template #reference>
              <el-button size="small" type="danger" @click="handleDelete(scope.$index,scope.row)">删除</el-button>
            </template>
          </el-popconfirm>

          <el-button link type="primary" size="small"   @click="handleEdit(scope.row)">编辑</el-button>
        </template>
      </el-table-column>

方法内:

 handleEdit(row){
      //弹出编辑框,和新增框一样的请求路径,深克隆
      this.form=JSON.parse(JSON.stringify(row))
      //弹出对话框
      this.dialogVisible=true
    },

在前端页面点击编辑按钮,弹出对话框,编辑后点击确认按钮,执行save方法
在这里插入图片描述
save方法内需要判断执行的是新增还是编辑,通过id是否为空进行判断

// 点击确认按钮后触发的添加保存方法save(){if(this.form.id){//更新
        request.put("/user",this.form).then(res =>{
          console.log(res)if(res.code ==='0'){this.$message({
              type:"success",
              message:"更新成功"})}else{this.message({
              type:"error",
              message:res.msg
            })}this.load()//刷新表格数据//  关闭弹窗this.dialogVisible=false})}else{//新增
        request.post("/user",this.form).then(res =>{
          console.log(res)if(res.code ==='0'){this.$message({
              type:"success",
              message:"新增成功"})}else{this.message({
              type:"error",
              message:res.msg
            })}})}}

后端

在UserController中,新增一个方法

/**
 * 实现user对象的更新,修改功能
 * @param user
 * @return
 */@PutMappingpublicResult<?>update(@RequestBodyUser user){
    userMapper.updateById(user);returnResult.success();}

过程中遇到的一个bug:在这里插入图片描述
解决方案
自己重新把那里的代码敲了一遍,觉得最有可能的原因就是当初选择类型的时候form没有选正确,导致的错误,唉服了,在这里插入图片描述
生气!
在这里插入图片描述

八、分页功能

前端

<!--    分页组件--><div style="margin: 10px 0"><el-pagination
          @size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[5, 10, 20]":page-size="pageSize":small="small":disabled="disabled":background="background"
          layout="total, sizes, prev, pager, next, jumper":total="total"/>

对方法的实现

//改变每页的条数handleSizeChange(pageSize){this.pageSize=pageSize
        this.load()},//改变当前页handleCurrentChange(pageNum){this.currentPage=pageNum
      this.load()}

后端

后端内容没有添加

遇到的bug

无论怎么切换每页的条数,下方控制台给出的响应都是pageNum=1&pageSize=10,故问题出在这里
在这里插入图片描述
查看elementPlus分页组件的使用方法后发现需要给分页对应的方法传递参数

在这里插入图片描述
运行效果图:
在这里插入图片描述

九、删除功能

需要注意的就是在后端controller中它的路径,如下图所示,因为它前端的
在这里插入图片描述

如果不写id
在这里插入图片描述

在这里插入图片描述
那么就会报如下错误
在这里插入图片描述

前端

注意 request.delete(“/user/”+ id ) 这个里边的路径写法和连接方式

handleDelete(id){
      console.log(id)//删除 + id
      request.delete("/user/"+ id ).then(res =>{if(res.code ==='0'){this.$message({
            type:"success",
            message:"删除成功"})}else{this.message({
            type:"error",
            message:res.msg
          })}this.load()//重新加载})},

后端

/**
     * 删除
     * @param id
     * @return
     */@DeleteMapping("/{id}")publicResult<?>delete(@PathVariableLong id){
        userMapper.deleteById(id);returnResult.success();}

运行结果图

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

十、路由设置

原理

在router文件夹下的index.js文件中也把App.vue设置为根路由,因为布局相关的代码都在里边,所以以后访问登录页面的时候也会有布局信息出来,如下图
在这里插入图片描述

把App.vue中的布局代码拷贝到一个心新的vue中命名为Layout.vue

<template><div><!--  头部--><Header/><!--  主体 侧边栏再定义一个div flex布局--><div style="display: flex"><!--    侧边栏--><Aside/><!--    内容区域--><router-view style="flex: 1"/></div></div></template><script>importHeader from "@/components/Header";importAside from "@/components/Aside";

export default{
  name:"Layout",
  components:{//光标对着Header然后alt+enter,进行引入Header,//引入侧边栏vue组件Aside}}</script><style scoped></style>

解决方案:

在router文件夹下的index.js文件中的路由改成Layout
在这里插入图片描述

再次输入http://lcoalhost:9876/home时会有如下界面
在这里插入图片描述

登录功能

前端

在创建一个login.vue,里边写登录页面

<template><!--100vh表示高度整个屏幕 overflow:hidden表示隐藏空白处--><div style="width: 100%; height:100vh; background-color: darkslateblue; overflow:hidden "><div style="width: 400px; margin: 150px auto"><div style="color: #cccccc; text-align: center; font-size:30px; padding: 30px 0">欢迎登陆</div><!--    对应的数据变量如果没有变紫色,表示没有用成功--><el-form  ref="form":model="form" size="normal":rules="rules"><el-form-item prop="username"><el-input   v-model="form.username"></el-input></el-form-item><el-form-item prop="password"><el-input  v-model="form.password"  show-password></el-input></el-form-item><el-form-item><el-button style="width: 100% " type="primary"@click="login">登录</el-button></el-form-item></el-form></div></div></template><script>importrequest from "@/utils/request";

export default{
  name:"Login",data(){return{
       form:{},
       rules:{
         username:[{required:true, message:'请输入用户名', trigger:'blur'},],
         password:[{required:true, message:'请输入密码', trigger:'blur'},]},}},
  methods:{//登录login(){//表单验证内容,满足一下验证需求,他才会执行下面的请求this.$refs['form'].validate((valid)=>{if(valid){
          request.post("/user/login",this.form).then(res =>{if(res.code ==='0'){this.$message({
                type:"success",
                message:"登陆成功"})//  登陆成功后页面跳转this.$router.push("/")}else{this.$message({
                type:"error",
                message:res.msg
              })}})}})},},}</script><style scoped></style>

在登录方法里把请求路径写好

在这里插入图片描述
在前端router文件夹里边找到index.js这个文件,设置路由

import{ createRouter, createWebHistory } from 'vue-router'
importLayout from '../layout/Layout.vue'

const routes =[{
    path:'/',
    name:'Layout',
    component:Layout,//输入/的时候页面会自动跳转到/home页面
    redirect:"/home",
    children:[{
        path:'home',
        name:'Home',
        component:()=>import("@/views/HomeView"),}]},{//写登录页面路由
    path:'/login',
    name:'Login',//导入Login页面
    component:()=>import("@/views/Login")},//    写注册页面路由{
    path:'/register',
    name:'Register',
    component:()=>import("@/views/register")}]const router =createRouter({
  history:createWebHistory(process.env.BASE_URL),
  routes
})
export default router

后端

在controller中写的PostMapping

@PostMapping("/login")publicResult<?>login(@RequestBodyUser user){//        查询用户名,密码是否存在User res= userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPassword,user.getPassword()));if(res ==null){returnResult.error("-1","用户名密码错误");}returnResult.success();}

注册功能

前端

<template><!--100vh表示高度整个屏幕 overflow:hidden表示隐藏空白处--><div style="width: 100%; height:100vh; background-color: darkslateblue; overflow:hidden "><div style="width: 400px; margin: 150px auto"><div style="color: #cccccc; text-align: center; font-size:30px; padding: 30px 0">欢迎注册</div><!--    对应的数据变量如果没有变紫色,表示没有用成功--><el-form  ref="form":model="form" size="normal":rules="rules"><el-form-item prop="username"><el-input   v-model="form.username"></el-input></el-form-item><el-form-item prop="password"><el-input  v-model="form.password"  show-password></el-input></el-form-item><!--      确认密码--><el-form-item  prop="confirm"><el-input  v-model="form.confirm"  show-password></el-input></el-form-item><el-form-item><el-button style="width: 100% " type="primary"@click="register">注册</el-button></el-form-item></el-form></div></div></template><script>importrequest from "@/utils/request";

export default{
  name:"register",data(){return{
       form:{},
       rules:{
         username:[{required:true, message:'请输入用户名', trigger:'blur'},],
         password:[{required:true, message:'请输入密码', trigger:'blur'},],
         confirm:[{required:true, message:'请确认密码', trigger:'blur'},]}}},
  methods:{//表单验证register(){if(this.form.password !=this.form.confirm){this.$message({
          type:"error",
          message:"两次密码输入不一致!"})return}//表单验证this.$refs[form].validate((valid)=>{if(valid){
          request.post("/user/register",this.form).then(res =>{if(res.code ==='0'){this.$message({
                type:"success",
                message:"注册成功"})//  成功后页面跳转this.$router.push("/login")}else{this.$message({
                type:"error",
                message:res.msg
              })}})}})},},}</script><style scoped></style>

同登录功能一样,设置路由
在这里插入图片描述

后端

1.查询用户名是否存在
2.如果没有设置密码,默认为******

@PostMapping("/register")publicResult<?>register(@RequestBodyUser user){//        查询用户名,密码是否存在User res= userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()));if(res !=null){returnResult.error("-1","用户名重复");}if(user.getPassword()==null){
            user.setPassword("123456");}
        userMapper.insert(user);returnResult.success();}

表单验证功能

效果图:
在这里插入图片描述
怎样实现:
1.在表单位置引入验证
在这里插入图片描述3.验证表单内容,只有满足这个条件才执行下面的请求路径
在这里插入图片描述

bug:
在这里插入图片描述
解决方案:这种错误一般都是这个单词对应的代码格式写的不正确,导致没有识别出来
在这里插入图片描述

个人信息查看

1.写一个Person.vue

<template><div><el-card style="width: 40%; margin: 10px"><el-form ref="form":model="form" label-width="80px"><el-form-item style="text-align: center" label-width="0"><el-upload
              class="avatar-uploader"
              action="http://localhost:9090/files/upload":show-file-list="false":on-success="handleAvatarSuccess"><img v-if="form.avatar":src="form.avatar"class="avatar"><i v-elseclass="el-icon-plus avatar-uploader-icon"></i></el-upload></el-form-item><el-form-item label="用户名"><el-input v-model="form.username" disabled></el-input></el-form-item><el-form-item label="昵称"><el-input v-model="form.nickName"></el-input></el-form-item><el-form-item label="年龄"><el-input v-model="form.age"></el-input></el-form-item><el-form-item label="性别"><el-input v-model="form.sex"></el-input></el-form-item><el-form-item label="地址"><el-input v-model="form.address"></el-input></el-form-item><!--<el-form-item label="密码">--><!--<el-input v-model="form.password" show-password></el-input>--><!--</el-form-item>--><el-form-item label="余额(¥)"><el-input v-model="form.account" show-password></el-input></el-form-item></el-form><div style="text-align: center"><el-button type="primary"@click="update">保存</el-button></div></el-card></div></template><script>importrequest from "@/utils/request";

export default{
  name:"Person",data(){return{
      form:{}}},created(){
    let str = sessionStorage.getItem("user")||"{}"this.form =JSON.parse(str)},
  methods:{handleAvatarSuccess(res){this.form.avatar = res.data
      this.$message.success("上传成功")// this.update()},update(){
      request.put("/user",this.form).then(res =>{
        console.log(res)if(res.code ==='0'){this.$message({
            type:"success",
            message:"更新成功"})
          sessionStorage.setItem("user",JSON.stringify(this.form))// 触发Layout更新用户信息this.$emit("userInfo")}else{this.$message({
            type:"error",
            message: res.msg
          })}})}}}</script><style>.avatar-uploader .el-upload {
  border:1px dashed #d9d9d9;
  border-radius:6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;}.avatar-uploader .el-upload:hover {
  border-color: #409EFF;}.avatar-uploader-icon {
  font-size:28px;
  color: #8c939d;
  width:120px;
  height:120px;
  line-height:120px;
  text-align: center;}.avatar {
  width:178px;
  height:178px;
  display: block;}</style>

2.然后在Layout路由下设置一个子路由

import{ createRouter, createWebHistory } from 'vue-router'
importLayout from '../layout/Layout.vue'

const routes =[{
    path:'/',
    name:'Layout',
    component:Layout,//输入/的时候页面会自动跳转到/home页面
    redirect:"/home",
    children:[{
        path:'home',
        name:'Home',
        component:()=>import("@/views/HomeView"),},//  个人信息界面{
        path:'person',
        name:'Person',
        component:()=>import("@/views/Person"),}]},{
    path:'/login',
    name:'Login',//导入Login页面
    component:()=>import("@/views/Login")},//    写路由{
    path:'/register',
    name:'Register',
    component:()=>import("@/views/register")}]const router =createRouter({
  history:createWebHistory(process.env.BASE_URL),
  routes
})

export default router

在这里插入图片描述
3.给“个人信息”绑定点击事件,实现跳转

在这里插入图片描述

在这里插入图片描述

鸡肋拦截器

没有写(不会写,哈哈)

页面跳转

点击书籍管理的时候,它会跳转到新的一个功能页
在这里插入图片描述

在侧边栏vue中这样写
在这里插入图片描述
然后添加一个Book.vue(到这里其实就可以直接把User.vue复制过来,然后改一下table和新增表单里边的关键词,还有一些路径)

<template><div style="padding: 10px"><!--    功能区--><div style="margin: 10px 0"><el-button type="primary"@click="add">新增</el-button><el-button type="primary">导入</el-button><el-button type="primary">导出</el-button></div><!--    搜索区--><div style="margin:10px 0"><el-input v-model="search" placeholder="请输入..." style="width: 20%"  clearable ></el-input><el-button type="primary" style="margin-left: 5px"@click="load">查询</el-button></div>……
    <!--    表格--><el-table :data="tableData"  border stripe style="width: 100%"><el-table-column prop="id" label="ID" width="150"/><el-table-column prop="name" label="名称"/><el-table-column prop="price" label="价格"/><el-table-column prop="author" label="作者"/><el-table-column prop="createTime" label="出版时间"/><!--      操作框--><el-table-column fixed="right" label="操作"><template #default="scope"><el-button  size="mini"@click="handleEdit(scope.row)">编辑</el-button><!--elementPlus提供的方法  因为要根据id进行删除,索引就需要传入id--><el-popconfirm title="确认删除吗?"@confirm="handleDelete(scope.row.id)"><template #reference><el-button size="mini" type="danger">删除</el-button></template></el-popconfirm></template></el-table-column></el-table><!--    分页组件--><div style="margin: 10px 0"><el-pagination
          @size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[5, 10, 20]":page-size="pageSize":small="small":disabled="disabled":background="background"
          layout="total, sizes, prev, pager, next, jumper":total="total"/><!--    弹出对话框  --><el-dialog v-model="dialogVisible" title="提示" width="30%"><!--     表单组件   --><el-form :model="form" label-width="120px"><el-form-item label="名称"><el-input v-model="form.name" style="width:80%"/></el-form-item><el-form-item label="价格"><el-input v-model="form.price" style="width:80%"/></el-form-item><el-form-item label="作者"><el-input v-model="form.author" style="width:80%"/></el-form-item><el-form-item label="出版时间"><el-date-picker v-model="form.createTime" value-format="YYYY-MM-DD"  type="date" style="width:80%" clearable></el-date-picker></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary"@click="save">确认</el-button></span></template></el-dialog></div></div></template><script>// @ is an alias to /srcimportrequest from "@/utils/request";

export default{
  name: 'HomeView',
  components:{},//先为表格填入假数据data(){return{
      form:{},
      dialogVisible:false,
      search:'',
      pageSize:10,
      currentPage:1,
      tableData:[],
      total:0,}},// 加载的方法,在加载的时候调用created(){this.load()},
  methods:{//刷新表格的数据load(){
      request.get("/book",{
        params:{
          pageNum:this.currentPage,
          pageSize:this.pageSize,
          search:this.search,}}).then(res =>{
        console.log(res)this.tableData = res.data.records
        this.total=res.data.total
      })},add(){//表单其实一直都在,只是把它设置成为不可见得了this.dialogVisible=true//  新增的时候一定要清空一下表单域,不会影响下一次操作this.form={}},// 点击确认按钮后触发的添加保存方法save(){if(this.form.id){//更新
        request.put("/book",this.form).then(res =>{
          console.log(res)if(res.code ==='0'){this.$message({
              type:"success",
              message:"更新成功"})}else{this.message({
              type:"error",
              message:res.msg
            })}this.load()//刷新表格数据//  关闭弹窗this.dialogVisible=false})}else{//新增
        request.post("/book",this.form).then(res =>{
          console.log(res)if(res.code ==='0'){this.$message({
              type:"success",
              message:"新增成功"})this.load()this.dialogVisible=false}else{this.message({
              type:"error",
              message:res.msg
            })}})}},handleDelete(id){
      console.log(id)//删除 + id
      request.delete("/book/"+ id ).then(res =>{if(res.code ==='0'){this.$message({
            type:"success",
            message:"删除成功"})}else{this.message({
            type:"error",
            message:res.msg
          })}this.load()//重新加载})},handleEdit(row){//弹出编辑框,和新增框一样的请求路径,深克隆this.form=JSON.parse(JSON.stringify(row))//弹出对话框this.dialogVisible=true},//改变每页的条数handleSizeChange(pageSize){this.pageSize=pageSize
      this.load()},//改变当前页handleCurrentChange(pageNum){this.currentPage=pageNum
      this.load()}},}</script>

改的路径
在这里插入图片描述
然后就是设置一下路由 (在Layout下设置的子路由,以Layout为背景)在这里插入图片描述

日期格式化:

问题
在这里插入图片描述
怎么做:
后端实体类数据上加 @JsonFormat

效果:
在这里插入图片描述

高亮显示不正确

在这里插入图片描述
基本功能就这么多啦!


本文转载自: https://blog.csdn.net/qq_48602526/article/details/127880266
版权归原作者 qq_48602526 所有, 如有侵权,请联系我们删除。

“springboot+vue”的评论:

还没有评论