File Exception while trying to upload file via spock test - spring-boot

I'm getting the below exception while trying to test from a spock test to upload a file.
How can I fix this?
java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
Rest End point
#PostMapping(path = "/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void uploadAssessment(#RequestParam("file") MultipartFile file) {
System.out.println("Reached here with file ");
}
My Test
LinkedMultiValueMap<String, Object> parameters =
new LinkedMultiValueMap<String, Object>();
parameters.add(
"file",
new org.springframework.core.io.ClassPathResource("abc.txt")
);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> entity =
new HttpEntity<LinkedMultiValueMap<String, Object>>(parameters, headers);
ResponseEntity<String> response =
restTemplate.exchange(uri, HttpMethod.POST, entity, Object.class);

Related

Spring Boot RestTemplate: Bad request when directly copying from postman

So I have an API request where I am copying the details directly from postman where it works. I am however getting a bad request error.
#Service
public class GraphApiService {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Autowired
RestTemplate restTemplate;
#Autowired
Constants constants;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public ResponseEntity<String> getAccessTokenUsingRefreshToken(Credential cred) throws IOException{
try {
//https://learn.microsoft.com/en-us/graph/auth-v2-user
// section 5. Use the refresh token to get a new access token
String url = "url";
JSONObject body = new JSONObject();
body.put("grant_type", "refresh_token");
body.put("client_id", "clientid");
body.put("scope","User.Read offline_access Files.Read Mail.Read Sites.Read.All");
body.put("redirect_uri", "http://localhost");
body.put("client_secret","secret");
body.put("refresh_token", "token");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> request = new HttpEntity<String>(body.toString(), headers);
ResponseEntity<String> response= restTemplate.postForEntity(url, request,String.class);
return response;
}
catch(HttpClientErrorException e){
logger.error(e.getResponseBodyAsString());
logger.error(e.getMessage());
return null;
}
}
I would appreciate any help. The bad request error message from microsoft graph isn't a descriptive one that will help
You're sending JSON payload with FORM_URLENCODED header.
Either you need to check if API accepts json payload, if so you need to change content-type to application/json or you can post form data as follows.
public ResponseEntity<String> getAccessTokenUsingRefreshToken(Credential cred) throws IOException{
try {
//https://learn.microsoft.com/en-us/graph/auth-v2-user
// section 5. Use the refresh token to get a new access token
String url = "url";
MultiValueMap<String, String> multiValueMap= new LinkedMultiValueMap<String, String>();
multiValueMap.add("grant_type", "refresh_token");
multiValueMap.add("client_id", "clientid");
//.....
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(multiValueMap, headers);
ResponseEntity<String> response= restTemplate.postForEntity(url, request, String.class);
return response;
}catch(HttpClientErrorException e){
logger.error(e.getResponseBodyAsString());
logger.error(e.getMessage());
return null;
}
}

How to pipe request data from spring MVC controller to Spring RestTemplate

I have a Spring MVC application which takes requests from UI (multiform and json) and it has to post this data to another micro service using Spring RestTemplate. Copying request as string to RestTemplate works fine incase of json content type but doesnt seems to be working incase of multipart.
Here is my sample code
Spring MVC controller:
#Controller
public class MvcController {
#RequestMapping(value = "/api/microservice", method = RequestMethod.POST)
public ResponseEntity<?> callMicroservice(HttpServletRequest request) throws Exception {
RestTemplate rest = new RestTemplate();
String payload = IOUtils.toString(request.getReader());
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", request.getHeader("Content-Type"));
HttpEntity<String> requestEntity = new HttpEntity<String>(payload, headers);
return rest.exchange("https://remote.micrservice.com/api/backendservice", HttpMethod.POST, requestEntity, String.class);
}
}
And here how backend microservice looks like
#Controller
public class RestController {
#RequestMapping(value = "/api/backendservice", method = RequestMethod.POST)
public #ResponseBody Object createService(#RequestParam(value = "jsondata") String jsondata,
#RequestParam(value = "email") String email,#RequestParam(value = "xsltFile", required = false) MultipartFile xsltFile,
HttpServletRequest request) {
// process jsondata
// process xsltFile
// send response
}
}
If you look at MvcController, i am sending payload as string
String payload = IOUtils.toString(request.getReader());
instead, how can I send request data as it is to RestTemplate request so that it works for both string and multipart. If you look at MvcController signature, I do not know what details user would be sending at the sometime I do not know what would be micro service signature. I just need to pipe the data between MvcController and RestTemplate request.
#RequestMapping(value = "/api/microservice", method = RequestMethod.POST)
public ResponseEntity<?> callMicroservice(HttpServletRequest request) throws Exception {
RestTemplate rest = new RestTemplate();
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("jsondata", yourjsondata);
map.add("email", youremail);
map.add("xsltFile", new ClassPathResource(file));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String, Object>>(
map, headers);
ResponseEntity<String > result = template.get().exchange(
contextPath.get() + path, HttpMethod.POST, requestEntity,
String.class);
}

