Requesting to a servlet file downloading via ajax(no jquery please..) - javascript

The process is this:
from web(jsp) I upload some pdf file(submitting via ajax)
in the backend I merge these pdf
I get the response(the merged pdf) via ajax --> start the file download...
I'm having issues with the third step.
I've included only the relevant code where I submit the file to upload (post request) and start the download.
I put also a direct link, that calls the same steps in get method and works.
Where is my problem?
Thanks in advance...
Here is the jsp body tag
<a href="/TestAjaxServletDownload/DownloadServlet" >
download
</a>
<p><input id="sampleFile5" name="sampleFile5" type="file" /></p>
<p><input id="uploadBtn" type="button" value="Upload" onClick="javascript:performAjaxSubmit();"></input></p>
Here is my javascript tag content
function performAjaxSubmit() {
var sampleFile1 = document.getElementById("sampleFile5").files[0];
var formdata = new FormData();
formdata.append("sampleFile", sampleFile1);
var xhr = new XMLHttpRequest();
xhr.onload = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
// alert("ok..." + xhr.responseText);
//?????????????????????????????
document.location=xhr.responseText;
}
};
xhr.open("POST","/TestAjaxServletDownload/DownloadServlet", true);
xhr.send(formdata);
}
Here is my web.xml servelet mapping tags
<servlet>
<description></description>
<display-name>DownloadServlet</display-name>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>test.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/DownloadServlet</url-pattern>
</servlet-mapping>
Here is my servlet code
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("DO GET SERVLET MERGE");
execute (request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("DO POST SERVLET MERGE");
execute (request, response);
}
protected void execute(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
File downloadFile = new File("c:\\data\\example.pdf");
System.out.println("++++" + downloadFile.getAbsolutePath());
// System.out.println(uploadPathTemp+mergeFileName);
FileInputStream inStream = new FileInputStream(downloadFile);
// obtains ServletContext
ServletContext context = getServletContext();
// gets MIME type of the file
String mimeType = context.getMimeType(downloadFile.getCanonicalPath());
if (mimeType == null) {
// set to binary type if MIME mapping not found
mimeType = "application/octet-stream";
}
// modifies response
response.setContentType(mimeType);
response.setContentLength((int) downloadFile.length());
// forces download
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getName());
System.out.println(downloadFile.getName());
response.setHeader(headerKey, headerValue);
// obtains response's output stream
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
inStream.close();
outStream.close();
}

What about changing
<a href="/TestAjaxServletDownload/DownloadServlet" >
download
</a>
to
<a id="pdfLink" href="/TestAjaxServletDownload/DownloadServlet" >
download
</a>
and then use document.getElementById('pdfLink').click()?

Related

Sending Data from JS to servlet without using <form>

I am trying to get some dynamic buttons to send their id to my servlet. I think I am close but just cant figure out how to get the data on the backend.
HTML: (dynamically generated)
<button class="btn btn-success btn-reimb" id="${res[i][1].id}" onclick='approve(this)'><i class="fas fa-check"></i></button>
JS:
const approve = (e) => {
console.log(e.id);
const id = e.id;
var xhttp;
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
console.log("Sending...")
}
};
xhttp.open("POST", 'approve', true);
xhttp.send(id);
}
Servlet:
#WebServlet(name = "approve", urlPatterns = {"/approve"} )
public class ApproveServlet extends HttpServlet {
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String id = req.getParameter("id");
System.out.println(id);
}
}
Thanks in advance!
EDIT:
Thanks to Nikos Paraskevopoulos! My servlet code now looks like:
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
ServletInputStream input = req.getInputStream();
StringBuilder string = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(input, Charset.forName(StandardCharsets.UTF_8.name())))) {
int c = 0;
while ((c = reader.read()) != -1) {
string.append((char) c);
}
}
int id = Integer.parseInt(string.toString());
System.out.println(id);
The data you send with XMLHttpRequest is in the request body. Read it with req.getInputStream(). This gives you a ServletInputStream, which you can read as a standard InputStream.

Pass JSON Object through Jquery GET call to Java Servlet

