Add file upload routes.

This commit is contained in:
2018-05-18 20:39:49 +02:00
parent c62de5d6ed
commit 5f54a8e592
6 changed files with 170 additions and 1 deletions

View File

@@ -10,13 +10,21 @@ import org.codiki.core.entities.dto.PasswordWrapperDTO;
import org.codiki.core.entities.dto.UserDTO;
import org.codiki.core.entities.persistence.User;
import org.codiki.core.security.TokenService;
import org.codiki.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/account")
@@ -82,4 +90,24 @@ public class AccountController {
pResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
@PostMapping("/uploadAvatar")
public ResponseEntity<String> uploadAvatar(@RequestParam("file") MultipartFile pFile) {
String result;
try {
result = accountService.uploadFile(pFile);
return ResponseEntity.status(HttpStatus.OK).body(result);
} catch(final Exception pEx) {
result = StringUtils.concat("Fail to upload ", pFile.getOriginalFilename() + ".");
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(result);
}
}
@GetMapping("/loadAvatar/{avatarFileName}")
public ResponseEntity<Resource> loadAvatar(@PathVariable("avatarFileName") final String pAvatarFileName) {
final Resource avatarFile = accountService.loadAvatar(pAvatarFileName);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, StringUtils.concat("attachment; filename=\"", avatarFile.getFilename(), "\""))
.body(avatarFile);
}
}

View File

@@ -11,19 +11,25 @@ import org.codiki.core.entities.dto.UserDTO;
import org.codiki.core.entities.persistence.User;
import org.codiki.core.repositories.UserRepository;
import org.codiki.core.security.TokenService;
import org.codiki.core.services.FileUploadService;
import org.codiki.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class AccountService {
@Autowired
private UserRepository userRepository;
@Autowired
private TokenService tokenService;
@Autowired
private FileUploadService fileUploadService;
/**
* Check the user credentials and generate him a token if they are correct.
*
@@ -68,4 +74,12 @@ public class AccountService {
"Le mot de passe saisi ne correspond pas au votre.");
}
}
public String uploadFile(final MultipartFile pFile) {
return fileUploadService.uploadProfileImage(pFile);
}
public Resource loadAvatar(final String pAvatarFileName) {
return fileUploadService.loadAvatar(pAvatarFileName);
}
}

View File

@@ -0,0 +1,20 @@
package org.codiki.core.constant;
public enum FileEnum {
/** Folder in where pictures will be uploaded. */
FOLDER_UPLOAD("/opt/codiki/pictures/tmp/"),
/** Folder in where profile pictures will be stored. */
FOLDER_PROFILE_IMAGES("/opt/codiki/pictures/profiles/"),
/** Folder in where images will be stored. */
FOLDER_IMAGE("/opt/codiki/pictures/posts/");
private String value;
private FileEnum(final String pValue) {
value = pValue;
}
public String val() {
return value;
}
}

View File

@@ -0,0 +1,44 @@
package org.codiki.core.security;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Do nothing
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD");
httpResponse.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
httpResponse.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addIntHeader("Access-Control-Max-Age", 10);
chain.doFilter(request, httpResponse);
}
@Override
public void destroy() {
// Do nothing
}
}

View File

@@ -0,0 +1,61 @@
package org.codiki.core.services;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.lang.RandomStringUtils;
import org.codiki.core.constant.FileEnum;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class FileUploadService {
/** Length of uploaded file names. */
private static final int DESTINATION_IMAGE_NAME_LENGTH = 30;
/**
* Builds the destination file name, which is a random string with 30 char
* length.
*
* @return The file name.
*/
private String buildDestinationFileName() {
return RandomStringUtils.randomAlphanumeric(DESTINATION_IMAGE_NAME_LENGTH);
}
public String uploadProfileImage(final MultipartFile pFile) {
return uploadFile(pFile, FileEnum.FOLDER_PROFILE_IMAGES);
}
private String uploadFile(final MultipartFile pFile, final FileEnum pPath) {
String result;
try {
result = buildDestinationFileName();
Files.copy(pFile.getInputStream(), Paths.get(pPath.val()).resolve(result));
return result;
} catch (final Exception pEx) {
// TODO : Refactor exception
throw new RuntimeException();
}
}
public Resource loadAvatar(final String pAvatarFileName) {
try {
Path avatarFile = Paths.get(FileEnum.FOLDER_PROFILE_IMAGES.val()).resolve(pAvatarFileName);
Resource avatarResource = new UrlResource(avatarFile.toUri());
if(avatarResource.exists() || avatarResource.isReadable()) {
return avatarResource;
} else {
// TODO : Refactor exception
throw new RuntimeException();
}
} catch(final MalformedURLException pEx) {
// TODO : Refactor exception
throw new RuntimeException();
}
}
}

View File

@@ -12,4 +12,6 @@ spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
logging.level.org.hibernate=DEBUG
spring.servlet.multipart.max-file-size=104857600
cors.enabled=false