How to request POST using RestTemplate, authorized using user password

Can some one tell how I can use RestTemplate to POST a HttpEntity object using Authorization. I am using below code in test application
Client Side :
public class FifthWay extends Thread {
public void run() {
String plainCreds = "anuj:khare";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Creds);
HttpEntity<String> postRequest = new HttpEntity<String>("FifthWay",headers);
RestTemplate rt = new RestTemplate();
rt.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
rt.getMessageConverters().add(new StringHttpMessageConverter());
String postUri = new String("http://169.194.48.182:8080/trade-capture-service/deals/persist");
ResponseEntity<String> responseForPost = rt.exchange(postUri,HttpMethod.POST, postRequest, String.class);
String responseStringForPost = responseForPost.getBody();
System.out.println(responseStringForPost);
}
}
Server side :
#Controller
#RequestMapping("/deals")
public class RestController {
...
...
#RequestMapping(value = "/check", method = RequestMethod.GET)
public #ResponseBody
String justACheck() {
System.out.println("It Works");
return "It works";
}
Getting errors like :
Exception in thread "Thread-4" org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
OR
Exception in thread "Thread-4" org.springframework.web.client.HttpClientErrorException: 400 Bad Request
Please help
Here is the example of RestTemplate exchange :
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
final HttpEntity entity = new HttpEntity(restCanvas, requestHeaders);
return restTemplate.exchange(canvasAddUrl + value, HttpMethod.POST, entity, Integer.class);
Here canvasAddURL is the URL you wish to call with context-path. If you want to add a cookie to it, lemme know, i have removed that code as it is most of the time not necessary. The return value for this is ResponseEntity<Integer> . Check it out.

Issue creating stream definitions via rest interface

I want to make sure I am on the right track with this.
I am getting the following response when attempting to create my stream:
015-11-23T08:59:12-0800 1.3.0.RELEASE ERROR qtp1260026681-23 rest.RestControllerAdvice - Caught exception while handling a request
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:204) ~[spring-webmvc-4.2.2.RELEASE.jar:4.2.2.RELEASE]
Here is my sample code:
HttpEntity<String> requestEntity;
ResponseEntity<String> responseEntity;
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("name", "testStream");
map.add("definition", "file | log");
map.add("deploy", "true");
requestEntity = new HttpEntity<MultiValueMap>(map, headers);
String url = "http://localhost:9393/streams/definitions"
try
{
responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
body = responseEntity.getBody();
statusCode = responseEntity.getStatusCode();
}
catch (Exception e)
{
String test = e.getMessage();
}
Here is the code that returns the: exception is java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0
*
^
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
def streamName = "TEST";
def url= "http://localhost:9393/streams/definitions";
String definition = "dod-file-source --dir='zxcv' --dir='([^\s]+(\.(?i)(tar))$)' | transform --script=dod.file.transform.groovy --variables='hotfolderId=1' > queue:StorageStream";
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>()
map.add("name", streamName)
map.add("definition", definition)
map.add("deploy", 'true')
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
String body = responseEntity.getBody();
HttpStatus statusCode = responseEntity.getStatusCode();
That is a custom source module dod-file-source but it just adds a few additional features to the file source module
I just ran (a slightly modified version of) your code and had no problems...
HttpEntity<MultiValueMap<String, String>> requestEntity;
ResponseEntity<String> responseEntity;
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("name", "testStream");
map.add("definition", "time | log");
map.add("deploy", "true");
requestEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
String url = "http://localhost:9393/streams/definitions";
try
{
responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
String body = responseEntity.getBody();
HttpStatus statusCode = responseEntity.getStatusCode();
}
catch (Exception e)
{
e.printStackTrace();
}
2015-11-23T13:00:44-0500 1.3.0.RELEASE INFO task-scheduler-1 sink.testStream - 2015-11-23 13:00:44
2015-11-23T13:00:45-0500 1.3.0.RELEASE INFO task-scheduler-1 sink.testStream - 2015-11-23 13:00:45
2015-11-23T13:00:46-0500 1.3.0.RELEASE INFO task-scheduler-1 sink.testStream - 2015-11-23 13:00:46
2015-11-23T13:00:47-0500 1.3.0.RELEASE INFO task-scheduler-1 sink.testStream - 2015-11-23 13:00:47

