基于Springboot2+Vue3的Partner交友项目(四)

目录

    • 后台管理
      • 环境搭建
      • 后台登录及数据请求
      • 后台管理增删改查
      • 导入导出和批量删除
      • 问题集

后台管理

环境搭建

1 创建vue3项目 npm init vue@latest

2 运行项目 cd partner-managernpm installnpm run dev

3 npm 配置淘宝镜像 npm config set registry https://registry.npm.taobao.org

4 配置启动

基于Springboot2+Vue3的Partner交友项目(四)_第1张图片

5 vite.config.js 配置端口号

export default defineConfig({
  server: {
    host: '0.0.0.0',
    port: 7000,
    https: false,
  }
})

6 安装依赖

element-plus 安装:npm install element-plus --save

// main.js
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

app.use(ElementPlus)

iicon组件 安装:npm i @element-plus/icons-vue -S

axios 安装:npm i axios -S 封装 request.js 和 config.js

// config.js
export default {
    serverUrl: 'localhost:9090'
}
// request.js   直接复制前端项目的  

缓存持久化插件 pinia数据是缓存到内存的,开启持久化后才能缓存到浏览器

安装: npm i pinia-plugin-persistedstate -S

// main.js 引用
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)

7 布局主页面
基于Springboot2+Vue3的Partner交友项目(四)_第2张图片

8 分页插件中文设置:

// 在main.js里引入:
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

app.use(ElementPlus, {
  locale: zhCn,
})

9 完成后台管理基本框架:头部菜单、左侧菜单、主体。主体分文搜索区域、表格区域、分页区域。

后台登录及数据请求

后台登录:实现 Login.vue,用到了 request.js 、config.js 、user.js。直接复制前端项目的,但 user.js 里面的 user 属性需

​ 要改为 manager。否则前后端用的同一个缓存且变量名一样,退出登录时删除后端数据会导致前台数据被删。

数据请求:实现 load 方法。

const namex = ref('')
const address = ref('')
const pageNum= ref(1)
const pageSize = ref(6)
const total = ref(0)

const state = reactive({
  tableData: [],
  form: {} // 绑定表单类容
})

// 拿后台数据
const load = () => {
  request.get('user/page',{
    params: {
      namex: namex.value, // 注意.value
      address: address.value,
      pageNum: pageNum.value,
      pageSize: pageSize.value,
    }
  }).then(res => {
    console.log(res)
    state.tableData = res.data.records
    total.value = res.data.total
  })
}
load()

后台管理增删改查

实现退出登录

   // UserServiceImpl
    @Override
    public void logout(String uid) {
        // 退出登录 satoken提供
        StpUtil.logout(uid);
        log.info("用户{}退出成功", uid);
    }

   //  WebController 
    @ApiOperation(value = "用户退出登录接口")
    @GetMapping("/logout/{uid}")
    public Result logout(@PathVariable String uid) {
        userService.logout(uid);
        return Result.success();
    }
  const logout = () => {
    request.get('/logout/' + user.uid).then(res => {
      if (res.code === '200') {
        userStore.logout() // 把当前用户信息删除
      } else {
        ElMessage.error(res.msg)
      }
    })
  }

实现分页 分页插件 Mybatis-plus官网:https://baomidou.com/

package com.partner.boot.common;

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

@Configuration
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

实现查询和重置 多条件分页模糊查询 前端还是调用load

     // UserController 
	@GetMapping("/page")
    public Result findPage(@RequestParam(defaultValue = "") String namex,
                           @RequestParam(defaultValue = "") String address,
                           @RequestParam Integer pageNum,
                           @RequestParam Integer pageSize) {
        System.out.print(namex + "  " +address  + "  " + pageNum  + "  " + pageSize);
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().orderByDesc("id");
        // !"" = StrUtil.isNotBlank(name)  name and address
        queryWrapper.like(StrUtil.isNotBlank(namex), "namex", namex);
        queryWrapper.like(StrUtil.isNotBlank(address), "address", address);
        return Result.success(userService.page(new Page<>(pageNum, pageSize), queryWrapper));
    }
// 刷新
const reset = () => {
  namex.value = ''
  load()
}

设置每页信息数 当前页面数

    // 页面数
    const  currentChange = (num) => {
      console.log(num)
      pageNum.value = num
      load()
    }

    // 页面大小
    const handleSizeChange = (size) => {
      console.log(size)
      pageSize.value = size
      load()
    }

    
    

实现新增与编辑,element弹窗组件,dialog

const dialogFormVisible = ref(false)

const ruleFormRef = ref()

// 新增校验规则
const rules = reactive({
  namex: [
    { required: true, message: '请输入名称', trigger: 'blur' },
    {min: 3, max: 20, message: '长度在3-20之间', trigger: 'blur'}
  ]
})

// 新增
const handleAdd = () => {
  dialogFormVisible.value = true
  ruleFormRef.value.resetFields() // 取消校验提示
  state.form = {}
}

// 保存
const save = () => {
  ruleFormRef.value.validate(valid => {
    // valid就是校验的结果
    // if (valid) {
    //   request.post('/user',state.form).then(res => {
    //     // 保存新用户
    //     if (res.code === '200') {
    //       ElMessage.success('保存成功')
    //       // 关闭弹窗
    //       dialogFormVisible.value = false
    //       load()  // 刷新表格数据
    //     } else {
    //       ElMessage.error(res.msg)
    //     }
    //   })

    // 区分新增与修改
    request.request({
      url: '/user',
      method: state.form.id ? 'put' : 'post',
      data: state.form
    }).then(res => {
      if (res.code === '200') {
        ElMessage.success('保存成功')
        dialogFormVisible.value = false
        load()  // 刷新表格数据
      } else {
        ElMessage.error(res.msg)
      }
    })

  })
}

