esoe
6 months ago
20 changed files with 131 additions and 447 deletions
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.config; |
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
||||
@ConfigurationProperties(prefix = "storage") |
||||
public class StorageProperties { |
||||
private String location; |
||||
|
||||
public String getLocation() { |
||||
return location; |
||||
} |
||||
|
||||
public void setLocation(String location) { |
||||
this.location = location; |
||||
} |
||||
|
||||
} |
@ -1,74 +0,0 @@
@@ -1,74 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.controller; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.stream.Collectors; |
||||
|
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.stereotype.Controller; |
||||
import org.springframework.ui.Model; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.PathVariable; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RequestParam; |
||||
import org.springframework.web.bind.annotation.ResponseBody; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; |
||||
|
||||
import ru.molokoin.explorer_rs.entity.FileResponse; |
||||
import ru.molokoin.explorer_rs.service.StorageService; |
||||
|
||||
@Controller |
||||
@RequestMapping(path = "/explorer_rs") |
||||
public class FileController { |
||||
private StorageService storageService; |
||||
|
||||
public FileController(StorageService storageService) { |
||||
this.storageService = storageService; |
||||
} |
||||
|
||||
@GetMapping("/list") |
||||
public String listAllFiles(Model model) { |
||||
model.addAttribute("files", storageService.loadAll().map( |
||||
path -> ServletUriComponentsBuilder.fromCurrentContextPath() |
||||
.path("/explorer_rs/download/") |
||||
.path(path.getFileName().toString()) |
||||
.toUriString()) |
||||
.collect(Collectors.toList())); |
||||
return "listFiles"; |
||||
} |
||||
|
||||
@GetMapping("/download/{filename:.+}") |
||||
@ResponseBody |
||||
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) { |
||||
Resource resource = storageService.loadAsResource(filename); |
||||
return ResponseEntity.ok() |
||||
.header(HttpHeaders.CONTENT_DISPOSITION, |
||||
"attachment; filename=\"" + resource.getFilename() + "\"") |
||||
.body(resource); |
||||
} |
||||
|
||||
@PostMapping("/upload-file") |
||||
@ResponseBody |
||||
public FileResponse uploadFile(@RequestParam("file") MultipartFile file) { |
||||
String name = storageService.store(file); |
||||
String uri = ServletUriComponentsBuilder.fromCurrentContextPath() |
||||
.path("/download/") |
||||
.path(name) |
||||
.toUriString(); |
||||
|
||||
return new FileResponse(name, uri, file.getContentType(), file.getSize()); |
||||
} |
||||
|
||||
@PostMapping("/upload-multiple-files") |
||||
@ResponseBody |
||||
public List<FileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) { |
||||
return Arrays.stream(files) |
||||
.map(file -> uploadFile(file)) |
||||
.collect(Collectors.toList()); |
||||
} |
||||
|
||||
} |
@ -1,62 +0,0 @@
@@ -1,62 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.controller; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.web.bind.annotation.DeleteMapping; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.PathVariable; |
||||
import org.springframework.web.bind.annotation.PostMapping; |
||||
import org.springframework.web.bind.annotation.RequestBody; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import ru.molokoin.explorer_rs.repository.PackageFace; |
||||
import ru.molokoin.explorer_rs.entity.Package; |
||||
|
||||
@RestController |
||||
@RequestMapping(path = "/", consumes = {"*/*"}) |
||||
public class PackageController { |
||||
@Autowired |
||||
private PackageFace repo; |
||||
|
||||
@GetMapping("/package/list") |
||||
public ResponseEntity<?> getPackages(){ |
||||
return new ResponseEntity<>(repo.findAll(), HttpStatus.OK); |
||||
} |
||||
|
||||
@GetMapping("/package/{id}") |
||||
public ResponseEntity<?> getPackageByID(@PathVariable Integer id){ |
||||
return new ResponseEntity<>(repo.findPackageById(id), HttpStatus.OK); |
||||
} |
||||
|
||||
@PostMapping(path = "/package/create", |
||||
consumes = MediaType.APPLICATION_JSON_VALUE, |
||||
produces = MediaType.APPLICATION_JSON_VALUE) |
||||
public ResponseEntity<?> savePackage(@RequestBody Package pack) { |
||||
repo.save(pack); |
||||
return new ResponseEntity<>(pack, HttpStatus.CREATED); |
||||
} |
||||
|
||||
@PostMapping(path = "/package/update/{id}", |
||||
consumes = MediaType.APPLICATION_JSON_VALUE, |
||||
produces = MediaType.APPLICATION_JSON_VALUE) |
||||
public ResponseEntity<?> updatePackage(@PathVariable Integer id, @RequestBody Package pack) { |
||||
Package p = repo.findPackageById(id); |
||||
p.setTitle(pack.getTitle()); |
||||
p.setOrigin_title(pack.getOrigin_title()); |
||||
p.setType(pack.getType()); |
||||
p.setExtension(pack.getExtension()); |
||||
p.setDate(pack.getDate()); |
||||
repo.save(p); |
||||
return new ResponseEntity<>(repo.findPackageById(id), HttpStatus.CREATED); |
||||
} |
||||
|
||||
@DeleteMapping("/package/delete/{id}") |
||||
public ResponseEntity<?> deletePackage(@PathVariable Long id){ |
||||
Package p = repo.findPackageById(id); |
||||
repo.delete(p); |
||||
return new ResponseEntity<>("Запись id#" + id + " удалена ... ", HttpStatus.OK); |
||||
} |
||||
} |
@ -1,10 +1,41 @@
@@ -1,10 +1,41 @@
|
||||
package ru.molokoin.explorer_rs.controller; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.http.ResponseEntity; |
||||
import org.springframework.stereotype.Controller; |
||||
import org.springframework.web.bind.annotation.GetMapping; |
||||
import org.springframework.web.bind.annotation.RequestMapping; |
||||
import org.springframework.web.bind.annotation.RestController; |
||||
|
||||
import ru.molokoin.explorer_rs.service.StorageFace; |
||||
import ru.molokoin.explorer_rs.entity.Document;; |
||||
|
||||
@Controller |
||||
@RequestMapping(path = "/stroage") |
||||
/** |
||||
* Контроллер предоставляющий http-api |
||||
* для доступа к файлам хранилища данных |
||||
* |
||||
*/ |
||||
@RestController |
||||
@RequestMapping(path = "/", consumes = {"*/*"}) |
||||
public class StorageController { |
||||
|
||||
@Autowired |
||||
private StorageFace storage; |
||||
|
||||
// public StorageController(StorageFace storage){
|
||||
// this.storage = storage;
|
||||
// }
|
||||
|
||||
/** |
||||
* Получение перечня документов размещенных в хранилище |
||||
* - перечень формируется на основании сканирования файловой системы |
||||
* @return |
||||
*/ |
||||
@GetMapping(path = "/storage/list") |
||||
public ResponseEntity<List<Document>> listStorage(){ |
||||
return new ResponseEntity<>(storage.list(), HttpStatus.OK); |
||||
} |
||||
} |
||||
|
@ -1,39 +1,15 @@
@@ -1,39 +1,15 @@
|
||||
package ru.molokoin.explorer_rs.entity; |
||||
|
||||
import jakarta.persistence.Entity; |
||||
import jakarta.persistence.GeneratedValue; |
||||
import jakarta.persistence.GenerationType; |
||||
import jakarta.persistence.Id; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
|
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
@Entity |
||||
@Data |
||||
public class Document { |
||||
@Id |
||||
@GeneratedValue(strategy=GenerationType.AUTO) |
||||
private long id; |
||||
public class Document extends Object{ |
||||
private String name;//наименование файла в файловой системе ({id}.{extension})
|
||||
private String name_origin;//оригинальное название загруженного файл
|
||||
private String path;//путь в файловой системе (root/{id}.{extension})
|
||||
private String extension;//расширение файла
|
||||
private long size;//размер файла
|
||||
|
||||
/** |
||||
* @param name |
||||
* @param name_origin |
||||
* @param path |
||||
* @param extension |
||||
* @param size |
||||
*/ |
||||
public Document(String name, String name_origin, String path, String extension, long size) { |
||||
this.name = name; |
||||
this.name_origin = name_origin; |
||||
this.path = path; |
||||
this.extension = extension; |
||||
this.size = size; |
||||
} |
||||
} |
||||
|
@ -1,18 +0,0 @@
@@ -1,18 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.entity; |
||||
|
||||
import lombok.Data; |
||||
|
||||
@Data |
||||
public class FileResponse { |
||||
private String name; |
||||
private String uri; |
||||
private String type; |
||||
private long size; |
||||
|
||||
public FileResponse(String name, String uri, String type, long size) { |
||||
this.name = name; |
||||
this.uri = uri; |
||||
this.type = type; |
||||
this.size = size; |
||||
} |
||||
} |
@ -1,48 +0,0 @@
@@ -1,48 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.entity; |
||||
|
||||
import java.util.Date; |
||||
|
||||
import jakarta.persistence.Entity; |
||||
import jakarta.persistence.GeneratedValue; |
||||
import jakarta.persistence.GenerationType; |
||||
import jakarta.persistence.Id; |
||||
import lombok.AllArgsConstructor; |
||||
import lombok.Data; |
||||
import lombok.NoArgsConstructor; |
||||
|
||||
/** |
||||
* Обертка для хранения данных о загружаемом пакете |
||||
*/ |
||||
@NoArgsConstructor |
||||
@AllArgsConstructor |
||||
@Entity |
||||
@Data |
||||
public class Package { |
||||
@Id |
||||
@GeneratedValue(strategy=GenerationType.AUTO) |
||||
private long id; |
||||
private String title;// Наименование файла в файловой системе
|
||||
private String origin_title;// Наименование загружаемого файла
|
||||
private String type;// Наименование загружаемой формы
|
||||
private String extension;// Расширение файла
|
||||
private Date date;// Время загрузки пакета на сервер
|
||||
|
||||
// Пока не работает блок авторизации, учет автора безсмысленен
|
||||
// private Person author;// Пользователь, загрузивший файл
|
||||
|
||||
/** |
||||
* Конструктор без id |
||||
* @param title |
||||
* @param origin_title |
||||
* @param type |
||||
* @param extension |
||||
* @param date |
||||
*/ |
||||
public Package(String title, String origin_title, String type, String extension, Date date) { |
||||
this.title = title; |
||||
this.origin_title = origin_title; |
||||
this.type = type; |
||||
this.extension = extension; |
||||
this.date = date; |
||||
} |
||||
} |
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.repository; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.data.repository.ListCrudRepository; |
||||
import org.springframework.stereotype.Repository; |
||||
|
||||
import ru.molokoin.explorer_rs.entity.Document; |
||||
|
||||
@Repository |
||||
public interface DocumentFace extends ListCrudRepository<Document, Long>{ |
||||
List<Document> findAll(); |
||||
Document findDocumentById(long id); |
||||
} |
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.repository; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.springframework.data.repository.ListCrudRepository; |
||||
import org.springframework.stereotype.Repository; |
||||
|
||||
import ru.molokoin.explorer_rs.entity.Package; |
||||
|
||||
@Repository |
||||
public interface PackageFace extends ListCrudRepository<Package, Long>{ |
||||
List<Package> findAll(); |
||||
Package findPackageById(long id); |
||||
} |
@ -1,5 +1,12 @@
@@ -1,5 +1,12 @@
|
||||
package ru.molokoin.explorer_rs.repository; |
||||
|
||||
public interface RecordFace { |
||||
import java.util.List; |
||||
|
||||
import org.springframework.data.repository.ListCrudRepository; |
||||
import org.springframework.stereotype.Repository; |
||||
|
||||
@Repository |
||||
public interface RecordFace extends ListCrudRepository<Record, Long>{ |
||||
List<Record> findAll(); |
||||
Record findRecordById(long id); |
||||
} |
||||
|
@ -1,107 +0,0 @@
@@ -1,107 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.service; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.net.MalformedURLException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.nio.file.Paths; |
||||
import java.nio.file.StandardCopyOption; |
||||
import java.util.stream.Stream; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.core.io.UrlResource; |
||||
import org.springframework.stereotype.Service; |
||||
import org.springframework.util.FileSystemUtils; |
||||
import org.springframework.util.StringUtils; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import jakarta.annotation.PostConstruct; |
||||
import ru.molokoin.explorer_rs.config.StorageProperties; |
||||
import ru.molokoin.explorer_rs.exception.StorageException; |
||||
import ru.molokoin.explorer_rs.exception.FileNotFoundException; |
||||
|
||||
@Service |
||||
public class FileSystemStorageService implements StorageService{ |
||||
private final Path rootLocation; |
||||
|
||||
@Autowired |
||||
public FileSystemStorageService(StorageProperties properties) { |
||||
this.rootLocation = Paths.get(properties.getLocation()); |
||||
} |
||||
|
||||
@Override |
||||
@PostConstruct |
||||
public void init() { |
||||
try { |
||||
Files.createDirectories(rootLocation); |
||||
} catch (IOException e) { |
||||
throw new StorageException("Could not initialize storage location", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String store(MultipartFile file) { |
||||
String filename = StringUtils.cleanPath(file.getOriginalFilename()); |
||||
try { |
||||
if (file.isEmpty()) { |
||||
throw new StorageException("Failed to store empty file " + filename); |
||||
} |
||||
if (filename.contains("..")) { |
||||
// This is a security check
|
||||
throw new StorageException( |
||||
"Cannot store file with relative path outside current directory " |
||||
+ filename); |
||||
} |
||||
try (InputStream inputStream = file.getInputStream()) { |
||||
Files.copy(inputStream, this.rootLocation.resolve(filename), |
||||
StandardCopyOption.REPLACE_EXISTING); |
||||
} |
||||
} |
||||
catch (IOException e) { |
||||
throw new StorageException("Failed to store file " + filename, e); |
||||
} |
||||
return filename; |
||||
} |
||||
|
||||
@Override |
||||
public Stream<Path> loadAll() { |
||||
try { |
||||
return Files.walk(this.rootLocation, 1) |
||||
.filter(path -> !path.equals(this.rootLocation)) |
||||
.map(this.rootLocation::relativize); |
||||
} |
||||
catch (IOException e) { |
||||
throw new StorageException("Failed to read stored files", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Path load(String filename) { |
||||
return rootLocation.resolve(filename); |
||||
} |
||||
|
||||
@Override |
||||
public Resource loadAsResource(String filename) { |
||||
try { |
||||
Path file = load(filename); |
||||
Resource resource = new UrlResource(file.toUri()); |
||||
if (resource.exists() || resource.isReadable()) { |
||||
return resource; |
||||
} |
||||
else { |
||||
throw new FileNotFoundException( |
||||
"Could not read file: " + filename); |
||||
} |
||||
}catch (MalformedURLException e) { |
||||
throw new FileNotFoundException("Could not read file: " + filename, e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void deleteAll() { |
||||
FileSystemUtils.deleteRecursively(rootLocation.toFile()); |
||||
} |
||||
|
||||
} |
@ -1,16 +0,0 @@
@@ -1,16 +0,0 @@
|
||||
package ru.molokoin.explorer_rs.service; |
||||
|
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.web.multipart.MultipartFile; |
||||
|
||||
import java.nio.file.Path; |
||||
import java.util.stream.Stream; |
||||
|
||||
public interface StorageService { |
||||
void init(); |
||||
String store(MultipartFile file); |
||||
Stream<Path> loadAll(); |
||||
Path load(String filename); |
||||
Resource loadAsResource(String filename); |
||||
void deleteAll(); |
||||
} |
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
{"properties": [{ |
||||
"name": "storage.location", |
||||
"type": "java.lang.String", |
||||
"description": "Path to local storage for uploaded files" |
||||
}]} |
Loading…
Reference in new issue