German/Special character support in form data rest web service - java

I am currently developing small project in Angular JS + Java, where user is registering his information with his profile picture using rest webservice. Everything is working fine, except in case of special character(Ä Ö Ü ä ö).
Java :
#POST
#Path("add_employee")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response addEmployee(MultipartFormDataInput input) {
try {
Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
if (formDataMap != null && !formDataMap.isEmpty()) {
InputPart inputPart = formDataMap.get("EmployeeProxy").get(0);
ObjectMapper mapper = new ObjectMapper();
//receiving wrong json below=>
EmployeeProxy admbo = mapper.readValue(inputPart.getBodyAsString(), EmployeeProxy.class);
List<InputPart> profilePic = formDataMap.get("profilePic");
.
.
.
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
} catch (Exception ex) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
}
Angular JS :
var fd = new FormData();
fd.append('EmployeeProxy', angular.copy(JSON.stringify($scope.empInfo)));
fd.append('profilePic', $scope.myFile);
$http.post(Server.url + 'add_employee', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (response) {
});
Sending Json : {"empName": "Ä Ö Ü ä ö","empSurname": "XYZ","emailId":
"abc#gmail.com"}
Receiving Json : {"empName": "�� �� �� �� �� ��","empSurname":
"XYZ","emailId": "abc#gmail.com"}
Please find below image for request header information :
This is working fine, if I am using APPLICATION_JSON without MULTIPART_FORM_DATA.

If your Content-Type header is undefined, RestEasy cannot identify the charset to use and will fallback to a default (us-ascii).
See also:Overwriting the default fallback content type for multipart messages
Edit after reading up on this: It should be the multipart body which specifies the Content-Type in order for RestEasy to parse the individual strings.
In the documentation of FormData it can be done in the following way:
Angular JS :
fd.append('EmployeeProxy', new Blob([angular.copy(JSON.stringify($scope.empInfo))], { type: "text/plain; charset=iso-8859-1"}));
Java :
String json = IOUtils.toString(inputPart.getBody(InputStream.class, null), StandardCharsets.UTF_8);
EmployeeProxy admbo = mapper.readValue(json, EmployeeProxy.class);

Related

How set custom 'Content-Disposition' Header in POST request in Java?

The server I am sending a POST request to requires extra parameters in the Content-Disposition field that are easily added in C# code, but I am struggling to replicate this functionality in Java.
The working C# code:
using (var content = new MultipartFormDataContent()) {
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes("filepath"));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = "file.zip.encrypted",
};
fileContent.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("Type", "CSV"));
fileContent.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("Token", jwt));
content.Add(fileContent);
var requestUri = "url";
var result = client.PostAsync(requestUri, content).Result;
When I print the above request headers the Content-Disposition header looks like:
Content-Disposition: form-data; name=file; filename=file.zip.encrypted; Type=CSV; Token=jwt
Attempting to replicate this POST request in Java Apache Http:
File file = new File("filepath");
String headerValue = "form-data; name=file; filename=\"file.zip.encrypted\"; Type=\"CSV\"; Token=\""+jwtToken+"\"";
try (CloseableHttpClient client2 = HttpClients.createDefault()) {
HttpPost post2 = new HttpPost(url);
HttpEntity entity = MultipartEntityBuilder.create().addPart("file", new FileBody(file)).build();
post2.setHeader("Content-Disposition", headerValue);
post2.setEntity(entity);
try (CloseableHttpResponse response2 = client2.execute(post2)) {
System.out.println(response2.toString());
}
}
However, when I print the Headers in this request, only the name and filename fields are captured, and not the other parameters required in the Content-Disposition header. This is leading to Internal Server Error responses, as the Header does not contain the required parameters. (tried with and without the added quotes around field values)
Content-Disposition: form-data; name="file"; filename="file.zip.encrypted"
Any help getting the C# POST request behavior replicated in Java would be greatly appreciated, thanks!

Save a PDF generated by SpringBoot in Angular

