feat: adding path system
This commit is contained in:
parent
5ce5332891
commit
5b01a66371
@ -7,6 +7,7 @@ import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.shell.command.annotation.EnableCommand;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@ -15,6 +16,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
@MapperScan("cn.wzpmc.filemanager.mapper")
|
||||
@EnableTransactionManagement
|
||||
@EnableCommand
|
||||
@EnableAsync
|
||||
public class FileManagerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
11
src/main/java/cn/wzpmc/filemanager/annotation/Address.java
Normal file
11
src/main/java/cn/wzpmc/filemanager/annotation/Address.java
Normal file
@ -0,0 +1,11 @@
|
||||
package cn.wzpmc.filemanager.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Address {
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cn.wzpmc.filemanager.commands;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.shell.standard.ShellComponent;
|
||||
@ -14,6 +15,6 @@ public class AuthorizationCommands {
|
||||
}
|
||||
@ShellMethod("创建一个密钥")
|
||||
public void key(){
|
||||
this.userService.genInviteCode();
|
||||
this.userService.genInviteCode(UserVo.CONSOLE, "0.0.0.0");
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package cn.wzpmc.filemanager.config;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.io.File;
|
||||
@ -8,11 +9,8 @@ import java.io.File;
|
||||
@ConfigurationProperties(prefix = "wzp.filemanager")
|
||||
@Data
|
||||
public class FileManagerProperties {
|
||||
@Getter
|
||||
private File savePath;
|
||||
private String hmacKey = "RANDOM";
|
||||
private FFmpegConfiguration ffmpeg;
|
||||
public File getSavePath() {
|
||||
System.out.println(this.savePath);
|
||||
return this.savePath;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cn.wzpmc.filemanager.configuration;
|
||||
|
||||
import cn.wzpmc.filemanager.utils.AddressArgumentResolver;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class AddressConfiguration implements WebMvcConfigurer {
|
||||
private final AddressArgumentResolver addressArgumentResolver;
|
||||
@Override
|
||||
public void addArgumentResolvers(@NonNull List<HandlerMethodArgumentResolver> resolvers) {
|
||||
WebMvcConfigurer.super.addArgumentResolvers(resolvers);
|
||||
resolvers.add(addressArgumentResolver);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package cn.wzpmc.filemanager.configuration;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.ChunkChecked;
|
||||
import cn.wzpmc.filemanager.entities.files.ChunkReady;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileVo;
|
||||
import lombok.Getter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -9,6 +9,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
@Configuration
|
||||
@Getter
|
||||
public class RedisConfiguration {
|
||||
private final RedisConnectionFactory redisConnectionFactory;
|
||||
|
||||
@ -17,14 +18,8 @@ public class RedisConfiguration {
|
||||
this.redisConnectionFactory = redisConnectionFactory;
|
||||
}
|
||||
@Bean
|
||||
public RedisTemplate<String, ChunkReady> uploadMapper() {
|
||||
RedisTemplate<String, ChunkReady> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
@Bean
|
||||
public RedisTemplate<String, ChunkChecked> chunkUploadMapper() {
|
||||
RedisTemplate<String, ChunkChecked> template = new RedisTemplate<>();
|
||||
public RedisTemplate<String, FileVo> linkMapper() {
|
||||
RedisTemplate<String, FileVo> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(redisConnectionFactory);
|
||||
return template;
|
||||
}
|
||||
|
@ -1,40 +1,78 @@
|
||||
package cn.wzpmc.filemanager.controller;
|
||||
|
||||
import cn.wzpmc.filemanager.annotation.Address;
|
||||
import cn.wzpmc.filemanager.annotation.AuthorizationRequired;
|
||||
import cn.wzpmc.filemanager.entities.PageResult;
|
||||
import cn.wzpmc.filemanager.entities.Result;
|
||||
import cn.wzpmc.filemanager.entities.files.CheckChunkResponse;
|
||||
import cn.wzpmc.filemanager.entities.files.DoneUploadRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.FileObject;
|
||||
import cn.wzpmc.filemanager.entities.files.PrepareUploadRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.DeleteRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.FolderCreateRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.entities.files.enums.FileType;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.service.FileService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/file")
|
||||
@RequiredArgsConstructor
|
||||
public class FileController {
|
||||
private final FileService fileService;
|
||||
|
||||
@Autowired
|
||||
public FileController(FileService fileService) {
|
||||
this.fileService = fileService;
|
||||
@PutMapping("/upload")
|
||||
public Result<FileVo> simpleUpload(MultipartHttpServletRequest file, @AuthorizationRequired UserVo user, @Address String address) {
|
||||
return fileService.simpleUpload(file, user, address);
|
||||
}
|
||||
@PostMapping("/prepare")
|
||||
public Result<String> prepareUploadChunks(@RequestBody PrepareUploadRequest prepareUploadRequest, @AuthorizationRequired UserVo user){
|
||||
return fileService.prepareUploadChunks(prepareUploadRequest, user);
|
||||
|
||||
@GetMapping("/get")
|
||||
public Result<PageResult<RawFileObject>> getFilePager(@RequestParam long page, @RequestParam int num, @RequestParam long folder, @Address String address) {
|
||||
return fileService.getFilePager(page, num, folder, address);
|
||||
}
|
||||
@PutMapping("/chunk/upload")
|
||||
public Result<Void> uploadChunk(MultipartFile file,@RequestParam String id){
|
||||
return fileService.uploadChunk(file, id);
|
||||
|
||||
@PostMapping("/mkdir")
|
||||
public Result<FolderVo> mkdir(@RequestBody FolderCreateRequest request, @AuthorizationRequired UserVo user, @Address String address) {
|
||||
return fileService.mkdir(request, user, address);
|
||||
}
|
||||
@GetMapping("/chunk/check")
|
||||
public Result<CheckChunkResponse> checkChunk(@RequestParam String hash, @RequestParam String id, @RequestParam long index){
|
||||
return fileService.checkChunk(hash, id, index);
|
||||
|
||||
@GetMapping("/detail")
|
||||
public Result<FileVo> getFileDetail(@RequestParam long id) {
|
||||
return fileService.getFileDetail(id);
|
||||
}
|
||||
@PostMapping("/done")
|
||||
public Result<FileObject> doneUpload(@RequestBody DoneUploadRequest data){
|
||||
return fileService.doneUpload(data.getId());
|
||||
|
||||
@DeleteMapping("/rm")
|
||||
public Result<Void> delete(@RequestBody DeleteRequest request, @AuthorizationRequired UserVo user, @Address String address) {
|
||||
return fileService.delete(request, user, address);
|
||||
}
|
||||
|
||||
@GetMapping("/link")
|
||||
public Result<String> getFileLink(@RequestParam long id, @Address String address, HttpServletRequest request) {
|
||||
return fileService.getFileLink(id, address, request);
|
||||
}
|
||||
|
||||
@GetMapping("/download/{id}")
|
||||
public void downloadFile(@PathVariable String id, @RequestHeader(value = "Range", defaultValue = "null") String range, HttpServletResponse response) {
|
||||
fileService.downloadFile(id, range, response);
|
||||
}
|
||||
|
||||
@GetMapping("/share")
|
||||
public Result<String> shareFile(@RequestParam Long id, @RequestParam(defaultValue = "9999-12-31") Date lastCouldDownloadTime, @RequestParam(defaultValue = "-1") int maxDownloadCount) {
|
||||
return fileService.shareFile(id, lastCouldDownloadTime, maxDownloadCount);
|
||||
}
|
||||
|
||||
@GetMapping("/path/resolve")
|
||||
public Result<RawFileObject> resolveFileDetail(@RequestParam String path) {
|
||||
return fileService.resolveFileDetail(path);
|
||||
}
|
||||
|
||||
@GetMapping("/path/{id}")
|
||||
public Result<String> findFilePathById(@PathVariable("id") long id, @RequestParam(value = "type", defaultValue = "FILE") FileType type) {
|
||||
return type.equals(FileType.FILE) ? fileService.findFilePathById(id) : fileService.findFolderPathById(id);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package cn.wzpmc.filemanager.controller;
|
||||
|
||||
import cn.wzpmc.filemanager.annotation.Address;
|
||||
import cn.wzpmc.filemanager.annotation.AuthorizationRequired;
|
||||
import cn.wzpmc.filemanager.entities.Result;
|
||||
import cn.wzpmc.filemanager.entities.user.UserLoginRequest;
|
||||
@ -8,28 +9,33 @@ import cn.wzpmc.filemanager.entities.user.enums.Auth;
|
||||
import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.service.UserService;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/user")
|
||||
public class UserController {
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
public UserController(UserService userService) {
|
||||
this.userService= userService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public void login(@RequestBody UserLoginRequest loginRequest, HttpServletResponse response) {
|
||||
userService.login(loginRequest, response);
|
||||
public void login(@RequestBody UserLoginRequest loginRequest, HttpServletResponse response, @Address String address) {
|
||||
userService.login(loginRequest, response, address);
|
||||
}
|
||||
|
||||
@PutMapping("/register")
|
||||
public void register(@RequestBody UserRegisterRequest registerRequest, HttpServletResponse response) {
|
||||
userService.register(registerRequest, response);
|
||||
public void register(@RequestBody UserRegisterRequest registerRequest, HttpServletResponse response, @Address String address) {
|
||||
userService.register(registerRequest, response, address);
|
||||
}
|
||||
|
||||
@GetMapping("/invite")
|
||||
@AuthorizationRequired(level = Auth.admin)
|
||||
public Result<String> invite(){
|
||||
return userService.invite();
|
||||
public Result<String> invite(@AuthorizationRequired(level = Auth.admin) UserVo userVo, @Address String address) {
|
||||
return userService.invite(userVo, address);
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Page<T> {
|
||||
private int total;
|
||||
public class PageResult<T> {
|
||||
private long total;
|
||||
private List<T> data;
|
||||
}
|
@ -3,10 +3,7 @@ package cn.wzpmc.filemanager.entities;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
@ -93,6 +90,7 @@ public class Result<T> {
|
||||
}
|
||||
|
||||
public void writeToResponse(HttpServletResponse response){
|
||||
response.addHeader("Content-Type", "application/json; charset=utf-8");
|
||||
try(ServletOutputStream outputStream = response.getOutputStream()){
|
||||
writeToOutputStream(outputStream);
|
||||
} catch (IOException e) {
|
||||
|
@ -1,18 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class CheckChunkResponse {
|
||||
private boolean has;
|
||||
private String uploadCode;
|
||||
public static CheckChunkResponse has() {
|
||||
return new CheckChunkResponse(true, null);
|
||||
}
|
||||
public static CheckChunkResponse shouldUpload(String uploadCode) {
|
||||
return new CheckChunkResponse(false, uploadCode);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ChunkChecked implements Serializable {
|
||||
private String fileId;
|
||||
private String hash;
|
||||
private long index;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ChunkReady implements Serializable {
|
||||
private long fileId;
|
||||
private long length;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.enums.FileType;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeleteRequest {
|
||||
private FileType type;
|
||||
private long id;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DoneUploadRequest {
|
||||
private String id;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.vo.ChunkVo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class FileData {
|
||||
private List<ChunkVo> chunks;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class FileObject extends RawFileObject {
|
||||
private String ext;
|
||||
private String mime;
|
||||
private String sha1;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class FolderCreateRequest {
|
||||
private long parent;
|
||||
private String name;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class FolderObject extends RawFileObject {
|
||||
private List<RawFileObject> children;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PrepareUploadRequest {
|
||||
private String name;
|
||||
private String ext;
|
||||
private Long size;
|
||||
private int folder;
|
||||
private String fullSha1;
|
||||
}
|
@ -1,14 +1,35 @@
|
||||
package cn.wzpmc.filemanager.entities.files;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.enums.FileType;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public abstract class RawFileObject {
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RawFileObject {
|
||||
private long id;
|
||||
private String name;
|
||||
private Integer id;
|
||||
private String uploader;
|
||||
private Date createTime;
|
||||
private String ext;
|
||||
private long size;
|
||||
private long owner;
|
||||
private long parent;
|
||||
private Date time;
|
||||
private FileType type;
|
||||
|
||||
public static RawFileObject of(FileVo file) {
|
||||
return new RawFileObject(file.getId(), file.getName(), file.getExt(), file.getSize(), file.getUploader(), file.getFolder(), file.getUploadTime(), FileType.FILE);
|
||||
}
|
||||
|
||||
public static RawFileObject of(FolderVo folder) {
|
||||
return new RawFileObject(folder.getId(), folder.getName(), null, -1, folder.getCreator(), folder.getParent(), folder.getCreateTime(), FileType.FOLDER);
|
||||
}
|
||||
public static String getRawFileName(RawFileObject object){
|
||||
return object.type.equals(FileType.FILE) ? object.getName() + '.' + object.getExt() : object.getName();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.wzpmc.filemanager.entities.files.enums;
|
||||
|
||||
public enum FileType {
|
||||
FILE, FOLDER;
|
||||
FILE, FOLDER
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package cn.wzpmc.filemanager.entities.statistics.enums;
|
||||
|
||||
public enum Actions {
|
||||
UPLOAD, DELETE, ACCESS, DOWNLOAD, SEARCH
|
||||
UPLOAD, DELETE, ACCESS, DOWNLOAD, SEARCH, LOGIN, INVITE, REGISTER
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.vo;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.Data;
|
||||
|
||||
@Table("chunk")
|
||||
@Data
|
||||
public class ChunkVo {
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private int id;
|
||||
private String sha1;
|
||||
private long size;
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package cn.wzpmc.filemanager.entities.vo;
|
||||
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Table("file_chunks")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class FileChunkVo {
|
||||
private long file;
|
||||
private long chunk;
|
||||
private long index;
|
||||
}
|
@ -6,20 +6,21 @@ import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
@Table("file")
|
||||
@Data
|
||||
public class FileVo {
|
||||
public class FileVo implements Serializable {
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private int id;
|
||||
private long id;
|
||||
private String name;
|
||||
private String ext;
|
||||
private String mime;
|
||||
private String sha1;
|
||||
private int uploader;
|
||||
private int folder;
|
||||
private String hash;
|
||||
private long uploader;
|
||||
private long folder;
|
||||
private long size;
|
||||
@Column(onInsertValue = "now()")
|
||||
private Date uploadTime;
|
||||
|
||||
|
@ -12,10 +12,10 @@ import java.util.Date;
|
||||
@Data
|
||||
public class FolderVo {
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private int id;
|
||||
private long id;
|
||||
private String name;
|
||||
private int parent;
|
||||
private int creator;
|
||||
private long parent;
|
||||
private long creator;
|
||||
@Column(onInsertValue = "now()")
|
||||
private Date createTime;
|
||||
|
||||
|
@ -4,16 +4,23 @@ import cn.wzpmc.filemanager.entities.statistics.enums.Actions;
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Table("statistics")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class StatisticsVo {
|
||||
private int actor;
|
||||
private Long actor;
|
||||
private Actions action;
|
||||
private String params;
|
||||
@Column(onInsertValue = "now()")
|
||||
private Date time;
|
||||
|
||||
public StatisticsVo(Long actor, Actions action, String params) {
|
||||
this.actor = actor;
|
||||
this.action = action;
|
||||
this.params = params;
|
||||
}
|
||||
}
|
@ -10,9 +10,10 @@ import lombok.Data;
|
||||
|
||||
@Table("user")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class UserVo {
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private int id;
|
||||
private long id;
|
||||
private String name;
|
||||
private String password;
|
||||
private Auth auth;
|
||||
@ -23,5 +24,13 @@ public class UserVo {
|
||||
this.password = password;
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
private UserVo(long id, String name, Auth auth){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.auth = auth;
|
||||
}
|
||||
public UserVo(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public static final UserVo CONSOLE = new UserVo(0L, "CONSOLE", Auth.admin);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package cn.wzpmc.filemanager.interfaces;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public interface FilePathService {
|
||||
@NonNull
|
||||
String getFilePath(@NonNull RawFileObject file);
|
||||
|
||||
@Nullable
|
||||
RawFileObject resolveFile(@NonNull String[] path);
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package cn.wzpmc.filemanager.interfaces.impl;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.mapper.FileMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FolderMapper;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FileVoTableDef.FILE_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FolderVoTableDef.FOLDER_VO;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
@Log4j2
|
||||
public class ComplexResolver extends SimplePathResolver {
|
||||
private final ReverseResolver reverseResolver;
|
||||
private final SimpleResolver simpleResolver;
|
||||
@Autowired
|
||||
public ComplexResolver(FileMapper fileMapper, FolderMapper folderMapper, ReverseResolver reverseResolver, SimpleResolver simpleResolver) {
|
||||
super(fileMapper, folderMapper);
|
||||
this.reverseResolver = reverseResolver;
|
||||
this.simpleResolver = simpleResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public RawFileObject resolveFile(@NonNull String[] path) {
|
||||
String strPath = Arrays.toString(path);
|
||||
String targetFileName = path[path.length - 1];
|
||||
int lastDotIndex = targetFileName.lastIndexOf('.');
|
||||
String name = targetFileName;
|
||||
String ext = "";
|
||||
if (lastDotIndex != -1) {
|
||||
name = targetFileName.substring(0, lastDotIndex);
|
||||
ext = targetFileName.substring(lastDotIndex + 1);
|
||||
}
|
||||
long start = new Date().getTime();
|
||||
long totalRawFileCount = this.fileMapper.selectCountByCondition(FILE_VO.NAME.eq(name).and(FILE_VO.EXT.eq(ext))) + this.folderMapper.selectCountByCondition(FOLDER_VO.NAME.eq(name));
|
||||
if (totalRawFileCount == 0) return null;
|
||||
if (totalRawFileCount > path.length) {
|
||||
log.info("use simple resolver to solve path with {}", strPath);
|
||||
RawFileObject rawFileObject = simpleResolver.resolveFile(path);
|
||||
long end = new Date().getTime();
|
||||
log.info("solve path {} cost {}ms", strPath, end - start);
|
||||
return rawFileObject;
|
||||
}
|
||||
log.info("use reverse resolver to solve path with {}", strPath);
|
||||
RawFileObject rawFileObject = reverseResolver.resolveFile(path);
|
||||
long end = new Date().getTime();
|
||||
log.info("solve path {} cost {}ms", strPath, end - start);
|
||||
return rawFileObject;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package cn.wzpmc.filemanager.interfaces.impl;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import cn.wzpmc.filemanager.mapper.FileMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FolderMapper;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FileVoTableDef.FILE_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FolderVoTableDef.FOLDER_VO;
|
||||
|
||||
@Component
|
||||
public class ReverseResolver extends SimplePathResolver {
|
||||
public ReverseResolver(FileMapper fileMapper, FolderMapper folderMapper) {
|
||||
super(fileMapper, folderMapper);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RawFileObject resolveFile(@NonNull String[] path) {
|
||||
List<String> pathList = removeEmptyPath(path);
|
||||
String targetFileName = pathList.get(pathList.size() - 1);
|
||||
int lastDotIndex = targetFileName.lastIndexOf('.');
|
||||
String name = targetFileName;
|
||||
String ext = "";
|
||||
if (lastDotIndex != -1) {
|
||||
name = targetFileName.substring(0, lastDotIndex);
|
||||
ext = targetFileName.substring(lastDotIndex + 1);
|
||||
}
|
||||
List<RawFileObject> rawFileObjects = new ArrayList<>();
|
||||
fileMapper.selectListByCondition(FILE_VO.NAME.eq(name).and(FILE_VO.EXT.eq(ext))).stream().map(RawFileObject::of).forEach(rawFileObjects::add);
|
||||
folderMapper.selectListByCondition(FOLDER_VO.NAME.eq(name)).stream().map(RawFileObject::of).forEach(rawFileObjects::add);
|
||||
if (rawFileObjects.isEmpty()) return null;
|
||||
if (rawFileObjects.size() == 1) return rawFileObjects.get(0);
|
||||
List<Long> possibleParents = rawFileObjects.stream().map(RawFileObject::getParent).toList();
|
||||
Optional<RawFileObject> inRoot = rawFileObjects.stream().filter(e -> e.getParent() == -1).findFirst();
|
||||
if (inRoot.isPresent()) {
|
||||
if (pathList.size() <= 1) {
|
||||
return inRoot.get();
|
||||
}
|
||||
}
|
||||
List<FolderVo> folderVos = folderMapper.selectListByIds(possibleParents);
|
||||
FolderVo parent = reverseFindFileParent(folderVos, pathList.subList(0, pathList.size() - 1));
|
||||
if (parent == null) return null;
|
||||
Optional<RawFileObject> first = rawFileObjects.stream().filter(e -> e.getParent() == parent.getId()).findFirst();
|
||||
return first.orElse(null);
|
||||
}
|
||||
|
||||
private FolderVo reverseFindFileParent(List<FolderVo> possibleParent, List<String> path) {
|
||||
if (path.isEmpty()) return null;
|
||||
if (possibleParent.size() == 1) return possibleParent.get(0);
|
||||
String currentLayerName = path.get(path.size() - 1);
|
||||
List<FolderVo> folderVoStream = possibleParent.stream().filter(e -> e.getName().equals(currentLayerName)).toList();
|
||||
Optional<FolderVo> inRoot = folderVoStream.stream().filter(e -> e.getParent() == -1).findFirst();
|
||||
if (inRoot.isPresent()) {
|
||||
if (path.size() <= 1) {
|
||||
return inRoot.get();
|
||||
}
|
||||
}
|
||||
List<Long> list = folderVoStream.stream().map(FolderVo::getParent).toList();
|
||||
if (list.isEmpty()) return null;
|
||||
List<FolderVo> parents = folderMapper.selectListByIds(list);
|
||||
FolderVo parent = reverseFindFileParent(parents, path.subList(0, path.size() - 1));
|
||||
if (parent == null) return null;
|
||||
Optional<FolderVo> first = folderVoStream.stream().filter(e -> e.getParent() == parent.getId()).findFirst();
|
||||
return first.orElse(null);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package cn.wzpmc.filemanager.interfaces.impl;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import cn.wzpmc.filemanager.interfaces.FilePathService;
|
||||
import cn.wzpmc.filemanager.mapper.FileMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FolderMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class SimplePathResolver implements FilePathService {
|
||||
protected final FileMapper fileMapper;
|
||||
protected final FolderMapper folderMapper;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getFilePath(@NonNull RawFileObject file) {
|
||||
return resolvePath(file.getParent()) + RawFileObject.getRawFileName(file);
|
||||
}
|
||||
|
||||
private String resolvePath(long id) {
|
||||
if (id == -1) {
|
||||
return "/";
|
||||
}
|
||||
FolderVo folderVo = folderMapper.selectOneById(id);
|
||||
long parent = folderVo.getParent();
|
||||
String name = folderVo.getName();
|
||||
return resolvePath(parent) + name + "/";
|
||||
}
|
||||
|
||||
protected List<String> removeEmptyPath(String[] path) {
|
||||
return Arrays.stream(path).filter(e -> !e.isEmpty()).toList();
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cn.wzpmc.filemanager.interfaces.impl;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import cn.wzpmc.filemanager.mapper.FileMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FolderMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FileVoTableDef.FILE_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FolderVoTableDef.FOLDER_VO;
|
||||
|
||||
@Component
|
||||
public class SimpleResolver extends SimplePathResolver {
|
||||
@Autowired
|
||||
public SimpleResolver(FileMapper fileMapper, FolderMapper folderMapper) {
|
||||
super(fileMapper, folderMapper);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public RawFileObject resolveFile(@NonNull String[] path) {
|
||||
return resolveFile(removeEmptyPath(path), -1);
|
||||
}
|
||||
|
||||
private RawFileObject resolveFile(List<String> path, long parentId) {
|
||||
String currentLayerName = path.get(0);
|
||||
if (path.size() == 1) {
|
||||
int lastDotIndex = currentLayerName.lastIndexOf('.');
|
||||
String name = currentLayerName;
|
||||
String ext = "";
|
||||
if (lastDotIndex != -1) {
|
||||
name = currentLayerName.substring(0, lastDotIndex);
|
||||
ext = currentLayerName.substring(lastDotIndex + 1);
|
||||
}
|
||||
FileVo file = fileMapper.selectOneByCondition(FILE_VO.NAME.eq(name).and(FILE_VO.EXT.eq(ext)).and(FILE_VO.FOLDER.eq(parentId)));
|
||||
if (file != null) {
|
||||
return RawFileObject.of(file);
|
||||
}
|
||||
return RawFileObject.of(folderMapper.selectOneById(FOLDER_VO.NAME.eq(name).and(FOLDER_VO.PARENT.eq(parentId))));
|
||||
}
|
||||
FolderVo folderVo = folderMapper.selectOneByCondition(FOLDER_VO.NAME.eq(currentLayerName).and(FOLDER_VO.PARENT.eq(parentId)));
|
||||
if (folderVo == null) {
|
||||
return null;
|
||||
}
|
||||
return resolveFile(path.subList(1, path.size()), folderVo.getId());
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cn.wzpmc.filemanager.mapper;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.vo.ChunkVo;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
public interface ChunkMapper extends BaseMapper<ChunkVo> {
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cn.wzpmc.filemanager.mapper;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.vo.FileChunkVo;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
public interface FileChunksMapper extends BaseMapper<FileChunkVo> {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package cn.wzpmc.filemanager.mapper;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.vo.StatisticsVo;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
|
||||
public interface StatisticsMapper extends BaseMapper<StatisticsVo> {
|
||||
}
|
@ -1,166 +1,372 @@
|
||||
package cn.wzpmc.filemanager.service;
|
||||
|
||||
import cn.wzpmc.filemanager.config.FileManagerProperties;
|
||||
import cn.wzpmc.filemanager.entities.PageResult;
|
||||
import cn.wzpmc.filemanager.entities.Result;
|
||||
import cn.wzpmc.filemanager.entities.files.*;
|
||||
import cn.wzpmc.filemanager.entities.vo.ChunkVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileChunkVo;
|
||||
import cn.wzpmc.filemanager.entities.files.DeleteRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.FolderCreateRequest;
|
||||
import cn.wzpmc.filemanager.entities.files.RawFileObject;
|
||||
import cn.wzpmc.filemanager.entities.files.enums.FileType;
|
||||
import cn.wzpmc.filemanager.entities.statistics.enums.Actions;
|
||||
import cn.wzpmc.filemanager.entities.user.enums.Auth;
|
||||
import cn.wzpmc.filemanager.entities.vo.FileVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.FolderVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.mapper.ChunkMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FileChunksMapper;
|
||||
import cn.wzpmc.filemanager.interfaces.FilePathService;
|
||||
import cn.wzpmc.filemanager.mapper.FileMapper;
|
||||
import cn.wzpmc.filemanager.mapper.FolderMapper;
|
||||
import cn.wzpmc.filemanager.utils.JwtUtils;
|
||||
import cn.wzpmc.filemanager.utils.RandomUtils;
|
||||
import cn.wzpmc.filemanager.utils.SizeStatisticsDigestInputStream;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.mybatisflex.core.audit.http.HashUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.tika.Tika;
|
||||
import org.apache.tomcat.util.http.fileupload.FileItemStream;
|
||||
import org.apache.tomcat.util.http.fileupload.FileUpload;
|
||||
import org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl;
|
||||
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StreamUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.List;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.ChunkVoTableDef.CHUNK_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FileChunkVoTableDef.FILE_CHUNK_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FileVoTableDef.FILE_VO;
|
||||
import static cn.wzpmc.filemanager.entities.vo.table.FolderVoTableDef.FOLDER_VO;
|
||||
import static com.mybatisflex.core.query.QueryMethods.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FileService {
|
||||
private final RedisTemplate<String, ChunkReady> uploadMapper;
|
||||
private final RedisTemplate<String, ChunkChecked> chunkUploadMapper;
|
||||
private final FileMapper fileMapper;
|
||||
private final ChunkMapper chunkMapper;
|
||||
private final FileChunksMapper fileChunksMapper;
|
||||
private final FolderMapper folderMapper;
|
||||
private final RandomUtils randomUtils;
|
||||
private final FileManagerProperties properties;
|
||||
private static final String UPLOAD_FILE_PREPARE_HEAD = "UPLOAD_";
|
||||
private static final String CHUNK_PREPARE_HEAD = "UPLOAD_CHUNK_";
|
||||
public Result<String> prepareUploadChunks(PrepareUploadRequest prepareUploadRequest, UserVo user) {
|
||||
String name = prepareUploadRequest.getName();
|
||||
String ext = prepareUploadRequest.getExt();
|
||||
int folder = prepareUploadRequest.getFolder();
|
||||
if (this.fileMapper.selectCountByCondition(FILE_VO.NAME.eq(name).and(FILE_VO.EXT.eq(ext)).and(FILE_VO.FOLDER.eq(folder))) > 0) {
|
||||
return Result.failed(HttpStatus.CONFLICT, "文件已存在!");
|
||||
private final StatisticsService statisticsService;
|
||||
private final RedisTemplate<String, FileVo> linkMapper;
|
||||
/*private final RedisTemplate<String, Long> linkCountMapper;*/
|
||||
private final StringRedisTemplate idAddrLinkMapper;
|
||||
private final JwtUtils jwtUtils;
|
||||
private final FilePathService pathService;
|
||||
public static final String ID_ADDR_PREFIX = "ID_ADDR_";
|
||||
public static final String SHARE_PREFIX = "SHARE_";
|
||||
public static final char PATH_SEPARATOR_CHAR = '/';
|
||||
public static final String PATH_SEPARATOR = "" + PATH_SEPARATOR_CHAR;
|
||||
|
||||
protected void tryDeleteOrDeleteOnExit(File tmpFile) {
|
||||
if (!tmpFile.delete()) {
|
||||
log.error("delete tmp file error");
|
||||
tmpFile.deleteOnExit();
|
||||
}
|
||||
String fullSha1 = prepareUploadRequest.getFullSha1();
|
||||
FileVo otherSameFile = this.fileMapper.selectOneByCondition(FILE_VO.SHA1.eq(fullSha1));
|
||||
ChunkReady chunkReady = new ChunkReady();
|
||||
FileVo fileVo = new FileVo();
|
||||
fileVo.setUploader(user.getId());
|
||||
fileVo.setName(name);
|
||||
fileVo.setExt(ext);
|
||||
fileVo.setFolder(folder);
|
||||
fileVo.setSha1(fullSha1);
|
||||
this.fileMapper.insert(fileVo);
|
||||
int fid = fileVo.getId();
|
||||
if (otherSameFile != null) {
|
||||
int id = otherSameFile.getId();
|
||||
List<FileChunkVo> fileChunkVos = this.fileChunksMapper.selectListByCondition(FILE_CHUNK_VO.FILE.eq(id));
|
||||
for (FileChunkVo fileChunkVo : fileChunkVos) {
|
||||
fileChunkVo.setFile(fid);
|
||||
this.fileChunksMapper.insert(fileChunkVo);
|
||||
}
|
||||
return Result.failed(HttpStatus.FOUND, "后台存在相同文件,无需上传!");
|
||||
}
|
||||
String uploadId = this.randomUtils.generatorRandomString(40);
|
||||
chunkReady.setFileId(fid);
|
||||
chunkReady.setLength(prepareUploadRequest.getSize());
|
||||
uploadMapper.opsForValue().set(UPLOAD_FILE_PREPARE_HEAD + uploadId, chunkReady);
|
||||
return Result.success("成功", uploadId);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Transactional
|
||||
public Result<Void> uploadChunk(MultipartFile file, String id) {
|
||||
ValueOperations<String, ChunkChecked> chunkOps = chunkUploadMapper.opsForValue();
|
||||
ChunkChecked chunkData = chunkOps.getAndDelete(CHUNK_PREPARE_HEAD + id);
|
||||
if (chunkData == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "未知的文件块");
|
||||
public Result<FileVo> simpleUpload(MultipartHttpServletRequest request, UserVo user, String address) {
|
||||
long folderParams = getFolderParams(request);
|
||||
ServletRequestContext servletRequestContext = new ServletRequestContext(request);
|
||||
FileUpload upload = new FileUpload();
|
||||
FileItemIteratorImpl fileItemIterator = new FileItemIteratorImpl(upload, servletRequestContext);
|
||||
FileVo lastUploadFile = null;
|
||||
while (fileItemIterator.hasNext()) {
|
||||
FileItemStream next = fileItemIterator.next();
|
||||
String fieldName = next.getFieldName();
|
||||
if (fieldName.equals("file")) {
|
||||
String name = next.getName();
|
||||
int i = name.lastIndexOf(".");
|
||||
String extName = null;
|
||||
String start = name;
|
||||
if (i != -1) {
|
||||
start = name.substring(0, i);
|
||||
}
|
||||
long size = file.getSize();
|
||||
if (size > 64 * 1024 * 1024) {
|
||||
return Result.failed(HttpStatus.PAYLOAD_TOO_LARGE, "文件块不应大于64MB");
|
||||
if (!(i == -1 || i == name.length() - 1)) {
|
||||
extName = name.substring(i + 1);
|
||||
}
|
||||
byte[] bytes = file.getBytes();
|
||||
String s = DigestUtils.sha1Hex(bytes);
|
||||
if (!s.equals(chunkData.getHash())) {
|
||||
return Result.failed(HttpStatus.CONFLICT, "文件块内容错误!");
|
||||
if (fileMapper.selectCountByCondition(FILE_VO.NAME.eq(start).and(FILE_VO.EXT.eq(extName)).and(FILE_VO.FOLDER.eq(folderParams))) > 0) {
|
||||
return Result.failed(HttpStatus.CONFLICT, "存在同名文件,请改名或删除后重试!");
|
||||
}
|
||||
ChunkVo chunkVo = new ChunkVo();
|
||||
chunkVo.setSize(size);
|
||||
chunkVo.setSha1(s);
|
||||
String hashHead = s.substring(0, 2);
|
||||
File hashHeadFolder = new File(properties.getSavePath(), hashHead);
|
||||
if (!hashHeadFolder.exists()) {
|
||||
if (!hashHeadFolder.mkdirs()) {
|
||||
return Result.failed(HttpStatus.INTERNAL_SERVER_ERROR, "写入文件块出现错误,创建文件夹失败");
|
||||
InputStream inputStream = next.openStream();
|
||||
SizeStatisticsDigestInputStream digestInputStream = new SizeStatisticsDigestInputStream(inputStream, DigestUtils.getSha512Digest());
|
||||
File savePath = properties.getSavePath();
|
||||
File tmpFile = new File(savePath, "cache-" + randomUtils.generatorRandomFileName(20));
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) {
|
||||
StreamUtils.copy(digestInputStream, fileOutputStream);
|
||||
}
|
||||
digestInputStream.close();
|
||||
String hex = HashUtil.toHex(digestInputStream.getMessageDigest().digest());
|
||||
long size = digestInputStream.getSize();
|
||||
if (size == 0) {
|
||||
tryDeleteOrDeleteOnExit(tmpFile);
|
||||
return Result.failed(HttpStatus.LENGTH_REQUIRED, "请勿上传空文件!");
|
||||
}
|
||||
Tika tika = new Tika();
|
||||
String detect = tika.detect(tmpFile);
|
||||
FileVo fileVo = new FileVo();
|
||||
fileVo.setUploader(user.getId());
|
||||
fileVo.setMime(detect);
|
||||
fileVo.setSize(size);
|
||||
fileVo.setName(start);
|
||||
fileVo.setExt(extName);
|
||||
fileVo.setHash(hex);
|
||||
fileVo.setFolder(folderParams);
|
||||
fileMapper.insert(fileVo);
|
||||
statisticsService.insertAction(user, Actions.UPLOAD, JSONObject.of("id", fileVo.getId(), "hex", hex, "address", address));
|
||||
File targetFile = new File(savePath, hex);
|
||||
lastUploadFile = fileVo;
|
||||
if (targetFile.isFile()) {
|
||||
tryDeleteOrDeleteOnExit(tmpFile);
|
||||
continue;
|
||||
}
|
||||
if (!tmpFile.renameTo(targetFile)) {
|
||||
throw new RuntimeException("error while moving file");
|
||||
}
|
||||
}
|
||||
File chunkFile = new File(hashHeadFolder, s);
|
||||
if (!chunkFile.createNewFile()) {
|
||||
return Result.failed(HttpStatus.INTERNAL_SERVER_ERROR, "写入文件块出现错误,无法写入块文件");
|
||||
}
|
||||
try(FileOutputStream fos = new FileOutputStream(chunkFile)) {
|
||||
fos.write(bytes);
|
||||
if (lastUploadFile == null) {
|
||||
return Result.failed(HttpStatus.BAD_REQUEST, "未找到文件参数");
|
||||
}
|
||||
String fileId = chunkData.getFileId();
|
||||
ChunkReady chunkReady = uploadMapper.opsForValue().get(UPLOAD_FILE_PREPARE_HEAD + fileId);
|
||||
assert chunkReady != null;
|
||||
long fileTableId = chunkReady.getFileId();
|
||||
this.chunkMapper.insert(chunkVo);
|
||||
int chunkId = chunkVo.getId();
|
||||
FileChunkVo fileChunkVo = new FileChunkVo(fileTableId, chunkId, chunkData.getIndex());
|
||||
this.fileChunksMapper.insert(fileChunkVo);
|
||||
return Result.success("成功");
|
||||
return Result.success("上传成功!", lastUploadFile);
|
||||
}
|
||||
|
||||
public Result<CheckChunkResponse> checkChunk(String hash, String id, long index) {
|
||||
ChunkReady chunkReady = uploadMapper.opsForValue().get(UPLOAD_FILE_PREPARE_HEAD + id);
|
||||
if (chunkReady == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "未知的文件ID!");
|
||||
private static long getFolderParams(MultipartHttpServletRequest request) {
|
||||
String params = request.getQueryString();
|
||||
long folderParams = -1L;
|
||||
if (params != null && !params.isEmpty()) {
|
||||
String[] param = params.split("&");
|
||||
for (String s : param) {
|
||||
String[] keyValue = s.split("=");
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0];
|
||||
String value = keyValue[1];
|
||||
if (key.equals("folder")) {
|
||||
folderParams = Long.parseLong(value);
|
||||
}
|
||||
long fileId = chunkReady.getFileId();
|
||||
ChunkVo chunkVo = chunkMapper.selectOneByCondition(CHUNK_VO.SHA1.eq(hash));
|
||||
if (chunkVo != null) {
|
||||
FileChunkVo fileChunkVo = new FileChunkVo(fileId, chunkVo.getId(), index);
|
||||
this.fileChunksMapper.insert(fileChunkVo);
|
||||
return Result.success(CheckChunkResponse.has());
|
||||
}
|
||||
ValueOperations<String, ChunkChecked> chunkOps = chunkUploadMapper.opsForValue();
|
||||
String chunkId = randomUtils.generatorRandomString(40);
|
||||
chunkOps.set(CHUNK_PREPARE_HEAD + chunkId, new ChunkChecked(id, hash, index));
|
||||
return Result.success(CheckChunkResponse.shouldUpload(chunkId));
|
||||
}
|
||||
}
|
||||
return folderParams;
|
||||
}
|
||||
|
||||
public Result<FileObject> doneUpload(String id) {
|
||||
ChunkReady andDelete = uploadMapper.opsForValue().getAndDelete(UPLOAD_FILE_PREPARE_HEAD + id);
|
||||
if (andDelete == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "未知的文件ID");
|
||||
public Result<PageResult<RawFileObject>> getFilePager(long page, int num, long folder, String address) {
|
||||
QueryWrapper queryWrapper = select(
|
||||
FILE_VO.ID.as("id"),
|
||||
FILE_VO.NAME.as("name"),
|
||||
FILE_VO.EXT.as("ext"),
|
||||
FILE_VO.SIZE.as("size"),
|
||||
FILE_VO.FOLDER.as("parent"),
|
||||
FILE_VO.UPLOADER.as("owner"),
|
||||
FILE_VO.UPLOAD_TIME.as("time"),
|
||||
string("FILE").as("type")
|
||||
).from(FILE_VO).
|
||||
where(FILE_VO.FOLDER.eq(folder)).
|
||||
unionAll(
|
||||
select(
|
||||
FOLDER_VO.ID.as("id"),
|
||||
FOLDER_VO.NAME.as("name"),
|
||||
null_().as("ext"),
|
||||
number(-1).as("size"),
|
||||
FOLDER_VO.PARENT.as("parent"),
|
||||
FOLDER_VO.CREATOR.as("owner"),
|
||||
FOLDER_VO.CREATE_TIME.as("time"),
|
||||
string("FOLDER").as("type")
|
||||
).from(FOLDER_VO).
|
||||
where(FOLDER_VO.PARENT.eq(folder))
|
||||
).
|
||||
orderBy(
|
||||
column("time").
|
||||
asc(),
|
||||
column("id").
|
||||
asc()
|
||||
);
|
||||
Page<RawFileObject> paginate = fileMapper.paginateAs(page, num, queryWrapper, RawFileObject.class);
|
||||
PageResult<RawFileObject> result = new PageResult<>(paginate.getTotalRow(), paginate.getRecords());
|
||||
return Result.success(result);
|
||||
}
|
||||
long totalLength = andDelete.getLength();
|
||||
long l = calcFileSize(andDelete.getFileId());
|
||||
if (l != totalLength) {
|
||||
fileMapper.deleteById(andDelete.getFileId());
|
||||
return Result.failed(HttpStatus.LENGTH_REQUIRED, "应收到" + totalLength + "字节,但只收到" + l + "字节!");
|
||||
|
||||
public Result<FolderVo> mkdir(FolderCreateRequest request, UserVo user, String address) {
|
||||
String name = request.getName();
|
||||
long parent = request.getParent();
|
||||
if (fileMapper.selectCountByCondition(FILE_VO.EXT.eq(null_()).and(FILE_VO.NAME.eq(name)).and(FILE_VO.FOLDER.eq(parent))) > 0) {
|
||||
return Result.failed(HttpStatus.CONFLICT, "创建文件夹失败,同名文件已存在!");
|
||||
}
|
||||
if (folderMapper.selectCountByCondition(FOLDER_VO.NAME.eq(name).and(FOLDER_VO.PARENT.eq(parent))) > 0) {
|
||||
return Result.failed(HttpStatus.CONFLICT, "创建文件夹失败,同名文件已存在!");
|
||||
}
|
||||
FolderVo folderVo = new FolderVo();
|
||||
folderVo.setCreator(user.getId());
|
||||
folderVo.setName(name);
|
||||
folderVo.setParent(parent);
|
||||
folderMapper.insert(folderVo);
|
||||
statisticsService.insertAction(user, Actions.UPLOAD, JSONObject.of("type", "folder", "id", folderVo.getId(), "address", address));
|
||||
return Result.success("创建成功", folderVo);
|
||||
}
|
||||
|
||||
protected void deleteFile(FileVo fileVo) {
|
||||
if (fileMapper.selectCountByCondition(FILE_VO.HASH.eq(fileVo.getHash())) <= 0) {
|
||||
String hash = fileVo.getHash();
|
||||
File file = new File(properties.getSavePath(), hash);
|
||||
if (file.exists()) {
|
||||
if (!file.delete()) {
|
||||
log.error("删除文件 {} 失败!", file);
|
||||
}
|
||||
} else {
|
||||
log.error("存储目录可能损坏,在删除文件 {} 时未发现文件", file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Result<Void> delete(DeleteRequest request, UserVo user, String address) {
|
||||
long id = request.getId();
|
||||
FileType type = request.getType();
|
||||
long actorId = user.getId();
|
||||
if (type.equals(FileType.FILE)) {
|
||||
FileVo fileVo = fileMapper.selectOneById(id);
|
||||
if (fileVo == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "文件不存在!");
|
||||
}
|
||||
if (user.getAuth().equals(Auth.user)) {
|
||||
if (fileMapper.selectCountByCondition(FILE_VO.ID.eq(id).and(FILE_VO.UPLOADER.eq(actorId))) <= 0) {
|
||||
return Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!");
|
||||
}
|
||||
}
|
||||
fileMapper.deleteById(fileVo.getId());
|
||||
deleteFile(fileVo);
|
||||
} else {
|
||||
FolderVo folder = folderMapper.selectOneById(id);
|
||||
if (folder == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "文件不存在!");
|
||||
}
|
||||
if (user.getAuth().equals(Auth.user)) {
|
||||
if (folderMapper.selectCountByCondition(FOLDER_VO.ID.eq(id).and(FOLDER_VO.CREATOR.eq(actorId))) <= 0) {
|
||||
return Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!");
|
||||
}
|
||||
}
|
||||
fileMapper.deleteByCondition(FILE_VO.FOLDER.eq(id));
|
||||
for (FileVo fileVo : fileMapper.selectListByCondition(FILE_VO.FOLDER.eq(id))) {
|
||||
deleteFile(fileVo);
|
||||
}
|
||||
}
|
||||
statisticsService.insertAction(user, Actions.DELETE, JSONObject.of("id", id, "type", type, "address", address));
|
||||
return Result.success();
|
||||
}
|
||||
private long calcFileSize(long id) {
|
||||
List<Long> longs = this.fileChunksMapper.selectListByQueryAs(new QueryWrapper().select(CHUNK_VO.SIZE).from(FILE_CHUNK_VO).where(FILE_CHUNK_VO.FILE.eq(id)).leftJoin(CHUNK_VO).on(CHUNK_VO.ID.eq(FILE_CHUNK_VO.CHUNK)), Long.class);
|
||||
long sum = 0L;
|
||||
for (Long aLong : longs) {
|
||||
sum += aLong;
|
||||
|
||||
public Result<FileVo> getFileDetail(long id) {
|
||||
FileVo fileVo = this.fileMapper.selectOneById(id);
|
||||
if (fileVo == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "未知文件");
|
||||
}
|
||||
return sum;
|
||||
return Result.success(fileVo);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void downloadFile(String id, String range, HttpServletResponse response) {
|
||||
FileVo fileVo = linkMapper.opsForValue().get(id);
|
||||
if (fileVo == null) {
|
||||
Result.failed(HttpStatus.NOT_FOUND, "未知文件!").writeToResponse(response);
|
||||
return;
|
||||
}
|
||||
long size = fileVo.getSize();
|
||||
long min = 0;
|
||||
long max = size;
|
||||
if (!range.equals("null")) {
|
||||
String[] unitRanges = range.split("=");
|
||||
String[] minMax = unitRanges[1].split("-");
|
||||
if (minMax.length > 0) {
|
||||
min = Long.parseLong(minMax[0]);
|
||||
}
|
||||
if (minMax.length > 1) {
|
||||
max = Long.parseLong(minMax[1]);
|
||||
}
|
||||
}
|
||||
String hash = fileVo.getHash();
|
||||
File file = new File(properties.getSavePath(), hash);
|
||||
String fullName = fileVo.getName();
|
||||
String ext = fileVo.getExt();
|
||||
if (ext != null) {
|
||||
fullName += '.' + ext;
|
||||
}
|
||||
response.setStatus(206);
|
||||
response.addHeader("Content-Length", String.valueOf(max - min));
|
||||
response.addHeader("Content-Range", "bytes " + min + "-" + max + "/" + size);
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fullName, StandardCharsets.UTF_8));
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
StreamUtils.copyRange(fis, outputStream, min, max);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
public Result<String> getFileLink(long id, String address, HttpServletRequest request) {
|
||||
FileVo fileVo = fileMapper.selectOneById(id);
|
||||
long fileId = fileVo.getId();
|
||||
String identify = ID_ADDR_PREFIX + fileId + address;
|
||||
String link = idAddrLinkMapper.opsForValue().get(identify);
|
||||
if (link == null) {
|
||||
link = randomUtils.generatorRandomFileName(8);
|
||||
String authorization = request.getHeader("Authorization");
|
||||
if (authorization != null) {
|
||||
jwtUtils.getUser(authorization).ifPresent(uid -> statisticsService.insertAction(new UserVo(uid), Actions.DOWNLOAD, JSONObject.of("id", fileId, "address", address)));
|
||||
} else {
|
||||
statisticsService.insertAction(Actions.DOWNLOAD, JSONObject.of("id", fileId, "address", address));
|
||||
}
|
||||
linkMapper.opsForValue().set(link, fileVo, 30, TimeUnit.MINUTES);
|
||||
idAddrLinkMapper.opsForValue().set(identify, link, 30, TimeUnit.MINUTES);
|
||||
}
|
||||
return Result.success("成功", link);
|
||||
}
|
||||
|
||||
public Result<String> shareFile(Long id, Date lastCouldDownloadTime, int maxDownloadCount) {
|
||||
FileVo fileVo = this.fileMapper.selectOneById(id);
|
||||
if (fileVo == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "未知文件");
|
||||
}
|
||||
String linkName = randomUtils.generatorRandomFileName(10);
|
||||
String innerId = randomUtils.generatorRandomString(30);
|
||||
long expireAfterMs = lastCouldDownloadTime.getTime() - new Date().getTime();
|
||||
return Result.success(linkName);
|
||||
}
|
||||
|
||||
public Result<RawFileObject> resolveFileDetail(String path) {
|
||||
String[] split = path.split(PATH_SEPARATOR);
|
||||
RawFileObject fileObj = pathService.resolveFile(split);
|
||||
if (fileObj == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "文件不存在!");
|
||||
}
|
||||
return Result.success(fileObj);
|
||||
}
|
||||
|
||||
public Result<String> findFilePathById(long id) {
|
||||
FileVo fileVo = fileMapper.selectOneById(id);
|
||||
if (fileVo == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "文件不存在!");
|
||||
}
|
||||
return Result.success("成功", pathService.getFilePath(RawFileObject.of(fileVo)));
|
||||
}
|
||||
|
||||
public Result<String> findFolderPathById(long id) {
|
||||
FolderVo folderVo = folderMapper.selectOneById(id);
|
||||
if (folderVo == null) {
|
||||
return Result.failed(HttpStatus.NOT_FOUND, "文件夹不存在");
|
||||
}
|
||||
return Result.success("成功", pathService.getFilePath(RawFileObject.of(folderVo)));
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.wzpmc.filemanager.service;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.statistics.enums.Actions;
|
||||
import cn.wzpmc.filemanager.entities.vo.StatisticsVo;
|
||||
import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.mapper.StatisticsMapper;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class StatisticsService {
|
||||
private final StatisticsMapper statisticsMapper;
|
||||
|
||||
public void insertAction(@Nullable UserVo actor, Actions actions, @Nullable Object params) {
|
||||
statisticsMapper.insert(new StatisticsVo(actor != null ? actor.getId() : null, actions, params != null ? params.toString() : null));
|
||||
}
|
||||
|
||||
public void insertAction(@Nullable UserVo actor, Actions actions) {
|
||||
this.insertAction(actor, actions, null);
|
||||
}
|
||||
|
||||
public void insertAction(Actions actions, @Nullable Object params) {
|
||||
this.insertAction(null, actions, params);
|
||||
}
|
||||
|
||||
public void insertAction(Actions actions) {
|
||||
this.insertAction(actions, null);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package cn.wzpmc.filemanager.service;
|
||||
|
||||
import cn.wzpmc.filemanager.entities.Result;
|
||||
import cn.wzpmc.filemanager.entities.statistics.enums.Actions;
|
||||
import cn.wzpmc.filemanager.entities.user.UserLoginRequest;
|
||||
import cn.wzpmc.filemanager.entities.user.UserRegisterRequest;
|
||||
import cn.wzpmc.filemanager.entities.user.enums.Auth;
|
||||
@ -8,6 +9,7 @@ import cn.wzpmc.filemanager.entities.vo.UserVo;
|
||||
import cn.wzpmc.filemanager.mapper.UserMapper;
|
||||
import cn.wzpmc.filemanager.utils.JwtUtils;
|
||||
import cn.wzpmc.filemanager.utils.RandomUtils;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryCondition;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@ -30,66 +32,77 @@ public class UserService {
|
||||
private final JwtUtils jwtUtils;
|
||||
private final StringRedisTemplate authTemplate;
|
||||
private final RandomUtils randomUtils;
|
||||
private final StatisticsService statisticsService;
|
||||
@Autowired
|
||||
public UserService(UserMapper userMapper, JwtUtils jwtUtils, StringRedisTemplate authTemplate, RandomUtils randomUtils) {
|
||||
public UserService(UserMapper userMapper, JwtUtils jwtUtils, StringRedisTemplate authTemplate, RandomUtils randomUtils, StatisticsService statisticsService) {
|
||||
this.userMapper = userMapper;
|
||||
this.jwtUtils = jwtUtils;
|
||||
this.authTemplate = authTemplate;
|
||||
this.randomUtils = randomUtils;
|
||||
this.statisticsService = statisticsService;
|
||||
long count = this.userMapper.selectCountByQuery(new QueryWrapper());
|
||||
if (count == 0) {
|
||||
String s = genInviteCode();
|
||||
String s = genInviteCode(UserVo.CONSOLE, "0.0.0.0");
|
||||
log.info("生成了管理员密钥:{},有效期15分钟,若失效请使用控制台命令/key或重启后端重新生成!", s);
|
||||
}
|
||||
}
|
||||
public void login(UserLoginRequest request, HttpServletResponse response) {
|
||||
public void login(UserLoginRequest request, HttpServletResponse response, String address) {
|
||||
String username = request.getUsername();
|
||||
String password = request.getPassword();
|
||||
String sha1edPassword = DigestUtils.sha1Hex(password);
|
||||
QueryCondition findUserCondition = USER_VO.NAME.eq(username).and(USER_VO.PASSWORD.eq(sha1edPassword));
|
||||
long count = this.userMapper.selectCountByCondition(findUserCondition);
|
||||
if (count < 0) {
|
||||
if (count <= 0) {
|
||||
this.statisticsService.insertAction(Actions.LOGIN, JSONObject.of("status", "error", "msg", "账号或密码错误", "address", address));
|
||||
Result.failed(HttpStatus.UNAUTHORIZED, "账号或密码错误").writeToResponse(response);
|
||||
return;
|
||||
}
|
||||
UserVo userVo = this.userMapper.selectOneByCondition(findUserCondition);
|
||||
String token = this.jwtUtils.createToken(userVo.getId());
|
||||
long id = userVo.getId();
|
||||
String token = this.jwtUtils.createToken(id);
|
||||
response.addHeader("Add-Authorization", token);
|
||||
this.statisticsService.insertAction(userVo, Actions.LOGIN, JSONObject.of("status", "success", "address", address));
|
||||
Result.success("登录成功").writeToResponse(response);
|
||||
}
|
||||
public void register(UserRegisterRequest request, HttpServletResponse response) {
|
||||
public void register(UserRegisterRequest request, HttpServletResponse response, String address) {
|
||||
String username = request.getUsername();
|
||||
String password = request.getPassword();
|
||||
Auth auth = request.getAuth();
|
||||
if (this.userMapper.selectCountByCondition(USER_VO.NAME.eq(username)) > 0) {
|
||||
this.statisticsService.insertAction(Actions.REGISTER, JSONObject.of("status", "error", "auth", auth, "msg", "用户名已存在", "address", address));
|
||||
Result.failed(HttpStatus.CONFLICT).msg("用户名已存在,若需要修改密码,请联系网站管理员处理").writeToResponse(response);
|
||||
return;
|
||||
}
|
||||
JSONObject statisticsData = JSONObject.of("status", "success", "auth", auth, "address", address);
|
||||
if (auth.equals(Auth.admin)) {
|
||||
String inviteCode = request.getInviteCode();
|
||||
ValueOperations<String, String> ops = authTemplate.opsForValue();
|
||||
String andDelete = ops.getAndDelete(inviteCode);
|
||||
if (andDelete == null) {
|
||||
this.statisticsService.insertAction(Actions.REGISTER, JSONObject.of("status", "error", "auth", auth, "msg", "邀请码错误", "inviteCode", inviteCode, "address", address));
|
||||
Result.failed(HttpStatus.NOT_FOUND, "过期或无效的邀请码").writeToResponse(response);
|
||||
return;
|
||||
}
|
||||
statisticsData.put("inviteCode", inviteCode);
|
||||
}
|
||||
UserVo userVo = new UserVo(username, password, auth);
|
||||
this.userMapper.insert(userVo);
|
||||
int id = userVo.getId();
|
||||
long id = userVo.getId();
|
||||
String token = this.jwtUtils.createToken(id);
|
||||
response.addHeader("Add-Authorization", token);
|
||||
this.statisticsService.insertAction(userVo, Actions.REGISTER, statisticsData);
|
||||
Result.success("注册成功!").writeToResponse(response);
|
||||
}
|
||||
|
||||
public Result<String> invite() {
|
||||
String s = genInviteCode();
|
||||
public Result<String> invite(UserVo userVo, String address) {
|
||||
String s = genInviteCode(userVo, address);
|
||||
return Result.success("生成了一个有效期15分钟的邀请码", s);
|
||||
}
|
||||
public String genInviteCode() {
|
||||
public String genInviteCode(UserVo actor, String address) {
|
||||
ValueOperations<String, String> ops = authTemplate.opsForValue();
|
||||
String s = this.randomUtils.generatorRandomString(8);
|
||||
log.info("生成了新的邀请码:{}", s);
|
||||
statisticsService.insertAction(actor, Actions.INVITE, address);
|
||||
ops.set(s, "", 15, TimeUnit.MINUTES);
|
||||
return s;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package cn.wzpmc.filemanager.utils;
|
||||
|
||||
import cn.wzpmc.filemanager.annotation.Address;
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AddressArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.hasParameterAnnotation(Address.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object resolveArgument(@NonNull MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, @NonNull NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
|
||||
if (webRequest instanceof ServletWebRequest servletWebRequest) {
|
||||
return servletWebRequest.getRequest().getRemoteAddr();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
|
||||
@Component
|
||||
@Log4j2
|
||||
@ -35,7 +34,7 @@ public class JwtUtils {
|
||||
}
|
||||
this.hmacKey = Algorithm.HMAC512(key);
|
||||
}
|
||||
public String createToken(int uid){
|
||||
public String createToken(long uid){
|
||||
Calendar instance = Calendar.getInstance();
|
||||
instance.add(Calendar.HOUR,24 * 5);
|
||||
JWTCreator.Builder builder = JWT.create();
|
||||
|
@ -16,4 +16,18 @@ public class RandomUtils {
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
public String generatorRandomFileName(int length) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
double random = Math.random();
|
||||
int c = new Random().nextInt(97,122);
|
||||
if (random < 0.3) {
|
||||
c = new Random().nextInt(48, 57);
|
||||
}else if(random < 0.6) {
|
||||
c = new Random().nextInt(65, 90);
|
||||
}
|
||||
builder.append((char) c);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package cn.wzpmc.filemanager.utils;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
@Getter
|
||||
public class SizeStatisticsDigestInputStream extends DigestInputStream {
|
||||
protected long size = 0;
|
||||
public SizeStatisticsDigestInputStream(InputStream stream, MessageDigest digest) {
|
||||
super(stream, digest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int read = super.read();
|
||||
if (read != -1) size++;
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
int read = super.read(b, off, len);
|
||||
if (read != -1) size += read;
|
||||
return read;
|
||||
}
|
||||
}
|
@ -15,8 +15,9 @@ spring:
|
||||
password: "MyCraftAdmin123"
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 100GB
|
||||
max-request-size: 100GB
|
||||
max-file-size: 400GB
|
||||
max-request-size: 400GB
|
||||
resolve-lazily: true
|
||||
wzp:
|
||||
filemanager:
|
||||
save-path: "./file"
|
||||
|
Loading…
x
Reference in New Issue
Block a user