I need to dispatch a web service caller to a new page using Response object:
#Path("controller")
#Stateless
public class ControllerEJB {
HttpSession session;
User user;
String url;
#POST
public Response registerUser(
#QueryParam("fornamn") String fornamn,
#QueryParam("efternamn") String efternamn,
#QueryParam("epost") String epost,
#QueryParam("epost2") String epost2,
#QueryParam("password") String password,
#Context HttpServletRequest request
){
session = request.getSession();
if(user == null)
user = new User();
user.setEmail(epost);
user.setPassword(password);
user.setFornamn(fornamn);
user.setEfternamn(efternamn);
session.setAttribute("user", user);
return Response.status(200)...... // e.g. url is a .jsp
}
What method should I be using?
JAX-RS is designed to build REST services.
REST services should return data, generally serialized using XML or JSON.
I wouldn't recommend to forward JAX-RS requests to a view layer such as JSP or JSF.
That said, i'm not sure you can forward the same way RequestDispatcher.forward(req, res) does.
But you can send a redirection using the following:
return Response.seeOther(new URI("/path/to/your/resource")).build();
But as the documenation says, this should be used in a POST/redirect/GET pattern: you may redirect a POST request to another REST resource using the GET method.
But again, redirecting REST resource to a JSP page is an awkward design.
Related
My objective is to pass model attributes from controller to JSP page during a redirect and avoid the attribute being displayed in URL. The source code below is validating login from datastore using java data objects.
Controller:
#Controller
public class LoginController {
int count;
PersistenceManager pm = PMF.get().getPersistenceManager();
//Instance of data class
User user;
ModelAndView modelAndView=new ModelAndView();
#RequestMapping(value="/Login",method = RequestMethod.POST)
public ModelAndView loginValidate(HttpServletRequest req){
//Getting login values
String uname=req.getParameter("nameLogin");
String pswd1=req.getParameter("pswdLogin");
count=0;
user=new User();
//Generating Query
Query q = pm.newQuery(User.class);
q.setFilter("userName == userNameParam");
q.declareParameters("String userNameParam");
try{
List<User> results = (List<User>) q.execute(uname);
for (User u: results) {
String userName=u.getUserName();
if(userName.equals(uname)){
System.out.println(u.getPassword());
if(u.getPassword().equals(pswd1)){
count=count+1;
modelAndView.setViewName("redirect:welcome");
modelAndView.addObject("USERNAME",uname);
return modelAndView;
}
//rest of the logic
}
JSP:
<h1>Welcome ${USERNAME} </h1>
My current URL is /welcome?USERNAME=robin
My goal is to display it as /welcome
Also, my page is supposed to display "Welcome robin" whereas it displays only Welcome.
RedirectAttributes only work with RedirectView, please follow the same
#RequestMapping(value="/Login",method = RequestMethod.POST)
public RedirectView loginValidate(HttpServletRequest req, RedirectAttributes redir){
...
redirectView= new RedirectView("/foo",true);
redir.addFlashAttribute("USERNAME",uname);
return redirectView;
}
Those flash attributes are passed via the session (and are destroyed immediately after being used - see Spring Reference Manual for details). This has two interests :
they are not visible in URL
you are not restricted to String, but may pass arbitrary objects.
You need to be careful here because I think what are you trying to do is not supported for a good reason. The "redirect" directive will issue a GET request to your controller. The GET request should only retrieve existing state using request parameters, this is the method contract. That GET request should not rely on a previous interaction or on any object stored some where in the session as a result of it. GET request is designed to retrieve existing (persisted) state. Your original (POST) request should have persisted everything you need for you GET request to retrieve a state.
RedirectAttributes are not designed to support you in this case, and even if you managed to correctly use it it will only work once and then they will be destroyed. If you then refresh the browser you will get an application error because it cannot find your attributes anymore.
I have an interceptor that implements PreProcessInterceptor.
I need to get the HttpSession object in the preProcess method, so I'm using:
#Context
private HttpServletRequest httpRequest;
and then:
httpRequest.getSession();
to get the HttpSession object.
At first I thought everything was working fine, but then I realized that the httpRequest.getSession() was returning a new HttpSession object on every request.
I need to set some session attributes on the user first request and then use those attributes on futher requests. The attributes are being set all right, I can even access those attributes down along that same request stack. However, as I am getting a new Session on every new request, I am not able to access those attributes.
Do I need to send something from the client side do my REST services, like a token or something?
Here is a more complete view of my Interceptor
#Provider
#ServerInterceptor
#SecurityPrecedence
public class SecurityInterceptor implements PreProcessInterceptor, AcceptedByMethod {
...
#Context
private HttpServletRequest httpRequest;
#Override
public boolean accept(Class classe, Method metodo) {
return metodo.getAnnotation(PermitAll.class) == null;
}
...
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod resourceMethod) {
HttpSession httpSession = httpRequest.getSession();
// Set attributes on httpSession
...
return null;
}
}
Session is tried to the concept of HTTP Cookies.
The processing of the First HTTP request would have detected that there is no current Session and created a new one. The Session ID would've then been populated as a Cookie (Http Response Header) whenever the Response was returned to the Client.
If your Second HTTP Request had a Request Header for that same Cookie, then httpSession wouldn't be created new.
So, whenever you are sending requests to the Server, check if there exists a Cookie in the Server and send that cookie with each request.
I have a very weird problem in my Spring MVC application. I am writing a login form and POSTing the data via AJAX into a Spring MVC controller that looks like this:
#Controller
public class LoginResourceController {
private static final Logger log = Logger.getLogger (LoginResourceController.class.getName());
#RequestMapping (value="/login", method = RequestMethod.POST)
public String checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB, and then if OK,
return "redirect:/login/redirectToMain";
}
#RequestMapping (value = "/login/redirectToMainpage", method = RequestMethod.GET)
public String redirectControllerToMainPage (HttpServletRequest httpRequest, HttpServletResponse httpResponse)
{
return "mainPage";
}
Now, the problem is, I have the client (browser) upon redirect requesting a URL that contains the entire contents of mainPage.jsp in the URL. So it looks like:
https://localhost:8443/<!DOCTYPE html><html><head><meta charset=utf-8 /><title>Page that the subscriber sees after login</title>....
I am quite confounded by this error. Is this some servlet setting in WEB-INF/web.xml or mvc-dispatcher-servlet.xml that I need to change? I am using Spring 3.0.5.
BTW, my redirect works flawlessly for GET method controllers in the same Spring MVC application. (e.g., when I re-load the main page of my application, the redirect to the logged in mainPage.jsp above works flawlessly). Moreover, other GET methods on other jsps work correctly too (example, redirect to /login page via login.jsp via a GET of https://localhost:8443/.
I have checked the following and they didn't help: 1 2.
Try not to put the redirect in the return of the controller. This seems to either cause the full page to be rendered as the ajax response, or a redirect header is filled in with an url with the full contents of the page as a string in the response body.
As a first approach, try to make the request a normal HTTP request instead of ajax, and it should just work.
Alternativelly try to make the return body empty, and return an HTTP status code to the client. Either 200 OKif the account is OK or 401 Unauthorized:
#RequestMapping (value="/login", method = RequestMethod.POST)
public ResponseEntity checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB
....
HttpStatus returnCode = null;
if(usernameAndPasswordOK) {
returnCode = HttpStatus.OK;
}
else {
returnCode = HttpStatus.UNAUTHORIZED;
}
return new ResponseEntity(returnCode);
}
And then on the client redirect with Javascript accordingly.
This was a little tricky for me to figure out, and being a web development noob doesn't help here. Anyway, #jhadesdev's answer above pointed me to the issue.
On my client, I do this:
$("#loginForm").submit(function(evt)
{
evt.preventDefault();
if (loginFormInputIsValid ())
{
$.ajax ({
type: "POST",
url: "/login",
data: $(this).serialize(),
success: function (response)
{
window.location = response;
}
});
}
}
which was the issue--you see, setting the window.location=response; caused the client (browser) to request the server for the funky URL above. I have to change my client call (this is where #jhadesdev's response helped) to make sure I don't do something so wrong.
Thanks for your time, #jhadesdev.
I am creating a jsp application in jsp.I am trying to redirect to login page on ajax request if user is not signed in.
My approach
The request is send from javascript that pass some parameters to
url.The server side code checks is user is signed in or not.
The server side code has a function to build sign in url
The Problem where i am stuck is i have to pass this text to client side from server to javascript so that i can use something like window.location.href=url;
Can anyone please explain how do i pass this url and access it in callback function in ajax success function.
Is there any other approach?..
Checking the user is logged in should probably be handled by your JSP code.
That way you can send redirect headers before the page is rendered, rather than having to wait for a ajax response to be returned before redirecting the user. Using ajax will mean they see the page they don't have access to before you redirect them.
There are tons of ways to handle ajax request. The simplest way (not necessarily best) is to create a servlet to handle your ajax request. Below servlet example will return the json string { status: 'not logged in'}:
package mycompany;
public CheckLoginServlet extends HttpServlet {
protected doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
res.setContentType("application/json");
HttpSession session = req.getSession();
// do your stuff to check if user logged in here ..
PrintWriter writer = res.getWriter();
writer.append("{ status: 'not logged in' }");
}
}
Declare & map this servlet on your web.xml deployment descriptor file:
<web-app>
<servlet>
<servlet-class>mycompany.CheckLoginServlet</servlet-class>
<servlet-name>CheckLoginServlet</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>CheckLoginServlet</servlet-name>
<url-pattern>/checklogin</url-pattern>
</servlet-mapping>
</web-app>
The servlet is now mapped to http://myhost/myappname/checklogin. You can then send ajax post request to this servlet via jquery:
$.ajax('checklogin', {
type: 'POST'
}).done(function(res) {
console.log(res.status); // will give you 'not logged in'
});
This approach is ofcourse an old and obsolete approach, but it's good for you to understand servlet basics. If you're building real-life enterprise application consider using web frameworks such as Spring or JSF.
You can send the user status and the sign-in URL in the response as JSON. Let us create a model for your response.
public class Result {
private boolean status;
private String url;
Result() {
}
Result(boolean status, String url) {
this.status = status;
this.url = url;
}
// getters and setters
}
Now in your action where you check the user status and build the sign in url, initialise your model.
Result res = new Result(status, url);
Now we need to send this model as json response. There are many ways to do that but I will be using the Google GSON to serialize the model into json string.
private String result;
public void getResult() {
return this.result;
}
public void setResult(Stringresult) {
this.result = result;
}
Gson gson = new Gson();
result= gson.toJson(res);
==> json is {"status": true,"url":"www.example.com"}
The last part is checking the response in your client side and taking the appropriate action.
$.ajax({
// ...
success: function(response) {
var responseJson = JSON.parse (response.responseText);
if (!responseJson.status) {
window.location.href = responseJson.url;
}
}
});
References : https://sites.google.com/site/gson/gson-user-guide
I have login controller methods like so:
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
// do stuff with locale and model
// return an html page with a login form
return "home";
}
#RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(Model model, /* username + password params */){
try {
// try to login
// redirect to account profile page
return "redirect:/account/profile";
} catch (LoginException e) {
// log
// here I want to reload the page I was on but not with a url /account/login
// possibly using a forward
model.addAttribute("error", e.getMessage());
return "forward:/home";
}
}
The above code works on successful log-in attempt. However, it fails when the log-in attempt fails because Spring's forward uses the current request with the same HTTP method. So because I used a POST to send my username/password (which caused log-in to fail), the forward will also use POST to go to the handler method for /home, home(), which is expecting a GET.
Is there any way in Spring to redirect to another controller method with a different HTTP method while maintaining the current model (since I want to show the error message)?
This is on Spring 3.2.1.
Do a redirect instead:
return "redirect:/home";
If you need Model attributes to be available after the redirect, you can use flash attributes.