I am trying to save a PDF using Angular and Spring Boot.
When I make an API call, my Java code is fetching the data from the database and transforming it to a byte-stream. This stream is sent as response.
if(format.equals(Constant.PDF_FORMAT)) {
ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "inline; filename=report.pdf");
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(stream));
}
I have to use this response and save the data into a PDF.
Component.ts
public getReports(type?: string): void {
this.params['expected-format'] = type;
if (type === 'json') {
this.Service.getPilotReports(this.params).subscribe((res) => {
this.reportsData = res;
this.pilotBankSpinnerService.closeSpinner();
});
} else {
this.Service.customGetForDownload(this.params).subscribe(
(data: Blob) => {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
var a = document.createElement('a');
a.href = fileURL;
a.target = '_blank';
a.download = 'reports.pdf';
document.body.appendChild(a);
a.click();
},
(error) => {
console.log('getPDF error: ', error);
}
);
}
}
Service.ts
public customGetForDownload<blob, T>(url: string, params: any): any {
const headers = new HttpHeaders({ 'Content-Type': 'application/json', responseType: 'blob' });
const httpParams = this.http.constructParams(params);
const absoluteUrl = this.getAbsoluteUrl(url);
return this.httpClient.get(absoluteUrl, {
headers: headers,
params: httpParams,
responseType: 'blob' as 'json',
observe: 'response',
});
}
Though the file is getting saved. When I try to open the file, it says "Failed to load pdf document".
Syntax Issues
First I see a syntax error:
missing argument in method-call: ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos, ); (after the comma)
With this syntax error you most likely receive a compilation-error on console.
Assume this is a lapse and you can fix it to something like ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos); then it should compile.
Boots without errors? Then test the endpoint!
Assume further your server application boots and runs without errors, then you could test the HTTP-endpoint with a HTTP-call.
You can test using a HTTP-client like CURL, postman or maybe even a browser.
Then you should receive a response with HTTP status code 200 and the body containing the PDF-file as binary with MIME-type application/pdf and specified header Content-Dispositon.
The browser is expected to prompt you with a download-dialogue.
Responding with a binary in Spring
Your InputStreamResource is a valid way, but you should be confident when using it.
In a Spring controller method, you can return the binary data in different types:
ResponseEntity<byte[]> as byte-array
ResponseEntity<ByteArrayOutputStream> as stream (not input-stream for reading input)
ResponseEntity<Resource> as abstract binary content, see Spring's Resource
ResponseEntity<File> as entire file
See also
Spring boot Angular2 file download not working
PDF Blob is not showing content, Angular 2
Return generated pdf using spring MVC
There are also some response-directed ways especially in Spring:
return a InputStreamResource as you did
return a StreamingResponseBody is very convenient
write to a HttpServletResponse, probably the oldest way
See: How To Download A File Directly From URL In Spring Boot
From input to output
Remember: Input is for reading (e.g. from a request), output is for writing (e.g. to a response). So you need an output type, like byte[] or ByteArrayOutputStream etc for your response-body.
When reading input into ByteArrayInputStream stream you could copy from that input to an output-stream with e.g. Apache-Commons IOUtils: IOUtils.copy(in, out);.
Or simply return the byte-array: byte[] data = stream.readAllBytes();
See: Java InputStream to Byte Array and ByteBuffer | Baeldung

How to parse multi-part form data in wicket

