首页技术栈归档照片墙音乐日记随想收藏夹友链留言关于

VUE3+elementui-plus实现简单的CURD上传以及下载工能

写作时间:2026-07-08

VUE3+elementui-plus实现简单的CURD上传以及下载工能

前端代码

Vue

<template>
   <div style="width: 88vh;display: flex;justify-content: space-between;margin: 10px auto;">
      <el-input v-model="name" placeholder="请输入商品名称" style="width: 200px;height: 32px;"  class="left_jianju"/>
      <el-button type="primary"  @click="goods()"  class="left_jianju">查询</el-button>
      <el-button type="warning"  @click="reset()"  class="left_jianju">重置</el-button>
      <el-button type="success" @click="handleAddUpdate()"  class="left_jianju">新增</el-button>
      <el-button type="info"    @click="batchDelete()"  class="left_jianju">批量删除</el-button>
      <el-button type="success"   @click="visibleUpload = true" class="left_jianju">导入</el-button>  

      <!--文件上传弹窗-->
    <el-dialog v-model="visibleUpload" :show-close="false" style="width: 60vh;margin: 15% auto;">
    <template #header="{ close, titleId, titleClass }">
      <div class="my-header">
        <h4 :id="titleId" :class="titleClass">文件上传</h4>
        <el-button type="danger" @click="close">
          <el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
          关闭
        </el-button>
      </div>
    </template>
    <el-upload
     class="left_jianju"
    :action="uploadUrl" 
    :before-upload="handleBeforeUpload"
    :on-success="handleSuccess"
    :on-error="handleError"
    accept=".xlsx, .xls">
      <template #trigger>
        <el-button type="primary">选择文件</el-button>
      </template>
      <template #default>
        <el-button type="success" style="margin-left: 10px;margin-top: -5px;" @click="submitUpload()">上传到服务器</el-button>
      </template>
   </el-upload>
  </el-dialog>

   <el-button  type="danger" @click="exportData()" class="left_jianju">导出</el-button>
   </div>
   <div>
    <el-table :data="state.tableData" style="width: 100%" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" />
    <el-table-column  prop="goodSid" label="编号" width="180" />  
     <el-table-column prop="goodType" label="品牌" />  
     <el-table-column prop="goodsSpname" label="类型" />
     <el-table-column prop="goodsName" label="商品名称" width="180" />
     <el-table-column prop="goodsPrice" label="价格" />
     <el-table-column label="状态">
       <template #default="scope">
         {{ scope.row.status === 1 ? '上架' : '下架' }}
       </template>
     </el-table-column>
     <el-table-column prop="creationDate" label="创建时间" />
     <el-table-column prop="modifyDate" label="修改时间" />                              
    <el-table-column label="操作">
      <template #default="scope">
        <el-button size="small" @click="handleEdit(scope.$index, scope.row)">
          修改
        </el-button>
        <el-button
          size="small"
          type="danger"
          @click="deleteConfirm(scope.row.goodSid)"
        >
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
  <div style="margin: 10px auto">
        <el-pagination
             @current-change="goods" 
              @size-change="goods" 
              v-model:current-page="pageNum"
            v-model:page-size="pageSize"
             background :page-sizes="[2, 5, 10, 20]"
            layout="total, sizes, prev, pager, next, jumper" 
            :total="total" 
           prev-text="上一页"
          next-text="下一页"
            style="text-align: center"
            small="mini"/>
    </div>
   </div>

   <!-- 新增弹窗 -->
   <el-dialog v-model="visible" :show-close="false">
    <template #header="{ close, titleId, titleClass }">
      <div class="my-header">
        <h4 :id="titleId" :class="titleClass">新增商品</h4>
        <el-button type="danger" @click="close">
          <el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>
          关闭
        </el-button>
      </div>
    </template>
    <el-form
    style="max-width: 600px"
    :model="state.form"
    ref="ruleFormRef"
    status-icon
    :rules="rules"
    label-width="auto"
  >
   <el-form-item label="品牌" prop="goodType">
      <el-input  v-model="state.form.goodType" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="类型" prop="goodsSpname">
      <el-input  v-model="state.form.goodsSpname" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="商品名称" prop="goodsName">
      <el-input v-model="state.form.goodsName" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="价格" prop="goodsPrice">
      <el-input v-model="state.form.goodsPrice"  type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="状态" prop="status">
      <el-input  v-model="state.form.status" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(ruleFormRef)">提交</el-button>
      <el-button @click="resetForm(ruleFormRef)">重置</el-button>
    </el-form-item>
  </el-form>
  </el-dialog>




   <!-- 修改弹窗 -->
   <el-dialog v-model="dialogFormVisibleUpdate" :show-close="false">
    <template #header="{ close, titleId, titleClass }">
      <div class="my-header">
        <h4 :id="titleId" :class="titleClass">修改商品</h4>
        <el-button type="danger" @click="close">
          <el-icon class="el-icon--left"><CircleCloseFilled /></el-icon>关闭</el-button>
      </div>
    </template>
    <el-form
    style="max-width: 600px"
    :model="state.form"
    ref="ruleFormRef"
    status-icon
    :rules="rules"
    label-width="auto"
  >
   <el-form-item label="品牌" prop="goodType">
      <el-input  v-model="state.form.goodType" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="类型" prop="goodsSpname">
      <el-input  v-model="state.form.goodsSpname" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="商品名称" prop="goodsName">
      <el-input v-model="state.form.goodsName" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="价格" prop="goodsPrice">
      <el-input v-model="state.form.goodsPrice"  type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item label="状态" prop="status">
      <el-input  v-model="state.form.status" type="text" autocomplete="off" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="saveUpdate(ruleFormRef)">提交</el-button>
      <el-button @click="resetForm(ruleFormRef)">重置</el-button>
    </el-form-item>
  </el-form>
  </el-dialog>