how can i pass a JSON Array/Object with the JQUERY get Method to my Java Servlet?
So far , here's my code:
var json = {
MA_ID : $("#emplID").val(),
MA_Nachname : $("#nachname").val()
}
$.get(url + "/MA_Update", json)
[...]
MA_Update.java
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuffer jb = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
jb.append(line);
}
try {
JSONObject jsonObject = HTTP.toJSONObject(jb.toString());
System.out.println(jsonObject);
} catch (JSONException e) {
// crash and burn
throw new IOException("Error parsing JSON request string");
}
}
But I only get
{"Request-URI":"","Method":"","HTTP-Version":""}
from my request
Do not use request.getReader(), use request.getParameter("MA_ID") etc., or request.getParameterMap() (and iterate over it).
The thing is, that $.get(url, jsObject) creates a HTTP GET request, where the fields of the jsObject are transformed into query parameters, i.e. http://your.server.com/MA_Update?MA_ID=someID&MA_Nachname=SomeLastName, so they are NOT available in the request body (as they would be in a POST request).

loading image without storing it to disk from a servlet with Jquery Asynchronously

I want to load an image from a servlet to a jsp file without storing it to any disk with help of jquery .It should be done Asynchronously . Below is my code
JSP.page ( Code of entire JSP page is not given ) . When the page is loaded GetCaptchaImage() function is called . This function will call doget method in the servlet Captcha. Image should be loaded in the result div. But nothing is been loaded . When I put an alert inside the javascript it shows data in encoded format .I have tried to encode the image in base64 format in servlet but still nothing comes to the browser. Even writing the response to printer object doesn't worked
data image link
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function GetCaptchaImage ()
{
$.get("Captcha",function(data){
$('.result').html('<img src="data:image/bmp;base64,' + data + '" />');
});
}
</script>
</head>
<body onload="GetCaptchaImage()">
<div class="result" >
</div>
Servlet code :
#WebServlet("/Captcha")
public class Captcha extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public Captcha() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
gtcResult = captcha.GenerateCaptchaCustom(100) // Generates the image
InputStream in = new ByteArrayInputStream(gtcResult.getbmp());
BufferedImage bImageFromConvert = ImageIO.read(in);
response.setContentType("image/bmp");
OutputStream out = response.getOutputStream();
ImageIO.write(bImageFromConvert, "bmp", out);
out.flush();
out.close();
}
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("duration : "+ duration);
}catch(Exception e){
System.out.println("Image Failed : "+ e.getMessage());
}
//response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}

Catch exception from controller in Window.open using Javascript

