Add user profile picture storage service
parent
907e0327df
commit
b3144e5601
2
config
2
config
|
@ -1 +1 @@
|
||||||
Subproject commit c02e79c9aad0a236f1549e849233f9b9193a025f
|
Subproject commit ccf6fbb013c16dbda4ce5c76de706caed5ccde72
|
|
@ -1,7 +1,7 @@
|
||||||
server.port = 9020
|
server.port = 9020
|
||||||
spring.datasource.url = jdbc:mysql://localhost:3306/events
|
spring.datasource.url = jdbc:mysql://localhost:3306/events
|
||||||
spring.datasource.username = root
|
spring.datasource.username = root
|
||||||
spring.datasource.password = root
|
spring.datasource.password = skorpion
|
||||||
spring.jpa.generate-ddl=true
|
spring.jpa.generate-ddl=true
|
||||||
user.password=dizda
|
user.password=dizda
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
server.port=9010
|
server.port=9010
|
||||||
spring.datasource.url = jdbc:mysql://localhost:3306/teams
|
spring.datasource.url = jdbc:mysql://localhost:3306/teams
|
||||||
spring.datasource.username = root
|
spring.datasource.username = root
|
||||||
spring.datasource.password = root
|
spring.datasource.password = skorpion
|
||||||
spring.jpa.generate-ddl=true
|
spring.jpa.generate-ddl=true
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package ba.steleks;
|
package ba.steleks;
|
||||||
|
|
||||||
|
import ba.steleks.storage.StorageProperties;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
|
@EnableConfigurationProperties(StorageProperties.class)
|
||||||
public class SteleksServiceApplication {
|
public class SteleksServiceApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package ba.steleks.controller;
|
||||||
|
|
||||||
|
import ba.steleks.model.User;
|
||||||
|
import ba.steleks.repository.UsersJpaRepository;
|
||||||
|
import ba.steleks.storage.StorageFileNotFoundException;
|
||||||
|
import ba.steleks.storage.StorageService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.rest.webmvc.RepositoryRestController;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by admin on 02/04/2017.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class ProfilePictureController {
|
||||||
|
|
||||||
|
private final StorageService storageService;
|
||||||
|
private final UsersJpaRepository repository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ProfilePictureController(StorageService storageService, UsersJpaRepository repository) {
|
||||||
|
this.storageService = storageService;
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/profilePictures/{filename:.+}")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
|
||||||
|
|
||||||
|
Resource file = storageService.loadAsResource(filename);
|
||||||
|
return ResponseEntity
|
||||||
|
.ok()
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\""+file.getFilename()+"\"")
|
||||||
|
.body(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/users/{userId}/profilePicture")
|
||||||
|
public String handleFileUpload(@PathVariable Long userId, @RequestParam("file") MultipartFile file,
|
||||||
|
RedirectAttributes redirectAttributes) {
|
||||||
|
|
||||||
|
String[] names = file.getOriginalFilename().split("\\.");
|
||||||
|
String dest = String.valueOf(userId + "_" + new Date().getTime()) + "." + names[names.length - 1];
|
||||||
|
storageService.store(file, dest);
|
||||||
|
redirectAttributes.addFlashAttribute("message",
|
||||||
|
"You successfully uploaded " + file.getOriginalFilename() + "!");
|
||||||
|
|
||||||
|
User user = repository.findOne(userId);
|
||||||
|
user.setProfilePictureUrl("http://localhost:8090/profilePictures/" + dest);
|
||||||
|
repository.save(user);
|
||||||
|
|
||||||
|
return "redirect:/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(StorageFileNotFoundException.class)
|
||||||
|
public ResponseEntity handleStorageFileNotFound(StorageFileNotFoundException exc) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ public class User {
|
||||||
private String firstName;
|
private String firstName;
|
||||||
@NotNull
|
@NotNull
|
||||||
private String lastName;
|
private String lastName;
|
||||||
@Column(updatable = false, insertable = false, columnDefinition="DATETIME default NOW()")
|
@NotNull
|
||||||
private Timestamp registrationDate;
|
private Timestamp registrationDate;
|
||||||
@NotNull
|
@NotNull
|
||||||
private String email;
|
private String email;
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
package ba.steleks.storage;
|
||||||
|
|
||||||
|
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.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FileSystemStorageService implements StorageService {
|
||||||
|
|
||||||
|
private final Path rootLocation;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FileSystemStorageService(StorageProperties properties) {
|
||||||
|
this.rootLocation = Paths.get(properties.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void store(MultipartFile file, String dest) {
|
||||||
|
try {
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
|
||||||
|
}
|
||||||
|
Files.copy(file.getInputStream(),
|
||||||
|
this.rootLocation.resolve(dest));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<Path> loadAll() {
|
||||||
|
try {
|
||||||
|
return Files.walk(this.rootLocation, 1)
|
||||||
|
.filter(path -> !path.equals(this.rootLocation))
|
||||||
|
.map(path -> this.rootLocation.relativize(path));
|
||||||
|
} 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 StorageFileNotFoundException("Could not read file: " + filename);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
throw new StorageFileNotFoundException("Could not read file: " + filename, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAll() {
|
||||||
|
FileSystemUtils.deleteRecursively(rootLocation.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
try {
|
||||||
|
Files.createDirectory(rootLocation);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new StorageException("Could not initialize storage", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package ba.steleks.storage;
|
||||||
|
|
||||||
|
public class StorageException extends RuntimeException {
|
||||||
|
|
||||||
|
public StorageException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ba.steleks.storage;
|
||||||
|
|
||||||
|
|
||||||
|
public class StorageFileNotFoundException extends StorageException {
|
||||||
|
|
||||||
|
public StorageFileNotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageFileNotFoundException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package ba.steleks.storage;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
@ConfigurationProperties("storage")
|
||||||
|
public class StorageProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Folder location for storing files
|
||||||
|
*/
|
||||||
|
private String location = "/Users/admin";
|
||||||
|
|
||||||
|
public String getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(String location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ba.steleks.storage;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
void store(MultipartFile file, String dest);
|
||||||
|
|
||||||
|
Stream<Path> loadAll();
|
||||||
|
|
||||||
|
Path load(String filename);
|
||||||
|
|
||||||
|
Resource loadAsResource(String filename);
|
||||||
|
|
||||||
|
void deleteAll();
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
server.port = 8090
|
server.port = 8090
|
||||||
spring.datasource.url = jdbc:mysql://localhost:3306/users
|
spring.datasource.url = jdbc:mysql://localhost:3306/users
|
||||||
spring.datasource.username = root
|
spring.datasource.username = root
|
||||||
spring.datasource.password = root
|
spring.datasource.password = skorpion
|
||||||
spring.jpa.generate-ddl=true
|
spring.jpa.generate-ddl=true
|
||||||
|
|
||||||
|
|
Reference in New Issue