I have an Angular + spring REST and Wicket hybrid application.
Wicket serves a UserPage class. This UserPage contains my javascript page.
public class UserPage extends WebPage {
public UserPage() {
super();
}
#Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.render(JavaScriptHeaderItem.forUrl("https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js"));
response.render(JavaScriptHeaderItem.forReference(new JavaScriptResourceReference(UserPage.class, "user.js")));
response.render(CssHeaderItem.forReference(new CssResourceReference(UserPage.class, "user.css")));
}
I have implemented a Filter to check if a session is active, if this is not the case, the page should redirect.
WicketSession s = WicketSession.get();
if (s == null) {
response.sendRedirect("/");
} else if (s.getUser() == null) {
response.sendRedirect("/");
} else {
filterChain.doFilter(request, response);
}
However, when i run this page without logging in, the browser receives 302 but does not redirect. This only happens when the page is served through wicket. If i manually go to UserPage.html, it does redirect.
Anyone know anyway why this is happening? It surely is wicket speficic, and im not that familiar with wicket yet.
When trying to reach /user, the page stays, and the html body is send as response data, which my script tries to parse and fails (hence all the empty checkboxes)
When manually going to UserPage.html, it does redirect.
Does anyone know why wicket does not redirect when its being sent a 302? Any clues on a possible fix?
1) If you keep the session data in WicketSession then it should be before Spring's Filter/Servlet in web.xml.
I would suggest to keep the user in Spring Security Authentication if you use it.
2) WicketSession.get() never returns null. It acts as "get or create". You need if (WicketSession.exists()) {...} instead.
Related
to give a brief about my situation:
Earlier I was using chart.js for creating charts in my dashboard. Then I came across Quicksight a couple of days back. So I thought of switching to it as it provides better handling without any hassle.
Before Quicksight I was using jsp for my page, js(jquery) for my frontend and Java as my backend (spring-boot) with MongoDB as my database.
Keeping my structure same I just defined a jsp so that the user can be directed to the particular page after hitting on the chats.
Then, in my js file, I have written a (my own defined) ajaxRequest that will direct it to the Java controller:
$(document).ready(
function(){
ajaxRequest("/myService/char/getQuickSight", "GET", "", function(response){
})
}
);
Now I am not able to understand how to go on with my controller class. I have written something like this:
private static AmazonQuickSight getClient() {
final AWSCredentialsProvider credsProvider = new AWSCredentialsProvider() {
#Override
public AWSCredentials getCredentials() {
// provide actual IAM access key and secret key here
return new BasicAWSCredentials("access-key", "secret-key");
}
#Override
public void refresh() {
}
};
return AmazonQuickSightClientBuilder.standard().withRegion(Regions.SA_EAST_1.getName())
.withCredentials(credsProvider).build();
}
For he above code I refered to this
It is also throughing an error:
ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.NoSuchMethodError: com.amazonaws.client.AwsSyncClientParams.getAdvancedConfig()Lcom/amazonaws/client/builder/AdvancedConfig;] with root cause
java.lang.NoSuchMethodError: com.amazonaws.client.AwsSyncClientParams.getAdvancedConfig()Lcom/amazonaws/client/builder/AdvancedConfig;
(I can also provide the full stacktrace..)
But I am not able to understand how to move forward and what to do with the code. So if anyone can help me out I'll really appreciate it.
P.S. I have also added the following dependency in my POM
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-quicksight</artifactId>
<version>1.11.457</version>
</dependency>
I have a .JSP file that has three forms on it whose fields are dynamically shown/hidden based on user interaction with Javascript/Jquery elements.The forms are spring forms sending their action to a URL that matches a controller.
The issue is that when I submit a form, and it does not validate, the URL the form submitted to stays in the URL. Then any action I take that is URL dependent is basically corrupted because the URL has the form action appended to it.
For example, if my .JSP's normal URL is /admin/, and my spring form is:
<form:form id="form" method="POST" action="${pageContext.request.contextPath}/admin/createUser" modelAttribute="User">
If validation fails my URL will now be /admin/createUser. If I am then taking some action using Javascript/Jquery the URL is no longer a valid way to navigate. I could just work around the URL but it just seems...un-ideal.
I have tried using redirects like: "redirect:/admin/", but spring validation will not work with this because you are basically just reloading the page.
Are there any best-practice or "elegant" solutions to this, or something really simple that I'm overlooking?
The redirection should probably be done on the client side anyways with a param of returnToURL, and as for error handling in Spring, you can register method as error handler to return proper error responses:
class YourController {
/**
* see #link{org.springframework.web.bind.annotation.ExceptionHandler}
*/
#ExceptionHandler(Exception.class)
public #ResponseBody String handleException(Exception e, HttpServletResponse rsp) {
// set the response status
return "{\"error\" : ...}"'
}
}
If you get error you can return error message to a custom error page to display the error message. or in your case you can return the admin page again..
here is some example code .
#RequestMapping(value = "/createUser" ,method = RequestMethod.POST)
public ModelAndView create(#ModelAttribute User user) {
if(user == null){
Map<String, String> model = new HashMap<String, String>();
model.put("errorCode", "00");
model.put("errorText", "Error Message Here");
return new ModelAndView("error_page", model);
}
return new ModelAndView("Welcome_page");
}
As a followup to my earlier question about using Thymeleaf and preventing page refresh:
http://forum.thymeleaf.org/Preventing-page-refresh-Thymeleaf-amp-Spring-MVC-td4029155.html
Basically I had a working Spring MVC app that uses Thymeleaf to save form data. When the user saves the data the page would refresh (since I wanted to leave them on the page for more edits) and I wanted to eliminate the page refresh.
I have coded up some Javascript to use JQuery Ajax to post the data to my Spring MVC Controller. The trick seemed to be to not use a submit button, just a regular button and bind a JS function to it for sending the data to the server.
It all seems to work perfectly, but I want to make sure I understand what is happening. In particular I'm wondering if Thymeleaf is now redundant. I don't think it is because when I initially load the page Thymeleaf is still bound to the data bean. From using the debugger on the server side in the controller it looks like the post request calls the mapped method and passes in the data to the model.
I would appreciate your comments on whether or not this is the correct way to accomplish this.
Finally, how do I handle an error, say for example the repository fails to persist the data for any reason?
Thanks very much.
Here are the important parts of the form:
<FORM id="adminDataForm" action="#" th:action="#{/admin_ajax}" th:object="${adminFormAjax}" method="post">
<input type="button" value="Save Changes" id="post" onClick="sendData()" />
Here is the Javascript:
function sendData()
{
$.ajax(
{
type: "POST",
data: $("#adminDataForm").serialize(),
cache: false,
url: "/admin_ajax",
success: function(data)
{
alert("Your changes have been saved");
},
error: function()
{
alert("Error - Data not saved");
}
});
}
Here is the controller:
#SessionAttributes("adminFormAjax")
#Controller
public class TestController
{
final static protected long INDEX_RA = 2L;
#Autowired
private AdminDataRepository rep;
#RequestMapping(value="/admin_ajax", method=RequestMethod.GET)
public String adminFormAjax(Model model)
{
AdminData ad = rep.findById(INDEX_RA);
// If there is no configuration record, create one and assign the primary key
if(ad == null)
{
ad = new AdminData();
ad.setId(INDEX_RA);
}
model.addAttribute("adminFormAjax", ad);
return "adminFormAjax";
}
#RequestMapping(value="/admin_ajax", method=RequestMethod.POST)
public #ResponseBody AdminData adminSubmit(#ModelAttribute("adminFormAjax") AdminData ad, Model model)
{
rep.save(ad);
model.addAttribute("adminFormAjax", ad);
return ad;
}
}
So breakdown of answer.
Thymeleaf not redundant, it will still render the HTML page prior to sending to client. Ajax just does the further processing for you on client side.
You can use submit button as well, you just need to ensure your form is properly structured and you have javascript listening for your submit button click e.g.
$("#submitbutton").on('click', function (){//do stuff});
You handle any and all exceptions/issues within your Ajax controller as you would with standard controller. You need to separate issue handling at different levels. e.g. respository level issues should be managed at rep level, controller/pojo should be at controller level (or pojo if you using one for processing). You should also be capturing any exceptions through a global medium (e.g. ControllerAdvice).
Any issues/errors you pick up you should be communicating back via your return call in adminSubmit, and managing the relevant client response in ajax.
I am writing a tiny MVC app that is a utility to simulate the actions of getting an id from a portal and setting it in a database for another app to obtain while this app is open. I attempted to write it using ASP.NET MVC to "get my feet wet." In it, I am attempting to use the JavaScriptResult (DESPITE all the warnings) to execute Javascript's window.open function but I get only a file dialog that is acting like the FilePathResult - it displays a dialog box asking if I want to save my file which is the name of the ActionEResult. How do I do this?
public JavaScriptResult SessionTransferDesktop(string PortalUserId)
{
/// .... Call Oracle SP to set token
// Redirect to RON Scheduler
string js = "window.open('/RONSchedulerMVC/default.aspx?p_token=' + portalToken);";
// string js ="window.open('http://microsoft.com')";
return JavaScript(js);
}
public ActionResult SessionTransferDesktop(string PortalUserId)
{
/// .... Call Oracle SP to set token
// build url and redirect
var uriBuilder = new UriBuilder("http://example.com");
uriBuilder.Path = "/RONSchedulerMVC/default.aspx";
uriBuilder.Query = "p_token=" + Url.Encode(portalToken);
return Redirect(uriBuilder.ToString());
}
You are getting the file result because your browser is requesting something and getting content-type:application/javascript back.
The easiest way to get this to work is to simply make the route redirect the response to the portal. You can then just call window.open directly on said route and profit.
The reason i need to do this is because of Facebook Connect - which is another story, so i'll save you the drama for that. =)
Anyway, i have this function that runs on window.onload:
function userAuth() {
SomeFunctionWhichGetsFacebookCookes();
if (!loggedInUsingFormsAuth && loggedInViaFacebook) {
window.location.reload(); // refresh page, so i can perform auto-login
}
}
So, i need help in getting the flag "loggedInUsingFormsAuth".
I dont care what is in the cookie, just need to know if the current user is authenticated.
Why am i doing this?
Well, on window load, if the user is logged into Facebook but not on my website (according to the Forms Authentication cookie), i want to reload the page - which allows my ASP.NET website to read the Facebook cookies in the HttpContext and log the user in. I need to do this in JavaScript, because i dont have the Facebook cookies until i call "SomeFunctionWhichGetsFacebookCookies" - which can only be done in JavaScript.
So, how can i work out if the current user is authenticated via JavaScript? Do i have to manually traverse through the cookies, find the one i want, and inspect it? Is this a safe thing to do?
Or should i alternatively write out the flag to the client from the server using RegisterClientScript?
You could add the following to your web.config file.
<system.web.extensions>
<scripting>
<webServices>
<!-- Allows for ajax.net user authentication -->
<authenticationService enabled="true" requireSSL="false" />
</webServices>
</scripting>
</system.web.extensions>
and then you are able to find out via javascript if you are authenticated
like so.
function isAuth() {
var result = Sys.Services.AuthenticationService.get_isLoggedIn();
return result;
}
A better way to do it than you have described inn your comment is to create a simple web service that you call to retrieve the value.
As i am registering the JavaScript via the server on every page load, i decided to set the HttpContext.Current.Request.IsAuthenticated property into the JavaScript itself.
In other words i had some JavaScript defined in the C# itself:
public class SomeClassWhichHasAccessToHttpContext
{
private const string MyScript = "var foo='{0}'";
public static string GetMyScript()
{
return string.Format(MyScript, HttpContext.Current.Request.IsAuthenticated);
}
}
Then on the HTML for my main master page:
<%= SomeClassWhichHasAcccessToHttpContext.GetMyScript() =>
Normally i would not opt for a solution like this, i would normally call an asynchronous web service (as Ben's answer's mentions). But the fact is that this property and JavaScript is evaluated on a page-request basis, so the evaluation of this property will never be stale for each given HTTP Request.
I have a solution that only needs code in one place:
Add the code below to Global.asax.cs
protected void Application_EndRequest(object sender, EventArgs e)
{
try
{
System.Web.UI.Page P = (System.Web.UI.Page)HttpContext.Current.Handler;//will throw error if request is not for a page
if (P.IsCallback) { return; }
if (P.IsPostBack)
{
try
{
//if using AjaxControlToolKit and UpdatePanels
if (AjaxControlToolkit.ToolkitScriptManager.GetCurrent(P).IsInAsyncPostBack)
{
//Async postback caused by update panel
return;
}
}
catch (Exception)
{
//will throw error if no scriptmanager- which doesn't matter
}
}
//skip this part if not using AjaxControlToolkit or if you have it set up to get scripts from a web handler: http://blogs.msdn.com/b/delay/archive/2007/06/20/script-combining-made-better-overview-of-improvements-to-the-ajax-control-toolkit-s-toolkitscriptmanager.aspx
foreach (string key in P.Request.QueryString)
{
//request is from AjaxControlToolkit to get scripts. Don't want to mess with the response for this
if (key.ToLower().Contains("TSM"))
{
if(P.Request.QueryString[key].ToLower().Contains("toolkitscriptmanager"))
return;
}
}
//dont want to inject this when a page is outputting a file
if (Response.ContentType != "text/html") { return; }
//still going: request is for a page and its a first load or a full page postback
Response.Write(" <script> try{ window.UserLoggedIn=" + HttpContext.Current.User.Identity.IsAuthenticated.ToString().ToLower()+ ";} catch(ex){} </script> ");
}
catch (Exception)
{
}
}
Now client side the variable UserLoggedIn is available on every page.