Adjusting the jackson value might have worked but that is not the optimal way to send a file to a endpoint. Best is to use MultipartFile, using multipart/request type, which Spring Boot has support for.
Sample Controller
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Objects;
@Controller
public class FileUploadController {
// upload directory, should exist and be writable.
private static final String UPLOAD_DIR = "./uploads/";
@PostMapping("/upload")
public ResponseEntity<?> handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("Please select a file to upload.");
}
// sanitize original filename, to prevent path traversal, more secure
String fileName = Objects.requireNonNull(file.getOriginalFilename());
Path destinationFile = Paths.get(UPLOAD_DIR).resolve(
Paths.get(fileName).getFileName()
).normalize();
// ensure the file is saved within the designated UPLOAD_DIR
if (!destinationFile.getParent().equals(Paths.get(UPLOAD_DIR).normalize().toAbsolutePath())) {
return ResponseEntity.badRequest().body("Cannot store file outside current directory.");
}
try {
try (InputStream inputStream = file.getInputStream()) {
// copy, over write if exists, or make a unique save name for every upload and save it to a table/ persistence linked to user/ transaction
Files.copy(inputStream, destinationFile, StandardCopyOption.REPLACE_EXISTING);
}
redirectAttributes.addFlashAttribute("message",
" uploaded '" + fileName + "'");
return ResponseEntity.ok("Uploaded successfully: " + fileName);
} catch (IOException e) {
e.printStackTrace();//todo logger
return ResponseEntity.internalServerError().body("Failed file upld: " + e.getMessage());
} catch (SecurityException e) {
e.printStackTrace();
return ResponseEntity.internalServerError().body("Permissions error: " + e.getMessage());
}
}
}
The client has to construct the message in the correct way. For testing can use a html form with correct attributes.
Curl to send multipart request
curl -X POST http://localhost:8080/api/uploadWithMeta \
-H "Content-Type: multipart/form-data" \
-F "file=@/path/to/your/local/file.txt" \
-F "userId=123" \
-F "description=A test uplad"
Or as HTML form, action is url of controller
<form method="POST" action="/upload" enctype="multipart/form-data">
File to upload:</td><td><input type="file" name="file" /><input type="submit" value="Upload" />
</form>
Java client to send multipart programmatially
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.File;
import java.io.IOException;
public class ApacheHttpClientFileUpload {
public static void uploadFile(String url, String filePath, String parameterName) throws IOException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
File fileToUpload = new File(filePath);
// Build the multipart entity
HttpEntity multipartEntity = MultipartEntityBuilder.create()
.addBinaryBody(parameterName, fileToUpload, ContentType.DEFAULT_BINARY, fileToUpload.getName())
// You can add text fields too:
// .addTextBody("description", "A sample file upload", ContentType.TEXT_PLAIN)
.build();
httpPost.setEntity(multipartEntity);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
// Print the response status and body
System.out.println("Status line: " + response.getStatusLine());
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
System.out.println("Response body: " + EntityUtils.toString(responseEntity));
}
}
}
}
public static void main(String[] args) throws IOException {
String serverUrl = "http://localhost:8080/api/upload"; // The Spring Boot endpoint URL
String fileLocation = "./sample.txt"; // The local file path
String formFieldName = "file"; // Must match the @RequestParam name in Spring Boot
uploadFile(serverUrl, fileLocation, formFieldName);
}
}
This will work for even 500 MB, i have not tested more.
For extremely large files (gigabytes), the external client can split file into chunks and send each chunk as separate request. Need another endpoint to handle each chunk part and a final endpoint to reassemble them on the server (client calls 'done' end point with last chunk.