This has tons of example on the internet but for some reason I just cannot download a csv file. I keep getting the error:
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation`.
Here is the code below for my #RestController:
#GetMapping(value = "/tasks/{taskId}/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<InputStreamResource> download(#PathVariable String taskId, #RequestParam String format) throws IOException {
var path = "string path to file"
var file = new UrlResource(Path.of(path).normalize().toUri());
return ResponseEntity
.ok()
.contentLength(file.contentLength())
.contentType(
MediaType.parseMediaType("application/octet-stream"))
.body(new InputStreamResource(file.getInputStream()));
}
I set the header Accept: application/octet-stream but still get the same error. What could be wrong any ideas?
Related
I'm using SpringBoot 3.0.1 and I'm trying to get a file stored in the backend using Axios.
The controller is the following:
#GetMapping(value = "/api/files/{fileName}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<?> getFile(final #PathVariable("fileName") String fileName) {
try {
Path filePath = Path.of(fileName);
File file = filePath.toFile();
HttpHeaders responseHeaders = new HttpHeaders();
String filename = filePath.getFileName().toString();
responseHeaders
.setContentDisposition(ContentDisposition.builder("attachment")
.filename(filename, StandardCharsets.UTF_8)
.build());
FileSystemResource fileSystemResource = new FileSystemResource(file);
return ResponseEntity
.ok()
.headers(responseHeaders)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(file.length())
.lastModified(file.lastModified())
.body(fileSystemResource);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
When I get the answer (status is 200), the header I've set in the controller is not given. In particular, the Content-Disposition header is not defined in the answer.
I'm wondering if there is any missing configuration that must be set in Sprint Boot in order to be allowed to set a custom header. Anyone who knows what can cause this and how to fix it?
I am getting this error in test case for following api.
Required request part 'document' is not present
#PostMapping(value = "/testModel/{modelName}", consumes = {
MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<Object> testModel(#PathVariable("modelName") String modelName,
#RequestPart MultipartFile document) {
}
following is the test case for above api
#Test
#Transactional
void testModel() throws Exception {
service.save(domainModelDTo);
FileInputStream fi2 = new FileInputStream(new File("test.pdf"));
MockMultipartFile file = new MockMultipartFile("file", "test.pdf", DEFAULT_BINARY.toString(), fi2);
log.debug("file name {}", file.getOriginalFilename()); // test.pdf print in log
log.debug("file length {}", file.getBytes().length); // 44782 print in log
mockMvc.perform(multipart(ENTITY_API_URL, domainModelDTo.getName()).file(file)).andExpect(status().isOk());
}
I have implemented this from the following link as it is:
https://www.baeldung.com/sprint-boot-multipart-requests
In your MockMultipartFile the first parameter (name) must match the request parameter property (in this case document).
So if you change your code to:
MockMultipartFile file = new MockMultipartFile("document", "test.pdf", DEFAULT_BINARY.toString(), fi2);
The problem should be resolved.
I am using apache compress in order to create and compress a number of files into a tar.gz file. I am then attempting to create an endpoint that another application can contact in order to receive the tar.gz file.
I have tried a number of different methods but I cannot seem to get the desired output. Currently I have am able to return the compressed file as a .gz file but I need it as a .tar.gz file.
My Controller method looks like:
public ResponseEntity<?> getBundle(){
BundleService bundleService = new BundleService();
List<File>fileList = new ArrayList<File>();
List<String> implementationIds = policyService.getImplementationIdListForBundle(EnvironmentType.DEV, PlatformEngineType.REGO);
List<PolicyImplementation> implementationList = policyService.getImplementationsForBundle(implementationIds);
fileList = bundleService.createImplementationFiles(implementationList);
bundleService.createTarBall(fileList);
File tarball = new File("./policyadmin/bundleDirectory/bundle.tar");
//File gzippedTarball = bundleService.gzipTarBall();
String gzippedLocation = tarball.getAbsolutePath() + ".gz";
//File gzippedFile = new File(gzippedLocation);
Resource tarResource = new FileSystemResource(tarball);
//bundleService.deleteTarball(tarball);
return new ResponseEntity<Object>(tarResource, HttpStatus.OK); //! If I return a File instead of a resource gives me No converter for [class java.io.File] with preset Content-Type 'null']
}
I also have the following code to handle the request:
//GET: Endpoint for OPA to retrieve on the fly gzipped tarball for Bundles
#ApiOperation(value = "Method to retrieve on the fly gzipped tarball for bundles", nickname = "getBundle", notes="", response = Resource.class)
#ApiResponses(value = {
#ApiResponse(code = 200, message = "Request for Bundle.tar.gz received", response = Resource.class),
#ApiResponse(code = 404, message = "Unable to find requested Bundle.tar.gz")
})
#GetMapping(value = "/policyadmin/bundle", produces= { "application/gzip" })
default ResponseEntity<?> getBundle(){
return new ResponseEntity<File>(HttpStatus.NOT_IMPLEMENTED);
}
Note: Make sure you've tar.gz file
Set the content type like:
public ResponseEntity<?> getBundle(HttpServletResponse response){
// Your other code
response.setContentType("application/gzip");
response.setHeader("Content-Disposition", "attachment; filename=\"bundle.tar.gz\"");
return new ResponseEntity<Object>(tarResource, HttpStatus.OK); //! If I return a File instead of a resource gives me No converter for [class java.io.File] with preset Content-Type 'null']
}
I have two apps, both are on SpringBoot. I'm trying to upload file from one app to another using #FeignClient
Here is Controller code that accepts file upload
#PostMapping(
path = "/result/output/{resultId}",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#ResponseStatus(HttpStatus.OK)
public Result uploadOutputProviderMetadata(#PathVariable(value = "resultId") UUID resultId,
#RequestParam("file") MultipartFile multipartFile) {
return resultService.storeResult(providerSearchTaskId, getString(multipartFile));
}
Here is the test snippet call for this controller
new MockMultipartFile(
"file",
file.getName(),
"application/zip",
FileUtils.readFileToByteArray(file));
var resultAsString = getMockMvc()
.perform(MockMvcRequestBuilders
.multipart("/private/api/v1/result/output/" + resultId.toString(), getPort())
.file(multipartFile)
.contentType(MediaType.MULTIPART_FORM_DATA)
)
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsString();
Test works, MvcMock can upload file using MockMultipartFile and MediaType.MULTIPART_FORM_DATA
Here is my poor FeignClient from another app that tries to upload file
#FeignClient(name = "Client", url = "${server.url}")
trait UploadClient {
#PostMapping(
path = Array("/private/api/v1/result/output/{resultId}"),
consumes = Array(MediaType.MULTIPART_FORM_DATA_VALUE))
def uploadResult(#PathVariable resultId: UUID,
#RequestPart(name = "file") file: MultiValueMap[String, Object]): Result
}
}
#Configuration
#EnableFeignClients(clients = Array(classOf[UploadClient]))
class FeignActivationConfiguration {
#Bean
def clientFeignEncoder(messageConverters: ObjectFactory[HttpMessageConverters]): Encoder = {
new SpringFormEncoder(new SpringEncoder(messageConverters))
}
}
I have e2e test and feign throws
status 400 reading AdsManagerClient#uploadResult(UUID,MultiValueMap)
feign.FeignException$BadRequest: status 400 reading UploadClient#uploadResult(UUID,MultiValueMap)
Why?
I've added error decoder, controller wasn't very informative
// Error response code: 400, responseText: ERROR, reason: null
val errorMessage = s"Error response code: ${response.status()}, responseText: $responseText, reason: ${response.reason()} while calling $methodKey"
I am trying to consume an http rest call that takes input of two files a dto
#RequestMapping(name = "/my/endpoint", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody
EndpointDto createEndpoint(#RequestBody MultipartFile requestFile, #RequestBody MultipartFile responseFile,
#RequestBody MyDto myDto){
return endpointService.createEndpoint(requestFile, responseFile, myDto);
}
I received the following error:
org.springframework.web.HttpMediaTypeNotSupportedException:
Content type 'multipart/form-data;boundary=----WebKitFormBoundarylq2UHYfBi0nAsRo7;charset=UTF-8' not supported
I consume the endpoint through swagger.
I think that the problem lies in the way I handle the input fields but I don't know what is the problem.
You can change the controller parameter as below
#RequestMapping(name = "/my/endpoint", method = RequestMethod.POST)
public ResponseEntity<EndpointDTO> createEndpoint(
#RequestPart(value = "file1") MultipartFile filea,
#RequestPart(value = "file2") MultipartFile fileb,
#RequestPart MyDto myDto){
return endpointService.createEndpoint(filea, fileb, myDto);
}
You can get the files and DTO values using #RequestPart.
You can test above API using following curl
curl -v -H "Content-Type:multipart/form-data" -F "myDto=#body;type=application/json" -F "file1=#file1.txt" -F "file2=#file2.txt" -X POST http://<path>/my/endpoint
Note: Here I'm using 'body' file to pass the payload and file1.txt & file2.txt to pass the MultipartFile. Hope you are familiar with the curl command and understand it.
Sample controller
#PostMapping(value = "/documents")
#Timed
public ResponseEntity<DocumentDTO> createDocument(#RequestPart String document, #RequestParam("file") MultipartFile file, HttpServletRequest httpServletRequest) throws URISyntaxException {
DocumentDTO documentDTO = convertStringToDTO(document);
DocumentDTO result = documentService.save(documentDTO, file);
return ResponseEntity.created(new URI("/api/documents/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
.body(result);
}
// com.fasterxml.jackson.databind.ObjectMapper;
private DocumentDTO convertStringToDTO(String document) {
ObjectMapper objectMapper = new ObjectMapper();
DocumentDTO documentDTO = null;
try {
documentDTO = objectMapper.readValue(document, DocumentDTO.class);
} catch (IOException e) {
log.error("DocumentString to JSON", e);
}
return documentDTO;
}
You have to send the data in form-data format from front-end with key as a file containing bytes and document JSON object.