When my page gets hit from a third party page, I get the below data in request payload:
Content-type: multipart/form-data, boundary----------14048
Content-Length = 590
----------14048
Content-disposition: form-data; name ="xyz"
{"abc":"lmn","def":"ghi"}
----------14048
I need to read the JSON string from this parameter in my Java class. How can I do that?
My current code looks like this:
IRequestParameters requestParameters = getRequest().getPostParameters();
if (requestParameters != null && requestParameters.getParameterNames().contains( "abc" )&&requestParameters.getParameterValue( "abc" ) != null){
  value = requestParameters.getParameterValue( "abc" ).toString();
}
Thanks in advance.
First, you need to parse multipart form data in Wicket:
MultipartServletWebRequest multiPartRequest =
webRequest.newMultipartWebRequest(getMaxSize(), "ignored");
// multiPartRequest.parseFileParts(); // this is needed after Wicket 6.19.0+
IRequestParameters params = multiPartRequest.getRequestParameters();
Then you need to parse the JSON fragment, one way to do that is by using org.json.
import org.json.*;
JSONObject jsondict = new JSONObject(params.getParameter("xyz");
Then you need to get the JSON parameter you are interested in:
string payload = jsondict.getString("abc");
The below code works fine for me.
HttpSevletRequest request = (HttpSevletRequest )getRequest.getContainerRequest();
try{
InputStreamReader inputReader = new InputStreamReader(request.getInputStream());
BufferedReader reader = new BufferedReader(inputReader );
for(String line;(line = reader.readLine())!=null;){
if(line.contains("abc")){
//perform task....
}
}
}catch(IOException e){
//logs
}

File download with Ext JS 6

I'm trying to download a file from the server with an Ext JS 6 component based on this post: download a file via Ext js 4
This is the component code:
Ext.define('Aft.view.search.FileDownload', {
extend: 'Ext.Component',
alias: 'widget.acw-fileDownload',
autoEl: {
tag: 'iframe',
cls: 'x-hidden',
src: Ext.SSL_SECURE_URL
},
load: function(config){
var e = this.getEl();
e.dom.src = config.url +
(config.params ? '?' + Ext.urlEncode(config.params) : '');
e.dom.onload = function() {
if(e.dom.contentDocument.body.childNodes[0].wholeText == '404') {
console.
Ext.create('Acw.view.commons.notifications.Error', {
html: 'The document you are after can not be found on the server.',
closeAll: true
}).show();
}
}
}
});
This is the call to get the file:
doExportData: function(){
this.getView().load({
url: '/aft/faults/download-file'
});
And this is the Spring rest service returning a mock file:
#RequestMapping(value = "/download-file", method = RequestMethod.POST)
public void downloadFilePost(HttpServletResponse response) {
String csvFileName = "searchFaults.csv";
response.setContentType("text/csv");
// creates mock data
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", csvFileName);
response.setHeader(headerKey, headerValue);
try {
CSVWriter writer = new CSVWriter(response.getWriter(), '\t');
String[] entries = "first#second#third".split("#");
writer.writeNext(entries);
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
However when I do the call I get something like this:
[E] Ext.JSON.decode(): You're trying to decode an invalid JSON String: "first" "second" "third"
Uncaught Error: You're trying to decode an invalid JSON String: "first" "second" "third"
It seems that something arrives to the client, but it is trying to parse it as JSON. In spite of this, if I change the RequestMethod to GET and I type the URL directly in the browser I get the file and that makes me think that the header is right.
Could someone help me with this issue, or are you using a different approach/component to download files from the server?
The file can be downloaded just with this code:
doExportData: function(config){
window.location.assign(config.url +
(config.params ? '?' + Ext.urlEncode(config.params) : ''));
});

Http response through service sends content (mime) type in text/html but not application/json

My application using Oauth for basecam api. I am trying to get Httpresponse into json format but it revert into plain html (text/html) content-type. so there is no method to parse HTML content and get the token from basecamp. This is not homework but a small R&D to quick start Oauth protocol. as am new to oauth.
//HERE -> final String JSON_CONTENT = "application/json"
String contentType = OAuthConstants.JSON_CONTENT;
if (response.getEntity().getContentType() != null) {
contentType = response.getEntity().getContentType().getValue();
//BELOW -> getting contentType is in "text/html; utf-8
System.out.println(response.getEntity().getContentType().getValue()); //text/html; charset=utf-8
}
if (contentType.contains(OAuthConstants.JSON_CONTENT)) {
return handleJsonResponse(response);
} else
if (contentType.contains(OAuthConstants.URL_ENCODED_CONTENT)) {
return handleURLEncodedResponse(response);
} else
if (contentType.contains(OAuthConstants.XML_CONTENT)) {
return handleXMLResponse(response);
}
else {
// Unsupported Content type
throw new RuntimeException(
"Cannot handle "
+ contentType
+ " content type. Supported content types include JSON, XML and URLEncoded");
}
So above lines explain very well that control won't come is json, xml or url_encoded if-else. Si either i need to parse text/html into json or xml response or i have to create another method name handleHtmlResponse(). what way it would be continent to get contentType.
After the response is set with all the data(header, body ...), commit it by calling ServletResponse#flushBuffer.

Categories