I'm trying to get started with session-scoped beans in Spring Web MVC 3. I put this line in my dispatcher configuration:
<bean id="userInfo" class="net.sandbox.sessionbeans.UserInfo" scope="session" />
Here is net.sandbox.sessionbeans.UserInfo:
package net.sandbox.sessionbeans;
public class UserInfo {
public String username;
public UserInfo() {
this.username = "Unregistered User";
}
}
How can I access session-scoped beans inside the JSP files that represent the View part of my application? I tried this...
<p align="right">${userInfo.username}</p>
... but that didn't give me the expected result, i.e.
<p align="right">Unregistered User</p>
Instead I just get
<p align="right"></p>
What am I doing wrong?
You can do it as you show in your question. The problem is probably in your configuration. Look if you expose your beans in the view, like this:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
<property name="exposeContextBeansAsAttributes" value="true" />
</bean>
You can expose individual beans to JSTL with Spring.
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="exposedContextBeanNames">
<list>
<value>someBean</value>
<value>someOtherBean</value>
</list>
</property>
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
This answer is partially based on some advice that was posted in the question's comments but was later deleted by the poster. I added this to every JSP page that needs to use the bean:
<jsp:useBean id="userInfo" scope="session" class="net.sandbox.sessionbeans.UserInfo" />
I then found this article detailing how you can use beans in a JSP page.
You need to make sure that you have
<aop:scoped-proxy/>
enabled in your xml configuration.
For Example:
<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<!-- this next element effects the proxying of the surrounding bean -->
<aop:scoped-proxy/>
</bean>
You can read more about it in Spring reference guide, "Bean scopes" chapter.
Elaborating on #sinuhepop suggestion below.
An easy way to do this is to configure spring so that it exposes the spring bean ids as varibales to JSTL this can be done by setting the exposeContextBeansAsAttributes property to true
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="exposeContextBeansAsAttributes" value="true"/>
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
If you have a bean configured like so
#Component
#Scope(proxyMode=ScopedProxyMode.TARGET_CLASS,value=WebApplicationContext.SCOPE_SESSION)
public class SomeBean {
}
Then in the JSP page you can access the bean using the name ${someBean.someProp} because that is the name that Spring will auto assign to the SomeBean unless the bean is defined with a name such as #Component("someName") then the JSTL would be ${someName.someProp}
An update to this answer for those, who want to use Spring 5 Java configuration. Addding this to your WebMvcConfigurer
#Override
public void configureViewResolvers(ViewResolverRegistry registry){
InternalResourceViewResolver resolver = new InternalResourceViewResolver("/WEB-INF/view", ".jsp");
resolver.setExposeContextBeansAsAttributes(true);
registry.viewResolver(resolver);
}
is equivalent to this XML config mentioned by others:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
<property name="exposeContextBeansAsAttributes" value="true" />
</bean>
Note, that the "convenient" fluent API of the registry (registry.jsp(). ...) does not offer you the possibility to configure the exposeContextBean.... properties.
If possible, you should consider using exposeContextBeanNames. Use constants as much as possible for your bean names, though, to avoid duplicating string literals in your code. So maybe define a String Array within some class, which collects all theses constants and exposes them to your view resolver.
Related
I have handler bean with a url property which needs different value for different class injections .How can I do this without creating multiple beans
<bean id="handler" class="com.Handler">
<property name="url" value="/"/>
</bean>
<bean id="a" class="com.A">
<property name="handler" ref="handler"> for this I need url to be /aaa
</bean>
<bean id="b" class="com.B">
<property name="handler" ref="handler"> for this I need url to be /bbb
</bean>
.....
I do not want to create multiple handler beans
I would like to use different controllers in spring with different application configurations.
For example lets say I have one configuration using jsf/primefaces and another one using thymeleaf (for no special reason). Is it possible to map these configurations independently to different controllers?
Not sure but may be You can do it in two ways buy either returning view in your controller method as
#RequestMapping("/view1")
public String thymleaf(){
return "thymleaf.html";
}
#RequestMapping("/view2")
public String jspView(){
return "jspView.html";
}
or by configuring it in xml
<bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".html" />
<property name="viewNames" value="thymeleaf/*" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="viewNames" value="jsp/*" />
<property name="suffix" value=".jsp" />
</bean>
My Current Working code for resolving html views is like this
<mvc:resources mapping="/static/**" location="/WEB-INF/static/html/" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="" />
<property name="suffix" value=".html" />
</bean>
But i need to return view such as
return "/static/html/index";
How can i make it like this?
return "index";
if you are using spring Boot, it will automatically add static web resources located within any of the following directories:
/META-INF/resources/
/resources/
/static/
/public/
in case of consuming , restful web service it might be a good approach if you put the resources in to the public folder,and this is how your controller should look like.
#Controller
class Controller{
#RequestMapping("/")
public String index() {
return "index.html";
}
}
Change the prefix to /static/html/
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/static/html/" />
<property name="suffix" value=".html" />
</bean>
So when you will return as "index" it will change to /static/html/index.html.
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
<property name="resourceLoaderPath" value="/WEB-INF/html/"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".html"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="order" value="1" />
</bean>
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="true"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value=""/>
<property name="suffix" value=".jsp"/>
<property name="order" value="2" />
</bean>
I have all html pages so it works fine with viewResolver but now I added jsp so created another bean with InternalResourceViewResolver. Somehow it doesn't seem to fall through jsp view resolver & gives exception SEVERE: ResourceManager : unable to find resource '/users.html' in any resource loader. when trying to access user.jsp
Controller code is
#RequestMapping("/layout")
public String getUserPage(ModelMap modelMap) {
return "users";
}
I think you should add prefix's value:
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="true"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="2" />
Spring Docs says :
The contract of a view resolver specifies that a view resolver can
return null to indicate the view could not be found. Not all view
resolvers do this, however, because in some cases, the resolver simply
cannot detect whether or not the view exists. For example, the
InternalResourceViewResolver uses the RequestDispatcher internally,
and dispatching is the only way to figure out if a JSP exists, but
this action can only execute once. The same holds for the
VelocityViewResolver and some others. Check the Javadoc for the view
resolver to see whether it reports non-existing views. Thus, putting
an InternalResourceViewResolver in the chain in a place other than the
last, results in the chain not being fully inspected, because the
InternalResourceViewResolver will always return a view!
for your code to work; Please change the order of jspViewResolver from 2 to 1 like below,
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="cache" value="true"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value=""/>
<property name="suffix" value=".jsp"/>
<property name="order" value="1" />
as the higher the order property, the later the view resolver is positioned in the chain.
My applications uses Spring3+MyBatis3. I'm trying to setup multiple data source for it. Setup looks like:
<!-- db1 setup-->
<bean id="db1SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
p:dataSource-ref="db1DataSource" />
<bean id="db1SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="db1SqlSessionFactory"/>
</bean>
<!-- db2 setup -->
<bean id="db2SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:configLocation="WEB-INF/mybatis/sqlMapConfig.xml"
p:dataSource-ref="db2DataSource" />
<bean id="db2SqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="db2SqlSessionFactory"/>
</bean>
In the logs, I've found this message:
No unique bean of type [org.apache.ibatis.session.SqlSessionFactory] is defined: expected single matching bean but found 2: [db1SqlSessionFactory, db2SqlSessionFactory]
I googled and looked into mybatis manuals but couldn't find way how to setup multiple data sources with mybatis.
Any ideas?
also solved ! just reference your factory bean in MapperScannerConfigurer : sqlSessionFactoryBeanName
First data source >>>>>>>
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<bean id="sqlSessionFactory1" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.package.p1"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory1"/>
</bean>
Second data source >>>>>>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<bean id="sqlSessionFactory2" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
</bean>
<bean id="MapperScannerConfigurer1" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.package.p2"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory2"/>
</bean>
solved, the problem was that I must specify directly reference to sqlSessionFactory
<bean id="myDao" class="org.mybatis.spring.mapper.MapperFactoryBean"
p:sqlSessionTemplate-ref="db1SqlSessionTemplate"
p:mapperInterface="my.project.domain.dao.MyDao"
p:sqlSessionFactory-ref="db1SqlSessionFactory"/>
In a DAO implementation use SqlSessionTemplate instead of SqlSessionDaoSupport. Inject bean db1SqlSessionTemplate or db2SqlSessionTemplate.
#Repository
public class TestDaoImpl implements TestDao{
#Autowired
private SqlSession db1SqlSessionTemplate;
...
db1SqlSessionTemplate.selectList("testSelect");
...
}
When extending SqlSessionDaoSupport the context Spring does not know that you use SqlSession.