黑马学成在线-媒资管理

目录

一、媒资需求分析

二、搭建Nacos

三、分布式文件系统介绍

四、上传图片

        1.需求分析 ,上传课程图片总体上包括两部分:

        2.环境准备

        3.接口定义          

        4.数据模型开发

        5.业务层开发

五、上传视频

           1.文件分块的流程如下:

           2.文件合并流程: 

           3.测试文件分块、合并的测试代码

           4.视频上传流程

           5.接口定义,分别定义了:

           6.业务层接口定义

           7.实现业务层service方法       

           8. 分块文件清理问题                

六、视频处理

        1.需求分析

        2.执行流程

        3.环境搭建

        4.视频处理方案

        5.添加待处理任务

        6.查询待处理任务

        7.开始执行任务

        8.更新任务状态

        9.视频处理      

       10.启动任务调度

       11.其它问题。

七、绑定媒资

        1.业务流程分析

        2.接口定义

        3.在内容管理模块定义请求参数模型类型:

        4.在TeachplanService中定义绑定接口

        5.实现Service接口


一、媒资需求分析

        目前媒资管理的主要管理对象是视频、图片、文档等,包括:媒资文件的查询、文件上传、视频处理等。

        媒资查询:教学机构查询自己所拥有的媒资信息。

        文件上传:包括上传图片、上传文档、上传视频。

        视频处理:视频上传成功,系统自动对视频进行编码处理。

        文件删除:教学机构删除自己上传的媒资文件。

二、搭建Nacos

        略(在后续的网关工程会详细介绍)

三、分布式文件系统介绍

        简单理解为:一个计算机无法存储海量的文件,通过网络将若干计算机组织起来共同去存储海量的文件,去接收海量用户的请求,这些组织起来的计算机通过网络进行通信。

        本项目采用MinIO构建分布式文件系统,MinIO 是一个非常轻量的服务,可以很简单的和其他应用的结合使用,MinIO集群采用去中心化共享架构,每个结点是对等关系,通过Nginx可对MinIO进行负载均衡访问。

四、上传图片

        1.需求分析 ,上传课程图片总体上包括两部分:

                 1.1、上传课程图片前端请求媒资管理服务将文件上传至分布式文件系统,并且在媒资管理数据库保存文件信息。

                 1.2、上传图片成功保存图片地址到课程基本信息表中。

        

         2.环境准备

                2.1、首先在minio配置bucket,bucket名称为:mediafiles,并设置bucket的权限为公开。

                2.2、在nacos配置中minio的相关信息,进入media-service-dev.yaml:

minio:
  endpoint: http://192.168.101.65:9000
  accessKey: minioadmin
  secretKey: minioadmin
  bucket:
    files: mediafiles
    videofiles: video

                2.3、在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;

@Configuration
public class MinioConfig {
 @Value("${minio.endpoint}")
 private String endpoint;
 @Value("${minio.accessKey}")
 private String accessKey;
 @Value("${minio.secretKey}")
 private String secretKey;

 @Bean
 public MinioClient minioClient() {

      MinioClient minioClient =
          MinioClient.builder()
                  .endpoint(endpoint)
                  .credentials(accessKey, secretKey)
                  .build();
      return minioClient;
     }
}

        3.接口定义          

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 {

    @Autowired
    MediaFileService mediaFileService;

    @ApiOperation("上传图片")
    @RequestMapping(value = "/upload/coursefile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile filedata,
                                      @RequestParam(value = "objectName", required = false) String objectName) 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, objectName);

        return uploadFileResultDto;
    }
}

        4.数据模型开发

                4.1、定义文件上传的响应模型类

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 {

}

               4.2、定义文件上传的接收数据模型类

package com.xuecheng.media.model.dto;

import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class UploadFileParamsDto {

    /**
     * 文件名称
     */
    private String filename;


    /**
     * 文件类型(文档,音频,视频)
     */
    private String fileType;
    /**
     * 文件大小
     */
    private Long fileSize;

    /**
     * 标签
     */
    private String tags;
    /**
     * 上传人
     */
    private String username;
    /**
     * 备注
     */
    private String remark;

}

        5.业务层开发

                5.1业务层的接口开发

package com.xuecheng.media.service;

import com.xuecheng.base.model.PageParams;
import com.xuecheng.base.model.PageResult;
import com.xuecheng.base.model.RestResponse;
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 io.minio.UploadObjectArgs;
import org.springframework.web.bind.annotation.RequestBody;
import java.io.File;
import java.util.List;

public interface MediaFileService {

 //根据媒资id查询文件信息
 MediaFiles getFileById(String mediaId);


 /**
  * 上传文件
  * @param companyId 机构id
  * @param uploadFileParamsDto 文件信息
  * @param localFilePath 文件本地路径
  * @param objectname 如果传入objectname要按objectname的目录去存储,如果不传就按年月日目录结构去存储
  * @return UploadFileResultDto
  */
 public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath,String objectname);
}

                5.2、实现业务层的service接口

