健韵坊(详细项目实战二)Spring系列 + Vue3

回顾昨天的项目需求:

1.视频的上传,查看,点赞,评论,收藏

2.用户的个人模块的完善(包括常见的权限,增删改查这样几个)✔

3.手机号,邮箱的登录注册。✔

4.动态关注,消息提醒这些

5.使用爬虫技术,加上定时任务长期获取数据源✔

6.匹配系统,匹配相似度高的用户✔

ok,再出一期,把下面的的需求给完成以下(其实主要也就是视频模块的东西),顺便再用一些比较有意思的技术试试。

对于视频这种比较大的文件建议使用minio进行对象存储(这里再展示一下minio的使用方式)

在云服务器上面安装mimio

sudo docker run -itd \
    --name=minio \
    -p 9000:9000 \
    -p 9001:9001 \
    -e MINIO_ROOT_USER=minioadmin \
    -e MINIO_ROOT_PASSWORD=minioadmin \
    -v /path/to/your/data:/data \
    -v /path/to/your/config:/root/.minio \
    minio/minio server /data --console-address ":9001"

访问端口号:9001即可,这里设置的账号密码都是minioadmin

进入访问然后创建一个bucketName(取名的时候用小写)

代码操作minio:

引入依赖:

html 复制代码
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.4.3</version>
</dependency>

踩坑:使用

java 复制代码
static MinioClient minioClient = MinioClient.builder()
        .endpoint("http://xxx.xxx.xxx.xxx:9001")
        .credentials("minioadmin","minioadmin")
        .build();

这里使用9001无法实现存储。

根据异常信息 S3 API Requests must be made to API port,这表明您的 Minio 服务器配置了一个专用的端口用于处理 S3 API 请求,而您当前使用的端口可能不是正确的 API 端口。

通常情况下,Minio 服务会运行在两个端口上:

API端口:默认为 9000,用于处理 S3 兼容的 API 请求。

控制台端口:默认为 9001,用于 Minio 控制台界面。

您当前使用的端口是 9001,这是用于 Minio 控制台的端口,并不接受 S3 API 请求。因此,您需要将 MinioClient 的 endpoint 修改为正确的 API 端口,通常是 9000。

下面是修改后的代码示例:

java 复制代码
@SpringBootTest
public class MinioTest {
    static MinioClient minioClient = MinioClient.builder()
            .endpoint("http://xxx.xxx.xxx.xxx:9000") // 修改端口为 9000
            .credentials("minioadmin", "minioadmin")
            .build();

    @Test
    public void test() {
        try {
            UploadObjectArgs uploadObjectArgs = UploadObjectArgs.builder()
                    .bucket("cetide846513")
                    .object("BigFileTest.java")
                    .filename("BigFIleTest.java")
                    .build();

            // 在上传之前,确保桶已经存在
            if (!minioClient.bucketExists(BucketExistsArgs.of("cetide"))) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket("cetide").build());
            }

            minioClient.uploadObject(uploadObjectArgs);
            System.out.println("上传成功");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

为了使用 com.j256.simplemagic.ContentInfo 和 com.j256.simplemagic.ContentInfoUtil 这两个类,你需要在你的项目中添加 Simple Magic 库的依赖。

Simple Magic 是一个用于检测文件类型的 Java 库,它可以基于文件的内容来确定文件的 MIME 类型。

如果你使用的是 Maven,可以在 pom.xml 文件中添加以下依赖:

html 复制代码
<dependencies>
    <dependency>
        <groupId>com.j256.simplemagic</groupId>
        <artifactId>simplemagic</artifactId>
        <version>1.2.1</version> <!-- 请替换为最新的版本 -->
    </dependency>
</dependencies>

那么开始编写代码:

Controller层

java 复制代码
@RestController
public class FileUploadController {

    @Autowired
    private MediaFileService mediaFileService;

    @Autowired
    private RedisTemplate redisTemplate;

    @PostMapping("/upload")
    public Result<String> uploadPic(@RequestPart MultipartFile file) throws Exception {
        // 生成文件名
        String originalFilename = file.getOriginalFilename();
        String filename = null;
        if (originalFilename != null) {
            filename = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        // 上传文件
        String publicUrl = CosUtils.uploadFile(file, filename);
        return Result.success(publicUrl);
    }
    @ApiOperation("上传图片")
    @PostMapping(value = "/upload/course_file",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result<UploadFileResultDto> uploadMedia(@RequestPart("filedata")MultipartFile filedata) throws IOException {

        //准备上传文件的信息
        UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();
        //原始文件名称
        uploadFileParamsDto.setFilename(filedata.getOriginalFilename());
        //文件大小
        uploadFileParamsDto.setFileSize(filedata.getSize());
        //文件类型
        uploadFileParamsDto.setFileType("视频");
        //设置创建人
        User user = (User) redisTemplate.opsForValue().get("user");
        uploadFileParamsDto.setUsername(user.getUsername());
        //备注和标签从前端获取到
        //创建一个临时文件
        File tempFile = File.createTempFile("minio", ".temp");
        //将上传的文件写到临时文件中
        filedata.transferTo(tempFile);
        Long companyId = 1232141425L;
        //文件路径
        String localFilePath = tempFile.getAbsolutePath();
        //调用service上传图片
        return mediaFileService.uploadFile(companyId, uploadFileParamsDto, localFilePath);
    }

}
java 复制代码
 public PageResult<MediaFiles> queryMediaFiels(Long companyId, PageParams pageParams, QueryMediaParamsDto queryMediaParamsDto);

 public Result<UploadFileResultDto> uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath);

 public MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName);
java 复制代码
private final String bucket_mediafiles = "cetide";

    private final String bucket_video = "cetide";

    @Override
    public 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();
        // 构建结果集
        return new PageResult<>(list, total, pageParams.getPageNo(), pageParams.getPageSize());

    }

    //根据扩展名获取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
     * @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;
    }
    //获取文件的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;
        }
    }

那么,demo项目的功能也基本就能够跑通了。

剩下的就开始前后端联调,然后完善具体的业务方法吧.

此时回到前端:

npm开启,(这里的前端比较简单,vue+ element-ui +vite)

进行文章帖子列表的展示与刷新,随机推送几条数据。

这边就不细讲了,下面来看看如何部署前后端:

后端用云服务器安装宝塔进行部署:

前端的话用vercel进行部署

"build": "vue-tsc -b && vite build",

vite build打包成dist

然后使用vercel --prod

相关推荐
迷雾漫步者1 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-1 小时前
验证码机制
前端·后端
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭3 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论