</template>

<script setup lang="ts">
import { nextTick, reactive, ref } from "vue";
import { CircleCloseFilled } from '@element-plus/icons-vue'
import type { FormInstance } from 'element-plus'
import { ElMessageBox, ElMessage, ElNotification } from 'element-plus'
import http from "@/http";
const name = ref('')
const pageNum = ref(1)
const pageSize = ref(10)
const total = ref(0)


//--------------------------------------------------查询部分--------------------------------------------------
// 定义表格数据,请求后台方法
const state = reactive({
    tableData: [],
    form: {
            goodsName: '',
            goodsPrice: '',
            goodType: '',
            status: '',
            goodsSpname: ''
    }
})
const goods = ()=>{//请求后台数据进行查询
    return http.get("/goods/listGoods", {
      params: {
        goodsName: name.value,
        pageNum: pageNum.value,
        pageSize: pageSize.value
      }
    }).then(res=>{
      // console.log(res.data.total)
      total.value = res.data.data.total
      state.tableData = res.data.data.records
    })
}
//调用查询方法
goods();



// 重置搜索框方法
const reset = () => {
    name.value = ''
    goods()
}

//--------------------------------------------------新增部分--------------------------------------------------
const visible = ref(false)//定义弹窗是否显示
//定义表单ref,用于提交表单,获取表单数据,相当于就是一个接口
const ruleFormRef = ref<FormInstance>()
// 新增弹窗方法
const handleAddUpdate = () => {
     visible.value = true
     //新增之前清空表单
        state.form = {
            goodsName: '',
            goodsPrice: '',
            goodType: '',
            status: '',
            goodsSpname: ''
        }
}
// 添加效验规则
const rules = reactive({
    goodsName: [
        { required: true, message: '请输入商品名称', trigger: 'blur' },
     ],
    goodsPrice: [
        { required: true, message: '请输入价格', trigger: 'blur' },
    ],
    goodType: [
        { required: true, message: '请输入品牌', trigger: 'blur' },
    ],
    status: [
        { required: true, message: '请输入状态', trigger: 'blur' },
    ],
    goodsSpname: [
        { required: true, message: '请输入名称', trigger: 'blur' },
    ],
})
// 提交表单方法
const submitForm = (formEl: FormInstance | undefined) => {//表单提交
  if (!formEl) return
  formEl.validate((valid) => {//表单校验
    if (valid) {
      // 表单校验成功,提交表单数据
      http.post("/goods/insertGoods", state.form).then(res => {
        if(res.data.code === 200){
          ElNotification.success({
            title: 'Success',
            message: '数据新增成功',
            offset: 100,
          })
          visible.value = false
          goods()
        } else {
          ElNotification.error({
            title: 'Error',
            message: '数据新增失败',
            offset: 100,
          })
        }
      })
    } else {
      console.log('error submit!')
    }
  })
}
// 重置表单方法
const resetForm = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.resetFields()
}
//--------------------------------------------------修改部分--------------------------------------------------
// 修改弹窗
const dialogFormVisibleUpdate = ref(false)
// 修改触发方法
const handleEdit = (index: number,raw ) => {
    dialogFormVisibleUpdate.value = true
    nextTick(() => {//异步操作
        ruleFormRef.value.resetFields()//清空表单
        state.form = JSON.parse(JSON.stringify(raw))//深拷贝
    })
}
// 修改提交方法
const saveUpdate = (formEl: FormInstance | undefined ) => {  
    if (!formEl) return
       formEl.validate(valid => {    
        if (valid) {
          http.post('/goods/updateById', state.form).then(res => {
        if (res.data.code === 200) {
          ElNotification.success({
            title: 'Success',
            message: '数据修改成功',
            offset: 100,
          })
          dialogFormVisibleUpdate.value = false
          goods()
        } else {
          ElNotification.error({
            title: 'Error',
            message: '数据修改失败',
            offset: 100,
          })
        }
     })
   }
})

}
//--------------------------------------------------删除部分--------------------------------------------------
// 在删除前弹窗提示
const deleteConfirm = (id) => {
  ElMessageBox.confirm(
    '确定要删除吗?',
    '提示',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    }
  )
    .then(() => {
      //开始删除数据,请求后台
      http.get('/goods/deleteById', {params: {goodSid: id}}).then(res => {
        if (res.data.code === 200) {
          ElMessage({
          type: 'success',
          message: '删除成功',
         })
          goods()
        } else {
          ElMessage({
          type: 'error',
          message: '删除失败',
          })
        }
    })
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '取消删除',
      })
    })
}
//--------------------------------------------------批量删除部分--------------------------------------------------
// 批量删除
const multipleSelection = ref([])
const handleSelectionChange = (val) => {
    multipleSelection.value = val
}
//批量删除方法
const batchDelete = () => {
  if (!multipleSelection.value || !multipleSelection.value.length) {
        ElMessage.warning("请选择数据")
        return
    }
   console.log(multipleSelection.value.map(item => item.goodSid))
    http.post('/goods/deleteByIds', multipleSelection.value.map(item => item.goodSid)).then(res => {
      if (res.data.code === 200) {
        ElMessage.success('批量删除成功')
        goods()
      } else {
        ElMessage.error('批量删除失败')
      }
    })
}

