I am trying to use Ajax with Spring Portlet 2.5 (I can't upgrade to higher version because I need to run tests on this one - therefore I can't use #ResourceMapping). So this is what I tried
<script type='text/javascript'>
function <portlet:namespace />setCurrentDateTime() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
//now what?
}
};
xhr.open("GET", '${actionURL}', true);
xhr.send();
}
</script>
<table>
<tr>
<td><b>Refresh</b></td>
</tr>
</table>
<br/>
<div id="<portlet:namespace />messageText">${date}</div>
By this code, action on the server side is correctly trigerred but I am not sure how do I refresh the messageText to have there updated value from the server.
This is my server side code
#RequestMapping
public ModelAndView defaultView(RenderRequest request, RenderResponse response) {
String date = (String) request.getPortletSession().getAttribute("date");
if (date == null) {
return new ModelAndView("home");
} else {
Map<String, Object> map = new HashMap<String, Object>();
map.put("date", date);
return new ModelAndView("home", map);
}
}
#RequestMapping(params = "action=getDateTime")
public void handleActionRequest(ActionRequest ar, ActionResponse ar1) {
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
ar.getPortletSession().setAttribute("date", sdf.format(new Date()));
}
Updating the contents of the messageText element would require adding the following into the JavaScript where you currently have "now what?":
document.getElementById("<portlet:namespace />messageText").innerHTML = xhr.responseText;
However, the larger problem is that you're attempting to use Ajax in a portlet with a version of Spring that only supports JSR 168 (Portlet Spec 1.0). Resource Requests, which are how Ajax calls are typically handled, were not introduced until JSR 286 (Portlet Spec 2.0).
Updating the JavaScript with my suggested code results in the entire portal page being added as the innerHTML of the messageText element, as the ActionRequest resulted in a full RenderRequest being triggered for the portlet.
Related
I use Servlet 3.0, PrimeFaces 6.0, WildFly 8.2, Eclipse Neon, Mozilla or Chrome browsers. Despite following these nice links below:
Oracle Tutorial on File Upload
GitHub: getting the original file name example
I am still not able to determine the actual file name of an uploaded file. My problem is that in the below mentioned servlet the method call:
String fileNamer = getFileName(filePart);
gives me back NULL for the file name, i.e. fileNamer is null. What am I doing wrong? Please help:
1.) Here is my controller (servlet):
#WebServlet("/fileUpload")
#MultipartConfig
public class ImageUploadServlet extends HttpServlet {
private String getFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
return cd.substring(cd.indexOf('=') + 1).trim()
.replace("\"", "");
}
}
return null;
}
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
HttpSession session = request.getSession(false);
Long savedKundeId = (Long) session.getAttribute(NewCustomerBean.SESSION_ATTRIBUTE_CUST_ID);
Part filePart = null;
PrintWriter pw = null;
try {
filePart = request.getPart("uploadImageForNewCustomerformId");
String fileNamer = getFileName(filePart);
// rest of code not shown here
2.) My view (Prime Faces 6.0 facelet):
<h:form id="newCustomerformId">
<!-- rest of code not shown -->
<p:commandButton type="submit" value="Create Customer"
icon="ui-icon-check"
actionListener="#{newCustomerBean.saveNewCustomer}"
update = "#form"
oncomplete="ajaxUploadFile();"/>
</h:form>
<h:form id="uploadImageForNewCustomerformId"
enctype="multipart/form-data">
<div id="dropzone">
<img id="librarypreview" src='' alt='library'
style="width: 280px; height: 160 px;" /> <select name="top5"
id="flist" size="5" onchange="previewFile()">
</select>
<output id="list"> </output>
</div>
<input id="fileInput" type="file" name = "file"></input>
<span id="uploadStatusId"></span>
</h:form>
3.) My Java Scipt function for ajax-uploading the file:
function ajaxUploadFile() {
var form = document.getElementById('uploadImageForNewCustomerformId');
if (form == null)
return;
var formData = new FormData(form);
for (var i = 0; i < fileList.length; i ++){
//append a File to the FormData object
formData.append("file", fileList[i], fileList[i].name);
}
var uploadStatusOutput = document.getElementById("uploadStatusId");
var request = new XMLHttpRequest();
request.open("POST", "/javakurs3-biliothek-jsf-mobile/fileUpload");
request.responseType = 'text';
request.onload = function(oEvent) {
if (request.readyState === request.DONE) {
if (request.status === 200) {
if (request.responseText == "OK") {
form.action = "/javakurs3-biliothek-jsf-mobile/pages/customers.jsf";
form.submit();
return;
}
}
uploadStatusOutput.innerHTML = "Error uploading image";
} // request.readyState === request.DONE
}; // function (oEvent)
request.send(formData);
};
I was finally was able to solve the problem. As BalusC correctly put it, I am not only doing a preview of the image using Java Script, but also uploading it using Java script. This caused confusion, as PrimeFaces supports an image preview and an image upload using their custom, own tag, as shown here .
p:fileUpload showcase
The problem using this p:fileUpload is that it has its own button for the image submission, or upload. However, I want to both submit my newly entered customer data AND upload the image using EXACTLY ONE button and button click.
The solution to my requirement is that I used the following code in my ImageUploadServlet
for (Part fPart : request.getParts()){
if (fPart.getName()!=null && fPart.getName().equals("file") && StringUtils.isNotEmpty(fPart.getSubmittedFileName())){
fileNamer = fPart.getSubmittedFileName();
filePart = fPart;
break;
}
}
instead of the code I mentioned in my question:
private String getFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
return cd.substring(cd.indexOf('=') + 1).trim()
.replace("\"", "");
}
}
return null;
}
I created an angular js program for downloading a file from the server here follows the code
HTML Code
<a download="fullList.csv" ng-href="{{ fullListUrl }}" type="button" class="btn btn-success btn-xs exec-batch" ng-click="exportCSVBulk(batchExec)">
<span class="glyphicon glyphicon-ok"></span> EXPORT AS CSV
</a>
AngularJS Controller
$scope.exportCSVBulk=function(){
var page = "../importExportService/exportBulkCSV/"+batchExec.id;
$http.get(page).success(function(response) {
$scope.fullListUrl = 'data:text/csv;charset=utf-8,' + escape(response);
});
}
Here what i am doing is when a user click on the EXPORT AS CSV link the function exportCSVBulk fires and from that function the url value (fullListUrl) sets. But this is an ajax request, so when a user click on the link the url, the response time become little bit long which results the url will not redirected properly. Is it possible to fix this problem? or is there is any alternative way to fix this?
I have faced the similar issue for downloading files such as .pdf, .xls, .xlsx etc through Ajax.
Its a fact that we cant download files through Ajax, even though i came up with a solution which downloads files through Ajax like.
You can use jquery.fileDownload - A jQuery File Download Plugin for Ajax like, feature rich file downloads.
Demo Working
Server Side
I am using Spring at the server side
#RequestMapping(value = "exportXLS", method = RequestMethod.POST, produces = APP_JSON)
#ResponseBody
public void getCSV(final HttpServletResponse response, #RequestParam(value = "empId", required = true) final String empId) throws IOException, Exception
{
final byte[] csv = ExportXLSUtil.getFileBytes(empId); // get the file bytes
final OutputStream output = getOutputStream(response);
response.setHeader("Content-Disposition", "attachment; filename=documents_" + new DateTime() + ".xls");
response.setContentType(CONTENT_TYPE);
response.setContentLength(csv.length);
write(output, csv);
}
Client Side
At the client side, I am using AngularJS
$downloadXLS = function(id)
{
$.fileDownload('/user/exportXLS',
{
httpMethod : "POST",
data : {
empId : id
}
}).done(function(e, response)
{
// success
}).fail(function(e, response)
{
// failure
});
}
Download Link - jquery.fileDownload.js
I created a more angular way solution. The server has to provide content-type and content-disposition if you want to sync with server info, although you could add type and download properties manually.
vm.export = function () {
//PopUps.showLoading()
$http.get(Url).then(function (result) {
//PopUps.hideLoading()
var headers = result.headers()
var blob = new Blob([result.data], { type: headers['content-type'] })
var windowUrl = (window.URL || window.webkitURL)
var downloadUrl = windowUrl.createObjectURL(blob)
var anchor = document.createElement("a")
anchor.href = downloadUrl
var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
anchor.download = fileNamePattern.exec(headers['content-disposition'])[1]
document.body.appendChild(anchor)
anchor.click()
windowUrl.revokeObjectURL(blob)
})
}
I have a html page and a java application with Thymeleaf templating engine and I'm looking for a tutorial to make a request to the server and render only part of the page based on response.
At this moment, I have some buttons having a link of the same page with a different parameter, my div is created based on attribute articleList (which I receive from the server based on button_id)
HTML:
button 1
button 2
<div class="" th:each="article : ${articleList}">
<p th:text="${article.getText()}">Article</p>
Java:
public class NodController implements IGTVGController {
public void process(
final HttpServletRequest request, final HttpServletResponse response,
final ServletContext servletContext, final TemplateEngine templateEngine)
throws Exception {
final WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
Integer button_id = Integer.valueOf(request.getParameter("button_id"));
List<String> articleList = getArticleList(button_id);
request.getSession().setAttribute("articleList",articleList);
templateEngine.process("/index", ctx, response.getWriter());
}
I want my buttons to process my index controller and only change the div with the articles and not refresh the entire page.
I have tried using ajax but I didn't find code examples for server-side that I could understand, so I don't know how to process the request and I don't know how to use servlets. Also I didn't manage to send any request to my current controller.
I have also found in thymeleaf api this method:
public final void process(String templateName, IContext context,
IFragmentSpec fragmentSpec, Writer writer)
where IFragmentSpec should "select a fragment of a template to be processed (once read and parsed), discarding the rest of the template" but I couldn't find more information about it as how to use it or if it is what I'm looking for.
this is the javascript code
//get text 1 by ajax
function getText1(urlstarted) {
xmlHttp = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
xmlHttp = new XMLHttpRequest();
if (xmlHttp.overrideMimeType) {
// set type accordingly to anticipated content type
//http_request.overrideMimeType('text/xml');
xmlHttp.overrideMimeType('text/html');
}
} else if (window.ActiveXObject) { // IE
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if (!xmlHttp) {
alert('Cannot create XMLHTTP instance');
return false;
}
var url=urlstarted+"/jsp/viewText1.jsp"; //put the link to ur Ajax page here
xmlHttp.onreadystatechange = startAjaxingText;
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
}
function startAjaxingText() {
if (xmlHttp.readyState != 4) {
document.getElementById('image').style.display='block' ;
document.getElementById('result').style.display='none' ;
}
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
document.getElementById('image').style.display='none' ;
document.getElementById('result').style.display='block';
document.getElementById('result').innerHTML = xmlHttp.responseText;
} else {
alert("There was a problem with the request.");
}
}
}
//get text 2 by ajax
function getText2(urlstarted) {
xmlHttp = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
xmlHttp = new XMLHttpRequest();
if (xmlHttp.overrideMimeType) {
// set type accordingly to anticipated content type
//http_request.overrideMimeType('text/xml');
xmlHttp.overrideMimeType('text/html');
}
} else if (window.ActiveXObject) { // IE
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if (!xmlHttp) {
alert('Cannot create XMLHTTP instance');
return false;
}
var url=urlstarted+"/jsp/viewText2.jsp"; //put the link to ur Ajax page here
xmlHttp.onreadystatechange = startAjaxingText2;
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
}
function startAjaxingText2() {
if (xmlHttp.readyState != 4) {
document.getElementById('image').style.display='block' ;
document.getElementById('result').style.display='none' ;
}
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
document.getElementById('image').style.display='none' ;
document.getElementById('result').style.display='block';
document.getElementById('result').innerHTML = xmlHttp.responseText;
} else {
alert("There was a problem with the request.");
}
}
}
now your buttons will look like this
<input name="button_1" id="button_1" type="button" value="button_1" onclick="getText1('<%=request.getContextPath()%>');" />
<input name="button_2" id="button_2" type="button" value="button_2"
onclick="getText2('<%=request.getContextPath()%>');" />
your div will look like
<div id="image" style="display:none"><img src="<%= request.getContextPath()%>/images/ajax-loader.gif" alt="Loading...."/> </div>
<div id="result" style="display:none"></div></td>
your viewText1.jsp page that doing ajax part
out.println("text1");//or any logic u want
your viewText2.jsp page that doing ajax part
out.println("text2");//or any logic u want
note that : the result of viewText1.jsp or viewText2.jsp must be a text either a table or paragraphs
Client-side implementation
You will have to use AJAX to load content from the server dynamically.
Consider designing your frontend as SPA. Look into AngularJS or Knockout.
Also, you can use old-school approach by using something like jQuery AJAX if this is just a small area of your application.
Separation of concerns
I strongly suggest to consider the idea to separate concerns by using server as a REST service and frontend as a client. This is the best practice for large applications if you want to keep them maintainable and scalable.
You should look for tutorials of how to implement REST with your server-side technology. It's very common practice so I think you should be able to find one.
If you have any questions I will be glad to update this answer.
I am creating a web application in java. On client side I have a bar chart that display some data stored in a tsv file created by the java server page. By clicking on a button the server updates these data in the file. Now I want to read the refreshed data, but I get the older ones. It seems that the browser cached the file so it can't get the changed file.
This is my servlet code:
public class GetDataServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private User user;
Utility utility;
public void init() throws ServletException {
reset();
}
public void doGet (HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
PrintWriter out = response.getWriter();
user.getProfile().get(0).setWeigth(user.getProfile().get(0).getWeigth()+0.03);
user.getProfile().get(1).setWeigth(user.getProfile().get(1).getWeigth()+0.02);
user.getProfile().get(5).setWeigth(user.getProfile().get(5).getWeigth()+0.01);
utility.createTsvFile(user, "/usr/local/apache-tomcat-7.0.50/webapps/Visualizer/data.tsv");
String message = String.format("data.tsv");
i++;
out.print(message);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(request.getParameter("reset").compareTo("yes")==0)
reset();
}
private void reset(){
List<Concept> children = new ArrayList<Concept>();
Concept food = new Concept();
food.setWeigth(0.10);
food.setLabel("food");
food.setColor("#98abc5");
Concept dish = new Concept();
dish.setWeigth(0.08);
dish.setLabel("dish");
dish.setParent(food);
dish.setColor("#8a89a6");
Concept cuisine = new Concept();
cuisine.setWeigth(0.06);
cuisine.setLabel("cuisine");
cuisine.setParent(food);
cuisine.setColor("#8a89a6");
children.add(dish);
children.add(cuisine);
food.setChildren(children);
children.clear();
Concept pizza = new Concept();
pizza.setWeigth(0.05);
pizza.setLabel("pizza");
pizza.setParent(dish);
pizza.setColor("#6b486b");
Concept spaghetti = new Concept();
spaghetti.setWeigth(0.05);
spaghetti.setLabel("spaghetti");
spaghetti.setParent(dish);
spaghetti.setColor("#6b486b");
Concept sushi = new Concept();
sushi.setWeigth(0.06);
sushi.setLabel("sushi");
sushi.setParent(dish);
sushi.setColor("#6b486b");
children.add(pizza);
children.add(spaghetti);
children.add(sushi);
dish.setChildren(children);
List<Concept> profile = new ArrayList<Concept>();
profile.add(food);
profile.add(dish);
profile.add(cuisine);
profile.add(pizza);
profile.add(spaghetti);
profile.add(sushi);
user = new User("mario", profile);
utility = new Utility("");
}
}
This is the javascript code that calls the servlet:
function ajaxSyncRequest(reqURL) {
//Creating a new XMLHttpRequest object
var xmlhttp;
if (window.XMLHttpRequest) {
xmlhttp = new XMLHttpRequest(); //for IE7+, Firefox, Chrome, Opera, Safari
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); //for IE6, IE5
}
//Create a asynchronous GET request
xmlhttp.open("GET", reqURL, false);
xmlhttp.send(null);
//Execution blocked till server send the response
if (xmlhttp.readyState == 4) {
if (xmlhttp.status == 200) {
document.getElementById("message").innerHTML = xmlhttp.responseText;
update(xmlhttp.responseText);
//alert(xmlhttp.responseText);
} else {
alert('Something is wrong !!');
}
}
}
function update(file){
d3.tsv(file, function(error, data) {
......
In the html page I have also put this:
<meta http-equiv="Cache-control" content="no-cache">
but it doesn't work.
With this code I can display the correct data the first time I call the servlet, than even if the data in the file tsv changes I get the first one.
Which is the best way to read the refreshed data in the file?
Okay I you are facing problem from browser caching problem like this so two hings can be done
1)You can create a filter and instruct in filter not to cache some what like this Prevent user from seeing previously visited secured page after logout
2)Each time you are hitting the url of tsv file add a random variable in end .(This is usually in case of internet exlorer)
I'm new to wicket and AJAX and trying to set up a simple page that passes messages from the html page via jQuery & ajax to a wicket servlet. The page then updates a label with an appropriate response.
I tried to use the code below from Marrying Wicket And jQuery UI Autocomplete Ajax but the code does not compile using Wicket 1.5.4. getParameterMap(), setRequestTarget and StringRequestTarget are all unrecognised in wicket 1.5.4.
Any help would be much appreciated.
add(aab = new AbstractAjaxBehavior() {
#Override
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.renderJavaScript("var callbackUrl = '" + aab1.getCallbackUrl() + "';", "callbackurl");
}
// handle the ajax request
#Override
public void onRequest() {
System.out.println("ajax request received");
RequestCycle requestCycle = RequestCycle.get();
Request request = requestCycle.getRequest();
IRequestParameters irp = request.getRequestParameters();
String json = getJSON();
requestCycle.scheduleRequestHandlerAfterCurrent(new TextRequestHandler("application/json", "UTF-8", json));
}
});
This was solved as the tutorial code was updated.