I have a controller, which is used to flush the bytes, which inturn will generate the PDF on the client side. But, if an exception occurs, I want to catch that and show some appropriate message to the user.
I tried Ajax, but Ajax uses only JSON, String or XML for message exchange format. How can I handle this conditon?
I have to generate the pdf in success case or catch the exception. Here is my controller and javascript code
try {
MyUtil.generatePdf(response, documentBytes, "DU"); // --> This method will flush the bytes
} catch (Exception e) {
result.setStatus("EXCEPTION OCCURED.");
}
return result;
Generate pdf method
public static void GeneratePdf(HttpServletResponse response, byte[] documentBytes,
String fileName) {
response.setHeader("Content-Disposition", "inline;filename=" + fileName + ".pdf");
response.setContentType("application/pdf");
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, postcheck=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentLength(documentBytes.length);
ServletOutputStream out = null;
try {
out = response.getOutputStream();
out.write(documentBytes);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Javascript code
try {
window.open("http://localhost:8080/INQ/CBU/5559901410151HELMPFN");
} catch (e) {
console.log(e);
}
I do not think that you can do this with window.open().
My suggestion is to use servlet API in a way that you either download the PDF or in case of an error show an error page to the user.
I have some test code for exactly the scenario in which either the PDF is written out OR an error page is sent to the user with an error message.
The clue is that an exception is caught and in that case an error message is sent out to the user using a different encoding.
servlet code
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#WebServlet("/download")
public class PDFServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String fileName = "asset_report1.pdf"; // Dummy file
// This throws sometimes an exception.
byte[] documentBytes = MyUtil.generatePdf(fileName);
response.setHeader("Content-Disposition", "inline;filename=" + fileName);
response.setContentType("application/pdf");
expireCache(response);
response.setHeader("Pragma", "public");
response.setContentLength(documentBytes.length);
ServletOutputStream out = response.getOutputStream();
out.write(documentBytes);
out.flush();
} catch (IOException e) {
expireCache(response);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"The PDF file could not be retrieved.");
}
}
private void expireCache(HttpServletResponse response) {
response.setHeader("Expires", "0");
response.setHeader("Cache-Control", "must-revalidate, postcheck=0, pre-check=0");
}
}
This works out pretty well. Either you get the PDF downloaded OR you get an error page. You will need to eventually work on you error page to make it look pretty, but the default error page is a start.
Sometimes you see the PDF and in case of an error the default error page:
In your case its best to get the pdf response as arraybuffer in angular side and store it as a blob and then download it. You can do it making a post rquest to the server. And add a error block in your angular code.
Server Side Code..
List<PhysicalCountEntityTo> salaryList = exportNonDashBoardReportManager.fetchSalaryDetails(payloadBean);
HashMap<String, Object> parametersPDF = new HashMap<String, Object>();
JasperPrint jasperPrint = null;
JRBeanCollectionDataSource beanCollectionDataSource = null;
beanCollectionDataSource = new JRBeanCollectionDataSource(salaryList);
String reportPath = httpServletRequest.getServletContext().getRealPath("//WEB-INF//JasperReports//Salary.jasper");
jasperPrint = JasperFillManager.fillReport(reportPath, parametersPDF, beanCollectionDataSource);
httpServletResponse.addHeader("Content-disposition","attachment; filename=Salary.pdf");
ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint, servletOutputStream);
Angular Side Code -- you can use this code under your ajax request as you're using javascript
exportPDF(event){
this.showPageSpinner=true;
this.httpRestClient.fetchPDF("download_salary_report", this.payloadBean).subscribe(
response => {
var blob = new Blob([response], {type: 'application/pdf'});
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE');
var trident = ua.indexOf('Trident/');
var edge = ua.indexOf('Edge/');
if(msie > 0 || trident > 0 || edge > 0){
window.navigator.msSaveOrOpenBlob(blob,'Salary.pdf');
}
else if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
var link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = "Salary.pdf";
document.body.appendChild(link);
link.click();
window.setTimeout(function() {
URL.revokeObjectURL(link.href);
document.body.removeChild(link);
}, 0);
}
else{
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="Salary.pdf";
link.click();
}
this.showPageSpinner=false;
},
error=>{
// show your message here
});
}
Important - In request header add response type to 'arraybuffer' as 'json' otherwise it won't work
fetchPDF(url: string,data): Observable<any> {
this.getCredentials();
const authHeaders = this.createBasicAuthorizationHeader(this.credentials);
return this.http.post(this.getApiUrl(url),data,{headers: authHeaders,'responseType' : 'arraybuffer' as 'json'})
}
It works in IE,Mozilla and Crome..

AJAX, send() seems to be redirected unintentionally

