day4--上傳圖片、視頻

1.?分布式文件系統

1.1?什么是分布式文件系統

????????文件系統是負責管理和存儲文件的系統軟件,操作系統通過文件系統提供的接口去存取文件,用戶通過操作系統訪問磁盤上的文件。

????????下圖指示了文件系統所處的位置:

常見的文件系統:FAT16/FAT32、NTFS、HFS、UFS、APFS、XFS、Ext4等 。

????????現在有個問題,一此短視頻平臺擁有大量的視頻、圖片,這些視頻文件、圖片文件該如何存儲呢?如何存儲可以滿足互聯網上海量用戶的瀏覽。

????????通過分布式文件系統實現海量用戶查閱海量文件

好處

1、一臺計算機的文件系統處理能力擴充到多臺計算機同時處理。

2、一臺計算機掛了還有另外副本計算機提供數據。

3、每臺計算機可以放在不同的地域,這樣用戶就可以就近訪問,提高訪問速度。

1.2 MinIo

1.2.1 介紹

????????本項目采用MinIO構建分布式文件系統,MinIO 是一個非常輕量的服務,可以很簡單的和其他應用的結合使用,它兼容亞馬遜 S3 云存儲服務接口,非常適合于存儲大容量非結構化的數據,例如圖片、視頻、日志文件、備份數據和容器/虛擬機鏡像等。

????????它一大特點就是輕量,使用簡單,功能強大,支持各種平臺,單個文件最大5TB,兼容 Amazon S3接口,提供了 Java、Python、GO等多版本SDK支持。

官網:https://min.io

中文:https://www.minio.org.cn/,http://docs.minio.org.cn/docs/

????????在大數據領域,通常的設計理念都是無中心和分布式。Minio分布式模式可以幫助你搭建一個高可用的對象存儲服務,你可以使用這些存儲設備,而不用考慮其真實物理位置。

????????它將分布在不同服務器上的多塊硬盤組成一個對象存儲服務。由于硬盤分布在不同的節點上,分布式Minio避免了單點故障。如下圖:

1.2.2?測試Docker環境

開發階段和生產階段統一使用Docker下的MINIO。

????????虛擬機中已安裝了MinIO的鏡像和容器,執行sh /data/soft /restart.sh啟動Docker下的MinIO

啟動完成登錄MinIO查看是否正常。訪問 http://192.168.101.65:9000,賬號和密碼為:minioadmin / minioadmin

本項目創建兩個buckets:

mediafiles: 普通文件

video:視頻文件

1.2.4 SDK

1)上傳文件

MinIO提供多個語言版本SDK的支持,下邊找到java版本的文檔:

地址:https://docs.min.io/docs/java-client-quickstart-guide.html

  • media-service工程中導入依賴

<dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.4.3</version>
</dependency>
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.8.1</version>
</dependency>

參數說明:

需要三個參數才能連接到minio服務。

參數說明
Endpoint對象存儲服務的URL
Access KeyAccess key就像用戶ID,可以唯一標識你的賬戶。
Secret KeySecret key是你賬戶的密碼。
  • 創建一個桶進行測試

  • 在xuecheng-plus-media-service工程 的test下編寫測試代碼如下