//--------------------------------------------------文件导出--------------------------------------------------
// 导出接口
const exportData = () => {
  http.get('/goods/exportGoods', 
  { responseType: 'blob' ,
    params: {
      date: '2023-12-20'
    }
  }//设置响应类型为blob
) .then(res => {
      const url = window.URL.createObjectURL(new Blob([res.data]));
      const link = document.createElement('a');
      link.href = url;
      link.setAttribute('download', '数据下载.xlsx');
      document.body.appendChild(link);
      link.click();
    })
    .catch(error => {
      ElMessage.error('导出失败'+error);
    });
}


//--------------------------------------------------文件导入--------------------------------------------------


const uploadUrl = 'http://127.0.0.1/goods/upLoadExcel'//文件上传地址,由于这里使用的是axios上传,所以该地址暂时用不到,已经改成axios上传方式
const visibleUpload = ref(false)//文件上传弹窗
//上次的excel文件
const excelFile = reactive({
    fileList: null,
})

// 阻止默认上传行为,改成axios上传
const handleBeforeUpload = (file) => {
  excelFile.fileList = file
  // console.log("aaaaaaa", excelFile.fileList)
  return false
}

//开始上传文件
const submitUpload = () => {
  //文件上传前校验文件是否为空
  if (!excelFile.fileList) {
    ElMessage.error('请选择文件')
    return
  }
  //如果文件不为空,则开始上传文件
  const formData = new FormData();//创建formData对象
  formData.append('file', excelFile.fileList);//将文件添加到formData对象中
  //formData.append('name', 'customValue')//添加自定义字段
  http.post('/goods/upLoadExcel', formData).then(res => {
    if (res.data.code === 200) {
      ElMessage({
          type: 'success',
          message: res.data.data,
         })
         visibleUpload.value = false;
         goods();
    } else {
          ElMessage({
          type: 'error',
          message: res.data.data,
         })
     }
  })
}

// 成功回调
const handleSuccess = (response, file, fileList) => {
         ElMessage({
          type: 'success',
          message: '导入成功'+response.data.data,
         })
}
// 失败回调
const handleError = (error, file, fileList) => {
        ElMessage({
          type: 'error',
          message: '导入失败'+error.data.data,
         })
}

</script>
<style scoped>
.left_jianju{
    margin-right: 5px;
}

.my-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
</style

后端代码

