Except for this article http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
I cannot find any good examples of the new AJAX related features in Spring 3.0. I am interested in how the web application build utilizing Spring MVC with Annotations can be integrated with the various AJAX frameworks, such as Dojo to provide rich user experience on the front end.
I think the article is pretty clear about the options. For example, based on it, I created the following method for verifying whether a username is in use or not:
/**
* #param username
* #return true if the username is free, false otherwise
*/
#RequestMapping("/account/checkUsername/{username}")
#ResponseBody
public boolean checkUsername(#PathVariable("username") String username) {
return userService.checkUsername(username);
}
And on the client side, using jQuery:
$("#username").live("blur", function() {
$.getJSON("account/checkUsername/" + $("#username").val(),
function(response) {
// do something with JSON response
}
);
});
var xhrArgs = {
url: "account/checkUsername/" +dojo.byId('').value,
handleAs: 'json',
load: function(response) { response(data);}
};
dojo.xhrGet(xhrArgs);
function YourJavaScriptFunctionHere(){
byObj1.loading()
setGridData(gridNon,[])
var url='dispatch=getMETHOD&PARAMETER='+Math.random()*9999;
var ajax=new ajaxObject('YOUR CONTROLLER MAPPING');
ajax.callback=function(responseText, responseStatus, responseXML) {
if (responseStatus == 200) {
var myArray = eval("("+responseText+")");
if(myArray["error"]){
alert(myArray["error"]);
}else{
setGridData(byObj1,myArray)
}
byObj1.loadingCompleted();
}
}
ajax.update(url,'POST');
}
Related
I want to solve following issue. I have a Spring-MVC Application with Thymeleaf, with a post request (sent by a form) I trigger a simulation task, what could take several minutes. The task process big number of data and we would like to have a progress bar via JavaScript. If there are two sessions, the simulation should be triggered independently and each browser shows its progress status.
Currently we have a solution, what is not really working well all the time.
The MVC Controller gets the Post request:
#Autowired SimulatorView view; // SESSION SCOPE
#PostMapping("/view")
public String run(#ModelAttribute(CHECKS) ChecksDto checksWrapper, Model model) throws InterruptedException, ExecutionException {
view.setStatisticDto(simulate(checksWrapper)); // Can take several minutes
return "simulation/result :: simulated";
}
When I trigger the simulation on my WebGUI, a progress bar has been displayed and via JavaScript I am calling Rest Methods frequently to ask for the status of the progress.
RestController
#RequestMapping("simulation/api")
public class SimulatorApi {
#Autowired SimulatorView view; // SESSION SCOPE
#RequestMapping("/progressStream")
public double progressStream() {
return view.getProgress().progressStream();
}
#RequestMapping("/progressInvoice")
public double progressInvoice() {
return view.getProgress().progressInvoice();
}
}
My JavaScript code snippet looks like:
function registerSimulationRunEvent() {
// this is the id of the form
$("#simulatorForm").submit(function(e) {
handleSimulationStarted();
var url = location.protocol + "//" + location.host + "/fdsclient/simulation/view";
$.ajax({
type: "POST",
url: url,
data: $("#simulatorForm").serialize(), // serializes the form's elements.
success: function(data) { handleSimulationFinished(); },
error: function(xhr, error) { handleSimulationError(); }
});
e.preventDefault(); // avoid to execute the actual submit of the form.
});
}
function handleSimulationStarted() {
replaceResultPanelRunning(); // THYMELEAF FRAGMENT EXCHANGE
}
function handleSimulationFinished() {
stopResultPanelAnimation(); // STOP PROGRESS BAR ANIMATION
replaceResultPanelSimulated(); // EXCHANGE THYMELEAF FRAGMENT
}
function handleSimulationError() {
stopResultPanelAnimation();
replaceResultPanelError();
}
function replaceResultPanelRunning() {
var url = // URL;
$("#resultDiv").load(url);
startResultPanelAnimation();
}
// ANIMATION
var animationInterval = null;
function startResultPanelAnimation() {
animationInterval = setInterval(animateResultPanel,4000);
}
function stopResultPanelAnimation() {
clearInterval(animationInterval); // stop the interval
}
function animateResultPanel() {
$("#simulatorProgressLabel").animate({opacity: '0.4'}, "slow");
$("#simulatorProgressLabel").animate({opacity: '1.0'}, "slow");
}
I know using session scope for rest services is a bad thing, but I didn`t know yet what is a good and easy solution. On the other hand currently different browser can simulate independently, but not always the progress bar works (especially when trigger first time mostly doesnt work). The IE11 only works when the Developer Tools are activated. When deactivating the tool while progress, the progress bar stops to grow.
What I would like to know is, how a good solution looks like when using template engine with Spring-MVC and Thymeleaf for triggering the process and displaying the status of progress via Javascript (as JQUery). Thank you in advance.
I have done a similar thing using Jquery AJAX POST submission. You can do something like this. This will submit POST request as a JSON format to the controller and wait for a response. A progress UI component can be shown during this waiting period.
//Start Progress display
function setStatistic(){
var data = JSON.stringify(//build your ChecksDto)
if (data) {
$.ajax({
url : '/view',
headers : {
'Content-Type' : 'application/json'
},
method : 'POST',
dataType : 'json',
data : data,
success : function(data) {
if (data.status == 200) {
// Stop Progress display
// Handle success status
}
},
error : function(xhr, status, error) {
// Stop Progress display
// Handle errors here
}
});
}
}
You also need to change Controller method to retrieve ajax requests as follows,
#ResponseBody
#PostMapping("/view")
public String run(#RequestBody ChecksDto checksWrapper, Model model) throws InterruptedException, ExecutionException
At least I found the solution in another Stackoverflow Page. The magic word is setting ajax cache to false.
$.ajaxSetup ({
// Disable caching of AJAX responses */
cache: false
});
Im working on a SOA project using, ASP.NET MVC and ASP.NET WEB API. Both projects are inside different solutions, so we have a mvc site and a web api site and the mvc site calls the web api site using http methods operations.
With that cenario in mind, im facing a strange behaviour when POSTING some data to the web API from my mvc controller. When I do GET operations everything works fine. Here's what Im doing:
Inside my cshtml view, i have a js code that do an ajax call to my MVC controller:
> JS Code inside Create.cshtml:
var create = (function () {
var _init = function (container, starter, url) {
$(starter).autocomplete({
minLength: 3,
focus: function () {
return false;
},
select: function (event, ui) {
var terms = this.value.replace(" ", "").split(',');
terms.pop();
terms.push(ui.item.label);
terms.push("");
this.value = terms.join(",");
return false;
},
search: function (event, ui) {
if (_extractLast(this.value).length < 3)
return false;
return true;
},
source: function (request, response) {
_execute(request, response, url);
}
});
};
var _extractLast = function (term) {
var termArray = term.split(',');
var lastTerm = termArray[termArray.length - 1];
return lastTerm.replace(' ', '');
};
var _execute = function (request, response, url) {
var responseCallback = response;
$.ajax({
url: '\Comunication\Contacts',
async: true,
type: 'POST',
dataType: 'json',
data: { termo: _extractLast(request.term) },
success: function (data) {
responseCallback($.map(data, function (item) {
return { label: item.Name, value: item.Id }
}));
}
});
}
return { init: _init };})();
And from inside my controller I call a method from a specialized Service layer to do a POST request to my WEB API SITE doing the SOA thing, as you can see bellow:
> The MVC CONTROLLER CODE:
public class ComunicationController : BaseController{
[HttpPost]
public async Task<JsonResult> Contacts(string termo)
{
var contacts = new ContactServices.ConsumeAsync(new ContactParameter{Term: termo});
return Json(contacts, JsonRequestBehavior.AllowGet);
}
}
> The Layer SERVICE CODE:
public class ContactServices{
public async Task<List<ContactsDTO>> ConsumeAsync(ContactParameter parameter)
{
using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient())
{
httpClient.BaseAddress = new Uri("http://localhost:123456/api/comunication/contacts");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await httpClient.PostAsJsonAsync(new Uri("http://localhost:123456/api/comunication/contacts"), parameter);
return JsonConvert.DeserializeObjectAsync<ResponseProxy<List<ContactsDTO>>>(response.Content.ReadAsStringAsync().Result).Result.data;
}
}
}
My WEB API SITE accept the request, process the request like expected, no concerns here. But when I return the HttpResponseMessage from my WEB API CONTROLLER to the MVC Site under a POST operation, the request response hangs on forever pending status according to my network monitor....
So basically my request is hanging, the Protocol status is Pending and I never get the request response, heres is a pic:
Pending Status from My Post Request
As I said, when I do GET requests to my web api, everything works fine but when I do POST requests this happens...
Your problem lies in this line:
return JsonConvert.DeserializeObjectAsync<ResponseProxy<List<ContactsDTO>>>(response.Content.ReadAsStringAsync().Result).Result.data;
The use of the Result property of your Task generates a deadlock on you MVC controller. If an API is asynchronous, then always await the task.
var content = await response.Content.ReadAsStringAsync();
var deserialized = await JsonConvert.DeserializeObjectAsync<ResponseProxy<List<ContactsDTO>>>(content);
return deserialized.data;
To learn more about why you should never block on async methods check this great post:
Don't Block on Async Code
I am developing a small spring project in which the login page has two type of users admin and staff. on login attempt i want to apply session using spring MVC4 and also wants to open jsp based on the user role(Admin or Staff).
the session has four/five fields like name,id,role,SessionId. i want these information to travel through the jsp pages. But i don't want to do this using url parameter passing.
I don't know how to do this because i am new in spring and this is my first project. Help me Please.
If someone can provide me the sample code and guide me on this then it would be very helpfull.
// Login.jsp code
var MobileNo=$('#mobno').val();
var StaffPwd=$('#pwd').val();
$.ajax
(
{
url: "http://localhost:8080/OnlineStore/kmsg/grocery/Login",
type: "POST",
data: {MobileNo: MobileNo,StaffPwd: StaffPwd},
success: function(data)
{
var vUserRole = data["UserRole"];
var vUserName = data["UserName"];
if(data==="")
{
alert("Login Failed");
}
else
{
if(vUserRole == "Admin")
{
alert("Login Success: " + vUserName);
window.location.href = "http://localhost:8080/OnlineStore/JspPages/City.jsp";
}
if(vUserRole == "CityAdmin")
{
alert("Login Success: " + vUserName);
window.location.href = "http://localhost:8080/OnlineStore/JspPages/Locality.jsp";
}
if(vUserRole == "Staff")
{
alert("Login Success: " + vUserName);
window.location.href = "http://localhost:8080/OnlineStore/JspPages/CustomerOrder.jsp";
}
}
},
error: function(e)
{
alert('Error:' +e)
}
}
);
// this is controller code
#RequestMapping("/Login")
public #ResponseBody UserServiceModel selectStaff(#RequestParam Map<String,String> requestParams) throws Exception
{
String MobileNo = requestParams.get("MobileNo");
String StaffPwd = requestParams.get("StaffPwd");
return staffAdapter.login(MobileNo, StaffPwd);
}
--------------
Just store your data in some serializable object. For e.g.:
public class SessionData implements Serializable {
private String name;
private String id;
private String role;
//etc..
}
then set this object as the session attribute when the user first logs in:
session.setAttribute("sessionData", new SessionData(name, id, role, etc...))
To access this object in a JSP page you can use: ${sessionScope['sessionData']}, to access a specific field:
${sessionScope['sessionData'].id}
${sessionScope['sessionData'].name}
${sessionScope['sessionData'].role}
To access these attributes in JavaScript files just define some page data in your JSP page, for e.g.:
<script type="text/javascript">
pageData = {
id: "${sessionScope['sessionData'].id}",
name: "${sessionScope['sessionData'].name}",
role: "${sessionScope['sessionData'].role}"
}
</script>
and in js file reference them via:
pageData.id
pageData.name
pageData.role
I can see that you trying to create roles based application. You are already using Spring MVC, any reason why not use Spring Security along with it? I would highly advice doing so as it will make your life much easier.
I'm trying to implement an extremely simple spike using Nancy as an alternative to ASP.NET MVC.
It should take a username (no password) and provide meaningful error messages on the same login page without requiring a refresh. If login was successful, the response includes the URL to navigate to.
The POCO for the response looks like this:
public class LoginResponseModel
{
public bool IsSuccess { get; set; }
public string RedirectUrl { get; set; }
public string ErrorMessage { get; set; }
}
The JS handler for the login request:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The problem I'm having is with Nancy's Forms-based authentication. I've walked through half a dozen different tutorials which all more or less do the same thing, as well as gone over the Nancy authentication demos. The one thing they all have in common is that they rely on the LoginAndRedirect extension method. I don't want to return a redirect. I want to return a result of the login attempt and let the client handle the navigation.
The IUserMapper implementation I'm using:
public class UserMapper : IUserMapper
{
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
{
// Don't care who at this point, just want ANY user...
return AuthenticatedUser {UserName = "admin"};
}
}
The relevant part of my LoginModule action:
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.Guid != null) this.Login(UserMapper.GUID_ADMIN, expiry);
return Response.AsJson(result.Response);
but for subsequent requests Context.CurrentUser is always null.
If I add the following method to the Nancy.Demo.Authentication.Forms sample it reproduces the behaviour I'm seeing in my own project, leading me to believe LoginWithoutRedirect doesn't work how I expected.
Get["/login/{name}"] = x =>
{
Guid? userGuid = UserDatabase.ValidateUser(x.Name, "password");
this.LoginWithoutRedirect(userGuid.Value, DateTime.Now.AddYears(2));
return "Logged in as " + x.Name + " now <a href='~/secure'>see if it worked</a>";
};
The problem turns out to be that Context.CurrentUser with FormsAuthentication is dependent upon a cookie which isn't set if you don't return the NancyModule.Login() response.
var result = _userMapper.ValidateUser(input.AccessCode);
if (result.IsSuccess) {
this.LoginWithoutRedirect(result.Guid);
}
return Response.AsJson(result);
In this example, the LoginWithoutRedirect call returns a Response object with the cookie set. To handle this in an Ajax scenario I've had to add a AuthToken property to the LoginAjaxResponse class, then pass the cookie like so:
var result = _userMapper.ValidateUser(input.AccessCode);
var response = Response.AsJson(result);
if (result.IsSuccess) {
var authResult = this.LoginWithoutRedirect(result.Guid);
result.AuthToken = authResult.Cookies[0].Value;
}
return Response.AsJson(result);
On the client, the Ajax response handler changes to (assuming use of jQuery cookie plugin:
$.ajax({
url: '/login',
type: "POST",
data: { UserName: username }
}).done(function (response) {
if (response.IsSuccess) {
showSuccess();
$.cookie("_ncfa", response.AuthToken); // <-- the magic happens here
document.location.href = response.RedirectUrl;
return;
}
showError(response.ErrorMessage);
}).fail(function (msg) {
showError("Unable to process login request: " + msg.statusText);
});
The AuthToken is the GUID which has been encrypted and base64-encoded. Subsequent requests with this.RequiresAuthentication() enabled will first check for this auth token cookie.
If no "_ncfa" cookie is present,the UserMapper's GetUserFromIdentifier() is never called.
If the value in Context.Request.Cookies["_ncfa"] does not result in a valid GUID when base64-decoded and decrypted, GetUserFromIdentifier() is never called.
If GetUserFromIdentifier() isn't called, Context.CurrentUser is never set.
If you want the source for a working example it's on GitHub.
LoginAndRedirect is only one option, there are equivalent methods for not redirecting (LoginWithoutRedirect), or one that picks up on whether it's an AJAX request and handles it appropriately (Login). The same applies to logging out.
This is all covered, in detail, in the documentation.
I can't seem to get a JSON response from an Ajax post within a Dot Net Nuke site. It returns HTML as a response instead.
I was able to get this to work in a normal test site just fine and am wondering if anybody may know what I need to do.
Below is the code I'm testing with for now:
JavaScript:
$("#ClearTaxFormButton").click(function (e) {
e.preventDefault();
var testValue = 7;
$.ajax({
type: "GET",
url: "localhost/mywebsite/tabid/100/Default.aspx/SumbitByAjaxTest",
data: '{ "taxRate":' + testValue + '}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
// Replace the div's content with the page method's return.
//$("#Result").text(msg.d);
alert(msg.d);
}
});
});
C# Function:
//just using ths for testing
[WebMethod]
public static string SumbitByAjaxTest(string taxRate)
{
return taxRate;
}
Like I said, this exact code (aside from a different URL) works fine in a normal .NET site but when I move it over to the Dot Net Nuke site, it returns HTML.
Any ideas??
DNN's service layer allows you to follow a Webapi like approach, I think you'll find that easier for controlling the data to/from.
Here's an example of a controller for an open source articles module
https://dnnsimplearticle.codeplex.com/SourceControl/latest#cs/services/DnnSimpleArticleController.cs
Something like
public HttpResponseMessage GetAllArticles(int portalId, bool sortAsc)
{
try
{
//todo: get the latest X articles?
var articles = ArticleController.GetAllArticles(portalId, sortAsc);
//because of the circular reference when cerealizing the taxonomy within content items we have to build out our article view models manually.
var cleanArticles = new List<ArticleViewModel>();
foreach (Article a in articles)
{
var newArt = new ArticleViewModel
{
ArticleId = a.ArticleId,
Body = WebUtility.HtmlDecode(a.Body),
CreatedByUser = a.CreatedByUser,
CreatedByUserId = a.CreatedByUserId,
CreatedOnDate = a.CreatedOnDate,
Description = WebUtility.HtmlDecode(a.Description),
LastModifiedByUser = a.LastUpdatedByUser,
LastModifiedByUserId = a.LastModifiedByUserId,
LastModifiedOnDate = a.LastModifiedOnDate,
ModuleId = a.ModuleId,
Title = a.Title,
url = DotNetNuke.Common.Globals.NavigateURL(a.TabID, "", "&aid=" + a.ArticleId)
};
cleanArticles.Add(newArt);
}
var articleViewModels = new ArticleViewModels
{
Articles = cleanArticles
};
return Request.CreateResponse(HttpStatusCode.OK, articles);
}
catch (Exception exc)
{
DnnLog.Error(exc); //todo: obsolete
return Request.CreateResponse(HttpStatusCode.BadRequest, "error in request"); //todo: probably should localize that?
}
}