package com.xuecheng.media;import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import io.minio.*;
import io.minio.errors.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;/*** 測試 minio*/
public class MinioTest {MinioClient minioClient =MinioClient.builder().endpoint("http://192.168.101.65:9000").credentials("minioadmin", "minioadmin").build();@Testpublic void test_upload() throws Exception {//通過擴展名得到媒體資源類型 mimeType//根據擴展名取出mimeTypeContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(".jpg");String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字節流if(extensionMatch!=null){mimeType = extensionMatch.getMimeType();}//上傳文件的參數信息UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket("testbucket")//桶.filename("D:\\學習\\images\\3.jpg") //指定本地文件路徑
//                .object("3.jpg")//對象名 在桶下存儲該文件.object("test/01/3.jpg")//對象名 放在子目錄下.contentType(mimeType)//設置媒體文件類型.build();//上傳文件minioClient.uploadObject(uploadObjectArgs);}//刪除文件@Testpublic void test_delete() throws Exception {//RemoveObjectArgsRemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket("testbucket").object("3.jpg").build();//刪除文件minioClient.removeObject(removeObjectArgs);}//查詢文件 從minio中下載@Testpublic void test_getFile() throws Exception {GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket("testbucket").object("test/01/1.mp4").build();//查詢遠程服務獲取到一個流對象FilterInputStream inputStream = minioClient.getObject(getObjectArgs);//指定輸出流FileOutputStream outputStream = new FileOutputStream(new File("D:\\develop\\upload\\1a.mp4"));IOUtils.copy(inputStream,outputStream);//校驗文件的完整性對文件的內容進行md5FileInputStream fileInputStream1 = new FileInputStream(new File("D:\\develop\\upload\\1.mp4"));String source_md5 = DigestUtils.md5Hex(fileInputStream1);FileInputStream fileInputStream = new FileInputStream(new File("D:\\develop\\upload\\1a.mp4"));String local_md5 = DigestUtils.md5Hex(fileInputStream);if(source_md5.equals(local_md5)){System.out.println("下載成功");}}}

2. 上傳圖片

2.1 需求分析

2.1.1 業務流程

????????課程圖片是宣傳課程非常重要的信息,在新增課程界面上傳課程圖片,也可以修改課程圖片。

上傳課程圖片總體上包括兩部分:

  • 上傳課程圖片前端請求媒資管理服務將文件上傳至分布式文件系統,并且在媒資管理數據庫保存文件信息。
  • 上傳圖片成功保存圖片地址到課程基本信息表中。

詳細流程如下:

