I am getting myself familiar to Springboot. We are creating this Microservice based architecture were I am trying to consume this file upload service using RestTemplate.
Basically the Serve Side API code is
#PostMapping("/upload")
public ResponseEntity<?> fileUpload(#RequestParam String appender,
#RequestParam("file") MultipartFile file) {
...
}
Now on the client side
#Override
public String attachFile(String id, MultipartFile file) {
String status = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> upParams = new LinkedMultiValueMap<String,
Object>();
upParams.add("appender", id);
upParams.add("file", file.getOriginalFilename());
HttpEntity<MultiValueMap<String, Object>> request =
new HttpEntity<MultiValueMap<String, Object>>(upParams, headers);
String response = restTemplate.postForObject(uploadEndPoint, request,
String.class);
return status;
}
I get this error
org.springframework.web.client.HttpServerErrorException: 500
and if I change the line to below
upParams.add("file", file);
I get Error
"Could not write JSON: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[\"inputStream\"]->java.io.FileInputStream[\"fd\"])
Related
I am trying to implement custom ILogger . NetCore 3.1
CustomLogger class implements the ILogger. one of the methods thats need to be implemented is:
public class AuditLogLogger: ILogger
{
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
// How can I access the parameters I sent it from the controller?
}
}
From My controller I triggered the LogInformation Method and passeed a string,
and a List of KeyValuePair as such:
List<KeyValuePair<string, string>> udf = new List<KeyValuePair<string, string>>();
udf.Add(new KeyValuePair<string, string>("Test", "Test"));
_logger.LogInformation("This is a test", udf);
My code is able to make it to the Log<TState> but I need to perform some logic based on the parameters passed in. How can I access the parameters passed?
I ended up doing a dirty solution
Basically, have my controller send in a json string containing the list and message then have the Log function deserialize it such as
string message = "this is a test";
List<KeyValuePair<string, string>> udf = new List<KeyValuePair<string, string();
udf.Add(new KeyValuePair<string, string>("Test", "Test"));
JObject obj = new JObject();
obj["Message"] = message;
obj["MyList"] = JArray.FromObject(udf);
The Log Message needs to deserialize
I am sure there is a cleaner solution
I'm unable to upload large files.Please assist.
Controller:
#RequestMapping(value = "/fileToTempLoc", method = RequestMethod.POST)
public ResponseEntity<ResponseVO> fileToTempLoc(HttpServletRequest request, HttpServletResponse response) {
return new ResponseEntity<ResponseVO>(documentService.fileToTempLoc(request,response), HttpStatus.OK);
}
documentService:
public ResponseVO fileToTempLoc(HttpServletRequest request, HttpServletResponse response){
ResponseVO ResponseVO = new ResponseVO();
final String tempPath = "C:/Users/";
MultipartHttpServletRequest mRequest;
try {
mRequest = (MultipartHttpServletRequest) request;
mRequest.getParameterMap();
Iterator<String> itr = mRequest.getFileNames();
while (itr.hasNext()) {
String uploadedFile = (String) itr.next();
MultipartFile mFile = mRequest.getFile(uploadedFile);
String fileName = mFile.getOriginalFilename();
Path path = Paths.get(tempPath+"/" + fileName);
Files.deleteIfExists(path);
InputStream in = mFile.getInputStream();
Files.copy(in, path);
ResponseVO.setStatus(ResponseStatus.SUCCESS);
ResponseVO.setSuccessMsg("File Uploaded Successfully ");
ResponseVO.setRedirectUrl(path.toString());
}
} catch (Exception e) {
ResponseVO.setStatus(ResponseStatus.ERROR);
ResponseVO.setSuccessMsg("Error While Uploading File ");
return ResponseVO;
}
return ResponseVO;
}
properties:
multipart.enabled=true multipart.max-file-size=250MB multipart.max-request-size=250MB
I'm able to upload small file(upto 10MB) but not able to upload large files. Please help
Posting in case someone finds this useful in the future. This works with a REST controller as of Spring Boot 2.4.2.
Class annotations:
#RestController
#RequestMapping("/api")
Method declaration:
#RequestMapping(path = "/file-upload/{depot}/{fileName}", method = {RequestMethod.POST, RequestMethod.PUT})
public ResponseEntity<String> fileUpload(
#PathVariable(name = "depot") String depot,
#PathVariable(name = "fileName") String fileName,
InputStream inputStream,
HttpServletRequest request,
HttpServletResponse response)
The above is the Spring Boot configuration for a REST Controller that worked for me for large file upload. The key was adding InputStream inputStream directly.
I also have the following values set in my application.yaml, but as I am not using the Spring multipart processing it's not clear to me if this is in use.
spring:
servlet:
multipart:
max-file-size: 500MB
max-request-size: 500MB
location: ${java.io.tmpdir}
file-size-threshold: 0B
I meet a request to upload files with spring resttemplate to upload files
with http header "multipart/form-data", also some other normal parameters need to be posted. how to implements that?
you can use the following code in your application to have both multipartfile and normal request parameters at the same time.
Replace the url with your own.
replace param and value according to your normal parameters.
String url ="http://example.com";
String fileAbsPath ="absolute path of your file";
String fileName = new File(fileAbsPath).getName();
Files.readAllBytes(Paths.get(fileAbsPath));
MultiValueMap<String, Object> data = new LinkedMultiValueMap<String, Object>();
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(Paths.get(fileAbsPath))) {
#Override
public String getFilename() {
return fileName;
}
};
data.add("file", resource);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("file","application/pdf");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("param1", "value1")
.queryParam("param2", "value2")
HttpEntity<> entity =
new HttpEntity<> (data, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result =restTemplate.exchange(
builder.toUriString(),
HttpMethod.POST,
entity,
String.class);
System.out.println(result.getBody());
you can use this code.
HttpHeaders headers = getCASHeaders(MediaType.MULTIPART_FORM_DATA);
LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("fileField", new FileSystemResource(""));//get file resource
params.add("stringfield", stringPayload);
HttpEntity requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<CasAssetApiResponse> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
This will send post call with two param, you can add more according to your wish.
Please have a look at this stackoverflow answer as well
I got the error "cannot be cast to java.lang.String" although my code does not have any casting.
I would like to write a spring MVC Controller class that just take any http request in input, add basic authentication headers to it and forward this request to another server.
I try something like this without success.
#Controller
#RequestMapping("/proxyws")
public class ProxyController {
#RequestMapping("/**")
#ResponseBody
public String mirrorRest( #RequestBody String body, HttpMethod method, HttpServletRequest request, HttpServletResponse response) throws URISyntaxException
{
String server = "localhost";
int port = 8080;
URI uri = new URI("http", null, server, port, request.getRequestURI(), request.getQueryString(), null);
RestTemplate restTemplate=new RestTemplate();
HttpEntity entity = new HttpEntity<String>(body);
String plainCreds = "APP_CLIENT:APP_PASSWORD";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
entity.getHeaders().add("Authorization", "Basic " + base64Creds);
ResponseEntity<String> responseEntity = restTemplate.exchange(uri, method, entity, String.class);
return responseEntity.getBody();
}
For a GET method in input, I get the following exception :
org.springframework.http.converter.HttpMessageNotReadableException: Required request body content is missing:
org.springframework.web.method.HandlerMethod$HandlerMethodParameter#8051792a
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleEmptyBody(RequestResponseBodyMethodProcessor.java:189)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:170)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
For a POST request, I get other trouble with le basic auth headers:
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1342)
at org.springframework.http.HttpHeaders.add(HttpHeaders.java:831)
Thanx for your help!
You cannot modify the headers of the HttpEntity object once it's instantiated. You need to pass your headers in through a different HttpEntity constructor, e.g.
public HttpEntity(T body, MultiValueMap<String, String> headers) {
this.body = body;
HttpHeaders tempHeaders = new HttpHeaders();
if (headers != null) {
tempHeaders.putAll(headers);
}
this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);
}
Note the initialization of this.headers: that's where the read-only copy is created.
In my app,I use springMVC and tomcat,my controller return object,but when something wrong,I only want return some string message with content tye json,so I use response.error, but it not work,the return is a html.
my controller:
#RequestMapping(value = "{id}/{name}" ,method=RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody UserBean login(#PathVariable String id,#PathVariable("name") String userName,
#RequestHeader(value = "User-Agent") String user_agen,
#CookieValue(required = false) Cookie userId,
HttpServletRequest request,HttpServletResponse response,#RequestBody UserBean entity
) throws IOException {
System.out.println("dsdsd");
System.out.print(userName);
response.setContentType( MediaType.APPLICATION_JSON_VALUE);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "somethind wrong");
return null;
According to the Javadoc for the HttpServletReponse#sendError method:
Sends an error response to the client using the specified status. The
server defaults to creating the response to look like an
HTML-formatted server error page containing the specified message,
setting the content type to "text/html", leaving cookies and other
headers unmodified...
So sendError will generate an HTML error page using the message that you supplied and will override the content type to text/html.
Since the client end is expecting a JSON response, you may be better to manually set the response code and the message yourself using fields on your UserBean - assuming it can support it. That will then be serialized to a JSON response that your clientside Javascript can evaluate.
#RequestMapping(value = "{id}/{name}" ,method=RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody UserBean login(#PathVariable String id,#PathVariable("name") String userName,
#RequestHeader(value = "User-Agent") String user_agen,
#CookieValue(required = false) Cookie userId,
HttpServletRequest request,HttpServletResponse response,#RequestBody UserBean entity
) throws IOException {
System.out.println("dsdsd");
System.out.print(userName);
response.setContentType( MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
UserBean userBean = new UserBean();
userBean.setError("something wrong"); // For the message
return userBean;
There is also the option of using the Tomcat property org.apache.coyote. USE_CUSTOM_STATUS_MSG_IN_HEADER which will place the message into a custom response header. See this post and the Tomcat docs for more info.