use spring bean in JSP - spring

i have bean that contain method [void return] and want access to this bean in JSP.
public class A {
public void run() {}
}
add below code to spring config file.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="exposeContextBeansAsAttributes" value="true"/>
</bean>
<bean id="a" class="com.example.A"
>
</bean>
now in my JSP page :
${a.run}
but this solution not work.please help me for access spring bean on JSP page.

Inject the bean into your controller and expose it as part of the model.
But why do you need to call run from the JSP?
JSP EL expects to follow JavaBean naming conventions; this example won't work the way you expect. The easiest option is to rename the method, or provide an additional method, that follows the JavaBean naming convention and calls run.
Edit to reply to comment.
If you need to call a method from a link, you have two (reasonable) options: link to a controller action that calls the injected service, or make an Ajax call to a controller method that calls the injected service.
There's still zero reason to be making the service call directly from the view layer (the JSP).

You cannot call a method with ${a.run} you need to do #{a.run}.

# Dave Newton's comment : "There's still zero reason to be making the service call directly from the view layer".
Consider a scenario, where you want to develop a custom tag (say a dropdown which fetches values from a service class based upon the tag's attribute value, in your core web project) . and you provide the TAG implementation in a .tag file.
Keeping the service call in the .tag file seems preferable than to update the model in every controller, called prior to render the view which uses the tag. What do you suggest, Using an onload AJAX call in .tag file to fetch the dorpdown content?

Have you tried this?
${a.run()}
I haven't used org.springframework.web.servlet.view.InternalResourceViewResolver (use it's superclass instead), but this works if your controller injects a Java object profile which has toJson() method implemented. Don't see why the same syntax wouldn't work as long as a is accessible to the JSP and implements run().
<script>
$(function() {
var profileJson = ${profile.toJson()};
....
})
</script>
This is how is pre-load my page with initial content and save a trip to the back-end on page load.

You could write a scriptlet for this something like
<%
ApplicationContext ctx = RequestContextUtils.getWebApplicationContext(request);
A a = (A) ctx.getBean("yourBeanName");
%>
or use WebApplicationContextUtils if the requests are routed through DispatcherServlet.
You should look into Spring MVC . This would suit you more.

Related

Constructors in Bean

I have one small issue with creating a new bean. Basically as per request, I get some parameters, which needs to be passed to a bean. Below I am instantiating ControllerService for each request. Rather I would like it to be a bean with scope=protype. So that I get a fresh object for every request.
But then how do i set the 2 properties (kpiName, kpiInput) that I am sending via constructors in the bean??
#Autowired
#Qualifier("serviceManager")
Cleanser serviceManager;
#RequestMapping(method = RequestMethod.POST)
public #ResponseBody
String getKPIResult(#RequestParam("kpiName") String kpiName,
#RequestParam("kpiInput") String kpiInput) {
return serviceManager.checkAndExecute(new ControllerService(kpiName, kpiInput));
}
In situations like this where you're going against the grain of Spring, I'd suggest that perhaps you're doing something in a way that's not considered best practice. Without more context it's hard to see though.
Spring Social uses a request scope bean to embody a repository for a specific user. I've now idea why as it's a horribly inefficient way of doing things, and much less understandable IMHO.
<bean id="connectionRepository" factory-method="createConnectionRepository"
factory-bean="usersConnectionRepository" scope="request">
<constructor-arg
value="#{T(org.springframework.security.core.context.SecurityContextHolder).getContext().getAuthentication().getPrincipal()}" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
You can see here the use of factory-bean and factory-method to declare a class/method to call when wanting an instance of your class. The constructor argument is passed using SpEL. I'm not quite sure how you'd achieve this with Spring MVC responding to web requests, but I'm fairly sure you could use Spring Integration to pass a message and use SpEL to grab headers/payload form that message to pass to the constructor.
Again though, I'd really question your design pattern here - a more usual SOA idiom is to create services on startup, and have them as stateless as possible from there-on in, rather than create an instance with specific state for each request. Best of luck!
Don't. The Controller as it's intended in Spring MVC is largely derived from the old Java servlet, which should be stateless by specification.
In fact, Controller-objects are hard-cached inside the handler mapping framework and not fetched from the bean context on each request. Setting scope to "prototype" would, effectively, do nothing as the handler (controller) is really only gotten once.

Accessing Spring Controller Name from View