controller

package com.yuan.controller.goods;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yuan.dto.R;
import com.yuan.enums.SuccessErrorEnum;
import com.yuan.interfaces.GooodsInterfaces;
import com.yuan.pojo.Goods;
import com.yuan.service.GoodsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;

import org.apache.commons.lang3.time.DateUtils;
import io.swagger.v3.oas.annotations.tags.Tag;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.ibatis.executor.BatchResult;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 查询的增删改查
 */
@RestController
@RequestMapping("/goods")
@Tag(name = "返回的goods类")
@CrossOrigin
public class GoodsController {
    private static final Logger log = LoggerFactory.getLogger(GoodsController.class);
    @Autowired
    private GoodsService goodsService;


    @GetMapping("/list")
    @Operation(summary = "测试")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    @Parameters({
            @Parameter(name = "id",description = "文件id",in = ParameterIn.PATH),
            @Parameter(name = "token",description = "请求token",required = true,in = ParameterIn.HEADER),
            @Parameter(name = "name",description = "文件名称",required = true,in=ParameterIn.QUERY)
    })
    public Object getName() {
        List<Goods> list = goodsService.list();
        System.out.println("返回的数据"+list);
        return list;
    }


    /**
     * 查询操作
     * @return
     */
    @GetMapping("/listGoods")
    @Operation(summary = " 查询数据")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    @Parameters({
            @Parameter(name = "goodsName",description = "商品名称",required = true,in=ParameterIn.QUERY),
            @Parameter(name = "pageNum",description = "起始页",required = true,in=ParameterIn.QUERY),
            @Parameter(name = "pageSize",description = "分页条数",required = true,in=ParameterIn.QUERY)
    })
    public Object getList(
                         @RequestParam(value = "goodsName",defaultValue = "",required = false) String goodsName,
                         @RequestParam(value = "pageNum",defaultValue = "1",required = false) Integer pageNum,
                        @RequestParam(value = "pageSize", defaultValue = "3", required = false) Integer pageSize) {

        IPage<Goods> goods = goodsService.getGoods(goodsName, pageNum, pageSize);
        System.out.println("返回的数据"+goods);
        return   R.ok(goods);
    }



    /**
     * 新增操作
     * @return
     */
    @RequestMapping("/insertGoods")
    @Operation(summary = "新增数据")
    @ApiOperationSupport(ignoreParameters = {"goods.goodSid"})
    public Object insert(@RequestBody Goods goods) {
        System.out.println("接收前端提交的数据"+goods);
        boolean save = goodsService.save(goods);
        if (save){
            return R.ok("成功");
        }else {
            return R.error("失败");
        }
    }

    /**
     * 删除操作
     * 这里使用的逻辑删除,并不是直接将数据从数据库中进行抹除,而是增加一个字段来表示删除
     * @param goodSid
     * @return
     */
    @RequestMapping("/deleteById")
    @Operation(summary = "根据id删除数据")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    @Parameters({
            @Parameter(name = "goodSid",description = "删除的id",required = true,in=ParameterIn.DEFAULT),
    })
    public Object deleteById(@RequestParam("goodSid") Integer goodSid) {
        //传统的QueryWrapper会导致驼峰命名失效问题,不建议使用
//        QueryWrapper<Goods> queryWrapper = new QueryWrapper<Goods>();
//        QueryWrapper<Goods> queryWrapper = new QueryWrapper<Goods>();
//        queryWrapper.eq("good_sid",goods.getGoodSid());
        log.info("删除的id"+goodSid);

        //这种Lambda表达式的条件构造器,可以有效避免无法自动转换驼峰命名的问题
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Goods> getGoodsName = queryWrapper.eq(Goods::getGoodSid, goodSid);

        boolean remove = goodsService.remove(getGoodsName);
        if (remove){
            return R.ok(SuccessErrorEnum.SUCCESS);
        }else {
            return R.error(SuccessErrorEnum.ERROR);
        }
    }


    /**
     * 修改操作
     * @param goods
     * @return
     */
    @RequestMapping("/updateById")
    @Operation(summary = "根据id修改数据")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    @Parameters({
            @Parameter(name = "goods",description = "修改的实体类",required = true,in=ParameterIn.QUERY),
    })
    public Object update(@RequestBody Goods goods) {
//        QueryWrapper<Goods> queryWrapper = new QueryWrapper<Goods>();
//        queryWrapper.eq("good_sid",goods.getGoodSid());
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Goods> getGoodsName = queryWrapper.eq(Goods::getGoodSid, goods.getGoodSid());
        boolean update = goodsService.update(goods, getGoodsName);
        if (update){
            return R.ok(SuccessErrorEnum.SUCCESS);
        }else {
            return R.error(SuccessErrorEnum.ERROR);
        }
    }




