400 Bad Request with spring REST - java

I have spring rest service such this
#RequestMapping(method = RequestMethod.POST,
path = "/getdata", consumes = {"multipart/form-data"}, produces = MediaType.APPLICATION_JSON)
public
#ResponseBody
Result getBarcode(#RequestParam("text") String sl,
#RequestParam("imageFile") MultipartFile file) {
... some logic
return new Result(text, message, !processingError);
}
When i call this from http form it works fine and return json text. But when i trying to call this from java code
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("text", "123");
map.add("imageFile", new File("...path to file..."));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.setAccept(MediaType.parseMediaTypes("application/json,text/html,application/xhtml+xml,application/xml"));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
ResponseEntity<BcResult> response = restTemplate.exchange("http://localhost:8080/getdata", HttpMethod.POST, requestEntity, BcResult.class);
Then i am getting 400 Bad request error. Can`t figure out what is wrong with this code...

Set your file like this.
map.add("imageFile", new FileSystemResource(new File("...path to file...")));
or like this
map.add("imageFile", new ClassPathResource("...path to file..."));

Related

How to pass Headers and request body in POST request?

I am using RestTemplate restTemplate.exchangemethod to POST request to an endpoint. I have OAuth Header and HttpEntity in different file which I want to pass to POST request, in addition to this I also want to pass request to the endpoint.
I was able to successfully pass the headers and request, but not Http entity which contains credentials
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST,
new HttpEntity<>(request, dataRepo.getHeader()), String.class);
Is there any way I can pass all 3 things
HttpEntity
HttpHeaders
request
Here is my code
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource
public class DataTest {
#Inject
private Oauth oauth;
#Mock
private DataRepo dataRepo;
RestTemplate restTemplate = new RestTemplate();
#Qualifier(OAuth2HttpHeadersBuilder.BEAN_NAME)
NewHttpHeader headersBuilder;
#Test
public void testAddEmployeeSuccess() throws URISyntaxException {
URI uri = new URI(url);
Set<String> mockData = Stream.of("A","B").collect(Collectors.toSet());
String onsString = String.join(",", mockData);
Map<String, String> requestBody = new HashMap<>();
requestBody.put("name", onsString);
JSONObject jsonObject = new JSONObject(requestBody);
HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), null);
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST,
new HttpEntity<>(request, dataRepo.getHeader()), String.class);
Assert.assertEquals(201, result.getStatusCodeValue());
}
The below code is in NewHttpHeader.java file which contains
Header and HttpEntity
private HttpEntity<MultiValueMap<String,String>> getHttpEntity() {
MultiValueMap<String, String> store = new LinkedMultiValueMap<>();
store.add( "pas", "password" );
store.add( "name", config.getVaultServiceAccountName() );
return new HttpEntity<>( store, getHeader() );
}
private HttpHeaders getHeader() {
HttpHeaders httpHeaders = headersBuilder.build();
httpHeaders.add( HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.getMimeType() );
httpHeaders.add( HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType() );
return httpHeaders;
}
}
Quoting question:
Is there any way I can pass all 3 things
HttpEntity
HttpHeaders
request
Quoting javadoc of HttpEntity:
Represents an HTTP request or response entity, consisting of headers and body.
So the answer to your question is: Yes, you can pass all 3, since the first is nothing but a combination of the other two.
Just merge your two HttpEntity objects.
Before
HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), null);
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST,
new HttpEntity<>(request, dataRepo.getHeader()), String.class);
After
HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), dataRepo.getHeader());
ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.POST,
request, String.class);

Spring Rest Template creating multipart form/data client working like a postman throws non convertable exception

I want to turn this postman client with multipart/form-data header request to a spring template client.
Right now, I have a basic rest controller which works well.
#RestController
#RequestMapping("/api")
public class MainConroller {
private static final Logger log = LoggerFactory.getLogger(MainConroller.class);
#Autowired
private MainService mainService;
public MainConroller(MainService mainService) {
this.mainService = mainService;
}
#PostMapping("/mails/send")
public void send(
#RequestParam("usertoken") String usertoken,
#RequestParam("sendTo") String sendTo,
#RequestParam("subject") String subject,
#RequestParam("content") String content,
#RequestParam(required = false, name = "files") List<MultipartFile> multipartFiles) {
log.debug("{}, {}, {}, {}", usertoken, sendTo, subject, content);
mainService.processMessage(usertoken, sendTo, subject, content, multipartFiles);
}
}
I need to, however, create a rest client so I used a rest template, it right now looks like this:
ArrayList<HttpMessageConverter<?>> converters = new ArrayList<>(
Arrays.asList(new MappingJackson2HttpMessageConverter(), new ResourceHttpMessageConverter(), new FormHttpMessageConverter()));
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(converters);
}
File file = new File("*********");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> fileValueMap = new LinkedMultiValueMap<>();
fileValueMap.add(file.getName(), file);
fileValueMap.add(file.getName(), file);
fileValueMap.add(file.getName(), file);
HttpEntity<MultiValueMap<String, Object>> filesPart = new HttpEntity<>(fileValueMap, httpHeaders);
// String key values part
MultiValueMap<String, String> stringPart = new LinkedMultiValueMap<>();
stringPart.add("usertoken", "test");
stringPart.add("sendTo", "test");
stringPart.add("subject", "test");
stringPart.add("content", "test");
HttpEntity<MultiValueMap<String, String>> objectPart = new HttpEntity<>(stringPart, httpHeaders);
MultiValueMap<String, Object> multiPartRequest = new LinkedMultiValueMap<>();
multiPartRequest.add("ObjectPart", objectPart);
multiPartRequest.add("FilesPart", filesPart);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiPartRequest, httpHeaders);
String serverUrl = "****";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
The problem is when I try to send the post request, It throws
Exception in thread "main" org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [multipart/form-data]
Update
The solution on the client side is very simple, you can just send String values in the object values, which are going to be automatically casted to Strings via generics.
Also, the files cannot be send just as files but you have to create FileSystemResource instead, here is the complete code of the client side:
#Service
public class RestTemplatePost {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public void prepareMessage() throws Exception {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("usertoken", "test");
form.add("sendTo", "test");
form.add("subject", "test");
form.add("content", "test");
form.add("files", getTestFile());
form.add("files", getTestFile());
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, httpHeaders);
String serverUrl = "******";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
}
public static Resource getTestFile() throws IOException {
Path testFile = Paths.get("C****");
System.out.println("Creating and Uploading Test File: " + testFile);
Files.write(testFile, "Hello World !!, This is a test file.".getBytes());
return new FileSystemResource(testFile.toFile());
}
}
You are making things too complex. You should use a single map to hold the form values not a map of maps. Next to that Spring Boot already provides a RestTemplate so you don't need to configure your own again.
File file = new File("*********");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
form.add("files", file);
form.add("files", file);
form.add("files", file);
form.add("usertoken", "test");
form.add("sendTo", "test");
form.add("subject", "test");
form.add("content", "test");
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(form, httpHeaders);
String serverUrl = "****";
restTemplate().postForEntity(serverUrl, requestEntity, String.class);
The RestTemplate (or actually the FormHttpMessageConverter) will transform it into a correct request.
The default RestTemplate constructor does not include any message converters, you need to add it. For example, you can do it like:
HttpEntity<MultiValueMap<String, Object>> requestEntity = new
HttpEntity<MultiValueMap<String, Object>>(parts, requestHeaders);
RestTemplate restTemplate = getRestTemplate();
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
return restTemplate.postForObject(apiURI, requestEntity, String.class);

RestTemplate GET method with path variables

I am trying to make rest call using rest template. I have two header parameters and one path variable to set for the API call. Below is my implementation. But I am receiving HttpServerErrorException: 500 null. Am I setting the path variable in the right way?
Target API: drs/v1/{caseId}
String url = configProperties.getCaseCreateUrl();
if(!StringUtils.isEmpty(url)){
url = url.replace(ApplicationConstants.DOMAIN_NAME,currentUser.domainUrl());
url = url+ caseId;
}
HttpHeaders headers = new HttpHeaders();
headers.set(ApplicationConstants.PS_TOKEN_HEADER, currentUser.getToken());
headers.set(ApplicationConstants.WORGROUP_HEADER, currentUser.getWorkgroupId());
headers.set(ApplicationConstants.DOMAIN_HEADER, currentUser.getDomainId());
headers.set(HttpHeaders.CONTENT_TYPE, MediaType.ALL_VALUE);
HttpsTrustManager.allowAllSSL();
RestTemplate restTemplate = new RestTemplate();
HttpEntity<Map<String, String>> requestEntity = new HttpEntity(null, headers);
ResponseEntity<CaseDetailsDTO> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, CaseDetailsDTO.class);
I am providing a code snippet of RestTemplate GET method with path variables example
public ResponseEntity<List<String>> getNames(long id) {
final String url = "https://some/{id}/name";
//with cookies
ResponseEntity<String> cookie = getCookies();
String set_cookie = cookie.getHeaders().getFirst(HttpHeaders.SET_COOKIE);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Cookie", set_cookie);
HttpEntity request = new HttpEntity(headers);
ResponseEntity<List<String>> response = restTemplate.exchange(url, HttpMethod.GET, request,new ParameterizedTypeReference<List<String>>(){},id);
return response;
}

Spring RestTemplate POST Request with URL encoded data

I'm new to Spring and trying to do a rest request with RestTemplate. The Java code should do the same as below curl command:
curl --data "name=feature&color=#5843AD" --header "PRIVATE-TOKEN: xyz" "https://someserver.com/api/v3/projects/1/labels"
But the server rejects the RestTemplate with a 400 Bad Request
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("PRIVATE-TOKEN", "xyz");
HttpEntity<String> entity = new HttpEntity<String>("name=feature&color=#5843AD", headers);
ResponseEntity<LabelCreationResponse> response = restTemplate.exchange("https://someserver.com/api/v3/projects/1/labels", HttpMethod.POST, entity, LabelCreationResponse.class);
Can somebody tell me what I'm doing wrong?
I think the problem is that when you try to send data to server didn't set the content type header which should be one of the two: "application/json" or "application/x-www-form-urlencoded" . In your case is: "application/x-www-form-urlencoded" based on your sample params (name and color). This header means "what type of data my client sends to server".
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("PRIVATE-TOKEN", "xyz");
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("name","feature");
map.add("color","#5843AD");
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
ResponseEntity<LabelCreationResponse> response =
restTemplate.exchange("https://foo/api/v3/projects/1/labels",
HttpMethod.POST,
entity,
LabelCreationResponse.class);
You need to set the Content-Type to application/json. Content-Type has to be set in the request. Below is the modified code to set the Content-Type
final String uri = "https://someserver.com/api/v3/projects/1/labels";
String input = "US";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("PRIVATE-TOKEN", "xyz");
HttpEntity<String> request = new HttpEntity<String>(input, headers);
ResponseEntity<LabelCreationResponse> response = restTemplate.postForObject(uri, request, LabelCreationResponse.class);
Here, HttpEntity is constructed with your input i.e "US" and with headers.
Let me know if this works, if not then please share the exception.
Cheers!
It may be a Header issue check if the header is a Valid header, are u referring to "BasicAuth" header?
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());
headers.add("Accept", MediaType.APPLICATION_JSON.toString()); //Optional in case server sends back JSON data
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
requestBody.add("name", "feature");
requestBody.add("color", "#5843AD");
HttpEntity formEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);
ResponseEntity<LabelCreationResponse> response =
restTemplate.exchange("https://example.com/api/request", HttpMethod.POST, formEntity, LabelCreationResponse.class);
my issue, the MessageConverters contains other converters may converts then entity to json (like FastJsonHttpMessageConverter). So i added the FormHttpMessageConverter to ahead and it works well.
<T> JuheResult<T> postForm(final String url, final MultiValueMap<String, Object> body) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
return exchange(url, HttpMethod.POST, requestEntity);
}
<T> JuheResult<T> exchange(final String url, final HttpMethod method, final HttpEntity<?> requestEntity) {
ResponseEntity<JuheResult<T>> response = restTemplate.exchange(url, method, requestEntity,
new JuheResultTypeReference<>());
logger.debug("调用结果 {}", response.getBody());
return response.getBody();
}
public JuheSupplierServiceImpl(RestTemplateBuilder restTemplateBuilder) {
Duration connectTimeout = Duration.ofSeconds(5);
Duration readTimeout = Duration.ofSeconds(5);
restTemplate = restTemplateBuilder.setConnectTimeout(connectTimeout).setReadTimeout(readTimeout)
.additionalInterceptors(interceptor()).build();
restTemplate.getMessageConverters().add(0, new FormHttpMessageConverter());
}
fastjson prevent resttemplate converting other mediaTypes other than json

How Upload image to Server() via RestTemplate Client and Server

I am using RestTemplate Client Code and Want to access Image on Server side. I want to upload image on custom Directory of Tomcat, i am getting error:
Caused by: org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.apache.http.entity.mime.MultipartEntity] and content type [multipart/form-data]
RestTemplate Client Code:
public String saveCompanylogo(File file){
String url = COMPANY_URL+ "/saveCompanyLogo";
MultipartEntity multiPartEntity = new MultipartEntity ();
FileBody fileBody = new FileBody(file) ;
//Prepare payload
multiPartEntity.addPart("file", fileBody) ;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultipartEntity> entity = new HttpEntity<MultipartEntity> (multiPartEntity, headers);
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, entity, new ParameterizedTypeReference<String>() {
});
return exchange.getBody();
}
My Server side(Controller) code is :
#RequestMapping(method = POST, value = "/saveCompanyLogo")
#Consumes("multipart/form-data")
public String saveCompanylogo(#RequestParam("file") MultipartFile file) {
System.out.println(""+file);
//Todo coding
return "stringData";
}
I use FileSystemResource instead of FileBody. This is my code:
restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter());
Map params = new LinkedMultiValueMap();
params.put("file", new FileSystemResource(file));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity requestEntity = new HttpEntity<>(params, httpHeaders);
restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
And in server side (I use Jersey instead of MVC, but I guess no matters):
#RequestMapping(method = POST, value = "/saveCompanyLogo")
#Consumes("multipart/form-data")
public String saveCompanylogo(#RequestParam("file") InputStream file) {
//DO SOMETHING
}
Hope it helps

Categories

Resources