I uploaded a file using multipart successfully and appended the entity class id to it. Sending a get request returns a null value.
This is my post endpoint:
#PostMapping("/{id}/upload_multiple")
public ResponseEntity<ResponseMessage> createDocument(#PathVariable Long id,
#RequestParam("applicationLetter") MultipartFile appLetter,
#RequestParam("certificateOfInc") MultipartFile cInc, #RequestParam("paymentReceipt") MultipartFile payment,
#RequestParam("taxClearance") MultipartFile tax, #RequestParam("staffsResume") MultipartFile staffs,
#RequestParam("letterOfCredibility") MultipartFile credibility,
#RequestParam("workCertificate") MultipartFile workCert,
#RequestParam("consentAffidavit") MultipartFile affidavit,
#RequestParam("collaborationCert") MultipartFile colabo, #RequestParam("directorsId") MultipartFile idcard,
#RequestParam("membership") MultipartFile member) throws IOException {
documentService.create(id, appLetter, cInc, payment, tax, staffs, credibility, workCert, affidavit, colabo,
idcard, member);
String message = "Upload successful";
return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));
}
uploaded files are saved in a another folder 10001 which is the ID of the document entity. My challenge now is to get those files from 10001 folder.
This is what I tried but is returning null value for all the documents:
#GetMapping( "/files/{filename:.+}/{id}")
public ResponseEntity<Resource> getFile(#PathVariable String filename) {
Resource file = documentService.load(filename);
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"")
.body(file);
}
My service class:
private final Path root = Paths.get("documents");
#Override
public Resource load(String filename) {
try {
Path file = root.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new RuntimeException("Could not read the file!");
}
} catch (MalformedURLException e) {
throw new RuntimeException("Error: " + e.getMessage());
}
}
My Entity class:
#Entity
#Getter
#Setter
public class Documents {
#Id
#Column(nullable = false, updatable = false)
#SequenceGenerator(
name = "primary_sequence",
sequenceName = "primary_sequence",
allocationSize = 1,
initialValue = 10000
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "primary_sequence"
)
private Long id;
#Column(nullable = false)
private String applicationLetter;
#Column(nullable = false)
private String certOfIncorporation;
#Column(nullable = false)
private String paymentReceipt;
#Column(nullable = false)
private String taxClearance;
#Column(nullable = false)
private String staffsResume;
}
refer this example :
#GetMapping("/files")
public ResponseEntity<List<ResponseFile>> getListFiles() {
List<ResponseFile> files = storageService.getAllFiles().map(dbFile -> {
String fileDownloadUri = ServletUriComponentsBuilder
.fromCurrentContextPath()
.path("/files/")
.path(dbFile.getId())
.toUriString();
return new ResponseFile(
dbFile.getName(),
fileDownloadUri,
dbFile.getType(),
dbFile.getData().length);
}).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK).body(files);
}
#GetMapping("/files/{id}")
public ResponseEntity<byte[]> getFile(#PathVariable String id) {
FileDB fileDB = storageService.getFile(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileDB.getName() + "\"")
.body(fileDB.getData());
}
Try this method for loading resource. to see if it works
Resource file = fileStorageService.loadFileAsResource(fileName);
Try this code
#GetMapping( "/files/{filename:.+}/{id}")
public void getFile(#PathVariable String filename, HttpServletRequest request, final HttpServletResponse response) {
BufferedInputStream bufferedInputStream = null;
try {
File file = ...;
response.setHeader("Cache-Control", "must-revalidate");
response.setHeader("Pragma", "public");
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-disposition", "attachment; ");
bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
FileCopyUtils.copy(bufferedInputStream, response.getOutputStream());
} catch (Exception e) {
logger.error(e.getMesssage(), e);
} finally {
try {
response.getOutputStream().flush();
response.getOutputStream().close();
} catch (Exception ex) {
logger.error(ex);
}
try {
if (bufferedInputStream != null)
bufferedInputStream.close();
} catch (Exception ex) {
logger.error(ex);
}
}
}
I'm not sure it will work with your system, but for me I still use this method to download files normally.
Related
I have Spring Boot code with image upload as follows. Can anyone tell me how to not save the book when I don't upload pictures when I press save?
Here is code in controller
#PostMapping("/books")
public String saveBook(#ModelAttribute("book") Book book, Model model, BindingResult bindingResult, #RequestParam(value = "image") MultipartFile image) throws IOException { bookValidator.validate(book, bindingResult);
model.addAttribute("categories", bookCategoryService.findAll());
model.addAttribute("mode", "create");
if (bindingResult.hasErrors()) {
return "create_book";
}
String fileName = null;
if(image.getOriginalFilename() != null) {
fileName = StringUtils.cleanPath(image.getOriginalFilename());
book.setPhotos(fileName);
}
Book savedBook = bookService.saveBook(book);
String uploadDir = "book-photos/" + savedBook.getId();
if(fileName != null) {
FileUploadUtil.saveFile(uploadDir, fileName, image);
}
return "redirect:/";
}
This is code in FileUploadUtil
package com.example.bookmanagement.util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import org.springframework.web.multipart.MultipartFile;
public class FileUploadUtil {
public static void saveFile(String uploadDir, String fileName, MultipartFile multipartFile) throws IOException {
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = multipartFile.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ioe) {
throw new IOException("Could not save image file: " + fileName, ioe);
}
}
}
You can add validation while you are saving image details in saveBook business method ::
String fileName = null;
if (image != null && image.getOriginalFileName() != null) {
fileName = StringUtils.cleanPath(image.getOriginalFilename());
book.setPhotos(fileName);
Book savedBook = bookService.saveBook(book);
String uploadDir = "book-photos/" + savedBook.getId();
FileUploadUtil.saveFile(uploadDir, fileName, image);
}
Just ignore the save snippet when you are not uploading pictures.
I have the upload file option in jsp and the images are being uploaded in src\main\webapp\upload directory.Instead I want,the image to be upload in src\main\resources\images folder.I want to check at first whether if there is images folder or not and if there is no any images folder,then i want to make a new folder images.
Here is what I tried:
#Service
public class EmployeeService {
#Autowired
private EmployeeRepository empRepository;
public Employee saveEmployee(HttpServletRequest request, Employee employee){
// Root Directory.
String uploadRootPath = request.getServletContext().getRealPath("upload");
System.out.println("uploadRootPath=" + uploadRootPath);
File uploadRootDir = new File(uploadRootPath);
// Create directory if it not exists.
if (!uploadRootDir.exists()) {
uploadRootDir.mkdirs();
}
MultipartFile fileData = employee.getFileData();
String name = fileData.getOriginalFilename();
System.out.println("Client File Name = " + name);
if (name != null && name.length() > 0) {
try {
// Create the file at server
File serverFile = new File(uploadRootDir.getAbsolutePath() + File.separator + employee.getiNumber()+".jpg");
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
stream.write(fileData.getBytes());
stream.close();
//
System.out.println("Write file: " + serverFile);
} catch (Exception e) {
System.out.println("Error Write file: " + name);
}
}
if(employee.getiNumber()==null){
empRepository.save(employee);
}
else{
empRepository.save(employee);
}
return employee;
}
Here is the Employee.java class:
#Entity
#Table(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotBlank
private String iNumber;
#NotBlank
private String fullName;
// #NotBlank
private String joinedDate;
#NotBlank
private String position;
#NotBlank
private String reportsTo;
#NotBlank
private String cubicleNo;
#NotBlank
private String jobType;
// Upload files.
#Transient
private MultipartFile fileData;
//all getters setters constuctor
My image files are successfully loaded in src\main\webapp\upload directory,but I want images to be saved in src\main\resources\images.
You shouldn't really be uploading files there.
If you are using a war, redeploying will delete them. If they are intended to be temporary then use an os assigned temporary location.
If you intend to publish them afterwards then choose a location in which to store the files on your server, make this location known to the application and save and load files from the location.
If you are trying to replace resources dynamically such as an image which is referenced in the html or css templates, then consider publishing the external location separately, you can use mvc:resources for this e.g:
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/images/**").addResourceLocations("file:/absolute/path/to/image/dir");
}
and you would save your files to that location. This will make it more permanent between deployments.
To save an image to that location using your code you will need to add this into your properties or YML file
imagesFolder:"/absolute/path/to/image/dir"
just add your logic to this.
#value("${imagesFolder}")
private String imagesFolder;
public void setImagesFolder(String imagesFolder) {
this.imagesFolder = imagesFolder;
}
public String fileUpload(UploadedFile uploadedFile) {
InputStream inputStream = null;
OutputStream outputStream = null;
MultipartFile file = uploadedFile.getFile();
String fileName = file.getOriginalFilename();
File newFile = new File(imagesFolder + fileName);
try {
inputStream = file.getInputStream();
if (!newFile.exists()) {
newFile.createNewFile();
}
outputStream = new FileOutputStream(newFile);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
return newFile.getAbsolutePath();
}
Please bear in mind that you need to change /absolute/path/to/image/dir to an actual path that exists, also I would recommend to look at the Spring Resources documentation for a better way to deal with files and resources.
I am trying to store a file from user, using Java Spring boot and make a preview immediately after image upload. But now I get a 404 error on the console and when I refresh the page, the image shows up!
I tried to solve the problem by adding sleep or delay in the thread. Did not work. Here is some part of controller and service file:
public Resource getIllustrationAsResource(long id) throws MalformedURLException {
return new FileUrlResource(uploadLocation + id + ILLUSTRATION_FILE_ENDING);
}
public PostResult addIllustration(MultipartFile file) throws IOException {
Illustration illustration = getIllustrationMetadata(file);
long id = repo.insertIllustration(illustration);
storeFile(file, id);
return new PostResult(id);
}
private void storeFile(MultipartFile file, long id) throws IOException {
Path path = Paths.get(uploadLocation + id + ILLUSTRATION_FILE_ENDING);
System.out.println("storeFile path: " + path);
File uploadFile = new File(uploadLocation);
uploadFile.getParentFile().mkdirs();
try (InputStream inputStream = file.getInputStream()) {
Files.copy(inputStream, path);
}
}
Controller:
#GetMapping("/illustrations/{id}/image")
public ResponseEntity < Resource > getImageContent(#PathVariable("id") long id)
throws MalformedURLException {
Illustration illustrationInfo = service.getOneIllustration(id);
Resource body = service.getIllustrationAsResource(id);
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(illustrationInfo.getMime()));
return new ResponseEntity < > (body, headers, HttpStatus.OK);
}
#PostMapping("/illustrations")
public PostResult postOneIllustration(#RequestParam("file") MultipartFile image)
throws IOException {
ProjectId project = projectService.getCurrentProject();
if (project == null) {
throw new EntityMissingException();
}
if (!authorizationService.loggedInUserCanCreateObjectsInProject(project)) {
throw new EntityMissingException();
}
return service.addIllustration(image);
}
Frontend:
postFile: async function(data) {
//console.log("here")
try {
let fetchPromise = catchReject(
fetch(`${window.contextPath}/illustrations`, {
method: 'POST',
body: data
})
)
const response = await fetchPromise
validateHttpOkStatus(response)
return response.json()
} catch (e) {
console.log('in postFile')
console.log(e)
// store.dispatch(addGlobalError(e))
throw e
}
},
I'm trying to find a way to download file from api without window.open().
I'd like to get instant download when calling the api.
Currently downloading .xls file generated by a rest api using window.open()
API Endpoint
#GetMapping("/applications/export")
#Timed
public ResponseEntity<byte[]> exportApplicationsList() {
log.debug("REST request to export applications list");
byte[] result = applicationService.generateApplicationsListAsExcel();
if (result == null) {
return ResponseEntity.status(500).build();
}
String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd_MM_yyyy_HH_mm"));
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename=liste_applications_" + date + ".xls")
.contentLength(result.length)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(result);
}
Service
/**
* Generate xls file from applications list.
*
* #param applications list of applications
*/
public byte[] generateApplicationsListAsExcel() {
log.info("Génération fichier xls de la liste des applications");
List<Application> applications = applicationRepository.findAll();
Collections.sort(applications);
try (InputStream is = new FileInputStream(ResourceUtils.getFile("classpath:jxls-templates/liste_applications_template.xls"))) {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
Context context = new Context();
context.putVar("applications", applications);
JxlsHelper.getInstance().processTemplate(is, os, context);
return os.toByteArray();
} catch (IOException e) {
log.error(e.toString());
}
} catch (IOException e) {
log.error(e.toString());
}
return null;
}
Invocation
exportApplicationsList(): void {
window.open('/api/applications/export');
}
You can return file as blob as response from backend and then use file-saver to download the file
this.http.get(`/api/applications/export`, params, { responseType: 'blob' })
.subscribe((resp: any) => {
saveAs(resp, `filename}.xlsx`)
});
Quick solution : window.location.href = url;
I used this file-saver, I think it will fulfill your needs.
this.filesService.getDownloadFile(id).subscribe(
data => {
importedSaveAs(data, name);
},
err => {
console.error(err);
});
For the backend:
#GetMapping("download-file/{id}")
public ResponseEntity<?> downloadFile(#PathVariable(value = "id") Long id) {
final Optional<FileEntity> file = fileRepository.findById(id);
if (!file.isPresent()) {
return ResponseEntity.badRequest().body(getErrorResponse("File not found"));
}
ByteArrayOutputStream downloadInputStream = amazonClient.downloadFile(file.get().getLink());
return ResponseEntity.ok()
.contentType(contentType(file.get().getName()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.get().getName() + "\"")
.body(downloadInputStream.toByteArray());
}
I have a BLOB type image in mysql database and I want to show the image on the jsp. I am using Hibernate and Spring MVC. This is my Model class:
#Repository
#Entity
#Table(name = "foto")
public class Image {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_id_users", nullable = false)
private Users user;
#Id
#Column(name = "id_foto")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id_foto;
#Column(name = "tipo")
private String tipo;
#Column(name = "size")
private String size;
#Column(name = "nome")
private String nome;
#Column(name = "image")
private byte[] image;
//Getters and Setters
this is my controller:
#Controller
#SessionAttributes("UserSession")
public class LoginController {
#Autowired
private UsersService usersService;
#RequestMapping(value = "loginUsers", method = RequestMethod.POST)
public ModelAndView loginUsers(HttpServletRequest request,#RequestParam("username") String username,
#RequestParam("password") String password) {
Users user = usersService.loginUsers(username, password);
if( user == null ) {
ModelAndView MV = new ModelAndView("login");
MV.addObject("erroreLogin", "username e/o password errati");
return MV;
} else if ( user.getAmministratore() == false ){
request.getSession().setAttribute("UserSession",user);
ModelAndView mav = new ModelAndView("homeUtente");
mav.addObject("galleria", usersService.getAllFoto());
return mav;
} else {
request.getSession().setAttribute("UserSession",user);
ModelAndView mav = new ModelAndView("utenti");
mav.addObject("lista", usersService.getAllUtenti());
return mav;
}
}
#RequestMapping(value = "logout", method = RequestMethod.GET)
public ModelAndView logout(HttpServletRequest request) {
request.getSession().invalidate(); //invalido i dati presenti in sessione
return new ModelAndView("login");
}
}
and in my jsp I use this for show my image from Image List because each user have a gallery to display:
<img alt="Kangoo_image" src="data:image/jpeg;base64,${galleria.image}" />
when i'm trying to display it in my jsp.It is showing something binary like [B#59e73b47. how can i display the image here in jsp?
To show the image on JSP without storing to filesystem and linking to it, you'll have to do a Base64 encoding of the byte array. Easily done by following lines
byte[] encodeBase64 = Base64.encodeBase64(usersService.getAllFoto());
String base64Encoded = new String(encodeBase64, "UTF-8");
mav.addObject("galleria", usersService.getAllFoto());
Both IOUtils and Base64 are from org.apache.commonsEndFragment
this appends beacause galleria.image returns a byte[] type, and on the resulting html of the jsp appear the byte[].toString() value. exactly [B#59e73b47.
you should use something like:
<img alt="Kangoo_image" src="data:image/jpeg;base64,new String(${galleria.image})" />
or
<img alt="Kangoo_image" src="/getImage/${galleria.id_foto}" />
and in in the getImage controller somthing like this
#Autowired
private HttpServletRequest request;
#RequestMapping("/getImage/*")
public void getImage(ModelMap model, HttpServletResponse response)
throws IOException {
requestUri = requestUri.substring((request.getContextPath() + "/getImage/")
.length());
Image image = DAO.findById(requestUri);
String requestUri = request.getRequestURI();
InputStream is = new ByteArrayInputStream(image.getImage());
response.setContentType("image/jpeg");
String name = image.getName() + ".jpeg";
String attachment = "inline; filename=" + name;
response.setHeader("content-Disposition", attachment);
response.setContentLength((int) baos.toByteArray().length);
IOUtils.copy(is, response.getOutputStream());
response.flushBuffer();
is.close();
}
#Controller
#SessionAttributes("UserSession")
public class LoginController {
#Autowired
private UsersService usersService;
#RequestMapping(value = "loginUsers", method = RequestMethod.POST)
public ModelAndView loginUsers(HttpServletRequest request,#RequestParam("username") String username,
#RequestParam("password") String password) {
Users user = usersService.loginUsers(username, password);
if( user == null ) {
ModelAndView MV = new ModelAndView("login");
MV.addObject("erroreLogin", "username e/o password errati");
return MV;
} else if ( user.getAmministratore() == false ){
request.getSession().setAttribute("UserSession",user);
ModelAndView mav = new ModelAndView("homeUtente");
byte[] encodeBase64 = Base64.encode(usersService.getAllFoto());
String base64Encoded = new String(encodeBase64, "UTF-8");
mav.addObject("userImage", base64Encoded )
return mav;
} else {
request.getSession().setAttribute("UserSession",user);
ModelAndView mav = new ModelAndView("utenti");
mav.addObject("lista", usersService.getAllUtenti());
return mav;
}
}
#RequestMapping(value = "logout", method = RequestMethod.GET)
public ModelAndView logout(HttpServletRequest request) {
request.getSession().invalidate(); //invalido i dati presenti in sessione
return new ModelAndView("login");
}
}
and in jsp code use this code to display image
<img src="data:image/jpeg;base64,${userImage}" />