Using SpEL and eval to call a controller method - java

I was wondering if it was possible to call a controller method using the tag from a JSP page, a bit like the way it's done in JSF.
My Controller
#Controller(value="planesController")
#RequestMapping({"/planes"})
public class PlanesController {
#Autowired
private PlanesDAO planesDAO;
public List<Plane> allPlanes(){
return planesDAO.getAll();
}
My JSP
<sf:form>
<s:eval expression="planesController.allPlanes()" var="planes" />
<sf:checkboxes items="${planes}" path="planes" id="avions"/>
</sf:form>
I keep getting the exception :
org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Field or property 'planesController' cannot be found on null
I know I can use model.addAttribute but I call this method from several JSP pages and I thought one of the of the tag was to allow access to beans from views.
I'm using Spring 3.0.5
Thanks in Advance

Letting the view call controller code is just plain wrong, no matter if it works or not. This is MVC backwards.
It would be better if you write a service to do what you want to do and give your view access to that service, but you'd still violate MVC. It would be even better to do all of these calls in your controller in the first place and pass the resulting model to the view without any service calls there.

Related

Should I be using #Controller classes when doing Spring web flow

It seems like I can do everything that the Controller class do inside Spring Web-Flow, for example decision making and switching from page to page. To my understanding, its the C inside the MVC model. Am I correct about this?
So my question is, is there any advantage to still include a Controller class when using Spring Web-Flow?
If you need access to the request and response, an appropriate design might still include a controller while also having a flow.xml. For example, if you had this code:
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getNativeRequest();
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getNativeResponse();
It's more intelligible to put that in a controller rather than a service.
Also, if you want to register a custom editor, it might make sense to have the controller have this logic in the initBinder() method.
Spring Web Flow uses the Spring MVC framework. The DispatcherServlet handles the request. A FlowHandlerMapping is used to map the request to a particular Web Flow.
Web Flow is to solve the problem involved with controller logic that spans multiple-page navigation (a pageflow, or wizard).
Web Flow can eliminate the need for specialized controller classes to accomplish following a path of page transitions/form updates along a predefined workflow. If you don't need to do this, you can save yourself a lot of configuration/complexity just by using MVC.

How Do I Request an HTML View from a Controller in Java and not through a Web Browser using Spring MVC?

I am using Spring MVC.
In Controller1 I return a ModelAndView of the current progress of an item that is being 'published'. I am using Velocity as my view resolver if that makes any difference. What is returned, is obviously, HTML.
What I want is Controller2 and Controller3 to make a call to Controller1 and include the HTML view that Controller1 returns along with the HTML view that they will return.
I only know how to call controllers through the web browser using a URL. How do I call and receive HTML in java code?
If I can stick with just using the spring framework, that would be best.
I was reading about Spring's RestController, but I am unsure if I can return a ModelAndView using a view resolver?
Thanks.
Spring's RestTemplate is what I was looking for:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html
Here is a link where it is used used. Interesting part near the bottom:
http://dyutiman.wordpress.com/2010/12/09/simple-rest-web-service-spring/

Clear data of a session scoped bean when the view is revisited

Bean values are not getting removed when I come back to same screen.
I create user details and insert the data
I view all the listed users available in database
I search for particular user
when I come back to Create user page, I see data of searched user
How do I remove old data from bean? Managed bean is in session scope.
You need a good reason why you'd want to put a list of users into a session scoped bean. It may cause some trouble and in the end reflect outdated data in a multiuser environment. Make the bean #ViewScoped instead, and load all users, or a subset of users, in a #PostConstruct method.
As to the coherence when using a session scoped bean, my guess is that you didn't update a list of current users. Basically you need to double the operation in this case: the first operation is a database operation, and the second one is a list update operation. Like in the following code:
public void deleteUser() {
yourEJB.remove(user);
listOfUsers.remove(user);
}
Also, to have your UI updated, be sure to make a postback, by returning void/null from an action method, or update the needed component via AJAX, by specifying its client id in render attribute of <f:ajax> tag.
I think you're thinking about #Remove annotation, which should be on specific method (or I understand your problem wrong).
Reference: http://docs.oracle.com/javaee/5/api/javax/ejb/Remove.html
A couple things here: first, post a simple example: it allows us to run it to help you. But here's what is (probably) happening. Your bean is session scoped which means it will live for the entire time the user has a session. Unless you specifically destroy the session change the value it is going to "exist" for that seesion.
Using the JSF2 annotations try this:
#ManagedBean(name="seesionScopedBean")
#SessionScoped
public class SessionScopedBean { private String data;//create getter/setter}
#ManagedBean(name="viewScopedBean")
#ViewScoped
public class ViewScopedBean { private String data;}
#ManagedBean(name="requestScopedBean")
#RequestScoped
public class RequestScopedBean { private String data;}
Assuming your three scopes make a page that is basically
<f:view>
<h:form>
<h:inputText value="#{sessionScopedBean.data}" />
<h:inputText value="#{viewScopedBean.data}" />
<h:inputText value="#{requestScopedBean.data}" />
<!-- whatever listener/action to set things -->
</h::form>
</f:view>
You'll notice that the "SessionScoped" data stays until you log out, the view will stay as long as you interact with this view (not totally correct, but that's the gist of it. And the request scope lives in each request.
Basically your create user bean feels like it should have a Request or View scope (as stated in a previous answer). Hopefully this helps. It takes a bit of time to wrap your head around the life-cycle but JSF is rewarding to work with once you get the hang of it.

Where to store request specific values in Spring MVC?

I'm using Spring MVC and I want to store request specific values somewhere so that they can be fetched throughout my request context. Say I want to set a value into the context in my Controller (or some sort of handler) and then fetch that value from some other part of the Spring request/response cycle (could be a view, view resolver, interceptor, exception handler, etc)... how would I do that?
My question is:
Does Spring MVC already provide a method to do what I described above?
If Spring doesn't have this functionality, any ideas on the best way to do this (by extending something maybe)?
Thanks!
If you need to pass an object from your controller to view, you can use Spring's ModelMap.
#RequestMapping("/list")
public String list(ModelMap modelMap) {
// ... do foo
modelMap.addAttribute("greeting", "hello");
return viewName;
}
on your view:
<h1>${greeting}</h1>
You could use sessionAttributes.
Session Attributes
I took the latest version of the api (3.1) since you didn't mention your version of spring.

Can I find the URL for a spring mvc controller in the view layer?

I think what I need is called reverse url resolution in Django. Lets say I have an AddUserController that goes something like this:
#Controller
#RequestMapping("/create-user")
public class AddUserController{ ... }
What I want is some way to dynamically find the url to this controller or form a url with parameters to it from the view (JSP), so I don't have to hardcode urls to controllers all over the place. Is this possible in Spring MVC?
Since Spring 4 you can use MvcUriComponentsBuilder.
For the most type-safe method:
String url = fromMethodCall(on(MyController.class).action("param")).toUriString();
Note this example requires that the method returns a proxyable type - e.g. ModelAndView, not String nor void.
Since 4.2, the fromMappingName method is registered as a JSP function called mvcUrl:
Login
This method does not have the proxy restriction.
Have you considered having a bean that aggregates all of the controller URLs you need into a HashMap and then adding this controller/URL Map to any model that requires it? Each Spring controller has the ability to call an init() method, you could have each controller add it's name and URL to the controller/URL map in the init() methods so it would be ready to use when the controllers go live.
Can solve with Java Reflection API. By Creating Custom Tag library. methods looks like this
Class c = Class.forName("Your Controller");
for(Method m :c.getMethods()){
if(m.getName()=="Your Method"){
Annotation cc = m.getAnnotation(RequestMapping.class);
RequestMapping rm = (RequestMapping)cc;
for(String s:rm.value()){
System.out.println(s);
}
}
}
Possible Problem You Can Face is
1.Path Variable > Like this /pet/show/{id} so set of path name & value should be support then replace this String.replace() before return url
2.Method Overriding > only one method is no problem. if Method override Need to give support sequence of Parameter Type That you really want like Method.getParametersType()
3.Multiple Url to Single Method> like #RequestMapping(value={"/", "welcome"}). so easy rule is pick first one.
4.Ant Like Style Url > Like this *.do to solve this is use multiple url by placing ant like style in last eg. #RequestMapping(value={"/pet","/pet/*.do"})
So Possible link tag style is
<my:link controller="com.sample.web.PetController" method="show" params="java.lang.Integer">
<my:path name="id" value="1" />
</my:link>
Where parmas attribute is optional if there is no method override.
May be I left to think about some problem. :)
I would probably try to build a taglib which inspects the annotations you're using in order to find a suitable match:
<x:url controller="myController">
<x:param name="action" value="myAction"/>
</x:url>
Taglib code might be something roughly like
Ask Spring for configured beans with the #Controller annotation
Iterate in some suitable order looking for some suitable match on the controller class or bean name
If the #RequestMapping includes params, then substitute them
Return the string
That might work for your specific case (#RequestMapping style) but it'll likely get a bit hairy when you have multiple mappings. Perhaps a custom annotation would make it easier.
Edit:
AbstractUrlHandlerMapping::getHandlerMap, which is inherited by the DefaultAnnotationHandlerMapping you're most likely using, returns a Map of URL to Handler
Return the registered handlers as an
unmodifiable Map, with the registered
path as key and the handler object (or
handler bean name in case of a
lazy-init handler) as value.
So you could iterate over that looking for a suitable match, where "suitable match" is whatever you want.
You can get access to the request object in any JSP file without having to manually wire in or manage the object into the JSP. so that means you can get the url path off the request object, have a google into JSP implicit objects.
Here is a page to get you started http://www.exforsys.com/tutorials/jsp/jsp-implicit-and-session-objects.html
The problem with this is that there's no central router in SpringMVC where all routes are registered and ordered. Then reverse routing is not a static process and route resolution in the view layer can be hard to integrate.
Check out this project for a centralized router (like rails) and reverse routing in the view layer.

Categories