  • 前端進入上傳圖片界面
  • 上傳圖片,請求媒資管理服務。
  • 媒資管理服務將圖片文件存儲在MinIO。
  • 媒資管理記錄文件信息到數據庫。
  • 前端請求內容管理服務保存課程信息,在內容管理數據庫保存圖片地址。

2.1.2 數據模型

????????涉及到的數據表有:課程信息表中的圖片字段、媒資數據庫的文件表,下邊主要看媒資數據庫的文件表。

2.2 準備

????????首先在minio配置bucket,bucket名稱為:mediafiles,并設置bucket的權限為公開

????????在nacos配置中minio的相關信息,進入media-service-dev.yaml:

minio:endpoint: http://192.168.101.65:9000accessKey: minioadminsecretKey: minioadminbucket:files: mediafilesvideofiles: video

????????在media-service工程編寫minio的配置類

package com.xuecheng.media.config;import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** minio配置類*/
@Configuration
public class MinioConfig {@Value("${minio.endpoint}")private String endpoint;@Value("${minio.accessKey}")private String accessKey;@Value("${minio.secretKey}")private String secretKey;@Beanpublic MinioClient minioClient() {// 創建Minio客戶端實例,使用endpoint、accessKey和secretKey進行配置MinioClient minioClient =MinioClient.builder().endpoint(endpoint) // 設置Minio服務地址.credentials(accessKey, secretKey) // 設置訪問憑證.build(); // 構建客戶端實例return minioClient; // 返回構建好的Minio客戶端}}

2.3 接口定義

????????根據需求分析,下邊進行接口定義,此接口定義為一個通用的上傳文件接口,可以上傳圖片或其它文件。

請求地址:/media/upload/coursefile

請求內容Content-Type: multipart/form-data;

form-data; name="filedata"; filename="具體的文件名稱"

響應參數:文件信息,如下

{"id": "a16da7a132559daf9e1193166b3e7f52","companyId": 1232141425,"companyName": null,"filename": "1.jpg","fileType": "001001","tags": "","bucket": "/testbucket/2022/09/12/a16da7a132559daf9e1193166b3e7f52.jpg","fileId": "a16da7a132559daf9e1193166b3e7f52","url": "/testbucket/2022/09/12/a16da7a132559daf9e1193166b3e7f52.jpg","timelength": null,"username": null,"createDate": "2022-09-12T21:57:18","changeDate": null,"status": "1","remark": "","auditStatus": null,"auditMind": null,"fileSize": 248329
}
  • 定義上傳響應模型類

package com.xuecheng.media.model.dto;import com.xuecheng.media.model.po.MediaFiles;
import lombok.Data;
import lombok.ToString;@Data
@ToString
public class UploadFileResultDto extends MediaFiles {}
  • controller層接口

? ? ? ? 前端傳過來的文件名稱是filedata

package com.xuecheng.media.api;import com.xuecheng.base.model.PageParams;
import com.xuecheng.base.model.PageResult;
import com.xuecheng.media.model.dto.QueryMediaParamsDto;
import com.xuecheng.media.model.dto.UploadFileParamsDto;
import com.xuecheng.media.model.dto.UploadFileResultDto;
import com.xuecheng.media.model.po.MediaFiles;
import com.xuecheng.media.service.MediaFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;/*** 媒資文件管理接口*/@Api(value = "媒資文件管理接口",tags = "媒資文件管理接口")@RestController
public class MediaFilesController {@AutowiredMediaFileService mediaFileService;@ApiOperation("媒資列表查詢接口")@PostMapping("/files")public PageResult<MediaFiles> list(PageParams pageParams, @RequestBody QueryMediaParamsDto queryMediaParamsDto){Long companyId = 1232141425L;return mediaFileService.queryMediaFiels(companyId,pageParams,queryMediaParamsDto);}@ApiOperation("上傳圖片")@RequestMapping(value = "/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public UploadFileResultDto upload(@RequestPart("filedata")MultipartFile filedata) throws IOException {//準備上傳文件的信息UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();//原始文件名稱uploadFileParamsDto.setFilename(filedata.getOriginalFilename());//文件大小uploadFileParamsDto.setFileSize(filedata.getSize());//文件類型uploadFileParamsDto.setFileType("001001");//創建一個臨時文件File tempFile = File.createTempFile("minio", ".temp");filedata.transferTo(tempFile);Long companyId = 1232141425L;//文件路徑String localFilePath = tempFile.getAbsolutePath();//調用service上傳圖片UploadFileResultDto uploadFileResultDto = mediaFileService.uploadFile(companyId, uploadFileParamsDto, localFilePath);return uploadFileResultDto;}}

2.4 接口開發

2.4.1 Dao層

  • mapper層
@Mapper
public interface MediaFilesMapper extends BaseMapper<MediaFiles> {}
  • sql映射
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xuecheng.media.mapper.MediaFilesMapper"><!-- 通用查詢映射結果 --><resultMap id="BaseResultMap" type="com.xuecheng.media.model.po.MediaFiles"><id column="id" property="id" /><result column="company_id" property="companyId" /><result column="company_name" property="companyName" /><result column="filename" property="filename" /><result column="file_type" property="fileType" /><result column="tags" property="tags" /><result column="bucket" property="bucket" /><result column="file_id" property="fileId" /><result column="url" property="url" /><result column="timelength" property="timelength" /><result column="username" property="username" /><result column="create_date" property="createDate" /><result column="change_date" property="changeDate" /><result column="status" property="status" /><result column="remark" property="remark" /><result column="audit_status" property="auditStatus" /><result column="audit_mind" property="auditMind" /></resultMap><!-- 通用查詢結果列 --><sql id="Base_Column_List">id, company_id, company_name, filename, file_type, tags, bucket, file_id, url, timelength, username, create_date, change_date, status, remark, audit_status, audit_mind</sql></mapper>

2.4.2 Service層

1)定義請求參數類

@Data
@ToString
public class UploadFileParamsDto {/*** 文件名稱*/private String filename;/*** 文件類型(文檔,音頻,視頻)*/private String fileType;/*** 文件大小*/private Long fileSize;/*** 標簽*/private String tags;/*** 上傳人*/private String username;/*** 備注*/private String remark;}
2)定義service方法
 /*** 上傳文件* @param companyId 機構id* @param uploadFileParamsDto 文件信息* @param localFilePath 文件本地路徑* @return UploadFileResultDto*/public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath);
3)impl實現類實現service接口,重寫方法

?


@Autowired
MinioClient minioClient;@Autowired
MediaFilesMapper mediaFilesMapper;//普通文件桶
@Value("${minio.bucket.files}")
private String bucket_Files;//獲取文件默認存儲目錄路徑 年/月/日
private String getDefaultFolderPath() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String folder = sdf.format(new Date()).replace("-", "/")+"/";return folder;
}//獲取文件的md5
private String getFileMd5(File file) {try (FileInputStream fileInputStream = new FileInputStream(file)) {String fileMd5 = DigestUtils.md5Hex(fileInputStream);return fileMd5;} catch (Exception e) {e.printStackTrace();return null;}
}private String getMimeType(String extension){if(extension==null)extension = "";//根據擴展名取出mimeTypeContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);//通用mimeType,字節流String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;if(extensionMatch!=null){mimeType = extensionMatch.getMimeType();}return mimeType;
}
/*** @description 將文件寫入minIO* @param localFilePath  文件地址* @param bucket  桶* @param objectName 對象名稱*/
public boolean addMediaFilesToMinIO(String localFilePath,String mimeType,String bucket, String objectName) {try {UploadObjectArgs testbucket = UploadObjectArgs.builder().bucket(bucket).object(objectName).filename(localFilePath).contentType(mimeType).build();minioClient.uploadObject(testbucket);log.debug("上傳文件到minio成功,bucket:{},objectName:{}",bucket,objectName);System.out.println("上傳成功");return true;} catch (Exception e) {e.printStackTrace();log.error("上傳文件到minio出錯,bucket:{},objectName:{},錯誤原因:{}",bucket,objectName,e.getMessage(),e);XueChengPlusException.cast("上傳文件到文件系統失敗");}return false;
}/*** @description 將文件信息添加到文件表* @param companyId  機構id* @param fileMd5  文件md5值* @param uploadFileParamsDto  上傳文件的信息* @param bucket  桶* @param objectName 對象名稱* @return com.xuecheng.media.model.po.MediaFiles*/
@Transactional
public MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName){//從數據庫查詢文件MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);if (mediaFiles == null) {mediaFiles = new MediaFiles();//拷貝基本信息BeanUtils.copyProperties(uploadFileParamsDto, mediaFiles);mediaFiles.setId(fileMd5);mediaFiles.setFileId(fileMd5);mediaFiles.setCompanyId(companyId);mediaFiles.setUrl("/" + bucket + "/" + objectName);mediaFiles.setBucket(bucket);mediaFiles.setFilePath(objectName);mediaFiles.setCreateDate(LocalDateTime.now());mediaFiles.setAuditStatus("002003");mediaFiles.setStatus("1");//保存文件信息到文件表int insert = mediaFilesMapper.insert(mediaFiles);if (insert < 0) {log.error("保存文件信息到數據庫失敗,{}",mediaFiles.toString());XueChengPlusException.cast("保存文件信息失敗");}log.debug("保存文件信息到數據庫成功,{}",mediaFiles.toString());}return mediaFiles;}
@Transactional
@Override
public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath) {File file = new File(localFilePath);if (!file.exists()) {XueChengPlusException.cast("文件不存在");}//文件名稱String filename = uploadFileParamsDto.getFilename();//文件擴展名String extension = filename.substring(filename.lastIndexOf("."));//文件mimeTypeString mimeType = getMimeType(extension);//文件的md5值String fileMd5 = getFileMd5(file);//文件的默認目錄String defaultFolderPath = getDefaultFolderPath();//存儲到minio中的對象名(帶目錄)String  objectName = defaultFolderPath + fileMd5 + exension;//將文件上傳到minioboolean b = addMediaFilesToMinIO(localFilePath, mimeType, bucket_files, objectName);//文件大小uploadFileParamsDto.setFileSize(file.length());//將文件信息存儲到數據庫MediaFiles mediaFiles = addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);//準備返回數據UploadFileResultDto uploadFileResultDto = new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles, uploadFileResultDto);return uploadFileResultDto;}

2.5 前后端聯調測試

?

2.6 代碼優化

????????目前是在uploadFile方法上添加@Transactional,當調用uploadFile方法前會開啟數據庫事務,如果上傳文件過程時間較長那么數據庫的事務持續時間就會變長,這樣數據庫鏈接釋放就慢,最終導致數據庫鏈接不夠用。

????????我們只將addMediaFilesToDb方法添加事務控制即可,uploadFile方法上的@Transactional注解去掉。

方法上已經添加了@Transactional注解為什么該方法不能被事務控制呢?

如果是在uploadFile方法上添加@Transactional注解就可以控制事務,去掉則不行。

????????現在的問題其實是一個非事務方法調同類一個事務方法,事務無法控制,這是為什么?

原因分析如下:

????????如果在uploadFile方法上添加@Transactional注解,代理對象執行此方法前會開啟事務,如下圖

?????????如果在uploadFile方法上沒有@Transactional注解,代理對象執行此方法前不進行事務控制,如下圖:

????????所以判斷該方法是否可以事務控制必須保證是通過代理對象調用此方法,且此方法上添加了@Transactional注解?。現在在addMediaFilesToDb方法上添加@Transactional注解,也不會進行事務控制是因為并不是通過代理對象執行的addMediaFilesToDb方法。為了判斷在uploadFile方法中去調用addMediaFilesToDb方法是否是通過代理對象去調用,我們可以打斷點跟蹤

????????我們發現在uploadFile方法中去調用addMediaFilesToDb方法不是通過代理對象去調用?

解決方法是在MediaFileService的實現類中注入MediaFileService的代理對象,將addMediaFilesToDb方法提成接口

完整代碼如下:

@Slf4j
@Service
public class MediaFileServiceImpl implements MediaFileService {@Autowiredprivate MediaFilesMapper mediaFilesMapper;@AutowiredMinioClient minioClient;@AutowiredMediaFileService currentProxy;//存儲普通文件@Value("${minio.bucket.files}")private String bucket_mediafiles;//存儲視頻@Value("${minio.bucket.videofiles}")private String bucket_video;@Overridepublic PageResult<MediaFiles> queryMediaFiels(Long companyId, PageParams pageParams, QueryMediaParamsDto queryMediaParamsDto) {//構建查詢條件對象LambdaQueryWrapper<MediaFiles> queryWrapper = new LambdaQueryWrapper<>();//分頁對象Page<MediaFiles> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());// 查詢數據內容獲得結果Page<MediaFiles> pageResult = mediaFilesMapper.selectPage(page, queryWrapper);// 獲取數據列表List<MediaFiles> list = pageResult.getRecords();// 獲取數據總數long total = pageResult.getTotal();// 構建結果集PageResult<MediaFiles> mediaListResult = new PageResult<>(list, total, pageParams.getPageNo(), pageParams.getPageSize());return mediaListResult;}//根據擴展名獲取mimeTypeprivate String getMimeType(String extension){if(extension == null){extension = "";}//根據擴展名取出mimeTypeContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字節流if(extensionMatch!=null){mimeType = extensionMatch.getMimeType();}return mimeType;}/*** 將文件上傳到minio* @param localFilePath 文件本地路徑* @param mimeType 媒體類型* @param bucket 桶* @param objectName 對象名* @return*/public boolean addMediaFilesToMinIO(String localFilePath,String mimeType,String bucket, String objectName){try {UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder().bucket(bucket)//桶.filename(localFilePath) //指定本地文件路徑.object(objectName)//對象名 放在子目錄下.contentType(mimeType)//設置媒體文件類型.build();//上傳文件minioClient.uploadObject(uploadObjectArgs);log.debug("上傳文件到minio成功,bucket:{},objectName:{},錯誤信息:{}",bucket,objectName);return true;} catch (Exception e) {e.printStackTrace();log.error("上傳文件出錯,bucket:{},objectName:{},錯誤信息:{}",bucket,objectName,e.getMessage());}return false;}//獲取文件默認存儲目錄路徑 年/月/日private String getDefaultFolderPath() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String folder = sdf.format(new Date()).replace("-", "/")+"/";return folder;}//獲取文件的md5private String getFileMd5(File file) {try (FileInputStream fileInputStream = new FileInputStream(file)) {String fileMd5 = DigestUtils.md5Hex(fileInputStream);return fileMd5;} catch (Exception e) {e.printStackTrace();return null;}}@Overridepublic UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath) {//文件名String filename = uploadFileParamsDto.getFilename();//先得到擴展名String extension = filename.substring(filename.lastIndexOf("."));//得到mimeTypeString mimeType = getMimeType(extension);//子目錄String defaultFolderPath = getDefaultFolderPath();//文件的md5值String fileMd5 = getFileMd5(new File(localFilePath));String objectName = defaultFolderPath+fileMd5+extension;//上傳文件到minioboolean result = addMediaFilesToMinIO(localFilePath, mimeType, bucket_mediafiles, objectName);if(!result){XueChengPlusException.cast("上傳文件失敗");}//入庫文件信息MediaFiles mediaFiles = currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_mediafiles, objectName);if(mediaFiles==null){XueChengPlusException.cast("文件上傳后保存信息失敗");}//準備返回的對象UploadFileResultDto uploadFileResultDto = new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles,uploadFileResultDto);return uploadFileResultDto;}/*** @description 將文件信息添加到文件表* @param companyId  機構id* @param fileMd5  文件md5值* @param uploadFileParamsDto  上傳文件的信息* @param bucket  桶* @param objectName 對象名稱*/@Transactionalpublic MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName){//將文件信息保存到數據庫MediaFiles mediaFiles = mediaFilesMapper.selectById(fileMd5);if(mediaFiles == null){mediaFiles = new MediaFiles();BeanUtils.copyProperties(uploadFileParamsDto,mediaFiles);//文件idmediaFiles.setId(fileMd5);//機構idmediaFiles.setCompanyId(companyId);//桶mediaFiles.setBucket(bucket);//file_pathmediaFiles.setFilePath(objectName);//file_idmediaFiles.setFileId(fileMd5);//urlmediaFiles.setUrl("/"+bucket+"/"+objectName);//上傳時間mediaFiles.setCreateDate(LocalDateTime.now());//狀態mediaFiles.setStatus("1");//審核狀態mediaFiles.setAuditStatus("002003");//插入數據庫int insert = mediaFilesMapper.insert(mediaFiles);if(insert<=0){log.debug("向數據庫保存文件失敗,bucket:{},objectName:{}",bucket,objectName);return null;}return mediaFiles;}return mediaFiles;}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88765.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88765.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88765.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

極矢量與軸矢量

物理量分為標量和矢量&#xff0c;矢量又分為極矢量和軸矢量。 矢量是既有大小又有方向并按平行四邊形法則相加的量。矢量有極矢量和軸矢量兩種&#xff0c;其間的區別是在鏡像反射變換下遵循不同的變換規律,許多物理量都是矢量,同樣,其中也有極矢量和軸矢量的區分,在力學中,例…

文章發布易優CMS(Eyoucms)網站技巧

為了更快的上手數據采集及發布到易優CMS(eyoucms)網站&#xff0c;特地總結了些新手常常會遇到的操作問題與技巧&#xff0c;如下&#xff1a; 免費易優CMS采集發布插件下載&#xff0c;兼容火車頭、八爪魚、簡數采集等 目錄 1. 發布到易優CMS指定欄目 2. 發布文章到易優CM…

INA226 數據手冊解讀

INA226是一款數字電流檢測放大器&#xff0c;配備I2C和SMBus兼容接口。該器件可提供數字電流、電壓以及功率讀數&#xff0c;可靈活配置測量分辨率&#xff0c;并具備連續運行與觸發操作模式。該芯片通常由一個單獨的電源供電&#xff0c;電壓范圍為 2.7V 至 5.5V引腳說明??引…

Linux 中替換sed

以下是關于 sed&#xff08;Stream Editor&#xff09;的深度詳解和日常高頻使用場景&#xff0c;結合實用示例說明&#xff1a;一、sed 核心概念 流式編輯器&#xff1a;逐行處理文本&#xff0c;不直接修改源文件&#xff08;除非使用 -i 選項&#xff09;正則支持&#xff1…

ADB 調試日志全攻略:如何開啟與關閉 `ADB_TRACE` 日志

ADB 調試日志全攻略&#xff1a;如何開啟與關閉 ADB_TRACE 日志 ADB&#xff08;Android Debug Bridge&#xff09;是 Android 開發的核心工具&#xff0c;但在排查問題時&#xff0c;默認日志可能不夠詳細。通過設置環境變量 ADB_TRACE&#xff0c;可以開啟 全量調試日志&…

實現druid數據源密碼加密

生成加密密碼集成了druid鏈接池的&#xff0c;可以實現數據源密碼加密。加密方式如下構建單元測試&#xff0c;并輸入密碼即可生成加密密碼以及加密公鑰Test public void testPwd() throws Exception {String password "123456";String[] arr com.alibaba.druid.fi…

【TCP/IP】20. 因特網安全

20. 因特網安全20. 因特網安全20.1 安全威脅20.2 安全服務20.3 基本安全技術20.3.1 密碼技術20.3.2 報文鑒別技術20.3.3 身份認證技術20.3.4 數字簽名技術20.3.5 虛擬專用網&#xff08;VPN&#xff09;技術20.3.6 防火墻技術20.3.7 防病毒技術20.4 IP 層安全20.5 傳輸層安全20…

數據結構之位圖和布隆過濾器

系列文章目錄 數據結構之ArrayList_arraylist o(1) o(n)-CSDN博客 數據結構之LinkedList-CSDN博客 數據結構之棧_棧有什么方法-CSDN博客 數據結構之隊列-CSDN博客 數據結構之二叉樹-CSDN博客 數據結構之優先級隊列-CSDN博客 常見的排序方法-CSDN博客 數據結構之Map和Se…

Web攻防-PHP反序列化魔術方法觸發條件POP鏈構造變量屬性修改黑白盒角度

知識點&#xff1a; 1.WEB攻防-PHP反序列化-序列化和反序列化 2.WEB攻防-PHP反序列化-常見魔術方法觸發規則 3.WEB攻防-PHP反序列化-反序列化漏洞產生原因 4.WEB攻防-PHP反序列化-黑白盒&POP鏈構造 一、演示案例-WEB攻防-PHP反序列化-序列化和反序列化 什么是反序列化操作…

C# VB.NET多進程-管道通信,命名管道(Named Pipes)

要向已運行的進程發送特定命令&#xff08;如/exit&#xff09;&#xff0c;而不是啟動新進程&#xff0c;需要使用進程間通信&#xff08;IPC&#xff09;機制。以下是幾種常見的實現方法&#xff1a;一、使用命名管道&#xff08;Named Pipes&#xff09;如果ABC.EXE支持通過…

C++ 右值引用 (Rvalue References)

右值引用是C11引入的革命性特性&#xff0c;它徹底改變了C中資源管理和參數傳遞的方式。下面我將從多個維度深入講解右值引用。一、核心概念1. 值類別(Value Categories)lvalue (左值): 有標識符、可取地址的表達式int x 10; // x是左值 int* p &x; // 可以取地址rvalue…

反激變換器設計全流程(一)——電路拓撲及工作流程

一、電路拓撲原理 拓撲結構概述 開關反激電源采用反激式拓撲結構&#xff0c;主要由開關管&#xff08;通常為 MOSFET&#xff09;、變壓器、輸出整流二極管、輸出濾波電容以及控制電路等組成。其基本工作原理是通過開關管的周期性開關動作&#xff0c;將輸入直流電壓轉換為高…

uniapp語音播報天氣預報微信小程序

1.產品展示2.頁面功能(1)點擊上方按鈕實現語音播報4天天氣情況。3.uniapp代碼<template><view class"container"><view class"header"><text class"place">地址:{{city}}</text><text class"time"&g…

Pycharm 報錯 Environment location directory is not empty 如何解決

好長時間不看不寫代碼了&#xff0c;人也跟著犯糊涂。今天在Pycharm 導入虛擬環境時&#xff0c;一直報錯&#xff1a;“Environment location directory is not empty”&#xff0c;在網上百度很多很多方法都無法解決&#xff0c;直到我翻出我之前自己寫的導入虛擬環境的詳細過…

React強大且靈活hooks庫——ahooks入門實踐之場景類(scene)hook詳解

什么是 ahooks&#xff1f; ahooks 是一個 React Hooks 庫&#xff0c;提供了大量實用的自定義 hooks&#xff0c;幫助開發者更高效地構建 React 應用。其中場景類 hooks 是 ahooks 的一個重要分類&#xff0c;專門針對特定業務場景提供解決方案。 安裝 ahooks npm install …

大模型之Langchain篇(二)——RAG

寫在前面 跟著樓蘭老師學習【LangChain教程】2025吃透LangChain框架快速上手與深度實戰&#xff0c;全程干貨無廢話&#xff0c;三天學完&#xff0c;讓你少走百分之99彎路&#xff01;_嗶哩嗶哩_bilibili 計算相似度 一般用的余弦相似度&#xff0c;這里只是演示計算。 fr…

深入理解圖像二值化:從靜態圖像到視頻流實時處理

一、引言&#xff1a;圖像分析&#xff0c;從“黑與白”開始在計算機視覺任務中&#xff0c;**圖像二值化&#xff08;Image Binarization&#xff09;**是最基礎也是最關鍵的圖像預處理技術之一。它通過將灰度圖像中每個像素轉換為兩個離散值&#xff08;通常是0和255&#xf…

云蝠智能 VoiceAgent重構企業呼入場景服務范式

在數字化轉型浪潮中&#xff0c;企業呼入場景面臨客戶服務需求激增與人力成本攀升的雙重挑戰。傳統呼叫中心日均處理僅 300-500 通電話&#xff0c;人力成本占比超 60%&#xff0c;且服務質量受情緒波動影響顯著。云蝠智能推出的 VoiceAgent 語音智能體&#xff0c;通過全棧自研…

java進階(一)+學習筆記

1.JAVA設計模式1.1 什么是設計模式設計模式是軟件開發過程中前輩們在長期實踐中針對重復出現的問題總結出來的最佳解決方案。這些模式不是具體的代碼實現&#xff0c;而是經過驗證的、可重用的設計思想&#xff0c;能夠幫助開發者更高效地解決特定類型的問題。設計模式的重要性…

Pandas-數據清洗與處理

Pandas-數據清洗與處理一、數據清洗的核心目標二、缺失值處理1. 缺失值檢測2. 缺失值處理策略&#xff08;1&#xff09;刪除法&#xff08;2&#xff09;填充法三、異常值識別與處理1. 異常值檢測方法&#xff08;1&#xff09;統計法&#xff08;2&#xff09;業務規則法2. 異…