Spring Boot+Vue前后端分离项目练习03之网盘项目文件夹创建及文件查询接口开发

1.集成Swagger 3接口文档

在前后端分离的项目中,接口文档的存在十分重要。swagger 是一个自动生成接口文档的工具,在需求变更十分频繁的情况下,手写接口文档是效率十分低下,这时swagger自动生生文档的的作用就体现出来了,同时swagger还提供了接口测试功能,相当好用。

1.1 添加依赖

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.5.4</version>
</dependency>

1.2 添加配置

在config包下创建OpenApiConfig.java,用于对swagger页面进行基本的配置。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;

@Configuration
public class OpenApiConfig {
    @Bean
    public OpenAPI qiwenFileOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("前后端分离网盘项目API")
                        .description("用于练习前后端分离的项目- springboot+vue技术栈")
                        .version("v1.0.0")
                        .license(new License().name("MIT").url("http://springdoc.org")))
                .externalDocs(new ExternalDocumentation()
                        .description("个人网站地址")
                        .url("www.picacho.top"));
    }
}

1.3 常用注解

@Tag 注解
这个注解主要用在类或方法上,当作用在方法是用来定义单个操作,当作用在类上代表所有操作。

  • name 标签名
  • description 这里可以做一个简短的描述
  • externalDocs 添加一个扩展文档
  • extensions 可选的扩展列表

@Operation 注解
这个注解用于将资源方法定义为OpenAPI 操作,在该注解中也可以定义该操作的其他属性。

  • method HTTP 请求方法
  • tags 按照资源对操作进行逻辑分组
  • summary 提供此操作的简要说明。
  • description 对操作的详细描述
  • requestBody 与操作关联的请求报文
  • parameters 一个可选的参数数组
  • responses 执行此操作返回的可能响应的列表
  • deprecated 允许将操作标记为已弃用
  • security 可用于此操作的安全机制的声明。

@Schema 注解
这个注解用来定义模型,主要用来定义模型类及模型的属性,请求和响应的内容、报文头等。

  • not 提供用于禁止匹配属性的 java 类。
  • name 用于描述模型类或属性的名称
  • title 用于描述模型类的标题
  • maximum 设置属性的最大数值。
  • minimum 设置属性的最小数值。
  • maxLength 设置字符串值的最大长度。
  • minLength 设置字符串值的最大小度。
  • pattern 值必须满足的模式。
  • required 是否必输
  • description 描述
  • nullable 如果为 true 则可能为 null。
  • example 使用示例

1.4 添加接口信息

为前面实现的接口添加接口信息。

@Tag(name = "user", description = "该接口为用户接口,主要用于用户登录,注册和校验token")
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    UserService userService;

    @Resource
    JWTUtil jwtUtil;

    /**
     * 成功响应测试
     */
    @GetMapping(value="/testSuccess")
    @ResponseBody
    public RestResult testSuccess(){
        return RestResult.success();
    }

    /**
     * 失败响应测试
     */
    @GetMapping(value="/testFail")
    @ResponseBody
    public RestResult testFail(){
        return RestResult.fail();
    }


    /**
     * 空指针异常响应测试
     */
    @GetMapping(value="/testNullException")
    @ResponseBody
    public RestResult testNullException(){
        String s = null;
        int index = s.length();
        return RestResult.success();
    }



    @Operation(summary = "用户注册", description = "注册账号", tags = {"user"})
    @PostMapping(value = "/register")
    @ResponseBody
    public RestResult<String> register(@RequestBody RegisterDTO registerDTO) {
        RestResult<String> restResult = null;
        User user = new User();
        user.setUsername(registerDTO.getUsername());
        user.setTelephone(registerDTO.getTelephone());
        user.setPassword(registerDTO.getPassword());

        restResult = userService.registerUser(user);

        return restResult;
    }

    @Operation(summary = "用户登录", description = "用户登录认证后才能进入系统", tags = {"user"})
    @GetMapping(value = "/login")
    @ResponseBody
    public RestResult<LoginVO> userLogin(String telephone, String password) {
        RestResult<LoginVO> restResult = new RestResult<LoginVO>();

        LoginVO loginVO = new LoginVO();
        User user = new User();
        user.setTelephone(telephone);
        user.setPassword(password);
        RestResult<User> loginResult = userService.login(user);

        if (!loginResult.getSuccess()) {
            return RestResult.fail().message("登录失败!");
        }

        loginVO.setUsername(loginResult.getData().getUsername());
        String jwt = "";
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            jwt = jwtUtil.createJWT(objectMapper.writeValueAsString(loginResult.getData()));
        } catch (Exception e) {
            return RestResult.fail().message("登录失败!");
        }
        loginVO.setToken(jwt);

        return RestResult.success().data(loginVO);
    }


    @Operation(summary = "检查用户登录信息", description = "验证token的有效性", tags = {"user"})
    @GetMapping("/checkToken")
    @ResponseBody
    public RestResult<User> checkToken(@RequestHeader("token") String token) {
        RestResult<User> restResult = new RestResult<User>();
        User tokenUserInfo = null;
        try {
            Claims c = jwtUtil.parseJWT(token);
            String subject = c.getSubject();
            ObjectMapper objectMapper = new ObjectMapper();
            tokenUserInfo = objectMapper.readValue(subject, User.class);

        } catch (Exception e) {
            return RestResult.fail().message("认证失败");
        }
        if (tokenUserInfo != null) {
            return RestResult.success().data(tokenUserInfo);
        } else {
            return RestResult.fail().message("用户暂未登录");
        }
    }
}
@Schema(description="注册DTO")
@Data
public class RegisterDTO {
    @Schema(description="用户名")
    private String username;
    @Schema(description="手机号")
    private String telephone;
    @Schema(description="密码")
    private String password;
}
@Schema(description="登录VO")
@Data
public class LoginVO {
    @Schema(description="用户名")
    private String username;
    @Schema(description="token")
    private String token;
}

接着启动项目,就可以访问swagger接口文档界面了。
在这里插入图片描述

2.文件夹创建接口开发

2.1 创建文件DTO

创建文件DTO,在dto包下创建CreateFileDTO.java。

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(name = "创建文件DTO",required = true)
public class CreateFileDTO {
    @Schema(description="文件名")
    private String fileName;
    @Schema(description="文件路径")
    private String filePath;
}

2.2 创建接口

首先通过token进行身份认证,如果没有登陆,那么直接认证失败返回失败信息;接着通过前端传入的参数信息查询文件,如果文件存在,返回文件重名失败;如果都通过了就将用户文件存入数据库。

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.picacho.common.RestResult;
import com.picacho.dto.CreateFileDTO;
import com.picacho.entity.User;
import com.picacho.entity.UserFile;
import com.picacho.service.UserService;
import com.picacho.util.DateUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

@Tag(name = "file", description = "该接口为文件接口,主要用来做一些文件的基本操作,如创建目录,删除,移动,复制等。")
@RestController
@Slf4j
@RequestMapping("/file")
public class FileController {
    
    @Resource
    UserService userService;
    @Resource
    UserfileService userfileService;

    @Operation(summary = "创建文件", description = "目录(文件夹)的创建", tags = {"file"})
    @PostMapping(value = "/createfile")
    @ResponseBody
    public RestResult<String> createFile(@RequestBody CreateFileDTO createFileDto, @RequestHeader("token") String token) {
        
        User sessionUser = userService.getUserByToken(token);
        if (sessionUser == null) {
            RestResult.fail().message("token认证失败");
        }
        LambdaQueryWrapper<UserFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserFile::getFileName, "").eq(UserFile::getFilePath, "").eq(UserFile::getUserId, 0);
        List<UserFile> userfiles = userfileService.list(lambdaQueryWrapper);
        if (!userfiles.isEmpty()) {
            RestResult.fail().message("同目录下文件名重复");
        }

        UserFile userFile = new UserFile();
        userFile.setUserId(sessionUser.getUserId());
        userFile.setFileName(createFileDto.getFileName());
        userFile.setFilePath(createFileDto.getFilePath());
        userFile.setIsDir(1);
        userFile.setUploadTime(DateUtil.getCurrentTime());

        userfileService.save(userFile);
        return RestResult.success();
    }
}

2.3 创建业务层

第一步通过token获取用户信息。

public interface UserService {
    User getUserByToken(String token);
}
    @Resource
    JWTUtil jwtUtil;
    
    @Override
    public User getUserByToken(String token) {
        User tokenUserInfo = null;
        try {
            Claims c = jwtUtil.parseJWT(token);
            String subject = c.getSubject();
            ObjectMapper objectMapper = new ObjectMapper();
            tokenUserInfo = objectMapper.readValue(subject, User.class);
        } catch (Exception e) {
            log.error("解码异常");
            return null;

        }
        return tokenUserInfo;
    }

第二步,接着通过前端传入的参数信息查询文件。

import com.baomidou.mybatisplus.extension.service.IService;
import com.picacho.entity.UserFile;

public interface UserfileService extends IService<UserFile> {
    
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.picacho.entity.UserFile;
import com.picacho.mapper.UserfileMapper;
import com.picacho.service.UserfileService;
import org.springframework.stereotype.Service;

@Service
public class UserfileServiceImpl extends ServiceImpl<UserfileMapper, UserFile> implements UserfileService {

}

这里使用mybatis plus,因此可以使用其自带的列表方法list()和保存方法save()。

2.4 创建Mapper层

这里需要将mapper进行改造,才能使用mybatis plus自带的方法。

public interface UserfileMapper extends BaseMapper<UserFile> {
}

2.5 测试一下

启动项目:
第一步,进行登陆获取token。
在这里插入图片描述
接着文件夹创建,需要携带token。
在这里插入图片描述
在这里插入图片描述
可以看到创建成功了,接着去数据库查看一下。
在这里插入图片描述

3.文件列表查询接口

3.1 创建DTO实体类

创建DTO实体类 UserfileListDTO.java,用来作为文件列表查询接口接收前台请求信息的载体。

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(name = "文件列表DTO",required = true)
public class UserfileListDTO {
    @Schema(description = "文件路径")
    private String filePath;
    @Schema(description = "当前页码")
    private Long currentPage;
    @Schema(description = "一页显示数量")
    private Long pageCount;
}

3.2 创建VO实体类

创建VO实体类UserfileListVO.java,用来作为文件列表查询接口给前台返回的信息载体。

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

@Data
@Schema(description="用户文件列表VO")
public class UserfileListVO {
    @Schema(description="文件id")
    private Long fileId;
    @Schema(description="时间戳名称")
    private String timeStampName;
    @Schema(description="文件url")
    private String fileUrl;
    @Schema(description="文件大小")
    private Long fileSize;
    @Schema(description="是否是oss存储")
    private Integer isOSS;
    @Schema(description="引用数量")
    private Integer pointCount;
    @Schema(description="md5")
    private String identifier;
    @Schema(description="用户文件id")
    private Long userFileId;
    @Schema(description="用户id")
    private Long userId;

    @Schema(description="文件名")
    private String fileName;
    @Schema(description="文件路径")
    private String filePath;
    @Schema(description="扩展名")
    private String extendName;
    @Schema(description="是否是目录")
    private Integer isDir;
    @Schema(description="上传时间")
    private String uploadTime;
}

3.3 创建控制器

    @Operation(summary = "获取文件列表", description = "用来做前台文件列表展示", tags = { "file" })
    @GetMapping(value = "/getfilelist")
    @ResponseBody
    public RestResult<UserfileListVO> getUserfileList(UserfileListDTO userfileListDto,
                                                      @RequestHeader("token") String token) {


        User sessionUser = userService.getUserByToken(token);
        if (sessionUser == null) {
            return RestResult.fail().message("token验证失败");
        }

        List<UserfileListVO> fileList = userfileService.getUserFileByFilePath(userfileListDto.getFilePath(),
                sessionUser.getUserId(), userfileListDto.getCurrentPage(), userfileListDto.getPageCount());

        LambdaQueryWrapper<UserFile> userFileLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userFileLambdaQueryWrapper.eq(UserFile::getUserId, sessionUser.getUserId()).eq(UserFile::getFilePath, userfileListDto.getFilePath());
        int total = userfileService.count(userFileLambdaQueryWrapper);

        Map<String, Object> map = new HashMap<>();
        map.put("total", total);
        map.put("list", fileList);

        return RestResult.success().data(map);
    }

3.4 创建业务层

List<UserfileListVO> getUserFileByFilePath(String filePath, Long userId, Long currentPage, Long pageCount);
  @Resource
    UserfileMapper userfileMapper;

    @Override
    public List<UserfileListVO> getUserFileByFilePath(String filePath, Long userId, Long currentPage, Long pageCount) {
        Long beginCount = (currentPage - 1) * pageCount;
        UserFile userfile = new UserFile();
        userfile.setUserId(userId);
        userfile.setFilePath(filePath);
        List<UserfileListVO> fileList = userfileMapper.userfileList(userfile, beginCount, pageCount);
        return fileList;
    }

3.5 创建Mapper层

  List<UserfileListVO> userfileList(UserFile userfile, Long beginCount, Long pageCount);
<?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.picacho.mapper.UserfileMapper">
    <select id="userfileList" resultType="com.picacho.vo.UserfileListVO">
        select * from userfile a
        left join file on file.fileId = a.fileId
        <where>
            <if test="userfile.userId != null">
                and a.userId = #{userfile.userId}
            </if>
            <if test="userfile.filePath != null">
                and a.filePath = #{userfile.filePath}
            </if>
            <if test="userfile.extendName != null">
                and a.extendName = #{userfile.extendName}
            </if>
        </where>
        ORDER BY  isDir desc
        limit #{beginCount}, #{pageCount}
    </select>    
</mapper>

3.6 测试一下

启动项目:
在这里插入图片描述
在这里插入图片描述

4.文件分类查询接口

4.1 创建文件类型常量类

public class FileConstant {
    public static final String[] IMG_FILE = {"bmp", "jpg", "png", "tif", "gif", "jpeg"};
    public static final String[] DOC_FILE = {"doc", "docx", "ppt", "pptx", "xls", "xlsx", "txt", "hlp", "wps", "rtf", "html", "pdf"};
    public static final String[] VIDEO_FILE = {"avi", "mp4", "mpg", "mov", "swf"};
    public static final String[] MUSIC_FILE = {"wav", "aif", "au", "mp3", "ram", "wma", "mmf", "amr", "aac", "flac"};
    public static final int IMAGE_TYPE = 1;
    public static final int DOC_TYPE = 2;
    public static final int VIDEO_TYPE = 3;
    public static final int MUSIC_TYPE = 4;
    public static final int OTHER_TYPE = 5;
}

4.2 创建控制层

    @Operation(summary = "通过文件类型选择文件", description = "该接口可以实现文件格式分类查看", tags = {"file"})
    @GetMapping(value = "/selectfilebyfiletype")
    @ResponseBody
    public RestResult<List<Map<String, Object>>> selectFileByFileType(int fileType, Long currentPage, Long pageCount, @RequestHeader("token") String token) {
        User sessionUser = userService.getUserByToken(token);
        long userId = sessionUser.getUserId();

        Map<String, Object> map = userfileService.getUserFileByType(fileType, currentPage, pageCount, userId);
        return RestResult.success().data(map);

    }

4.3 创建业务层

Map<String, Object> getUserFileByType(int fileType, Long currentPage, Long pageCount, Long userId);
  @Override
    public Map<String, Object> getUserFileByType(int fileType, Long currentPage, Long pageCount, Long userId) {
        Long beginCount = (currentPage - 1) * pageCount;
        List<UserfileListVO> fileList;
        Long total;
        if (fileType == FileConstant.OTHER_TYPE) {

            List<String> arrList = new ArrayList<>();
            arrList.addAll(Arrays.asList(FileConstant.DOC_FILE));
            arrList.addAll(Arrays.asList(FileConstant.IMG_FILE));
            arrList.addAll(Arrays.asList(FileConstant.VIDEO_FILE));
            arrList.addAll(Arrays.asList(FileConstant.MUSIC_FILE));

            fileList = userfileMapper.selectFileNotInExtendNames(arrList,beginCount, pageCount, userId);
            total = userfileMapper.selectCountNotInExtendNames(arrList,beginCount, pageCount, userId);
        } else {
            List<String> fileExtends = null;
            if (fileType == FileConstant.IMAGE_TYPE) {
                fileExtends = Arrays.asList(FileConstant.IMG_FILE);
            } else if (fileType == FileConstant.DOC_TYPE) {
                fileExtends = Arrays.asList(FileConstant.DOC_FILE);
            } else if (fileType == FileConstant.VIDEO_TYPE) {
                fileExtends = Arrays.asList(FileConstant.VIDEO_FILE);
            } else if (fileType == FileConstant.MUSIC_TYPE) {
                fileExtends = Arrays.asList(FileConstant.MUSIC_FILE);
            }
            fileList = userfileMapper.selectFileByExtendName(fileExtends, beginCount, pageCount,userId);
            total = userfileMapper.selectCountByExtendName(fileExtends, beginCount, pageCount,userId);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("list",fileList);
        map.put("total", total);
        return map;
    }

4.4 创建Mapper层

 List<UserfileListVO> selectFileByExtendName(List<String> fileNameList, Long beginCount, Long pageCount, long userId);
    Long selectCountByExtendName(List<String> fileNameList, Long beginCount, Long pageCount, long userId);
    
    List<UserfileListVO> selectFileNotInExtendNames(List<String> fileNameList, Long beginCount, Long pageCount, long userId);
    Long selectCountNotInExtendNames(List<String> fileNameList, Long beginCount, Long pageCount, long userId);
}
    <sql id="selectByExtendName" >
        left join file on file.fileId = userfile.fileId
        where extendName in
        <foreach collection="fileNameList" open="(" close=")" separator="," item="fileName" >
            #{fileName}
        </foreach>
        and userId = #{userId}
    </sql>
    <sql id="selectByNotExtendName">
        left join file on file.fileId = userfile.fileId
        where extendName not in
        <foreach collection="fileNameList" open="(" close=")" separator="," item="fileName" >
            #{fileName}
        </foreach>
        and userId = #{userId}
    </sql>
    <select id="selectFileByExtendName" parameterType="com.picacho.entity.UserFile" resultType="com.picacho.vo.UserfileListVO">
        select * from userfile
        <include refid="selectByExtendName"></include>
        limit #{beginCount}, #{pageCount}
    </select>

    <select id="selectCountByExtendName" parameterType="com.picacho.entity.UserFile" resultType="java.lang.Long">
        select count(*) from userfile
        <include refid="selectByExtendName"></include>
    </select>

    <select id="selectFileNotInExtendNames" parameterType="com.picacho.entity.UserFile" resultType="com.picacho.vo.UserfileListVO">
        select * from userfile
        <include refid="selectByNotExtendName"></include>
        limit #{beginCount}, #{pageCount}
    </select>

    <select id="selectCountNotInExtendNames" parameterType="com.picacho.entity.UserFile" resultType="java.lang.Long">
        select count(*) from userfile
        <include refid="selectByNotExtendName"></include>
    </select>

4.5 测试一下

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
现有功能 + 资源管理(上传、下载、移动、修改、删除) + 资源分享 + 资源共享 + 资源转存 + 资源预览(pdf编辑、图片、视频)(office 三件套待支持) + 断点续传 + 敏感词过滤 + 流式视频播放 + 秒传支持 ## 部分界面展示 + 上传资源 ![1681026799763](https://user-images.githubusercontent.com/50403161/230761214-a032ac84-5a89-4b82-a958-2639dd365dae.jpg) + 分享资源 ![1679735946504](https://user-images.githubusercontent.com/50403161/227708656-6a4d8142-f6fc-40b0-884f-f9e36c0a6f6b.jpg) + 资源预览 - 视频预览 ![视频预览](https://user-images.githubusercontent.com/50403161/233643649-abdaa4e1-f0a2-4219-8b4c-eab403c2885a.png) - 图片预览 ![图片预览](https://user-images.githubusercontent.com/50403161/233643039-d2612446-3b3e-4792-aa36-63a60e00e3b5.png) - pdf预览 ![pdf预览](https://user-images.githubusercontent.com/50403161/233643073-ef11c03e-5dba-42ce-927f-032af0277ef0.png) ## 待完成 - 视频文件转码进度展示 - 订阅分享消息推送 - 后台管理 - 链接后台下载 - 生成分享链接二维码 - 办公套件预览支持 - 音频文件预览支持 - 使用HDFS升级存储系统 - ...... ## 更新日志 + 使用hls 流播放实现了视频在线播放 2023.3 + 视频与图片缩略图支持 2023.4.3 ## 前端地址 ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picacho_pkq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值