I use AJAX to fill a list asynchronously. Right after loading web page, an AJAX request to fill list box is triggered. But when I send this request to server, an unintended web page (on which the list box exists) is returned instead of list data(JSON).
[Components]
haveList.jsp = There is list box. It includes <script src="loadData.js"> tag.
loadData.js = It generates ajax request and send it to server. Right after loading haveList.jsp, loadData.js will be called. ( I'm just checking request get correct data from server using alert. )
returnPage.java = Servlet that forwards to haveList.jsp
returnJsonData.java = Servlet that returns json string that loadData.js asked for.
Each of these are shown below.
[web.xml]
<servlet>
<servlet-name>ReturnPage</servlet-name>
<servlet-class>pkg.ReturnPage</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReturnPage</servlet-name>
<url-pattern>/openHaveList.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>DataManager</servlet-name>
<servlet-class>pkg.ReturnJsonData</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DataManager</servlet-name>
<url-pattern>/requestListData.do</url-pattern>
</servlet-mapping>
[Phenomenon]
I sent "openHaveList.do" to server.
Page "haveList" returned.
Immediately an AJAX request to get JSON data occurred. (requestListData.do) (Refer to loadData.js below)
Using alert() I checked the content of responseText from server
I expected JSON data, but the HTML of haveList.jsp was there.
[Clues]
(1) When I got unintended html from server, browser's address bar showed http://localhost/openHaveList.do
( In other page, I click image. Then openHaveList.do occured. )
(2) When I captured request/response using ZAP (Zed Attack Proxy), I saw 2 requests occurred.
The first : requestListData.do ( Response : empty )
The second : openHaveList.do. ( Response : html of haveList.jsp )
Because of this, I suspect AJAX request is redirected unintentionally. ( requestListData.do --> openHaveList.do )
- Sources codes -
[haveList.jsp]
Nothing special. There is list box
[loadData.js]
( function () {
var conn=null, addEvent=null, createXHR=null, loadNations = null, setAsyncLoad=null;
addEvent = (function(window){
if(window.addEventListener){
return function (element, eventName, callback, canCapture) {
element.addEventListener(eventName, callback, canCapture);
};
} else if(window.attachEvent){
return function (element, eventName, callback) {
element.attachEvent("on" + eventName, callback);
};
} else {
return function (element, eventName, callback) {
element["on" + eventName] = callback;
}
}
}(window));
createXHR = function () {
var xhrObj = null;
try{
xhrObj = new XMLHttpRequest();
} catch (exception){
try{
xhrObj = new ActiveXObject('Msxml2.XMLHTTP');
} catch (innerException){
xhrObj = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xhrObj;
};
loadAsync = function () {
var list = document.getElementById("list");
conn = createXHR();
conn.onreadystatechange = function () {
if(conn.readyState == 4){
if(conn.status == 200){
alert(conn.responseText); //--> Here it shows the html of haveList.jsp
}
}
};
conn.open('GET', 'requestListData.do');
conn.send();
};
addEvent(window, 'load', function () { loadAsync(); } , false);
} () );
[returnPage.java]
public class ReturnPage extends HttpServlet {
private static String page = "/haveList.jsp";
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher = request.getRequestDispatcher(page);
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
dispatcher.forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher = request.getRequestDispatcher(page);
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
dispatcher.forward(request, response);
}
}
[returnJsonData.java]
public class ReturnJsonData extends HttpServlet {
private String command = null;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
strUri = request.getRequestURI();
command = strUri.substring(request.getContextPath().length());
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
response.setContentType("application/json; charset=UTF-8" );
response.getWriter().print( loadListData(request, command) );
} catch (Throwable e) {
System.out.println("Failed to load list");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
strUri = request.getRequestURI();
command = strUri.substring(request.getContextPath().length());
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 1L);
response.setContentType("application/json; charset=UTF-8" );
response.getWriter().print( loadListData(request, command) );
} catch (Throwable e) {
System.out.println("Failed to load list");
}
}
private String loadListData(HttpServletRequest request, String command) throws Throwable
{
String codeList = null;
if("/requestListData.do".equals(command)){
codeList = codeDao.select(conn);
}
}
}
I solved it!! ^^
[Reason]
Because of my Filter.
[Detail]
Actually, haveList.jsp is a login page. And I have a filter that checks if request was logged in. If not, that filter redirects request to "haveList.jsp (login page)".
When ajax call to server ( requestListData.do ) was triggered, filter redirected request to login page because it was not logged in. Refer to following web.xml (Before).
<filter>
<filter-name>Checker</filter-name>
<filter-class>filter.Checker</filter-class>
<init-param>
<param-name>escape</param-name>
<param-value>/Test/,/Test/gate.jsp,/Test/openHaveList.do</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Checker</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Checker</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
[Solution]
I registered ajax call to server as exception. (escape parameter) In my filter servlet, I do not redirect such exception to login page programmatically. Refer to following web.xml (After).
<filter>
<filter-name>Checker</filter-name>
<filter-class>filter.Checker</filter-class>
<init-param>
<param-name>escape</param-name>
<param-value>/Test/,/Test/gate.jsp,/Test/openHaveList.do,"/requestListData.do"</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Checker</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Checker</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
After this, I got JSON data from server. ^^

Categories