With Spring, how can i retrieve the following Controller attributes in the view?
Controller name
Controller's #RequestMapping URI
Action method name
Action method's #RequestMapping URI
One approach which i have tried is by creating a subclass of HandlerInterceptorAdapter and overriding postHandle. I register my subclass as an mvc:interceptor for a list of given paths - which is clunky to maintain but was the only way to avoid my interceptor being called for ResourceHandler requests (which i don't want). In my postHandle i can easily add the 2 name attributes, but not the URIs...
Parsing from the HttpRequest object requires constraints on all Controller RequestMappings. I.e. i must always map /Controller/Action or equiv scheme. Quite limiting.
Creating an ApplicationContext and querying that with the requestURI is too long-winded.
I am thinking about dropping the HandlerInterceptorAdapter and instead defining a BaseController for all my controllers to extend.
I wanted to ask before i do this, is there a better approach?
You haven't stated why you need to do this (it sometimes helps to include your motivation, as others can suggest alternative approaches).
But I'm guessing that the Spring 3.1 features loosely termed "end point documentation" may do what you are asking... See RequestMappingHandlerMapping in the Spring documentation which doesn't provide a lot of detail, so this example project is the best place to see it in action:
Spring MVC 3.1 Demo App
example controller
example JSP page

MVC Datasource: controller or model?

Just a quick question: In an OOP MVC application, one key principle is the seperation of responsibilities. I therefor think that a model and the object that fetches the model from a database, file, xml, webservice, etc. should be seperated from the model itself. This can for example be done by implementing a datamapper.
However, what do I do when I have a model that can be loaded from different sources? Should the model be in charge of the datasource, or is this the responsibility of the controller?
An simple example could be a config class that can be loaded from a database or a file. Should the controller instruct the datasource, or should the model know when to load the config info from a database or a file?
have used frameworks were the datasource is informed by the controller MachII, Model-Glue (Coldfusion frameworks) and also from the model layer (ColdSpring) - like Spring in Java.
I think the key thing is to use what makes more sense to you, keep the coupling to a minimum and be consistent, meaning don't put datasource or object dependencies in multiple places.
You could also consider using a service type object to abstract the datasource and have it serve either who it likes.
That IOC file could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="chartShareObj" class="model.charts.ChartShared" autowire="byType" />
<bean id="trendChartObj" class="model.charts.TrendChart" autowire="byType" />
<bean id="adminRightsDA0" class="org.datamentor.institution.RightsDAO">
<constructor-arg name="dsn">
<value>${dsn_dm}</value>
</constructor-arg>
</bean>
<bean id="assessmentManager" class="model.assessment.Manager">
<constructor-arg name="dsn">
<value>${dsn_au}</value>
</constructor-arg>
</bean>
</beans>
You can see the different datasources specified by args via args defined in a controller.
Based on your situation and response I would suggest looking into dependency injection. You can then let it handle determining which data source to use based on whatever set of variables you want to let it determine things by. This is what I use when I have multiple data sources and want to have the data source determined by some predetermined factors I have chosen.
http://en.wikipedia.org/wiki/Dependency_injection
As to who should handle the injection, I leave that to a repository factory and simply ask for an interface in the controller. The factory then determines based on the dependency injection which repository to provide.
Example:
Dependency Injection in an global Infrastructure class:
Bind<INewsArticleRepository>().ToMethod(context => NewsRepositoryFactory.Create((NewsRepositoryFactory.RepositoryType)Enum.Parse(typeof(NewsRepositoryFactory.RepositoryType), ConfigurationManager.AppSettings["NewsArticleRepositoryProvider"])));
Repository Factory
public static INewsArticleRepository Create(RepositoryType type)
{
switch (type)
{
case RepositoryType.Mock:
return new MockNewsArticlesRepository();
case RepositoryType.Sql:
return new SqlNewsArticleRepository();
default:
throw new NotImplementedException();
}
}
Call in the controller for a repository
private INewsArticleRepository newsItemRepository;
public NewsController(INewsArticleRepository newsItemRepository)
{
this.newsItemRepository = newsItemRepository;
}
They way I do it in Coldbox is using CB's INJECT method in the model. In the cfargument of the constructor, I specify:
<cfargument name="dsn" type="any" inject="coldbox:datasource:dsn">
And that's from specifying the dsn in the coldbox.cfc file, and calling it "dsn". I keep it generic so I can copy this stuff to other projects and only have to change the DSN name in the coldbox.cfc.
But then after doing that, you get the dsn like this:
variables.dsn = arguments.dsn.getName();
I hope this helps, at least a little.
Rob

Read a form bean property to pass on to a forward

I am using struts 1.3. I have a an action I am reusing in 3 different cases. The form bean backing this has a property that has the complete path(passed from the jsp) to which the action should forward in case of success/failure(the path is different for each case depending on what the user is doing). How do I specify this for the input attribute of the action in the struts config to read from that form bean property.
What you can do is return a dynamic ActionForward from your Action class. This lets you use an ActionForward that isn't defined in yourstruts-config.xml
return new ActionForward(path_to_forward, redirect_true_or_false);
This doesn't help you for the input, which expects a JSP and not an ActionForward, but you should be able to do that in the ActionForm's validate() method. The first parameter passed into that method is an ActionMapping. On that object, you should be able to call setInput(String) with the path of your JSP. I have not tried this, but it looks like it should work.

Can i use Spring's #RequestMapping and BeanNameUrlHandlerMapping in conjuntion with each other to map a URL to method?

What I would like to do is have a common Service class which has various methods such as "search" "retriveByID" etc.
Ideally this class would consume the service parameters and populate a request object and hand off to the appropriate data source handler.
I want to instantiated a service class as a Spring bean with different request handlers depending on the domain object being searched. Then using bean BeanNameUrlHandlerMapping invoke a different Service class based on the URL.
<bean name="/sequence/*" class="org.dfci.cccb.services.SearchServiceImpl">
<property name="searchHandler">
....
My problem is that when i try to do this I can't use method level RequestMapping annotations to select the appropriate method of the service class.
#RequestMapping("*/search/")
QueryResult search(...
Alternatively is it possible to inject annotation values through bean definitions?
UPDATE
There is also a Springsource article on this topic:
http://blog.springsource.com/2008/03/23/using-a-hybrid-annotations-xml-approach-for-request-mapping-in-spring-mvc/
Was very surprised to learn that it actually works. Just remove the trailing slash:
#RequestMapping("*/search")
And this works too:
#RequestMapping("search")

Resources