Can I get the current webflow state within a Spring MVC controller? - java

On the surface, a bit of a strange question! but I am creating a web app that uses both webflow and traditional Spring MVC controllers.
From one of the webflow views, a http request (ajax) is made from the client to a spring controller. When this was originally coded it didnt have much of a logical connection to the webflow, but now things have moved on and the controller could really do with knowing what screen (view-state) the request has come from.
My controller method signature looks like this:
#RequestMapping(value="/AjaxStuff", method=RequestMethod.POST)
public String ajaxStuff(#ModelAttribute("quote") QB2MotorQuote p_quote, BindingResult p_bindingResult,
HttpServletRequest p_req, Model p_model, DefaultMessageContext p_messages) {
I know from some of my webflow action classes that I can get the current state from the RequestContext object:
public Event checkDeclines(RequestContext p_ctx) throws Exception {
// get the current state
StateDefinition state = p_ctx.getCurrentState();
I've never really understood the 'voodoo' :) that Spring does where it can automagically inject parameters just by specifying them on the method signature (surely it can only inject things it knows about ??). I've tried simply changing the method signature of my controller method to inject in the RequestContext (in the vain hope that it will get injected), but it doesn't. It complains that RequestContext is an interface.
So, does anyone know how I can make my controller know about the current webflow state - either through injecting something into the controller method signature, or perhaps I can get it from the http request somehow (or session, which I can get from the request).
Any help with this very much appreciated.

inside your webflow view, you should have access to a variable ${flowRequestContext} that you can use in your ajax call.
you can just get the piece of information ${flowRequestContext.currentState} you want from it and add it as a parameter.
you cannot have the requestContext directly injected as your are not in a webflow environment. If you were, you could directly use RequestContext.getRequestContext(). Try calling it from your MVC controller and you will get null. Try from within a flow and you will get it.

Related

Are Spring Model objects (and their attributes) tied to their respective controller endpoints / templates?

I'm just starting with spring so please bear with me. I've just solved a bug in my code that was coming from my assumption that once an attribute is added to any Model object, it would also be available to the templating implementation at other endpoints.
#GetMapping("/user_page")
public String getUserPage( Model model ) {
Page page = new Page();
model.addAttribute("user_page", page);
return "user_page";
In my Thymeleaf template I was able to use this attribute fine at user_page.html. Now at another endpoint and template I was also trying to use this user_page attribute. Note that it was throwing some errors:
Exception evaluating SpringEL expression:
and
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
It looks like Thymeleaf couldn't find the user_page attribute.
but I also hadn't added a Model parameter to the controller that handled this other endpoint. After adding a Model to the method parameters and adding the page again model.addAttribute("user_page", page);, this time to the controller handling the different endpoint, the problem went away.
Is Spring autowiring non-singleton Model objects to these controllers? Why did I have to add the same page instance to the model twice? So are these Models tied specifically to the template (maybe even endpoint) that their respective controller returns?
Read Dispatcher Servlet Processing Sequence.
Are Spring Model objects (and their attributes) tied to their respective controller endpoints / templates?
There is no such a thing, as "Model's respective controller"; rather, a fresh instance of the Model's implementation gets instantiated each time, any handler method gets invoked.
When an HTTP request hits dispatcher servlet, and the latter passes the servlet request-response objects into the corresponding handler method, Spring MVC's infrastructure looks up the signature of corresponding handler method and passes a fresh instance of the Model (along with many others), if it is expected.
You can also use modelAttribute element in your template's form, and this way, you will directly bind the data to the handler method's Model parameter, having the argument being pre-filled with the form data. In this case, you can also enable Bean Validation.

Validation of request body AND request parameter in 1 step?

a question to validation of put calls to a REST endpoint using spring boot and javax.validation (not the spring validation).
You have the following method in the resource:
#PutMapping(...)
public Response getResult(#RequestBody #Valid myBody, #PathVariable #MyIdValidation long id) {
}
When I call the method, myBody gets validated and I get a MethodArgumentNotValidException in my exception handler. But parameter id gets not validated!
Only if myBody is valid, id gets validated as well.
The only solution I found is to not use #Valid, and implement the validation of the body myself.
Are there better solutions?
TIA
Kibu
I don't think its doable by Spring MVC framework itself because framework handles #RequestBody and others like #RequestParam or #PathVariable differently by using different components. Also, both pieces need to be disconnected because you might not like to validate all arguments of a method.
#RequestBody is handled by org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor and validations are called from there & for params or path variable validations are done by org.springframework.validation.beanvalidation.MethodValidationInterceptor.
So in my opinion, method arguments of a controller method are handled one by one by framework & are disconnected in logic so these validations can't be clubbed together.
I've put some effort into this issue and started a project on github
It's possible to validate in one stop, but you need a different approach. Check out the project and test it.
Kibu

Can a jsf managed bean behave like a servlet?

Normally, a servlet has doGet() and doPost() methods. They are utilized to capture the incoming request parameters, which can then be used in any part of the application, if the developer wishes so.
Now, If instead of using a servlet, a developer wishes to use a jsf managed bean, is there a way to get the request parameters in the bean itself ? If so , how can it be done ?
I have seen this POST which shows a way of getting stuff from request in JSF. Can this be used to get a request parameter in managed bean like this :
HttpServletRequest origRequest = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String myReqQuery1 = origRequest.getParameter("ReqQuery1");
In this case, will the application follow a jsf life cycle or a servlet life cycle or both ?
JSF does not really work like that. The form fields in the view (.jsf or whatever) are mirrored by fields and properties in the bean. They are automatically populated by JSF when the servlet is invoked further up the stack.
This makes the need to read HTTP parameters redundant except when the browser lands on a JSF page from a non-JSF based form. For that something like Spring-MVC can accept the URI being targetted and make a connection to the ManagedBean instance before redirecting the browser to a JSF powered URL.

#Autowired HttpServletResponse

I'm looking for a way to autowire HttpServletResponse. It doesn't work with spring out of the box, but I've found this description. This works but is sort of annoying, in that spring obviously has a mechanism to make objects request scoped (i.e. HttpServletRequest) and this seems to be a hack bolted on top.
Is there a way to hook into the same mechanism that spring uses for HttpServletRequest? And, any idea why spring team decided to only make HttpServletRequest autowire capable (and excluded HttpServletResponse)?
Perhaps there is some workaround, but it's not that obvious, because it's not the way it's meant to be. Spring MVC is meant to have singleton #Controller beans that provide #RequestMapping methods which take the request and response as arguments.
If you need the response in another place (the service layer) - don't do it. The response should not go beyond the web (controller) layer.
To inject the response, you need:
- to store the response in a ThreadLocal
- to make a factory bean that returns the current response
About the example code you showed - I'm not sure if you are not going to need the factory bean to return a proxy (implementing HttpServletResponse), which in turn to return the current response. And it gets rather complicated.
But ultimately - you should not do that. If you need to intercept multiple controller invocations, use an mvc-interceptor. If you really need to use an aspect, you can get the response if it is passed as argument to the intercepted method.
Can you simply include the request in the method handle?
#RequestMapping(method=Method.GET, value="myUrl")
public String doGet(HttpServletResponse response){//spring will put the response in for you
...
}

Spring Ajax controller - Accept submissions without refreshing page

I am using Starbox in my Spring page. I want to submit the user rating so I can store it in the database and not have to refresh the page for the user. How can I have a Spring controller that accepts this value and doesn't have to return a new view. I don't necessarily need to return any updated html - if the user clicks the Starbox, that is all that needs to happen.
Similarly, if I have a form with a submit button and want to save the form values on submit but not necessarily send the user to a new page, how can I have a controller do that? I haven't found a great Spring AJAX tutorial - any suggestions would be great.
If you use annotations, perhaps the more elegant way to return no view is to declare a void-returning controller method with #ResponseStatus(HttpStatus.OK) or #ResponseStatus(HttpStatus.NO_CONTENT) annotations.
If you use Controller class, you can simply return null from handleRequest.
To post a from to the controller via AJAX call you can use the appropriate features of your client-side Javascript library (if you have one), for example, post() and serialize() in jQuery.
The AJAX logic on the browser can simply ignore any data the server sends back, it shouldn't matter what it responds with.
But if you really want to make sure no response body gets sent back, then there are things you can do. If using annotated controllers, you can give Spring a hint that you don't want it to generate a response by adding the HttpServletResponse parameter to your #RequestMapping method. You don't have to use the response, but declaring it as a parameter tells Spring "I'm handling the response myself", and nothing will be sent back.
edit: OK, so you're using old Spring 2.0-style controllers. If you read the javadoc on the Controller interface, you'll see it says
#return a ModelAndView to render, or
null if handled directly
So if you don't want to render a view, then just return null from your controller, and no response body will be generated.

Categories

Resources