    /**
     * 批量删除操作
     * 这里使用的逻辑删除,并不是直接将数据从数据库中进行抹除,而是增加一个字段来表示删除
     * @param goodSids
     * @return
     */
    @RequestMapping(value = "/deleteByIds",method = RequestMethod.POST)
    @Operation(summary = "根据id删除数据")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    @Parameters({
            @Parameter(name = "goodSids",description = "删除的id",required = true,in=ParameterIn.DEFAULT),
    })
    public Object deleteByIds(@RequestBody Integer[] goodSids) {
        for (Integer goodSid : goodSids) {
            log.info("删除的id"+goodSid);
        }
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Goods> getGoodsName = queryWrapper.in(Goods::getGoodSid, goodSids);//由于是数组类型这里就用IN表示
        boolean remove = goodsService.remove(getGoodsName);
        if (remove){
            return R.ok(SuccessErrorEnum.SUCCESS);
        }else {
            return R.error(SuccessErrorEnum.ERROR);
        }
    }


    /**
     * 文件上传
     */
    @PostMapping(value = "/upLoadExcel")
    @Operation(summary = "文件上传,这里只能只是POST请求方式其他请求方式无效")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    public Object upLoadExcel(@RequestBody MultipartFile file) throws Exception {//这里使用的单文件上传,多文件改成数组即可
        log.info("接收前端上传的文件"+file);
        String name = file.getOriginalFilename();
        InputStream inputStream = file.getInputStream();//获取的表格转成文件流的形式
        //1、创建一个工作簿
        Workbook workbook =null;
        if(name.endsWith(".xlsx")) {
            workbook= new XSSFWorkbook(inputStream);
        }else if (name.endsWith(".xls")){
            workbook= new HSSFWorkbook(inputStream);
        }else {
         return  R.error("文件上传格式不正确,只能是.xlsx或者是.xls格式");
        }
        List<BatchResult> goodsUpLoad = goodsService.getGoodsUpLoad(workbook);
        if (!goodsUpLoad.isEmpty()) {
            return R.ok("数据上传成功");
        } else {
            return R.error("上传失败,请检查表格格式是否正确");
        }
    }


