多个文件上传

news2024/9/20 15:05:15

♥️作者:小宋1021
🤵‍♂️个人主页:小宋1021主页
♥️坚持分析平时学习到的项目以及学习到的软件开发知识,和大家一起努力呀!!!
🎈🎈加油! 加油! 加油! 加油
🎈欢迎评论 💬点赞👍🏻 收藏 📂加关注+


目录

​编辑

前端

html

js

useNewUpload.ts

FileApi

数据库

后端

项目构成

主表

实体类

ResearchingManageSaveReqVO

ResearchingManageRespVO

Mapper

service

controller

子表

实体类

Mapper


前端

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>

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()
}

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
  }
}

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

数据库

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

主表字段如下:

后端

项目构成

主表

实体类

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

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;



}

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;

}

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


}

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

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

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

子表

实体类

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;


}

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


}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【书生大模型实战营】LMDeploy 量化部署进阶实践

LMDeploy 量化部署进阶实践 【书生大模型实战营】LMDeploy 量化部署进阶实践任务环境将大模型封装为API接口服务以命令行形式连接API服务器以Gradio网页形式连接API服务器 LMDeploy Lite和InternLMkv cacheW4A16 模型量化和部署W4A16 量化 KV cacheKV cache 量化 LMDeploy与Int…

【JavaEE】MyBatis 实战指南:从 JDBC 到高效数据库操作的进阶教程

目录 MyBatis 操作数据库JDBC 操作⽰例回顾什么是MyBatis?MyBatis⼊⻔1. 准备⼯作2. 配置数据库连接字符串3. 写持久层代码4. 单元测试使用MyBatis可能遇到的问题 MyBatis的基础操作打印⽇志参数传递增(Insert)返回主键 删(Delete)改(Update)查(Select)起别名结果映射开启驼峰…

vue使用高德获取当前地区天气

1、收件箱 | 高德控制台 (amap.com) 首先打开高德开放平台注册一下 2、创建一个应用获取到key后面获取天气的时候 请求接口的时候会用到key 2.1.1 创建应用的时候注意类型选成天气 2.1.2 创建完成之后就点添加key 然后选择web服务就行 3、可以调取天气接口 天气查询-基础 API…

https握手过程详解

https握手过程详解 上一篇《HTTPS通讯全过程》中https握手过程实际上还有更多的细节&#xff0c;为什么会这样设计呢&#xff1f;是因为一开始将握手过程时&#xff0c;吧步骤说的太详细会导致更难理解惹。所以我就先在上一篇把部分细节忽略&#xff0c;把原来几步的过程先简化…

洛杉物理服务器怎么样?

洛杉矶作为美国科技和互联网的重要中心&#xff0c;物理服务器的质量通常非常高&#xff0c;可以提供卓越的性能、强大的安全性、多样的配置选项和专业的服务支持。以下是对洛杉物理服务器的详细介绍。 1. 优质的性能 稳定的网络连接&#xff1a;洛杉矶物理服务器位于先进的数据…

CASS11时空版 全新升级支持多版本CAD软件下载License使用

南方数码地形地籍成图软件CASS&#xff0c;经过二十余年的发展&#xff0c;市场和技术积累丰厚&#xff0c;用户遍及国内外测绘地理信息相关行业。软件销量和市场占有率持续领先&#xff0c;是业内应用广&#xff0c;服务优的软件品牌。 南方数码深刻理解信息化测绘的内…

合宙LuatOS生成毫秒级时间戳

合宙Luatos - os操作 os.time()生成时间戳的精度只能达到秒级&#xff0c;在很多联网应用中需要毫秒级的时间戳。 经查看LuatOS-SOC接口文档&#xff0c;发现了解决办法。 socket - 网络接口文档 通过文档&#xff0c;我们只要获取当前数&#xff0c;然后把毫秒数与os.time(…

【C语言】:字符和字符串中的字符比较

1.入门 当我们想要一个字符和字符串中的某个字符进行比较时&#xff0c;可以直接用“”进行比较。 为什么可以用“”&#xff1f; 因为字符是存放在常量区&#xff0c;字符变量的值是固定的&#xff0c;字符之间的比较&#xff0c;本质上是对字符的ASCII比较。ASCII_百度百科…

FinalData-绿色便携免安装数据恢复软件 下载

