I'm getting start with Play Framework, however it does not have any decent guide to teach what I wanna do.
I have a service that get Memory and disk statistics, I'd like to load/call this service automatically and pass the values from the controller to the view.
Anyone could provide me any tutorial or tips?
So many recipes for that meal! When you say automatically, I am assuming you mean without user interaction. So your web page will need a way to initiate that update, probably via a javascript timer or more old-fashionedly via http meta refresh. In the case of the javascript timer (perhaps setTimeOut or setInterval, each time it "fires" you would use an ajax call to your controller API which would return the data in JSON which you then insert into your page. Pseudo javascript code:
on timer event ->
ajax.GET '/api/monitor' (data) ->
if data.success
update $("#results") with data.statistics
A very simple view might just have:
#()
#main() {
<script src="your javascript.js" type="text/javascript">></script>
<div id="results">
</div>
}
and a controller method to talk to, along the lines (again pseudocode) of:
def apiMonitor = Action {
Ok(Json.obj(
"success" -> true,
"statistics" -> models.statisticsMethod()
))
}
In this case your play view would be a simple container, and the front end work is not really done in the template.
Using the refresh method, your controller could return a view each time, controller Scala pseudocode:
def apiMonitor = Action {
Ok(view.html.monitor(models.statisticsMethod()
}
and a view to format:
#(statistics:List[Statistic])
#main() { <!-- where main generates something with the meta refresh in -->
<table>
<tbody>
#statistics.map { statistic =>
<tr><td>#detail.attribute1</td><td><#detail.attribute2</td></tr>
}
</tbody>
</table>
}
There are lots of ways to design such things. The above is incomplete but covers some points you might need. A very useful place to work from is one of the templates on the LightBend Website where there is working code to play with.
Related
I have a web application, which is an implementation of the Front Controller Pattern, as described by the image below. Specifically, I have followed the code example of the Front Controller Pattern, as described in this question's answer:
Design Patterns web based applications
I'm having updating issues with one of my .jsp pages. This page in particular has a popup-editor, which allows the user to add or remove links to sets of data from an external database. If the user hits a save-button, it sends a request, which is intercepted by the Front Controller. Then, the correct action for saving or deleting a reference link (many to many ID numbers) is executed on the systems own database. After, the page should be reloaded, which triggers a chained command, which loads data from both databases, before redirecting to essentially the same page, without the popup.
However, the page is not reloaded, due to some form of caching that I do not understand. I've tried every solution I could find, to prevent loading cached data, from adding a unique value to the URL, to adding meta-tags on the jsp-page, to prevent it from caching at all. I've confirmed that the data is loading on server side. A simple F5-click updates the page like it should be doing automatically.
I've also implemented an onClose-function on the popup, that calls a window.location.reload(). However this call interrupts the Front Controller, and it stops everything it is currently doing, to handle the newest request. This creates a race condition, where the data is sometimes able to be inserted/deleted, and sometimes not, before the Front Controller starts reloading the page.
Should I make a queue?
Is there a good reason not to do it this way?
Should the Front controller's execution method, or the class itself implement some kind of Synchronization?
Your popup-editor should be placed inside an iframe so that it will not reload the window when it submits. The response that returns from request sent by the iframe should trigger the window.location.reload(). For example:
<html>
<script type='text/javascript'>
window.onload = function() {
window.location.reload();
};
</script>
</html>
Another option is to send the update with an Ajax call and then reload the page when the Ajax call returns. Or nicer, update the page dynamically without a reload but with JSON data returned by the Ajax call.
I want to pass a javascript variable to my servlet, where I need to use it.
In javascript, the variable count returns the rows of my table and I can show count in the jsp, using $('#counter').html(count); , but I cannot pass count's value to my servlet. I tried document.getElementById("hiddenField").value=count; but it doesn't work.
Javascript
<script>
var count = 3;
$(function() {
$('#counter').html(count);
$('#addButton').bind('click', function() {
count = document.getElementById("dataTable").getElementsByTagName("tr").length;
$('#counter').html(count);
});
$('#deleteButton').bind('click', function() {
count = document.getElementById("dataTable").getElementsByTagName("tr").length;
$('#counter').html(count);
});
});
document.getElementById("hiddenField").value=count; // ???
</script>
JSP
Count: <span id="counter"></span> <%-- it works --%>
<form method="post" action="newteamsubmit">
...
<input type="hidden" id="hiddenField" name ="countRows" />
<input type="submit" name ="button1" value=" Submit " />
<input type="submit" name = "button1" value=" Cancel " />
</form>
Servlet
String cr = request.getParameter("countRows"); //I' ve tried also to convert it
// to int, but that's not my problem, since I cannot pass the value as a start
I've spent many hours, trying to figure out how I can access a javascript variable in jsp, but I haven't found any solution.
Thanks in advance.
The count is computed each time the add button or the delete button are clicked. But you only set the hidden field value once, when the page is loaded (and its value is thus hard-coded to 3).
You must set it, as you're doing for the #counter element, in your click handlers:
$('#addButton').bind('click', function() {
count = document.getElementById("dataTable").getElementsByTagName("tr").length;
$('#counter').html(count);
$('#hiddenField').val(count);
});
$('#deleteButton').bind('click', function() {
count = document.getElementById("dataTable").getElementsByTagName("tr").length;
$('#counter').html(count);
$('#hiddenField').val(count);
});
Also note that you're repeating exactly the same code in two click handlers here. You should do that only once, for the two buttons:
$('#addButton, #deleteButton').bind('click', function() {
count = document.getElementById("dataTable").getElementsByTagName("tr").length;
$('#counter').html(count);
$('#hiddenField').val(count);
});
or even, since you're using jQuery:
$('#addButton, #deleteButton').bind('click', function() {
count = $("#dataTable tr").length;
$('#counter').html(count);
$('#hiddenField').val(count);
});
document.getElementById('hiddenField').value is not set because it is outside your document.ready. Put it inside your click handler.
Make sure of 2 things -
There is only one element with id "hiddenField" on your page.
Make sure that the following code
document.getElementById("hiddenField").value=count;
is after in the page.
Just make sure that js sets the hiddenField after the element has been loaded.
3. check for any JS errors using Javascript console.
Rest it looks good
The main issue here is that you are trying to access from the server, a variable that only exists at the client. To access that variable you have to send it from the client to the server using AJAX to trigger some form of API in the backend. REST, SOAP or XML-RPC are common technologies used for this sort of thing. The server side code is used for generating the UI and providing it with data from a database or such. Commonly the UI is generated only once, and then the client calls the server asking for more data in response to user actions, like clicking a button.
Imagine a table filled with information about books: title, author, publish date etc. This table can get quite large, and traditionally this table will be split up over several pages and possibly a dynamic filter. To save bandwidth and increase the user experience by not loading the entire page from scratch you can use AJAX to ask the server for just the relevant data. Doing so the page updates dynamically and smoothly for the user.
In your case, you can use this technique to update the server every time the user clicks the button.
If however you are really just looking to update a hidden field in a form with a value as the user performs actions, and the server wont do anything with it except show it you can just use javascript.
Remember also that the request variable contains the data you post to the server when you submit the form. The servlet will get the data after the client has posted it, which is after the JSP has generated the page. The sequence of the code execution is JSP -> Javascript -> Servlet.
Hope this helps!
You can use this way:
document.forms[0].countRows.value = counter
Hope this will help you
First of all I am mainly with a JSF background.
I have started recently studying Spring MVC. One thing that is bothering me is the ajax re-rendering when using Spring MVC and JQuery.
Let's imagine that I have defined a complex form in my people.jsp view:
<c:forEach var="person" items="${people}">
<table>
<tr class="trPersonClass">...</tr>
<tr>...</tr>
</table>
</c:forEach>
And I have a refresh button below. When the refresh button is clicked I want with ajax the people to rerender.
function refreshButtonClicked() {
$.ajax({
type: "GET",
url: "ajax/loadPeople.do"
}).done(function( msg ) {
//WHAT SHOULD I DO HERE???
}
});
So what I should do there? I have already defined how the people rendering should like with the c:forEach tag in my jsp. I don't want to repeat it again. I don't want to duplicate user interface code at both places - in the JQuery done callback and with JSP tags in my views. This is error prone in my opinion.
Please explain me kindly what I am missing here.
First of all, Spring MVC is very flexible. You can have backend handlers that return HTML generated by a view engine, you can have a handlers that returns JSON/XML/ProtocolBuffers/etc. and use client side rendering engines like Mustache etc. to display the page in the browser, or you can combine the two in the same application.
If you want to generate HTML on the server, Spring MVC allows you to use different template engines to do that. You can use JSP, Freemarker, Velocity etc. In order to do that, it uses a ViewResolver abstraction, and in your code you only have to deal with the ModelAndView API.
More details on ViewResolver can be found here: http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html
Based on your question it sounds like you have a backend that use JSP to create the html server side. In order to update only the table and not reload the entire page when a user clicks a refresh button, you could for example have a handler that returns only the html table like so:
#RequestMapping("/table")
public ModelAndView renderTable() {
List<People> people = peopleService.findAllPeople();
return new ModelAndView("/people", "people", people);
}
I'm also assuming you have another handler that returns the main page where the table is embedded via ajax.
<body>
...
/* Content of div will be populated via ajax*/
<div id="myTableContainer" />
...
</body>
The javaScript for this would be something like:
$(function() {
var myTableContainer = $("#myTableContainer");
var renderTable = function(container) {
$.get("/table", function(data) {
container.empty().html(data);
}
};
/* This is called on document ready */
renderTable(myTableContainer);
/* Use the same renderTable function when the refresh button is clicked */
$("#refreshButton").click(function() {
renderTable(myTableContainer);
});
}
Basically, I see 2 options:
Always load the table using ajax, even on the first rendering (table creation code only in your javascript function)
Modify ajax/loadPeople.do to return an already rendered table instead of a Json list. You could then factor the people table rendering code in a JSP Tag file or use some templating library (tiles, etc.) to reuse that JSP fragment.
I would like to pass a variable wordId through JSON GET to Spring-mvc Controller in my webapp. I have no problem with static url to work with json but I do not know what is best practice to do it with dynamic/parametric urls.
Controller part:
#RequestMapping(value="/delete/{wordId}", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(#RequestParam ("wordId") Long wordId, Principal principal) {
wordService.deleteWord(wordId, principal.getName());
}
JSP part:
<c:choose>
<c:when test="${not empty accountWords}">
<c:forEach items="${accountWords}" var="word" varStatus="status">
<li class="word">
<input type="checkbox" name="word" class="word_checkbox" value="" />
<span>${word.word}</span>
<s:url value="/words/delete/${word.wordId}" var="delete_word"></s:url>
<img src="resources/gfx/delete.png" />
</li>
</c:forEach>
</c:when>
</c:choose>
jQuery part so far:
$("li.word a").click(function(e) {
e.preventDefault();
var deleteUrl = ...
$.getJSON(deleteUrl, function() {
});
});
Could you tell how should my jquery part look like to pass wordId variable to controller? I can get url from href attribute of a tag but i would like to have relative url. I'm stucked...
UPDATE:
$("#testJSON").click(function() {
$.getJSON("admin/json.html", function(w) {
$('#span_json').html("w.wordId + "<br>" + w.word);
});
});
Since the wordId is part of the URL, you should be using the #PathVariable annotation instead of #RequestParam.
Also, since you asked about best practices, I should point out that it's not a good practice to use the HTTP GET method for actions that aren't idempotent. In other words, you shouldn't use GET for actions that make a change to data on the server-side, such as deleting records from the database.
The proper HTTP method for performing a record deletion is the HTTP DELETE method. Some older browsers don't support DELETE, so you'll find a lot of code out there that does a POST for deletion instead. I don't think that's much of a problem anymore though. See http://annevankesteren.nl/2007/10/http-method-support for more detail.
Using DELETE instead of GET isn't just a good idea for the sake of "doing things the right way"... it can actually help you avoid some nasty problems. There are browser plugins that will speed-up people's experience on the web by pre-fetching all links on a page and storing them in their local cache. If a user has one of these plugins installed the plugin will "click" on every delete link on your page! Also, if you're building a public-facing application, search engine crawlers will also follow your delete links. I've seen this happen in the real world, so trust me it's a real concern!
Another RESTful best practice is to use URLs that follow the pattern of /noun/{id}, with the HTTP method serving as the verb. So, instead of /delete/{wordId} with a GET, it would be better to go with /word/{wordId} with a DELETE.
With all of my suggested changes your code would look like this:
Controller
#RequestMapping(value="/word/{wordId}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void deleteWord(#PathVariable ("wordId") Long wordId, Principal principal) {
wordService.deleteWord(wordId, principal.getName());
}
Unfortunately, the jQuery and JSP become a little trickier when you use DELETE instead of GET. GET is really tempting because you can just build a link, as you did like this:
<img src="resources/gfx/delete.png" />
To get the browser to use DELETE instead, you either need to have a form whose method is DELETE, or you need to invoke some JavaScript that does an Ajax DELETE. (Since you're already using Ajax, that's the technique I'll go with.) I'd start by changing your link to a button:
<button class="delete-button" id="delete_${delete_word}"><img src="resources/gfx/delete.png" /></button>
This creates a button that stores the id of the word you want to delete in the id of the button itself. Somehow you need to associate the id of a word to delete with every button, and this is one way to do it. I've seen other people put the id in a hidden span next to the button. (To be honest, I've never loved either of these techniques, and I'm hoping somebody follows up my answer with a better way to do it.)
Anyway, with that change in the body of your JSP you'll also want to add some jQuery that handles the click of all delete buttons. (Notice I put a class on the button called "delete-button" so that it would be easy to reference in jQuery.)
jQuery:
$(".delete-button").on("click", function() {
var wordId = $(this).attr("id").substring("delete_".length);
$.ajax({
type: "DELETE",
url: "/word/" + wordId,
success: function() {
// Maybe put some code here that deletes the <li> ?
}
});
});
Notice how I extracted the word id from the id attribute of the button that was clicked:
var wordId = $(this).attr("id").substring("delete_".length);
Of course you could also do it this way:
var wordId = $(this).attr("id").substring(7);
I prefer the first way of doing it because it self-documents what the substring is doing. In the second example the number 7 is a magic number that doesn't explain what's happening.
I have a jsp page which should load a popup using ajax. The content of the page is determined by form filled by user.
Something like this:
javascript:
ajax('getPage.action', 'content_id', 'form_id');
foo.jsp:
<div id="content_id"></div>
<form id="form_id">
...
</form>
java/spring:
#RequestMapping("getPage.action")
MyController extends AbstractCommandController {
RealDto dto = (RealDto)command;
...
return new ModelAndView("foo", data);
}
The most difficult part for me is how to send the form data easily as an ajax call. Can I use jQuery here? The form changes dynamically so it would be quite bothersome to list all the fields of the form.
Would it help to use Springs XT (which I never have)?
Yes, you can use serialize to trivially convert the form to send the data.
$("#form1").submit(function() {
$.get("/desiredURL", $("#form1").serialize(), function(response) {
// send response data to a popup
}
}
You can use get or post to send the data.
For the popup I like facebox, but there's loads of choices.
jQuery form plug-in can help you easily transform a regular form to an Ajax one. You only need a single line of code:
$("#myform").ajaxForm(
{beforeSubmit: validate, success: showPopup} );
I don't know about jQuery, but for prototype this is easy:
new Ajax.Request('getPage.action', {
parameters: $('form_id').serialize(true),
onSuccess: someMethod
);
Check out the Prototype API docs.
This page has the same information for jQuery: http://docs.jquery.com/Ajax