多个文件上传

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 多个文件上传

 ♥️作者:小宋1021

🤵‍♂️个人主页:小宋1021主页

♥️坚持分析平时学习到的项目以及学习到的软件开发知识,和大家一起努力呀!!!

🎈🎈加油! 加油! 加油! 加油

🎈欢迎评论 💬点赞👍🏻 收藏 📂加关注+


目录

编辑

前端

html

js

useNewUpload.ts

FileApi

数据库

后端

项目构成

主表

实体类

ResearchingManageSaveReqVO

ResearchingManageRespVO

Mapper

service

controller

子表

实体类

Mapper


image.gif 编辑

前端

html

<div style="padding: 8px 0; background: #f8fbff">
        <el-upload
          name="file"
          ref="uploadRef"
          class="upload-file-uploader"
          v-model:file-list="fileList"
          :action="uploadUrl"
          :http-request="httpRequest"
          :auto-upload="autoUpload"
          :before-upload="beforeUpload"
          :drag="drag"
          :limit="props.limit"
          :multiple="props.limit > 1"
          :on-error="excelUploadError"
          :on-exceed="handleExceed"
          :on-remove="handleRemove"
          :on-success="handleFileSuccess"
        >
          <el-button type="primary">
            <Icon icon="ep:upload-filled" />
            选取文件
          </el-button>
          <template v-if="isShowTip" #tip>
            <div style="font-size: 10px">
              1.格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b> 的文件; 2.大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
            </div>
          </template>
        </el-upload>
        
        <el-table ref="multipleTableRef" :data="uploadList" style="width: 100%; margin-top: 10px; height: 200px; width:660px">
          <el-table-column label="序号" type="index"  header-align="center" align="center" width="60px" fixed />
          <el-table-column label="文件名称" align="center" prop="name" :show-overflow-tooltip="true" />
          <el-table-column label="文件路径" align="center" prop="url" :show-overflow-tooltip="true" />
          <el-table-column label="操作" align="center" fixed="right" width="140px">
            <template #default="scope">
              <el-button
                size="small"
                link
                type="primary"
                @click.prevent="deleteFileRow(scope.$index, uploadList)"
                >删除</el-button
              >
            </template>
          </el-table-column>
        </el-table>
      </div>

image.gif

js