    /**
     * 文件导出
     */
    @RequestMapping(value = "/exportGoods")
    @Operation(summary = "文件上传,这里只能只是POST请求方式其他请求方式无效")
    @ApiOperationSupport(author = "yuan")//添加接口作者
    public Object exportGoods(@RequestParam("date") String date,HttpServletResponse response) throws Exception {//这里使用的单文件上传,多文件改成数组即可
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date dateTime = sdf.parse(date);
        log.info("时间"+dateTime);

        /**
         *    SXSSFWorkbook是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excel,
         *    SXSSFWorkbook专门处理大数据,对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了。
         *    它的原理很简单,用硬盘空间换内存(就像hashmap用空间换时间一样)。 SXSSFWorkbook是streaming
         *     版本的XSSFWorkbook,它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到
         *     硬盘里(Windows电脑的话,是写入到C盘根目录下的temp文件夹)。被写入到硬盘里的rows是不可见的/不
         *     可访问的。只有还保存在内存里的才可以被访问到。
         *     注:HSSFWorkbook和XSSFWorkbook的Excel Sheet导出条数上限(<=2003版)是65535行、256列,(>=2007版)
         *     是1048576行,16384列,如果数据量超过了此上限,那么可以使用SXSSFWorkbook来导出。实际上上万条数据,
         *     甚至上千条数据就可以考虑使用SXSSFWorkbook了。
         */
        try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {
            //创建一个SXSSFSheet 这里使用SXSSFSheet可以调整列宽
            SXSSFSheet sheet = workbook.createSheet();
            //1.获取表头字段
            List<String> listTitle = new ArrayList<>();
//            listTitle.add("年月");
//            listTitle.add("厂部类型");
//            listTitle.add("环保设施名称");
//            listTitle.add("环保设施类型");
//            listTitle.add("介质名称");
//            listTitle.add("数值");
//            String goodSid = getChineseNameByFieldName(Goods.class, "goodSid");
//            System.out.println("字段goodSid的中文名为:" + goodSid);
                Goods goodsPojo = new Goods();
                // 使用反射获取所有字段
                Field[] fields = goodsPojo.getClass().getDeclaredFields();
                // 循环字段并打印中文名称
                for (Field field : fields) {
                    String chineseName = getChineseNameByField( field.getName());
                    log.info("获取实体类的字段名称{}", chineseName);
                    if (null!=chineseName){
                        listTitle.add(chineseName);//将通过反射获取的表头字段存储在List集合中
                    }
                  }
              //2.写入表头
              Row rowTitle = sheet.createRow(0);
            //3.写入表头
            sheet.trackAllColumnsForAutoSizing();//自动调整列宽设置
            for (int i = 0; i < listTitle.size(); i++) {
                sheet.autoSizeColumn(i);//自动调整列宽
                sheet.setColumnWidth(i, sheet.getColumnWidth(0) * 13 / 10);//设置宽度
                Cell cell = rowTitle.createCell(i);
                cell.setCellValue(listTitle.get(i));
             }

           //4.开始获取数据
            List<Goods> goods = goodsService.exportGoods(dateTime);
            List<Map<String, Object>> resultGoods=new ArrayList<>();
            Map<String, Object> map1=  new LinkedHashMap<>();//这里使用LinkedHashMap用于保存数据,他是一个有序集合
            map1.put("goodSid","");//由于第一例是空的,所以给第一列随便添加一个空的即可,或者是跳过第一列进行新增
            resultGoods.add(map1);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            //重新对返回的数据进行封装

            List<String> goodsKey = new ArrayList<>();
            goodsKey.add("goodsPrice");//这个是设置成数值类型的字段

            for (Goods goods1 : goods) {
                Map<String, Object> maps=  new LinkedHashMap<>();
                maps.put("goodSid",goods1.getGoodSid());
                maps.put("goodsName",goods1.getGoodsName());
                maps.put("goodsPrice",goods1.getGoodsPrice());
                maps.put("goodsType",goods1.getGoodType());
                maps.put("status",goods1.getStatus().toString().equals("1")?"上架":"下架");
                maps.put("goodsSpname",goods1.getGoodsSpname());
                maps.put("creationDate",simpleDateFormat.format(goods1.getCreationDate()));
                maps.put("modifyDate",simpleDateFormat.format(goods1.getModifyDate()));
                resultGoods.add(maps);
            }
            //开始下载数据
            downloadFile("数据下载", response, workbook, sheet, resultGoods,goodsKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    /**
     * 通过反射获取自定义的名称
     * @param clazz
     * @param fieldName
     * @return
     * @throws NoSuchFieldException
     */
    public static String getChineseNameByFieldName(Class<?> clazz, String fieldName) throws NoSuchFieldException {
        Field field = clazz.getDeclaredField(fieldName);
        GooodsInterfaces annotation = field.getAnnotation(GooodsInterfaces.class);
        if (annotation != null) {
            return annotation.value();
        }
        return null;
    }
    // 根据实体类字段名称获取中文名称
    public static String getChineseNameByField(String PojoName) throws NoSuchFieldException {
            return getChineseNameByFieldName(Goods.class, PojoName);
    }
    /**
     * 文件下载公共方法
     * @param type
     * @param response
     * @param workbook
     * @param sheet
     * @param resultEp
     * @throws UnsupportedEncodingException
     */
    private void downloadFile(@RequestParam String type, HttpServletResponse response, SXSSFWorkbook workbook, Sheet sheet, List<Map<String, Object>> data,List<String>  key) throws UnsupportedEncodingException {
        // 创建样式和格式化
        CreationHelper createHelper = workbook.getCreationHelper();
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setDataFormat(
                createHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
        for (int rowNum = 1; rowNum < data.size(); rowNum++) {
            //创建一个行
            Row row = sheet.createRow(rowNum);
            int count = 0;
            for (Map.Entry<String, Object> entry : data.get(rowNum).entrySet()) {
                SXSSFCell cell = (SXSSFCell) row.createCell(count);
                cell.setCellValue(entry.getValue() == null ? "" : entry.getValue().toString());
                //判断是是否和传的参数一致
                int  keys= key.indexOf(entry.getKey());//判断数据中是否包含传入的字段0代表存在1代表不存在
                if (keys!=-1){//如果不等于-1则是要转换的数据
                    setNumberFormat(workbook, cellStyle, cell, entry.getValue());
                }else {  //否则就是String类型
                    cell.setCellValue(entry.getValue()==null?"":entry.getValue().toString());
                }
                count++;
            }
        }
        response.setContentType("APPLICATION/OCTET-STREAM");
        String fileNameTo = URLEncoder.encode(type + ".xlsx", "UTF-8");
        response.addHeader("Content-Disposition", "attachment;filename=" + fileNameTo);
        try {
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     *  设置Excel单元格为数值类型便于公式运算
     *
     * @param workbook
     * @param contextstyle
     * @param cell
     * @param data
     */
    public static void setNumberFormat(SXSSFWorkbook workbook, CellStyle contextstyle, SXSSFCell cell, Object data){
        boolean isNum = false;//data是否为数值型
        boolean isInteger=false;//data是否为整数
        boolean isPercent=false;//data是否为百分数
        if (data != null || "".equals(data)) {
            //判断data是否为数值型
            isNum = data.toString().matches("^(-?\\d+)(\\.\\d+)?$");
            //判断data是否为整数(小数部分是否为0)
            isInteger=data.toString().matches("^[-\\+]?[\\d]*$");
            //判断data是否为百分数(是否包含“%”)
            isPercent=data.toString().contains("%");
        }
        //如果单元格内容是数值类型,设置data的类型为数值类型
        if (isNum && !isPercent) {
            // 此处设置数据格式
            DataFormat df = workbook.createDataFormat();
            if (isInteger) {
                contextstyle.setDataFormat(df.getFormat("0_ "));//数据格式只显示整数
            }else{
                contextstyle.setDataFormat(df.getFormat("0.00_ "));//保留两位小数点
            }
            // 设置单元格格式
            cell.setCellStyle(contextstyle);
            // 设置单元格内容为double类型
            cell.setCellValue(Double.parseDouble(data.toString()));
        } else {
            if (data != null && !"".equals(data)) {
                cell.setCellStyle(contextstyle);
                // 设置单元格内容为字符型
                cell.setCellValue(data.toString());
            }
        }
    }
}

service

package com.yuan.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yuan.pojo.Goods;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.executor.BatchResult;
import org.apache.poi.ss.usermodel.Workbook;

import java.util.Date;
import java.util.List;


public interface GoodsService extends IService<Goods> {


    /**
     *
     * @param name 名称
     * @param pageNum 起始页
     * @param pageSize 分页条数
     * @return
     */
    IPage<Goods> getGoods(@Param("name") String name , @Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize);


    /**
     * 文件上传接口
     *
     * @param inputStream 文件流
     * @param name        文件名称
     * @return
     */
    List<BatchResult> getGoodsUpLoad(Workbook workbook) throws Exception;



    /**
     * 文件下载接口
     *
     * @param inputStream 文件流
     * @param name        文件名称
     * @return
     */
    List<Goods> exportGoods(Date date) throws Exception;


}

package com.yuan.service.impl;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.ibatis.executor.BatchResult;
import org.apache.poi.ss.usermodel.*;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuan.mapper.GoodsMapper;
import com.yuan.pojo.Goods;
import com.yuan.service.GoodsService;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

@Service
@Transactional
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements GoodsService {

    @Autowired
    private GoodsMapper goodsMapper;


    @Override
    public IPage<Goods> getGoods(String name, Integer pageNum, Integer pageSize) {
        //放弃传统的xml写法使用最纯代码写sql
     //  return goodsMapper.getGoods(name, pageNum, pageSize);
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Goods> getGoodsName = queryWrapper.like(Goods::getGoodsName, name).orderByDesc(Goods::getCreationDate);
        Page<Goods> page = new Page<>(pageNum,pageSize, true);//传分页参数
        IPage<Goods> goodsIPage = goodsMapper.selectPage(page, getGoodsName);//进行分页
        return goodsIPage;
    }

    /**
     * 文件上传方法
     *
     * @return
     */
    @Override
    public List<BatchResult> getGoodsUpLoad(Workbook workbook) throws Exception{
        //获取第一个Sheet
        Sheet sheet = workbook.getSheetAt(0);
        //获取表格的标题
        Row rowTitle = sheet.getRow(0);//获取最上面一行也就是表头/标题的内容
        if (rowTitle!=null){
            int cellCount = rowTitle.getPhysicalNumberOfCells();//获取表格中所有的列
            for (int countNum = 0; countNum <cellCount ; countNum++) {
                Cell cell = rowTitle.getCell(countNum);//获取表头的数据
                if (cell != null) {
                    String stringCellValue = cell.getStringCellValue();
                    System.out.print(stringCellValue + " | ");
                }
            }
            System.out.println();
        }
        //方式 1:
        //1.开始获取表格数据
        List<Goods> goodsList = new ArrayList<>();//定义一个集合类存储数据
        Iterator<Row> rowIterator = sheet.iterator();
        while (rowIterator.hasNext()) {
            Row row = rowIterator.next();
            if (row.getRowNum() == 0) { // 跳过表头
                continue;
            }
            Goods goods = new Goods();//对实体类进行赋值
            //DataFormatter用于格式化单元格数据
            goods.setGoodsName(new DataFormatter().formatCellValue(row.getCell(0)));
            goods.setGoodsPrice(Integer.valueOf(new DataFormatter().formatCellValue(row.getCell(1))));
            goods.setGoodType(new DataFormatter().formatCellValue(row.getCell(2)));
            goods.setStatus(Integer.valueOf(new DataFormatter().formatCellValue(row.getCell(3))));
            goods.setGoodsSpname(new DataFormatter().formatCellValue(row.getCell(4)));
            goodsList.add(goods);
        }
        //关闭资源
        workbook.close();
        //打印输出
        goodsList.forEach(System.out::println);
        System.out.println("条件一"+goodsList.stream().map(Goods::getGoodsName).toList());
        // 2.表格资源获取完毕,在新增之前判断之前的数据是否存在如果存在则删除数据,这里使用 Lambda表达式的条件构造器 LambdaQueryWrapper
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
                 queryWrapper.in(Goods::getGoodsName, goodsList.stream().map(Goods::getGoodsName).toList()) // 第一个条件
                .and(wrapper->wrapper.in(Goods::getGoodType, goodsList.stream().map(Goods::getGoodType).toList()))//第二个条件
                .and(wrapper->wrapper.in(Goods::getStatus,goodsList.stream().map(Goods::getStatus).toList()))//第三个条件
                .and(wrapper->wrapper.in(Goods::getGoodsSpname,goodsList.stream().map(Goods::getGoodsSpname).toList()));//第四个条件
        // 设置查询条件,在新增之前判断之前的数据是否已经存在
        //上传之前根据表格存在的数据删除一遍,或者是查询出存在的数据在进行删除,这里也是使用逻辑删除并没有使用物理删除,
        goodsMapper.delete(queryWrapper);

        //方式 2:
        //获取表格的数据
//        int physicalNumberOfRows = sheet.getPhysicalNumberOfRows(); //获取所有的行数据
//        for (int rowNum = 1; rowNum <physicalNumberOfRows ; rowNum++) {//跳过第一行的数据从第二行开始
//            Row rowData = sheet.getRow(rowNum);
//            if (rowData!=null){
//                //读取列的数据
//                int cellCount=  rowTitle.getPhysicalNumberOfCells();
//                for (int cellNum = 0; cellNum < cellCount; cellNum++) {
//                    Cell cell = rowData.getCell(cellNum);
//                    //匹配列的数据类型
//                    if (cell!=null){
//                        CellType cellType = cell.getCellType();
//                        //判断单元格类型
//                        String cellValue="";
//                        switch (cellType){
//                            case CellType.STRING://字符串
//                                cellValue=String.valueOf(cell.getStringCellValue());
//                                break;
//                            case CellType.BOOLEAN://布尔
//                                cellValue = String.valueOf(cell.getBooleanCellValue());
//                                break;
//                            case CellType.BLANK://空
//                                break;
//                            case CellType.NUMERIC://数字
//                                    cell.setCellType(CellType.STRING);//转换为字符串输出
//                                    cellValue = cell.toString();
//                                break;
//                            case CellType.ERROR:
//                                System.out.print("【数据类型错误】");
//                                break;
//                        }
//                        System.out.print(cellValue+" | ");
//                    }
//                }
//                System.out.println();
//            }
//        }
        //3.数据删除后开始新增数据
            return goodsMapper.insert(goodsList);
    }

    /**
     * 文件下载接口
     * @param date 导出的时间
     * @return
     * @throws Exception
     */
    @Override
    public List<Goods> exportGoods(Date date) throws Exception {
        //根据时间查询要导出的字段,导出的时间大于某一个区间
        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(Goods::getCreationDate, date);
        List<Goods> goods = goodsMapper.selectList(queryWrapper);
        return goods;
    }
}

avatar

yuanyourdomain

写代码,做研究,记录生活。

RECOMMENDED

MyBatis 动态 SQL

2026-07-08

Nginx 基础入门

2026-07-08

Maven 多模块与私服

2026-07-08