Дилемма корзины покупок в JavaEE

Я работаю над интернет-магазином с использованием стека Java EE. Для презентации я использую JSF 2.2, JPA для сохранения и EJB 3.x для бизнес-логики (где x> = 1) и JAX-RS для сервисов, так как также будет мобильное приложение.

Актуальной проблемой является реализация корзины покупок. В какой-то момент корзина для покупок может быть SFSB (сеансовый компонент с отслеживанием состояния). Это означает, что контейнер EJB будет рассматривать сервлет / веб-контейнер как клиент и управлять диалогом между двумя контейнерами. Как мне затем идентифицировать конечного пользователя (фактического клиента), который добавляет товары в корзину, если клиент EJB является сервлетом / веб-контейнером?

Мой второй вариант - сохранить SFSB в HttpSession. Таким образом, конечный пользователь может получить корзину из HttpSession (а сеанс уже управляется из контейнера сервлета). Как это повлияет на транзакционные состояния диалога EJB?

Корзина для покупок сохраняется в базе данных с использованием JPA.

Есть ли еще что-нибудь, что мне нужно принять во внимание?

Спасибо.


person Buhake Sindi    schedule 06.01.2014    source источник


Ответы (1)


На самом деле это очень хороший вопрос.

Я использую тот же самый стек (Java EE 7, Glassfish 4, JSF 2.2, EclipseLink JPA, EJB 3.1) для 70% своей деятельности по разработке, и я часто разрабатываю собственные сайты электронной коммерции, поэтому я знаком с дизайном покупок тележки.

Два подхода, которым я следовал (прежде чем окончательно выбрать один из двух):

  • Сессионный EJB с отслеживанием состояния, реализующий @Remote простой интерфейс Java, который определяет логику деловой активности.
  • SessionScoped ManagedBean и EJB без сохранения состояния, реализующие @Local интерфейс, который определяет бизнес-логику.

Лично я начал с первого подхода, но недавно перешел на второй. Я объясню почему, позже в этом ответе.

Этот первый подход действительно прост. Вам просто нужен простой интерфейс с аннотацией @Remote и @Stateful Session Bean, реализующим его. Затем в вашем поддерживающем компоненте вы можете внедрить интерфейс через CDI, используя аннотацию @EJB вместо аннотации @Inject, чтобы использовать все полезные функции EJB-инъекций, такие как объединение. Для вашей тележки я бы создал:

1) интерфейс с именем ShoppingCart.java:

@Remote
public interface ShoppingCart{

  public void init(Integer id);
  public void addToCart(String product);

}

2) EJB сеанса с отслеживанием состояния с именем ShoppingCartImpl.java, реализующий интерфейс ShoppingCart.java.

 @Stateful
 public class ShoppingCartImpl implements ShoppingCart{

   private Integer uid;
   private ArrayList<String> products;

   @PostConstruct
   private void create(){
     producs = new ArrayList<String>();
   }

   @Override
   public void init(Integer id){
     if(id==null){
       uid = id;
     }
  }

  @Override
  public void addToCart(String product){
     if(product!=null){
        products.add(product);
     }

 }


 }

Клиентский класс может получить доступ к сессионному компоненту Statefull с помощью CDI через аннотацию @EJB.

public class ShoppingCartClient {

    @EJB
    private static ShoppingCart cart;

     // your methods here, using the ShoppingCart interface

}

Фактическая «связь» между физическим покупателем и его экземпляром экземпляра реализации ShoppingCart гарантирована, поскольку каждый клиент связан с новым экземпляром сеансового компонента с отслеживанием состояния. С точки зрения клиента кажется, что бизнес-методы выполняются локально, хотя в сеансовом компоненте они выполняются удаленно. Для записей ... Oracle в своих собственных руководствах предлагает этот подход.

МОЙ ПРЕДПОЧТИТЕЛЬНЫЙ ПОДХОД

Я предпочитаю использовать JSF-компонент поддержки SessionScoped, представляющий код, и использовать EJB без сохранения состояния для доступа к необходимой бизнес-логике. В этом случае тоже нужен интерфейс, но его можно сделать локальным, изменив код примерно так:

1) Локальный интерфейс Java

@Local
public interface ShoppingCart{
   public void doSomething(List<Product> list);
}

2) EJB без сохранения состояния

@Stateless
public class ShoppingCartImpl implements ShoppingCart{

   @Override
   public void doSomething(List<Product> list){
    // persistence, tax calculation, etc
   }
}

3) Бин с ограничением сеанса JSF

@ManagedBean
@SessionScoped
public class CartBean {

 private List<Product> products = new ArrayList<Product>();

 public void add(Product product) {
     products.add(product);
 }

 public void remove(Product product) {
     products.remove(product);
 }

 public List<Product> getProducts() {
     return products;
 }
}

Второй подход имеет следующие преимущества:

  • EJB без сохранения состояния быстрее, чем EJB с отслеживанием состояния
  • Создание пула поддержки EJB без сохранения состояния

Объем памяти такой же, как и в первом случае, поскольку JSF хранит управляемые компоненты с привязкой к сеансу точно так же, как и сеансовые компоненты с отслеживанием состояния.

Компоненты EJB с отслеживанием состояния подходят, если вы хотите иметь возможность использовать его где-то еще или делиться ими между разными веб-приложениями.

person elbuild    schedule 09.01.2014
comment
Рассмотрим следующий сценарий: у вас есть дополнительное приложение для Android, которое подключается к вашему приложению с помощью JAX-RS, и вам нужна корзина для покупок. Сервисы такие же, как и те, которые используются в веб-приложении JSF. Вы затем используете SFSB или SLSB для корзины покупок? - person Buhake Sindi; 09.01.2014
comment
Я бы также использовал SLSB для мобильных приложений. Я разработал мобильные приложения, которые взаимодействуют с серверами barebone, читая простые ответы JSON, созданные с использованием SLSB, введенного через CDI (аннотации @EJB). - person elbuild; 09.01.2014
comment
В вашем первом примере подхода вы сохраняете ShoppingCartClient как атрибут в объекте HttpSession, верно? - person Luigi Cortese; 18.04.2015