简体   繁体   English

如何使用CDI将http会话属性注入bean

[英]How to inject a http session attribute to a bean using CDI

I have some legacy code that put objects as http session attributes using code like this: 我有一些遗留代码,使用如下代码将对象作为http会话属性:

MyObject object = new MyObject();
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
sessionMap.put("attrname", object);

The old facelets accessed the code using 旧的facelets使用了访问代码

 @ManagedProperty("#{attrname}")
 private MyObject object;

Is there any way using CDI ( @Inject ) to inject this session attribute to a Bean? 有没有办法使用CDI( @Inject )将此会话属性注入Bean?

In new code that uses CDI what's the better way to create and inject objects that need to be created in a controlled way. 在使用CDI的新代码中,创建和注入需要以受控方式创建的对象的更好方法是什么。

Get hold of it in a session scoped managed bean with a @Produces @Named on the getter. 在getter上使用@Produces @Named在会话范围的托管bean中获取它。

@SessionScoped
public class MyObjectProducer implements Serializable {

    private MyObject myObject;

    @Produces
    @Named("attrname")
    public MyObject getMyObject() {
        return myObject;
    }

    public void setMyObject(MyObject myObject) {
        this.myObject = myObject;
    }

}

When you set it somehow via eg myObjectProducer.setMyObject(myObject) elsewhere (or perhaps a CDI @Observes event), then you can inject it anywhere using @Inject @Named . 当你以某种方式通过例如myObjectProducer.setMyObject(myObject)在其他地方(或者可能是CDI @Observes事件)设置它时,你可以使用@Inject @Named将它注入任何地方。

@Inject
@Named("attrname")
private MyObject myObject;

And yes, it's still available via #{attrname} in EL the usual way. 是的,它仍然通过EL中的#{attrname}以通常的方式提供。 And no, it won't be auto-created when not set, it'll remain null until you actually set it as a property of the producer class. 不,它不会在未设置时自动创建,它将保持为null直到您实际将其设置为生产者类的属性。


Alternatively, if you really intend to keep the legacy way of setting the instance via ExternalContext#getSessionMap() (eg because it's third party and you can thus not change it), then you can alternatively also let the producer return it directly from the session map: 或者,如果您真的打算通过ExternalContext#getSessionMap()继续设置实例的遗留方式(例如因为它是第三方而您不能更改它),那么您也可以让生产者直接从会话中返回它地图:

@SessionScoped
public class MyObjectProducer implements Serializable {

    @Produces
    @Named("attrname")
    public MyObject getMyObject() {
        return (MyObject) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("attrname");
    }

}

This however isn't guaranteed to work when injected in a non-JSF artifact, such as an arbitrary @WebServlet , as the FacesContext#getCurrentInstance() would obviously return null . 但是,当注入非JSF工件(例如任意的@WebServlet ,这并不能保证工作,因为FacesContext#getCurrentInstance()显然会返回null

This is the way to go, for both non-jsf and jsf artifacts. 这是非jsf和jsf工件的方法。

@Qualifier
@Retention(RUNTIME)
@Target({TYPE,METHOD,FIELD,PARAMETER});
public @interface SessionAttribute {

   @NonBinding
   String value() default "";
}

@ApplicationScope
public class SessionAttributeService {

  //Dont worry, this is a proxy, and CDI will ensure that the right one called at the right time.
  @Inject
  private HttpServletRequest servletRequest;

  @Produces
  @SessionAttribute
  @RequestScope
  public String sessionAttribute(final InjectionPoint ip){
     final SessionAttribute sa = ip.getAnnotated().getAnnotation(SessionAttribute.class);
     final HttpSession session = servletRequest.getSession();
     return session.getAttribute(sa.value());
  }
}

And use case: 用例:

@RequestScope
public class MyServiceBean {

  @Inject
  @SessionAttribute("theAttribute")
  private String attribute;

}

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

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