下载地址(资源制作整理不易&#xff0c;使用需付费&#xff0c;不能接受请勿浪费时间下载)&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/17CH5tkSc2qAj-6FuGvfb9Q?pwdvyze 提取码&#xff1a;vyze

基于Java语言的能源管理系统-水电气热油数据采集系统

基于Java语言的能源管理系统-水电气热油数据采集系统 介绍 适用于高能耗企业、建筑、工厂、园区的水、电、气、热、油、空压机等能源数据采集、分析、报表&#xff1b; 基于SpringCloud的能源管理系统-能源管理平台源码-能源在线监测平台-双碳平台源码-SpringCloud全家桶-能管…

string模拟

本章准备对string模拟进行讲解&#xff0c;以下是string的学习网址&#xff1a; string - C Reference (cplusplus.com) string本质可以理解为储存char类型的顺序表&#xff0c;其中string的迭代器用一个char*就可以解决。所以string类成员变量如下&#xff1a; 这里用了一个命…

PumpkinRaising靶机

端口扫描 目录扫描 访问80端口&#xff0c; 在页面上面发现提到了一个Jack&#xff0c;可能是一个用户名 f12查看源码 找到一个页面 拼接访问 查看源码 发现一个注释 解密 是一个目录 /scripts/spy.pcap 访问&#xff0c;自动下载了一个文件 wireshark打开流量包 找到第一个s…

Element plus部分组件样式覆盖记录

文章目录 一、el-button 样式二、Popconfirm 气泡确认框三、Popover 气泡卡片四、Checkbox 多选框五、Pagination 分页六、Form 表单七、Table 表格 一、el-button 样式 html&#xff1a; <el-button class"com_btn_style">button</el-button>样式覆盖…

端口隔离 Port isolation 华为交换机配置端口隔离

Port isolation 什么是端口隔离 如果用户想进行二层隔离&#xff0c;用户可以将不同的端口加入不同的VLAN&#xff0c;但这样会浪费有限的VLAN资源。采用端口隔离功能&#xff0c;可以实现同一VLAN内端口之间的隔离。用户只需要将端口加入到隔离组中&#xff0c;就可以实现隔离…

hyper-v连接显卡,hyper-v使用显卡能力、Hyper-V显卡虚拟化VMGpu设置

hyper-v连接显卡&#xff0c;hyper-v使用显卡能力、Hyper-V显卡虚拟化VMGpu设置 现在越来越多的软件在使用时&#xff0c;都会调用GPU获得更好的使用效果。如&#xff1a;浏览器的硬件加速模式。由于Nvidia和AMD都屏蔽了家用显卡虚拟化技术&#xff0c;常用的虚拟机也无法对显卡…

交互式散点图,快速提升你的PPT观赏性|每日科研绘图·24-08-17

一、散点图基础概念 散点图是一种非常直观且功能强大的图表&#xff0c;用于探索和展示两个数值变量之间的相关性。这种图表通过在二维平面上绘制数据点&#xff0c;使得观察者能够一眼看出变量间的潜在联系。 1-1&#xff1a;散点图的构成 X轴&#xff08;横轴&#xff09;&…

电话语音机器人优势很多

智能语音机器人近年来备受关注&#xff0c;受到很多个人或是企业的青睐&#xff0c;其广泛受到欢迎归因于智能语音机器人对电话销售提供了极大的帮助&#xff0c;其可以完美替代人工进行电销外呼服务&#xff0c;不间断的工作&#xff0c;不带有任何情绪色彩&#xff0c;且能实…

Hive:大数据时代的SQL魔法师

时间&#xff1a;2024年08月17日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 音频地址&#xff1a;https://xima.tv/1_ZRh54d?_sonic0 希望大家帮个忙&#xff01;如果大家有工作机会&#xff0c;希望帮小蒋内推一下&#x…

半岛体存储器常见类型简介

前言 个人邮箱&#xff1a;zhangyixu02gmail.com在学习 ESP32 的存储器结构时&#xff0c;发现 DRAM 是 Data RAM 而非 Dynamic RAM&#xff0c;IRAM 是 Instruction RAM 而非 Internal RAM 。突然发现自己对于这一块的知识还比较混乱&#xff0c;因此查阅相关资料进行学习整理…

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(一)---UnrealCV获取深度+分割图像

前言 本系列教程旨在使用UE5配置一个具备激光雷达深度摄像机的仿真小车&#xff0c;并使用通过跨平台的方式进行ROS2和UE5仿真的通讯&#xff0c;达到小车自主导航的目的。本教程使用的环境&#xff1a; ubuntu 22.04 ros2 humblewindows11 UE5.4.3python8 本系列教程将涉及以…