// 编辑
const handleEdit = (raw) => {

  state.form = JSON.parse(JSON.stringify(raw))  
  // 以下两段代码位置不可以互换
  dialogFormVisible.value = true
  ruleFormRef.value.resetFields() // 取消校验提示
}



    
    
      
        
        
          
        
        
          
        
        
          
        
        
          
        
      
      
    

增加地址字段,在数据库中加字段,在后端的实体类里也要增加。

实现删除

// 删除
const del = (id) => {
  request.delete('/user/' + id).then(res => {
    if (res.code === '200') {
      ElMessage.success('操作成功')
      load()  // 刷新表格数据
    } else {
      ElMessage.error(res.msg)
    }
  })
}

删除是逻辑删除,防止数据误删除

导入导出和批量删除

导出 先实现导出,因为导入需要一个模板导,导出成一个模板,再修改模板然后实现导入。 导出实际就是打开一个新

​ 的链接下载表格数据。导出是没有权限验证的,需要在 MyWebMvcConfig.java里面进行放 行: “/**/export”。

    // 导出接口
    const exportData = () => {
      window.open(`http://${config.serverUrl}/user/export`)
    }

     
      
        
          
           导出 
      

加上这个依赖,才能实现Excel导入导出

<dependency>
    <groupId>org.apache.poigroupId>
    <artifactId>poi-ooxmlartifactId>
    <version>5.2.3version>
dependency>
    /**
    *  UserController 导出接口
    */
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws Exception {
        // 从数据库查询出所有的数据
        List<User> list = userService.list();
        // 在内存操作,写出到浏览器 1操作ExcelWriter的一个对象
        ExcelWriter writer = ExcelUtil.getWriter(true);

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

        // 设置浏览器响应的格式 2 response对象
        response.setContentType("application/vnd.openxmlformats-"+ 
                                "officedocument.spreadsheetml.sheet;charset=utf-8");
        // 编码
        String fileName = URLEncoder.encode("User信息表", "UTF-8");
        // attachment 附件形式
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

        // 3 写出到浏览器
        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);
        out.close();
        writer.close();

    }

输出为excel统一请求头

application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8

导入 导入可以理解为文件上传 ,后端没有对导入进行放行,因为是一个Post请求,所以需要校验token

    const userStore = useUserStore()
    const token = userStore.getBearerToken

    const handleImportSuccess = () => {
      // 刷新表格
      load()
      ElMessage.success("导入成功")
    }
    
      
        
          
            
             导入 
        
      
    /**
    * excel 导入
    * @param file
    * @throws Exception
    */
    @PostMapping("/import")
    public Result imp(MultipartFile file) throws Exception {
        // 1 理解为文件上传 将file转换为流
        InputStream inputStream = file.getInputStream();
        // 2 操作ExcelReader的一个对象 从流里读数据
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        // 3 通过 javabean 的方式读取Excel内的对象,但是要求表头必须是英文,跟javabean的属性要对应起来
        List<User> list = reader.readAll(User.class);

        // userService.saveBatch(list);
        // 应该对用户存的数据进行校验
        for (User user : list) {
            userService.saveUser(user);
        }
        return Result.success();
    }

导入用户数据的时候,注意校验数据得合法性,我是通过 saveUser 方法进行保存数据的

注意模板的选择,id列要删除,否则会报错。敏感的数据要清空,比如:uid。

基于Springboot2+Vue3的Partner交友项目(四)_第3张图片

批量删除

    // 批量删除
    const multipleSelection = ref([])
    const handleSelectionChange = (val) => {
      multipleSelection.value = val
    }

    const confirmDelBatch = () => {
      if (!multipleSelection.value || !multipleSelection.value.length) {
        ElMessage.warning("请选择数据")
        return
      }
      // 把对象数组 multipleSelection.value  转化为只包含 id 的纯数字 的数组 idArr
      const idArr = multipleSelection.value.map(v => v.id)
      console.log(idArr)
      request.post('/user/del/batch', idArr).then(res => {
        if (res.code === '200') {
          ElMessage.success('操作成功')
          load()  // 刷新表格数据
        } else {
          ElMessage.error(res.msg)
        }
      })
    }

     
      
        
      
    //  UserController
    @PostMapping("/del/batch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {
       // 后端是list列表对象,前端是list数组,springMVC在做转换的时候,
        // 他会把前端的数组 通过json的方式 映射成一个list
        userService.removeByIds(ids);
        return Result.success();
    }

注意批量删除触发的时机,点击行的时候只是保存了行id数组,真正的删除是在点击

[批量删除] 按钮的时候触发的!

问题集

排查错误:先看请求,即前端传的值是否有问题;再看后台,后台记录可能有问题。

问题一:退出登录时删除后端数据会导致前台数据也被删除

解决:前后端用的同一个缓存且变量名一样,将前端变量名改为manager

基于Springboot2+Vue3的Partner交友项目(四)_第4张图片

问题二:新增保存不成功

解决:后台报错没设置默认密码,修改UserController里的save方法,将调用save改为调用saveUser,会校验用户是否存

​ 在,也会设置初始密码。同时需要在UserServiceImpl将saveUser方法改为public,在IUserService里的定义

​ saveUser方法。

问题三:form = JSON.parse(JSON.stringify(raw)) 这么赋值,form会变成响应式,就没法编辑

解决: const state = reactive({ form: {} })

你可能感兴趣的:(交友,vue.js,javascript)