I want to write a rest client for old code, which as I understand it accepts multipart.
My client is written in quarkus and uses resteasy-multipart-provider
I have old code which I want to call with:
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
public Response addFiles(#Context HttpServletRequest request, #Context ServletContext context)
{
try
{
File repository = (File) context.getAttribute("javax.servlet.context.tempdir");
DiskFileItemFactory factory = Utils.getDiskFileItemFactory(context, repository);
factory.setRepository(repository);
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List<FileItem> items = upload.parseRequest(request);
for (FileItem item: items)
{
if (!item.isFormField())
{
....
}
}
.....
}
And my client:
#Path("/upload")
#RegisterRestClient(configKey = "scannedimage")
#ClientHeaderParam(name = "Authorization", value = "{lookupAuth}")
public interface UploadClient extends BearerAuthorizedHeader {
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.MULTIPART_FORM_DATA)
Response upload(#MultipartForm UploadBody data);
}
public class UploadBody {
#FormParam("objectId")
#PartType(MediaType.TEXT_PLAIN)
public Long long1;
#FormParam("entityId")
#PartType(MediaType.TEXT_PLAIN)
public Long long2;
#FormParam("doctype")
#PartType(MediaType.TEXT_PLAIN)
public Long documentType;
#FormParam("file")
#PartFilename("{file.getName}")
#PartType(MediaType.APPLICATION_OCTET_STREAM)
public File file;
}
Response always return emty list
{
"lon1": 1,
"long2": 2,
"list": [],
"error": ""
}
what am I doing wrong
I have a valid request example creating using org.apache.httpcomponents:httpmime
HttpEntity entity = MultipartEntityBuilder.create().addTextBody("long1", "1").addTextBody("long2", "2499").addTextBody("doctype", "3306").addBinaryBody("file", file, ContentType.create("application/octet-stream"), "test.pdf").build();
HttpPost httpPost = new HttpPost("http://serviece/upload");
httpPost.setEntity(entity);
httpPost.setHeader("Authorization", "Bearer token");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity result = response.getEntity();
System.out.println(EntityUtils.toString(result));
But I would like to implement it with rest-client, if it possible
As a result. I used org.apache.httpcomponents:httpmime:4.5.3 and writed method:
public UploadResponse upload(String long1, String long2, String documentType, String fileName, InputStream file) {
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
HttpEntity entity = MultipartEntityBuilder
.create()
.addTextBody("long1", long1)
.addTextBody("long2", long2)
.addTextBody("documentType", documentType)
.addBinaryBody("file", file, ContentType.create(MediaType.APPLICATION_OCTET_STREAM), fileName)
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setCharset(StandardCharsets.UTF_8)
.build();
HttpPost httpPost = new HttpPost(url + "/upload");
httpPost.setEntity(entity);
httpPost.setHeader("Authorization", "Bearer " + token());
HttpResponse response = httpClient.execute(httpPost);
return objectMapper.readValue(response.getEntity().getContent(), UploadResponse.class);
} catch (IOException e) {
log.error("Error create httpClient", e);
}
return new UploadResponse();
}
Because i can't finded like through resteasy-multipart-provider add file name to file FormParam :(.
Maybe it's fix next version quarkus or restEasy
Related
I'm storing objects of type Binary in a database and I have a JAX-RS web service that can retrieve them by their ID.
public class Binary {
private InputStream data;
private String id;
private String name;
private String description;
... // constructors/getters/setters
}
I was able to get it working with this code:
#GET
#Path("{id}")
#Produces(MediaType.MULTIPART_FORM_DATA)
Response getBinary(#PathParam("id") String id) {
Binary binary = ... // get binary from database
FormDataMultiPart multipart = new FormDataMultiPart();
multipart.field("name", binary.getName());
multipart.field("description", binary.getDescription());
multipart.field("data", app.getData(),
MediaType.APPLICATION_OCTET_STREAM_TYPE);
return multipart;
}
I don't like wrapping the values in a FormDataMultiPart and unwrapping them in the client code. I want to directly return the Binary object like this:
#GET
#Path("{id}")
#Produces(/* ? */)
Binary getBinary(#PathParam("id") String id) {
Binary binary = ... // get binary from database
return binary;
}
I can't use XML or JSON representation because of the InputStream parameter.
I'd appreciate any help of how to deal with this problem. Thanks!
If you have data as InputStream you will have problems having to reset every time you read from the InputStream. Better have it as byte[].
If you are using jackson you can then return like:
#GET
#Path("{id}")
#Produces(/* ? */)
public Response get(String documentId) {
Binary binary = ... // get binary from database
return Response.ok(binary).build();
}
you can test it with:
CloseableHttpClient httpclient = HttpClients.createDefault();
ObjectMapper mapper = new ObjectMapper();
TestObj obj = new TestObj();
obj.setFile(IOUtils.toByteArray(new FileInputStream(new File("C:\\download.jpg"))));
obj.setMimetype("image/jpeg");
obj.setDescription("asd");
String jsonInString = mapper.writeValueAsString(obj);
HttpPost httpPost = new HttpPost("http://localhost:8080/url");
httpPost.setHeader("Authorization", "Bearer asdf");
httpPost.setHeader("Content-type", "application/json");
StringEntity se = new StringEntity(jsonInString);
httpPost.setEntity(se);
System.out.println(httpPost.toString());
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
System.out.println("!!!! " + jsonInString);
System.out.println("!!!! " + se.toString());
System.out.println("!!!! " + response2.getStatusLine());
HttpEntity entity2 = response2.getEntity();
EntityUtils.consume(entity2);
} finally {
response2.close();
}
service code:
#RequestMapping(value="/uploadFile", method=RequestMethod.POST, consumes = "multipart/form-data")
public String uploadFile(#RequestParam("file") MultipartFile file,#RequestParam("filePath") String filePath){
//logic here
}
Part of the client code:
public static synchronized String responseOfPost(String restUrl, FileSystemResource file,String filePath) {
PostMethod post = new PostMethod(restUrl);
HttpClient client = new HttpClient();
post.setParameter("filePath", filePath);
try {
Part[] parts = {new FilePart("file",file.getFile())};
post.addRequestHeader("Content-Type", "multipart/form-data; boundary=Endedlogging");
if (file != null) {
post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams()));
}
client.executeMethod(post);
String response = post.getResponseBodyAsString();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
this is the error I am getting:
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:251)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:96)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:78)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
How can I pass multipart file("file") and filePath("filePath") to POST method in client code? NOT FROM UI
I'm also getting the exception like FileNotFoundException with nearly same code as your's.So can you try with this change,it maybe helpful.
Part[] parts = {new FilePart(file.getName(),file)};
I wanna send my data to web service. But i can't send
{ "OrgID":"1",
"UserDepartment":"1",
"WorkType":"1977",
"WorkDefinition":"EXAMPLE_EXAMPLE",
"Confirmed":[
{ "Confirmed":"qaAgo/+/j/XhECIhlAo2SQ==",
"Confirmed":"PJNd6u9RwTIwM4SRrom+mQ==",
"Confirmed":"75qFEZ7bnq+kCFvLS625Ww=="}],
"FileName":"",
"FileMimeType":"",
"FileContent":""
}
i can send all data except "Confirmed".
My Java codes here..
public static void sendParameter(String organizationId, String departmentId, String workType, String comfirmedList, String fileName, String fileMimeType, String fileContent, String definition) {
parameterList = new ArrayList<NameValuePair>();
parameterList.add(new BasicNameValuePair("OrgID", organizationId));
parameterList.add(new BasicNameValuePair("UserDepartment", departmentId));
parameterList.add(new BasicNameValuePair("WorkType", workType));
parameterList.add(new BasicNameValuePair("Confirmed", comfirmedList));
parameterList.add(new BasicNameValuePair("FileName", fileName));
parameterList.add(new BasicNameValuePair("FileMimeType", fileMimeType));
parameterList.add(new BasicNameValuePair("FileContent", fileContent));
parameterList.add(new BasicNameValuePair("WorkDefinition", definition));
}
How can i send Confirmed datas?
You can manually format the data as json string and sent the json string as entity to the request. On the server side make sure you have a Class that matches the exact structure.
Example
String paramString = "{\"OrgID\":\"" + OrgID
+"\",\"UserDepartment\":\"" + UserDepartment
+"\",\"WorkType\":\"" + WorkType+ "\"}";
HttpEntity httpEntity = null;
try {
httpEntity = new StringEntity(paramString);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
httpPost.setEntity(entity);
EDIT
So sorry, my json must be
{ "OrgID":"1",
"UserDepartment":"1",
"WorkType":"1977",
"WorkDefinition":"EXAMPLE_EXAMPLE",
"Confirmed":[
{"Confirmed":"qaAgo/+/j/XhECIhlAo2SQ==,}
{"Confirmed":"qaAgo/+/j/XhECIhlAo2SQ=="}],
"FileName":"",
"FileMimeType":"",
"FileContent":""
}
I am writing a Junit test with apache httpclient. The testCreate method successfully insert a record to the database but the status return is 500 which make the test case to fail.
Below is the test case,
public void testCreate() throws Exception {
String url = "http://localhost:8080/mediaactivity/videoAssignment";
HttpPost request = new HttpPost(url);
request.addHeader("Content-Type", "application/json");
request.addHeader("xAuthorization", "123");
request.addHeader("correlationId", "123");
String json = "{"+
"\"VideoType\": \"Sample\","+
"\"groupType\": \"INDIVIDUAL\","+
"\"submissionMethod\": \"test\","+
"\"title\": \"test me\""+
"}";
StringEntity entity = new StringEntity(json);
request.setEntity(entity);
// When
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
// Then
assertThat(httpResponse.getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_CREATED));
}
The controller looks like,
#RequestMapping(value = "/videoAssignment", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE, method = RequestMethod.POST)
#ResponseBody
public HttpEntity<VideoAssignment> createVideoAssingnment(
//#ApiParam are there..){
//other methods
return new ResponseEntity<>(va, HttpStatus.CREATED);
}
what i am missing here?
With Apache HttpClient, it's possible to manipulate the retrieved content by adding a HttpResponseIntercepter. With this it is quite easy to add header attributes. But how to manipulate the content of the retrieved HttpEntitys?
As example I like to convert all Text to Uppercase.
#Test
public void shoudConvertEverythingToUpperCase() throws ClientProtocolException, IOException
{
final DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
defaultHttpClient.addResponseInterceptor(new HttpResponseInterceptor() {
#Override
public void process(final HttpResponse response, final HttpContext context) throws HttpException, IOException
{
final HttpEntity entity = response.getEntity();
final HttpEntity upperCaseEntity = makeAllUppercase(entity);
response.setEntity(upperCaseEntity);
}
private HttpEntity makeAllUppercase(final HttpEntity entity)
{
// how to uppercase everything and return the cloned HttpEntity
return null;
}
});
final HttpResponse httpResponse = defaultHttpClient.execute(new HttpGet("http://stackoverflow.com"));
assertTrue(StringUtils.isAllUpperCase(EntityUtils.toString(httpResponse.getEntity())));
}
private HttpEntity makeAllUppercase(final HttpEntity entity)
{
Header h = entity.getContentType();
ContentType contentType = h != null ? ContentType.parse(h.getValue()) : ContentType.DEFAULT_TEXT;
String content = EntityUtils.toString(entity, contentType.getCharset());
return new StringEntity(content.toUpperCase(Locale.US), contentType);
}
This is not the most efficient due to intermediate buffering of content in memory but the most concise implementation.