import type { UploadInstance, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus'
import { useNewUpload } from '@/components/UploadFile/src/useUpload'
import { CommonStatusEnum } from '@/utils/constants'
import { UploadFile } from 'element-plus/es/components/upload/src/upload'
import { propTypes } from '@/utils/propTypes'
// ========== 上传相关 ==========
const uploadRef = ref<UploadInstance>()
const uploadList = ref<UploadUserFile[]>([])
const fileList = ref<UploadUserFile[]>([])
const uploadNumber = ref<number>(0)
const props = defineProps({
  modelValue: propTypes.oneOfType<any>([]).isRequired,
  title: propTypes.string.def('文件上传'),
  fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileSize: propTypes.number.def(5), // 大小限制(MB)
  limit: propTypes.number.def(5), // 数量限制
  autoUpload: propTypes.bool.def(true), // 自动上传
  drag: propTypes.bool.def(false), // 拖拽上传
  isShowTip: propTypes.bool.def(true) // 是否显示提示
})
const fileData = ref<any>([])
const formData = ref({
  id: undefined,
  courseType: undefined,
  subject: undefined,
  fileType: undefined,
  appendixName: undefined,
  creator:  userStore.user.id,
  appendixFile: undefined,
  createTime: undefined,
  title: undefined,
  remark: undefined,
  courseId: undefined,
  fileData: undefined,
  fileExists: undefined,
})
// 文件上传之前判断
const beforeUpload: UploadProps['beforeUpload'] = (file: UploadRawFile) => {
  if (fileList.value.length >= props.limit) {
    message.error(`上传文件数量不能超过${props.limit}个!`)
    return false
  }
  let fileExtension = ''
  if (file.name.lastIndexOf('.') > -1) {
    fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
  }
  const isImg = props.fileType.some((type: string) => {
    if (file.type.indexOf(type) > -1) return true
    return !!(fileExtension && fileExtension.indexOf(type) > -1)
  })
  const isLimit = file.size < props.fileSize * 1024 * 1024
  if (!isImg) {
    message.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式!`)
    return false
  }
  if (!isLimit) {
    message.error(`上传文件大小不能超过${props.fileSize}MB!`)
    return false
  }
  const existFile = fileList.value.slice(0, fileList.value.length - 1).find(f => f.name === file.name)
  if (existFile) {
    message.error(`当前文件已经存在!`)
    return false
  }
  message.success('正在上传文件,请稍候...')
  uploadNumber.value++
}
const deleteFileRow = (index, rows) => {
  rows.splice(index, 1)
}
// 文件上传成功
const handleFileSuccess: UploadProps['onSuccess'] = (res: any): void => {
  uploadList.value.push({ uid: res.data.id, name: res.data.name, url: res.data.url })
  message.success('上传成功')
}
// 文件数超出提示
const handleExceed: UploadProps['onExceed'] = (): void => {
  message.error(`上传文件数量不能超过${props.limit}个!`)
}
// 上传错误提示
const excelUploadError: UploadProps['onError'] = (): void => {
  message.error('导入数据失败,请您重新上传!')
}
// 删除上传文件
const handleRemove = (file: UploadFile) => {
  const index = fileList.value.map((f) => f.name).indexOf(file.name)
  if (index > -1) {
    fileList.value.splice(index, 1)
  }
}
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  await formRef.value.validate()
  // 提交请求
  formLoading.value = true
  fileData.value = []
  for (let i = 0; i < uploadList.value.length; i++) {
    const UserCourse = {
      fileId: uploadList.value[i].uid
    }
    fileData.value.push(UserCourse)
  }
  try {
    const data = formData.value as unknown as ResearchingManageVO
    data.fileData = fileData.value
    if (uploadList && uploadList.value.length > 0) {
      data.fileExists = 97
    } else {
      data.fileExists = 98
    }
    // if (flag === 1) {
    //   data.status = CommonStatusEnum.DISABLE
    // } else {
    //   data.status = CommonStatusEnum.ENABLE
    // }
    if (formType.value === 'create') {
      await ResearchingManageApi.createResearchingManage(data)
      message.success(t('common.createSuccess'))
    } else {
      await ResearchingManageApi.updateResearchingManage(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}
/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
  courseType: undefined,
  subject: undefined,
  fileType: undefined,
  appendixName: undefined,
  creator:  userStore.user.id,
  appendixFile: undefined,
  createTime: undefined,
  title: undefined,
  remark: undefined,
  courseId: undefined,
  fileData: undefined,
  fileExists: undefined,
  }
  formRef.value?.resetFields()
}

image.gif

useNewUpload.ts

import * as FileApi from '@/api/infra/file'
import CryptoJS from 'crypto-js'
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
import axios from 'axios'
export const useUpload = () => {
  // 后端上传地址
  const uploadUrl = import.meta.env.VITE_UPLOAD_URL
  // 是否使用前端直连上传
  const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
  // 重写ElUpload上传方法
  const httpRequest = async (options: UploadRequestOptions) => {
    // 模式一:前端上传
    if (isClientUpload) {
      // 1.1 生成文件名称
      const fileName = await generateFileName(options.file)
      // 1.2 获取文件预签名地址
      const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
      // 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
      return axios.put(presignedInfo.uploadUrl, options.file).then(() => {
        // 1.4. 记录文件信息到后端(异步)
        createFile(presignedInfo, fileName, options.file)
        // 通知成功,数据格式保持与后端上传的返回结果一致
        return { data: presignedInfo.url }
      })
    } else {
      // 模式二:后端上传
      // 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
      return new Promise((resolve, reject) => {
        FileApi.updateFile({ file: options.file })
          .then((res) => {
            if (res.code === 0) {
              resolve(res)
            } else {
              reject(res)
            }
          })
          .catch((res) => {
            reject(res)
          })
      })
    }
  }
  return {
    uploadUrl,
    httpRequest
  }
}
/**
 * 创建文件信息
 * @param vo 文件预签名信息
 * @param name 文件名称
 * @param file 文件
 */
function createFile(vo: FileApi.FilePresignedUrlRespVO, name: string, file: UploadRawFile) {
  const fileVo = {
    configId: vo.configId,
    url: vo.url,
    path: name,
    name: file.name,
    type: file.type,
    size: file.size
  }
  FileApi.createFile(fileVo)
  return fileVo
}
/**
 * 生成文件名称(使用算法SHA256)
 * @param file 要上传的文件
 */
async function generateFileName(file: UploadRawFile) {
  // 读取文件内容
  const data = await file.arrayBuffer()
  const wordArray = CryptoJS.lib.WordArray.create(data)
  // 计算SHA256
  const sha256 = CryptoJS.SHA256(wordArray).toString()
  // 拼接后缀
  const ext = file.name.substring(file.name.lastIndexOf('.'))
  return `${sha256}${ext}`
}
/**
 * 上传类型
 */
enum UPLOAD_TYPE {
  // 客户端直接上传(只支持S3服务)
  CLIENT = 'client',
  // 客户端发送到后端上传
  SERVER = 'server'
}
export const useNewUpload = () => {
  // 后端上传地址
  const uploadUrl = import.meta.env.VITE_UPLOAD_URL
  // 是否使用前端直连上传
  const isClientUpload = UPLOAD_TYPE.CLIENT === import.meta.env.VITE_UPLOAD_TYPE
  // 重写ElUpload上传方法
  const httpRequest = async (options: UploadRequestOptions) => {
    // 模式一:前端上传
    if (isClientUpload) {
      // 1.1 生成文件名称
      const fileName = await generateFileName(options.file)
      // 1.2 获取文件预签名地址
      const presignedInfo = await FileApi.getFilePresignedUrl(fileName)
      // 1.3 上传文件(不能使用 ElUpload 的 ajaxUpload 方法的原因:其使用的是 FormData 上传,Minio 不支持)
      return axios.put(presignedInfo.uploadUrl, options.file).then(() => {
        // 1.4. 记录文件信息到后端(异步)
        createFile(presignedInfo, fileName, options.file)
        // 通知成功,数据格式保持与后端上传的返回结果一致
        return { data: presignedInfo.url }
      })
    } else {
      // 模式二:后端上传
      // 重写 el-upload httpRequest 文件上传成功会走成功的钩子,失败走失败的钩子
      return new Promise((resolve, reject) => {
        FileApi.uploadFile({ file: options.file })
          .then((res) => {
            if (res.code === 0) {
              resolve(res)
            } else {
              reject(res)
            }
          })
          .catch((res) => {
            reject(res)
          })
      })
    }
  }
  return {
    uploadUrl,
    httpRequest
  }
}

image.gif

FileApi

import request from '@/config/axios'
export interface FilePageReqVO extends PageParam {
  path?: string
  type?: string
  createTime?: Date[]
}
// 文件预签名地址 Response VO
export interface FilePresignedUrlRespVO {
  // 文件配置编号
  configId: number
  // 文件上传 URL
  uploadUrl: string
  // 文件 URL
  url: string
}
// 查询文件列表
export const getFilePage = (params: FilePageReqVO) => {
  return request.get({ url: '/infra/file/page', params })
}
// 删除文件
export const deleteFile = (id: number) => {
  return request.delete({ url: '/infra/file/delete?id=' + id })
}
// 获取文件预签名地址
export const getFilePresignedUrl = (path: string) => {
  return request.get<FilePresignedUrlRespVO>({
    url: '/infra/file/presigned-url',
    params: { path }
  })
}
// 创建文件
export const createFile = (data: any) => {
  return request.post({ url: '/infra/file/create', data })
}
// 上传文件
export const updateFile = (data: any) => {
  return request.upload({ url: '/infra/file/upload', data })
}
// 上传文件
export const uploadFile = (data: any) => {
  return request.upload({ url: '/infra/file/uploadFile', data })
}

image.gif

数据库

创建一个上传文件的子表,字段如下:

image.gif 编辑

image.gif 编辑

主表字段如下:

image.gif 编辑

后端

项目构成

image.gif 编辑

image.gif 编辑

主表

实体类

package com.todod.education.module.teach.dal.dataobject.researchingmanage;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import com.todod.education.framework.mybatis.core.dataobject.BaseDO;
/**
 * 教研管理 DO
 *
 * @author 平台管理员
 */
@TableName("teach_researching_manage")
@KeySequence("teach_researching_manage_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResearchingManageDO extends BaseDO {
    /**
     * 主键id
     */
    @TableId
    private Long id;
    /**
     * 课程产品 课程id
     */
    private Long courseId;
    /**
     * 标题
     */
    private String title;
    /**
     * 课程类型
     */
    private String courseType;
    /**
     * 课程名称
     */
    @TableField(exist = false)
    private String courseName;
    /**
     * 科目
     *
     */
    private String subject;
    /**
     * 文件类型
     */
    private String fileType;
    /**
     * 附件名称
     */
    private String appendixName;
    /**
     * 附件
     */
    private String appendixFile;
    /**
     * 附件(97:有/98:无)
     */
    private Short fileExists;
    /**
     * 备注
     */
    private String remark;
    /**
     * 教案管理附件id
     */
    @TableField(exist = false)
    private Long teachResearchingManageId;
}

image.gif

ResearchingManageSaveReqVO

package com.todod.education.module.teach.controller.admin.researchingmanage.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageFileDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 教研管理新增/修改 Request VO")
@Data
public class ResearchingManageSaveReqVO {
    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13167")
    private Long id;
    @Schema(description = "课程产品 课程id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13167")
    private Long courseId;
    @Schema(description = "标题", example = "2")
    private String title;
    @Schema(description = "课程类型", example = "2")
    private String courseType;
    @Schema(description = "科目")
    private String subject;
    @Schema(description = "文件类型", example = "2")
    private String fileType;
    @Schema(description = "附件名称", example = "芋艿")
    private String appendixName;
    @Schema(description = "创建人")
    private String creator;
    @Schema(description = "附件(97:有/98:无)", requiredMode = Schema.RequiredMode.REQUIRED)
    @ExcelProperty("附件(97:有/98:无)")
    private Short fileExists;
    @Schema(description = "创建时间")
    private LocalDateTime createTime;
//
//    @Schema(description = "附件")
//    private String appendixFile;
    @Schema(description = "备注")
    private String remark;
    @Schema(description = "备注")
    private String courseName;
//    @Schema(description = "附件子表数据", example = "测试")
//    private List<ResearchingManageFileDO> appendixFile;
    @Schema(description = "附件子表数据", example = "测试")
    private List<ResearchingManageFileDO> fileData;
}

image.gif

ResearchingManageRespVO

package com.todod.education.module.teach.controller.admin.researchingmanage.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
import com.todod.education.framework.excel.core.annotations.DictFormat;
import com.todod.education.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 教研管理 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ResearchingManageRespVO {
    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20302")
    private Long id;
    @Schema(description = "课程产品 课程id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20302")
    private Long courseId;
    @Schema(description = "标题", example = "2")
    @ExcelProperty("标题")
    private String title;
    @Schema(description = "课程名称", example = "2")
    @ExcelProperty("课程名称")
    private String courseName;
    @Schema(description = "课程类型", example = "2")
    @ExcelProperty("课程类型")
    private String courseType;
    @Schema(description = "科目")
    @ExcelProperty(value = "科目", converter = DictConvert.class)
    @DictFormat("subject") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
    private String subject;
    @Schema(description = "文件类型", example = "2")
    @ExcelProperty("文件类型")
    private String fileType;
    @Schema(description = "附件名称", example = "芋艿")
    @ExcelProperty("附件名称")
    private String appendixName;
    @Schema(description = "创建人")
    private Long creator;
    @Schema(description = "创建时间")
    @ExcelProperty("创建时间")
    private LocalDateTime createTime;
    @Schema(description = "最后编辑人")
    private Long updater;
    @Schema(description = "最后编辑时间")
    @ExcelProperty("最后编辑时间")
    private LocalDateTime updateTime;
    @Schema(description = "附件")
    private String appendixFile;
    @Schema(description = "备注")
    private String remark;
    @Schema(description = "教研管理附件id", requiredMode = Schema.RequiredMode.REQUIRED, example = "20302")
    private Long teachResearchingManageId;
    @Schema(description = "附件(97:有/98:无)", requiredMode = Schema.RequiredMode.REQUIRED)
    @ExcelProperty("附件(97:有/98:无)")
    private Short fileExists;
}

image.gif

Mapper

package com.todod.education.module.teach.dal.mysql.researchingmanage;
import com.todod.education.framework.mybatis.core.mapper.BaseMapperX;
import com.todod.education.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageFileDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
 * 教研管理文件 Mapper
 *
 * @author 平台管理员
 */
@Mapper
public interface ResearchingManageFileMapper extends BaseMapperX<ResearchingManageFileDO> {
    /**
     * 获得教研管理附件列表
     *
     * @param teacherResearchingManageId 公函明细
     * @return 教研管理文件明细列表
     */
    default List<ResearchingManageFileDO> getSimpleFileList(Long teacherResearchingManageId) {
        return selectList(new LambdaQueryWrapperX<ResearchingManageFileDO>()
                .eqIfPresent(ResearchingManageFileDO::getTeachResearchingManageId, teacherResearchingManageId)
        );
    }
}

image.gif

service

package com.todod.education.module.teach.service.researchingmanage;
import java.util.*;
import jakarta.validation.*;
import com.todod.education.module.teach.controller.admin.researchingmanage.vo.*;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageDO;
import com.todod.education.framework.common.pojo.PageResult;
import com.todod.education.framework.common.pojo.PageParam;
/**
 * 教研管理 Service 接口
 *
 * @author 平台管理员
 */
public interface ResearchingManageService {
    /**
     * 创建教研管理
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createResearchingManage(@Valid ResearchingManageSaveReqVO createReqVO);
    /**
     * 更新教研管理
     *
     * @param updateReqVO 更新信息
     */
    void updateResearchingManage(@Valid ResearchingManageSaveReqVO updateReqVO);
}

image.gif

package com.todod.education.module.teach.service.researchingmanage;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageFileDO;
import com.todod.education.module.teach.dal.mysql.researchingmanage.ResearchingManageFileMapper;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import com.todod.education.module.teach.controller.admin.researchingmanage.vo.*;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageDO;
import com.todod.education.framework.common.pojo.PageResult;
import com.todod.education.framework.common.pojo.PageParam;
import com.todod.education.framework.common.util.object.BeanUtils;
import com.todod.education.module.teach.dal.mysql.researchingmanage.ResearchingManageMapper;
import static com.todod.education.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.todod.education.module.teach.enums.ErrorCodeConstants.*;
/**
 * 教研管理 Service 实现类
 *
 * @author 平台管理员
 */
@Service
@Validated
public class ResearchingManageServiceImpl implements ResearchingManageService {
    @Resource
    private ResearchingManageMapper researchingManageMapper;
    @Resource
    private ResearchingManageFileMapper researchingManageFileMapper;
    @Override
    public Long createResearchingManage(ResearchingManageSaveReqVO createReqVO) {
        // 插入
        ResearchingManageDO researchingManage = BeanUtils.toBean(createReqVO, ResearchingManageDO.class);
        researchingManageMapper.insert(researchingManage);
        //往文件子表中插入数据
        for (ResearchingManageFileDO fileDO : createReqVO.getFileData()) {
            ResearchingManageFileDO researchingManageFileDO = new ResearchingManageFileDO();
            researchingManageFileDO.setTeachResearchingManageId(researchingManage.getId());
            researchingManageFileDO.setFileId(fileDO.getId());
            researchingManageFileMapper.insert(researchingManageFileDO);
        }
        // 返回
        return researchingManage.getId();
    }
    @Override
    public void updateResearchingManage(ResearchingManageSaveReqVO updateReqVO) {
        // 校验存在
        validateResearchingManageExists(updateReqVO.getId());
        // 更新
        ResearchingManageDO updateObj = BeanUtils.toBean(updateReqVO, ResearchingManageDO.class);
        researchingManageMapper.updateById(updateObj);
        //往文件子表中插入数据
        for (ResearchingManageFileDO fileDO : updateReqVO.getFileData()) {
            ResearchingManageFileDO researchingManageFileDO = new ResearchingManageFileDO();
            researchingManageFileDO.setTeachResearchingManageId(updateObj.getId());
            researchingManageFileDO.setFileId(fileDO.getId());
            researchingManageFileMapper.insert(researchingManageFileDO);
        }
    }
}

image.gif

controller

package com.todod.education.module.teach.controller.admin.researchingmanage;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.*;
import jakarta.validation.*;
import jakarta.servlet.http.*;
import java.util.*;
import java.io.IOException;
import com.todod.education.framework.common.pojo.PageParam;
import com.todod.education.framework.common.pojo.PageResult;
import com.todod.education.framework.common.pojo.CommonResult;
import com.todod.education.framework.common.util.object.BeanUtils;
import static com.todod.education.framework.common.pojo.CommonResult.success;
import com.todod.education.framework.excel.core.util.ExcelUtils;
import com.todod.education.framework.apilog.core.annotation.ApiAccessLog;
import static com.todod.education.framework.apilog.core.enums.OperateTypeEnum.*;
import com.todod.education.module.teach.controller.admin.researchingmanage.vo.*;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageDO;
import com.todod.education.module.teach.service.researchingmanage.ResearchingManageService;
@Tag(name = "管理后台 - 教研管理")
@RestController
@RequestMapping("/teach/researching-manage")
@Validated
public class ResearchingManageController {
    @Resource
    private ResearchingManageService researchingManageService;
    @PostMapping("/create")
    @Operation(summary = "创建教研管理")
    @PreAuthorize("@ss.hasPermission('teach:researching-manage:create')")
    public CommonResult<Long> createResearchingManage(@Valid @RequestBody ResearchingManageSaveReqVO createReqVO) {
        return success(researchingManageService.createResearchingManage(createReqVO));
    }
    @PutMapping("/update")
    @Operation(summary = "更新教研管理")
    @PreAuthorize("@ss.hasPermission('teach:researching-manage:update')")
    public CommonResult<Boolean> updateResearchingManage(@Valid @RequestBody ResearchingManageSaveReqVO updateReqVO) {
        researchingManageService.updateResearchingManage(updateReqVO);
        return success(true);
    }
}

image.gif

子表

实体类

package com.todod.education.module.teach.dal.dataobject.researchingmanage;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.todod.education.framework.mybatis.core.dataobject.BaseDO;
import lombok.*;
/**
 * 教研管理文件 DO
 *
 * @author 平台管理员
 */
@TableName("teach_researching_manage_file")
@KeySequence("teach_researching_manage_file_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResearchingManageFileDO extends BaseDO {
    /**
     * 主键id
     */
    @TableId
    private Long id;
    /**
     * 教研管理id
     */
    private Long teachResearchingManageId;
    /**
     * 附件id
     */
    private Long fileId;
}

image.gif

Mapper

package com.todod.education.module.teach.dal.mysql.researchingmanage;
import com.todod.education.framework.mybatis.core.mapper.BaseMapperX;
import com.todod.education.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.todod.education.module.teach.dal.dataobject.researchingmanage.ResearchingManageFileDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
 * 教研管理文件 Mapper
 *
 * @author 平台管理员
 */
@Mapper
public interface ResearchingManageFileMapper extends BaseMapperX<ResearchingManageFileDO> {
    /**
     * 获得教研管理附件列表
     *
     * @param teacherResearchingManageId 公函明细
     * @return 教研管理文件明细列表
     */
    default List<ResearchingManageFileDO> getSimpleFileList(Long teacherResearchingManageId) {
        return selectList(new LambdaQueryWrapperX<ResearchingManageFileDO>()
                .eqIfPresent(ResearchingManageFileDO::getTeachResearchingManageId, teacherResearchingManageId)
        );
    }
}

image.gif


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
C#文件上传
C#文件上传
60 0
|
10天前
|
存储 PHP 文件存储
32 单文件上传
路老师分享PHP文件上传教程,涵盖配置php.ini、使用$_FILES变量和move_uploaded_file()函数等关键步骤,帮助你轻松实现单文件上传功能。纯干货,技术知识分享。
25 1
|
15天前
|
Java
smartupload文件上传!
使用 `smartupload.jar` 实现文件上传和下载。首先将 `smartupload.jar` 添加到项目中,然后创建上传页面,确保表单使用 `POST` 方法并设置 `enctype=&quot;multipart/form-data&quot;`。接着在服务器端通过 `SmartUpload` 对象处理文件上传,保存文件到指定目录,并获取表单中的其他数据。最后,实现文件下载功能,设置响应头以触发浏览器下载文件。
23 0
|
6月前
|
JSON 数据格式
文件上传~~
文件上传~~
46 0
|
JavaScript 前端开发 移动开发
浅谈文件上传
浅谈文件上传
浅谈文件上传
|
存储 移动开发 JavaScript
|
安全 应用服务中间件 PHP
[SUCTF 2019]CheckIn(文件上传)
[SUCTF 2019]CheckIn(文件上传)
168 0
|
开发框架 安全 JavaScript
文件上传利用总结
文件上传利用总结
365 0
|
JavaScript
你真的了解文件上传吗?
你真的了解文件上传吗?