package com.xuecheng.media.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.model.PageParams;
import com.xuecheng.base.model.PageResult;
import com.xuecheng.base.model.RestResponse;
import com.xuecheng.media.mapper.MediaFilesMapper;
import com.xuecheng.media.mapper.MediaProcessMapper;
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.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.DeletedObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class MediaFileServiceImpl implements MediaFileService {

    @Autowired
    MediaFilesMapper mediaFilesMapper;

    @Autowired
    MinioClient minioClient;

    @Autowired
    MediaFileService currentProxy;

    @Autowired
    MediaProcessMapper mediaProcessMapper;

    //存储普通文件
    @Value("${minio.bucket.files}")
    private String bucket_mediafiles;

    //存储视频
    @Value("${minio.bucket.videofiles}")
    private String bucket_video;

        @Override
    public UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath,String objectName) {

        //文件名
        String filename = uploadFileParamsDto.getFilename();
        //先得到扩展名
        String extension = filename.substring(filename.lastIndexOf("."));

        //得到mimeType
        String mimeType = getMimeType(extension);

        //子目录
        String defaultFolderPath = getDefaultFolderPath();
        //文件的md5值
        String fileMd5 = getFileMd5(new File(localFilePath));
        if(StringUtils.isEmpty(objectName)){
            //使用默认年月日去存储
            objectName = defaultFolderPath+fileMd5+extension;
        }
        //上传文件到minio
        boolean 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;
    }
}

                //根据扩展名获取mimeType 

    //根据扩展名获取mimeType
    private String getMimeType(String extension){
        if(extension == null){
            extension = "";
        }
        //根据扩展名取出mimeType
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//通用mimeType,字节流
        if(extensionMatch!=null){
            mimeType = extensionMatch.getMimeType();
        }
        return mimeType;

    }

                //将文件上传到MINIO 

    /**
     * 将文件上传到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;
    }

                 //将文件信息添加到文件表

/**
     * @description 将文件信息添加到文件表
     * @param companyId  机构id
     * @param fileMd5  文件md5值
     * @param uploadFileParamsDto  上传文件的信息
     * @param bucket  桶
     * @param objectName 对象名称
     */
    @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);
            //文件id
            mediaFiles.setId(fileMd5);
            //机构id
            mediaFiles.setCompanyId(companyId);
            //桶
            mediaFiles.setBucket(bucket);
            //file_path
            mediaFiles.setFilePath(objectName);
            //file_id
            mediaFiles.setFileId(fileMd5);
            //url
            mediaFiles.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;
            }
            //记录待处理任务
            addWaitingTask(mediaFiles);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 黑马qt公开课是一套为期5天的课件,主要介绍了Qt框架的基础知识和应用。Qt框架是一个跨平台的开发工具,可以方便地进行应用程序的设计、开发和调试,被广泛应用于图形界面开发、嵌入式系统和移动应用等领域。 在5天的课程中,学习者将对Qt框架的整体架构有一个全面的认识,包括Qt及其常用库的概念、功能和用法,也学会了如何使用Qt Designer进行界面设计和基于信号与槽的事件编程。 此外,课程还将介绍Qt中常用的编程模式和技术,如MVC架构、文件操作、网络编程等,并通过实例让学习者深入理解和应用这些概念和技术。 5天的课件中还提供了大量的实践操作,让学习者通过编写实际案例,深入理解所学知识,并更好地掌握Qt框架的基础和应用,为以后的工作打下坚实的基础。 总之,如果你想快速入门Qt框架的基础知识和应用,那么黑马qt公开课—5天的课件,将是一个非常好的选择。 ### 回答2: 黑马qt公开课的课件共分为5天,内容涵盖了Qt的基础知识、UI设计、绘图系统、多线程编程和网络编程等方面。通过这5天的学习,学员可以全面掌握Qt的开发技能和应用场景,具备开发Qt应用程序的能力。 第一天课程主要介绍了Qt的基础知识,包括Qt窗口和控件、信号与槽机制、事件处理、布局和样式等内容。通过这些基础知识的学习,学员可以了解Qt的基本工作原理和操作方法。 第二天的课程主要讲解了Qt的UI设计,包括UI设计器的使用、自定义控件和样式等内容。学员可以从中学习到如何设计美观、直观的用户界面。 第三天的课程则主题为Qt的绘图系统,包括2D和3D绘图、动画效果和图形转换等内容。在这一天的课程中,学员可以学习到如何使用Qt进行图形绘制和界面效果的优化。 第四天的课程主要介绍了Qt的多线程编程,包括线程的创建和管理、互斥锁和信号量等内容。学员可以从中学习到如何在Qt中实现多线程应用程序。 第五天的课程则主题为Qt的网络编程,包括socket编程、HTTP协议和Web服务等内容。学员可以从中学习到如何使用Qt进行网络编程,实现客户端和服务器的互通。 总体来说,黑马qt公开课的5天课程涵盖了Qt的核心知识点,让学员能够全面掌握Qt的开发技能和应用场景。通过这些课程的学习,学员可以成为一名合格的Qt开发工程师。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值