简体   繁体   English

在JSP中自动装配Spring Beans的最简洁方法是什么?

[英]What is the cleanest way to autowire Spring Beans in a JSP?

We're currently adding some new features to an old webapp which was using only JSP without any framework for the front. 我们目前正在为一个旧的webapp添加一些新功能,它只使用了JSP而没有任何框架。 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. 我们最近添加了Spring,我们希望在修改后的JSP中自动装配bean,而不是重写所有内容以使用SpringMVC,Struts2或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") : 我们按类型使用自动装配,因此它导致在JSP中获得这样的代码,而之前获取Web应用程序上下文(作为“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. 我们不想使用这样的代码,而是直接在我们的JSP中自动注入我们的bean,就像在使用@Autowired注释的业务bean中那样。

In fact we're looking to the cleanest ways to inject our beans in our JSPs. 事实上,我们正在寻找在JSP中注入bean的最简洁方法。 What do you use ? 你用什么 ?

You can use Spring's ContextExposingHttpServletRequest : 您可以使用Spring的ContextExposingHttpServletRequest

HttpServletRequest decorator that makes all Spring beans in a given WebApplicationContext accessible as request attributes, through lazy checking once an attribute gets accessed. HttpServletRequest装饰器,通过在访问属性后通过延迟检查,使给定WebApplicationContext中的所有Spring bean可作为请求属性访问。

This would require your controller code to wrap the original HttpServletRequest in a ContextExposingHttpServletRequest , and then forward that to the JSP. 这将需要您的控制器代码将原始HttpServletRequest包装在ContextExposingHttpServletRequest ,然后将转发给JSP。 It can either expose specific named beans, or every bean in the context. 它可以公开特定的命名bean,也可以暴露上下文中的每个bean。

Of course, this just shifts the problem from your JSPs to your controller code, but that's perhaps a more manageable problem. 当然,这只是将问题从您的JSP转移到您的控制器代码,但这可能是一个更易于管理的问题。

You can't use @Autowired directly because both your jsps and servlets are instantiated by the servlet conainer. 你不能直接使用@Autowired ,因为你的jsps和servlet都是由servlet conainer实例化的。 So they are not part of the spring context and hence their dependencies aren't injected. 因此它们不是弹簧上下文的一部分,因此它们的依赖性不会被注入。

You can: 您可以:

  1. move all code that to pure servlets, rather than in jsps - leave only presentation in the jsps. 将所有代码移动到纯servlet而不是jsps - 只在jsps中保留表示。
  2. use @Configurable on your servlets (and add a javaagent, as described in the linked docs) 在servlet上使用@Configurable (并添加一个javaagent,如链接文档中所述)

Another way, is to make the servlet part of the current context manually. 另一种方法是手动使servlet成为当前上下文的一部分。 This is possible in both jsps and servlets: 这在jsps和servlet中都是可能的:

public void init() {
    WebApplicationContext ctx = WebApplicationContextUtils
         .getRequiredWebApplicationContext(getServletContext());

    AutowireCapableBeanFactory bf = ctx.getAutowireCapableBeanFactory();

    bf.autowireBean(this);
}

This will resolve the @Autowired annotated dependencies. 这将解析@Autowired注释的依赖项。

Now, I'm not sure whether servlet containers are required to use only one instance of a servlet class. 现在,我不确定servlet容器是否需要使用一个servlet类的实例。 If not, you'd better place the above code in a getter-method for the dependency ( getDao() ) and if the @Autowired property is null (ie another instance of the servlet-class is used by the container) - perform the above operation. 如果没有,你最好将上面的代码放在依赖的getter方法中( getDao() ),如果@Autowired属性为null (即容器使用另一个servlet类的实例) - 执行以上操作。


That all said, really consider using a web framework (any of the ones you listed). 总而言之, 真的考虑使用Web框架(您列出的任何一个)。 Having logic in jsps is completely wrong, hard to support, hard to read, etc. 在jsps中使用逻辑是完全错误的,难以支持,难以阅读等。

What about overriding jspInit() method and adding Autowiring support: 如何覆盖jspInit()方法并添加自动装配支持:

<%@ 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); %>

I doubt that there is a clean way to inject dependencies into a JSP. 我怀疑有一种干净的方式将依赖项注入JSP。

I think that the clean solution would be to start refactoring your code to get the business logic out of the JSPs, using either SpringMVC or one of the alternatives you cited. 我认为干净的解决方案是开始重构代码,以便使用SpringMVC或您引用的替代方法之一从JSP中获取业务逻辑。

Start with one or more minimalist controllers that simply pass the request to the JSPs with the injected beans as attributes; 从一个或多个简约控制器开始,这些控制器只是将注入的bean作为属性传递给JSPs; @skaffman's answer gives one way to do that, or you could do it more selectively. @skaffman的回答给出了一种方法,或者你可以更有选择性地做到这一点。 Then progressively migrate code out of the JSPs and into the controllers. 然后逐步将代码从JSP迁移到控制器中。

This isn't autowired, but Spring can expose your bean names into the request context, you just need to configure it in the viewResolver. 这不是自动装配的,但Spring可以将您的bean名称公开到请求上下文中,您只需要在viewResolver中配置它。

From: https://raibledesigns.com/rd/entry/spring_mvc_jstlview_and_exposecontextbeansasattributes 来自: https//raibledesigns.com/rd/entry/spring_mvc_jstlview_and_exposecontextbeansasattributes

<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="/"/>
    <property name="suffix" value=".jsp"/>
</bean>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM