Merge branch 'master' of ssh://gitea.ttstd.com:2222/tt/youlai-boot
This commit is contained in:
@@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
*/
|
||||
@Tag(name = "01.认证中心")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/auth/app")
|
||||
@RequestMapping("/api/v1/app/auth/")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AppAuthController {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.youlai.boot.app.controller;
|
||||
|
||||
import com.youlai.boot.app.model.vo.AppFileInfo;
|
||||
import com.youlai.boot.app.service.AppFileService;
|
||||
import com.youlai.boot.common.result.Result;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 文件控制层
|
||||
*
|
||||
* @author Ray.Hao
|
||||
* @since 2022/10/16
|
||||
*/
|
||||
@Tag(name = "10.文件接口")
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/app/files")
|
||||
@RequiredArgsConstructor
|
||||
public class AppFileController {
|
||||
|
||||
private final AppFileService fileService;
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "文件上传")
|
||||
public Result<AppFileInfo> uploadFile(
|
||||
@Parameter(
|
||||
name = "file",
|
||||
description = "表单文件对象",
|
||||
required = true,
|
||||
in = ParameterIn.DEFAULT,
|
||||
schema = @Schema(name = "file", format = "binary")
|
||||
)
|
||||
@RequestPart(value = "file") MultipartFile file
|
||||
) {
|
||||
Assert.isTrue(!file.isEmpty(), "上传文件不能为空文件");
|
||||
AppFileInfo fileInfo = fileService.uploadFile(file);
|
||||
return Result.success(fileInfo);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
@Operation(summary = "文件删除")
|
||||
@SneakyThrows
|
||||
public Result<?> deleteFile(
|
||||
@Parameter(description = "文件路径") @RequestParam String filePath
|
||||
) {
|
||||
boolean result = fileService.deleteFile(filePath);
|
||||
return Result.judge(result);
|
||||
}
|
||||
}
|
||||
23
src/main/java/com/youlai/boot/app/model/vo/AppFileInfo.java
Normal file
23
src/main/java/com/youlai/boot/app/model/vo/AppFileInfo.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.youlai.boot.app.model.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* 文件信息对象
|
||||
*
|
||||
* @author Ray.Hao
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Schema(description = "文件对象")
|
||||
@Data
|
||||
public class AppFileInfo {
|
||||
|
||||
@Schema(description = "文件名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文件URL")
|
||||
private String url;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.youlai.boot.app.service;
|
||||
|
||||
import com.youlai.boot.app.model.vo.AppFileInfo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 对象存储服务接口层
|
||||
*
|
||||
* @author haoxr
|
||||
* @since 2022/11/19
|
||||
*/
|
||||
public interface AppFileService {
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param file 表单文件对象
|
||||
* @return 文件信息
|
||||
*/
|
||||
AppFileInfo uploadFile(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param filePath 文件完整URL
|
||||
* @return 删除结果
|
||||
*/
|
||||
boolean deleteFile(String filePath);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.youlai.boot.app.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.youlai.boot.app.model.vo.AppFileInfo;
|
||||
import com.youlai.boot.app.service.AppFileService;
|
||||
import com.youlai.boot.file.service.FileService;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 本地存储服务类
|
||||
*
|
||||
* @author Theo
|
||||
* @since 2024-12-09 17:11
|
||||
*/
|
||||
@Data
|
||||
@Slf4j
|
||||
@Component
|
||||
//@ConditionalOnProperty(value = "oss.type", havingValue = "local")
|
||||
//@ConfigurationProperties(prefix = "oss.local")
|
||||
@RequiredArgsConstructor
|
||||
public class LocalAppFileService implements AppFileService {
|
||||
|
||||
@Value("${oss.local.storage-path}")
|
||||
private String storagePath;
|
||||
|
||||
/**
|
||||
* 上传文件方法
|
||||
*
|
||||
* @param file 表单文件对象
|
||||
* @return 文件信息
|
||||
*/
|
||||
@Override
|
||||
public AppFileInfo uploadFile(MultipartFile file) {
|
||||
// 获取文件名
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
// 获取文件后缀
|
||||
String suffix = FileUtil.getSuffix(originalFilename);
|
||||
// 生成uuid
|
||||
String fileName = IdUtil.simpleUUID()+ "." + suffix;;
|
||||
// 生成文件名(日期文件夹)
|
||||
String folder = DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
|
||||
String filePrefix = storagePath.endsWith(File.separator) ? storagePath : storagePath + File.separator;
|
||||
// try-with-resource 语法糖自动释放流
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
// 上传文件
|
||||
FileUtil.writeFromStream(inputStream, filePrefix + folder + File.separator + fileName);
|
||||
} catch (Exception e) {
|
||||
log.error("文件上传失败", e);
|
||||
throw new RuntimeException("文件上传失败");
|
||||
}
|
||||
// 获取文件访问路径,因为这里是本地存储,所以直接返回文件的相对路径,需要前端自行处理访问前缀
|
||||
String fileUrl = File.separator + folder + File.separator + fileName;
|
||||
AppFileInfo fileInfo = new AppFileInfo();
|
||||
fileInfo.setName(originalFilename);
|
||||
fileInfo.setUrl(fileUrl);
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param filePath 文件完整URL
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteFile(String filePath) {
|
||||
//判断文件是否为空
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// 判断filepath是否为文件夹
|
||||
if (FileUtil.isDirectory(storagePath + filePath)) {
|
||||
// 禁止删除文件夹
|
||||
return false;
|
||||
}
|
||||
// 删除文件
|
||||
return FileUtil.del(storagePath + filePath);
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public class SecurityConfig {
|
||||
|
||||
// 移动设备专用接口路径(需要设备签名验证,但不需要用户登录)
|
||||
requestMatcherRegistry.requestMatchers("/api/v1/sn/**").permitAll();
|
||||
requestMatcherRegistry.requestMatchers("/api/v1/auth/app/**").permitAll();
|
||||
requestMatcherRegistry.requestMatchers("/api/v1/app/**").permitAll();
|
||||
// 其他所有请求需登录后访问
|
||||
requestMatcherRegistry.anyRequest().authenticated();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user