Session closed error when performing subsequence requests to client via Spring RestTemplate

I'm trying to use spring rest template to do a post request to login in.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
LinkedMultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
mvm.add("LoginForm_Login", "login");
mvm.add("LoginForm_Password", "password");
ResponseEntity<String> result = restTemplate.exchange(uriDWLogin, HttpMethod.POST, requestEntity, String.class);
all goes well, but when I try to send a second request, It generates an error saying :
Business Manager closes your session after 15 minutes
What can I do to solve this problem ?!
When you receive the response in your first request you should store your session id which is received via cookie. You will retrieve it in a set-cookie response header which you can get via:
//first request
RestTemplate template = new RestTemplate();
ResponseEntity<String> forEntity = template.getForEntity("http://google.bg", String.class);
forEntity.getHeaders().get("Set-Cookie").stream().forEach(System.out::println);
then in every subsequent request you should set the Cookie request header with the values received in the first request:
//subsequent request
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Cookie",cookies.stream().collect(Collectors.joining(";")));
HttpEntity<String> entity = new HttpEntity<String>(headers);
restTemplate.exchange("http://url", HttpMethod.POST, entity, String.class);
I have a StaticRestTemplate class, this way I get the same RestTemplate instance.
public class StaticRestTemplate {
public volatile static RestTemplate rest = new RestTemplate();
public static volatile String jsessionid = "";
// This way, I can test on local or server just by changing one URL.
public static volatile String baseURL = "http://192.168.178.60:8080/";
}
Login code :
public static RestTemplate rest = new RestTemplate();
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
StaticRestTemplate.jsessionid = rest.execute(StaticRestTemplate.baseURL+"j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + email + "&j_password=" + password).getBytes());
}
}, new ResponseExtractor<String>() {
#Override
public String extractData(ClientHttpResponse response) throws IOException {
List<String> cookies = response.getHeaders().get("Cookie");
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
return null;
}
Now, my JsessionID is saved, and I can use it directly for subsequent requests this way :
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders requestHeaders = new HttpHeaders();
// This is where I add the cookie value
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
HttpEntity<String> requestEntity = new HttpEntity<>(requestHeaders);
HttpEntity<String> rssResponse = rest.exchange(
StaticRestTemplate.baseURL+"dashboard",
HttpMethod.GET,
requestEntity,
String.class);
StaticRestTemplate.replyString = rssResponse.getBody();
return StaticRestTemplate.replyString;
If there are doubts, let me know.
You can try to disable cookie management with factory for your RestTemplate:
HttpClient httpClient = HttpClientBuilder.create()
.disableCookieManagement()
.useSystemProperties()
.build();
factory.setHttpClient(httpClient);

Resources