We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. We have added Spring recently, and we would like to autowire our beans in our modified JSP, while not rewriting everything to use SpringMVC, Struts2 or Tapestry5.
We're using autowiring by type, so it leads to get some code like this in the JSP, while previously getting the web application context ( as "wap") :
MyDao myDao = (MyDao) wap.getBeansOfType(MyDao.class).values().toArray()[0];
We would like not to use such a code but rather automagically inject our beans directly in our JSPs as we would in a business bean using @Autowired annotation.
In fact we're looking to the cleanest ways to inject our beans in our JSPs. What do you use ?
You can use Spring's ContextExposingHttpServletRequest:
HttpServletRequest decorator that makes all Spring beans in a given WebApplicationContext accessible as request attributes, through lazy checking once an attribute gets accessed.
This would require your controller code to wrap the original HttpServletRequest
in a ContextExposingHttpServletRequest
, and then forward that to the JSP. It can either expose specific named beans, or every bean in the context.
Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem.
You can't use @Autowired
directly because both your jsps and servlets are instantiated by the servlet conainer. So they are not part of the spring context and hence their dependencies aren't injected.
You can:
@Configurable
on your servlets (and add a javaagent, as described in the linked docs)Another way, is to make the servlet part of the current context manually. This is possible in both jsps and servlets:
public void init() {
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(getServletContext());
AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();
bf.autowireBean(this);
}
This will resolve the @Autowired
annotated dependencies.
Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. If not, you'd better place the above code in a getter-method for the dependency (getDao()
) and if the @Autowired
property is null
(i.e. another instance of the servlet-class is used by the container) - perform the above operation.
That all said, really consider using a web framework (any of the ones you listed). Having logic in jsps is completely wrong, hard to support, hard to read, etc.
What about overriding jspInit() method and adding Autowiring support:
<%@ page import="com.example.ExampleService"%>
<%@ page import="org.springframework.beans.factory.annotation.Value"%>
<%@ page import="org.springframework.beans.factory.annotation.Autowired"%>
<%@ page import="org.springframework.web.context.support.SpringBeanAutowiringSupport"%>
<%!
public void jspInit()
{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
getServletContext());
}
@Value("${example.property}")
private String someField;
@Autowired
private ExampleService exampleService;
%>
<% final Object data = exampleService.getSomething(someField); %>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With