Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений" |
Технология Enterprise Java Beans. Часть 1
Тестовый клиент для ShoppingBasketBean
Тестовый клиент для компонента ShoppingBasketBean создает один экземпляр компонента и делает тестовый заказ.
public class TestClient2 { public static void main(String args[]) { try { Context jndiContext = createJBossContext(); Object ref = jndiContext.lookup("ShoppingBasketBean"); ShoppingBasketHome home = (ShoppingBasketHome) PortableRemoteObject.narrow(ref, ShoppingBasketHome.class); ShoppingBasketRemote remote = home.create("Boris"); System.out.println("Starting to work with the shop"); remote.addCommodity(2); remote.addCommodity(3); remote.addCommodity(4); remote.processOrder(); } catch (RemoteException e) { e.printStackTrace(); } catch (NamingException e) { e.printStackTrace(); } catch (CreateException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } public static Context createJBossContext() throws NamingException { Properties p = new Properties(); p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); p.put("java.naming.provider.url", "jnp://127.0.0.1:1099"); p.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); Context jndiContext = new InitialContext(p); return jndiContext; } }
В консоль данный тестовый клиент ничего не выводит, но можно посмотреть результат его работы, выполнив два запроса в базе данных в SQL*PLUS:
- select * from ORDERS;
- select * from COMMODITY_ORDER.
Результаты выполнения запросов показаны на Рис. 3.40. Как видно, в таблице ORDERS появилась информация о новом заказе, а в таблице COMMODITYORDERS - информация о составе заказа.
Дескрипторы развертывания
Дескрипторы развертывания определены для трех компонентов в одном файле ejb-jar.xml. Дескрипторы сеансовых компонентов без состояния CommoditiesListBean и OrdersListBean ничем не отличаются от дескрипторов развертывания компонентов из предыдущих примеров. У компонента ShoppingBasketBean в элементе session-type будет стоять вместо Stateless- Stateful.
<?xml version="1.0" encoding="UTF-8"?> <ejb-jar id="ejb-jar ID" version="2.1" xmlns = "http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"> <description>Beans for the Shopping Basket</description> <display-name>ShoppingBasketBean</display-name> <enterprise-beans> <session> <ejb-name>CommoditiesListBean</ejb-name> <home>shoppingBasket.CommoditiesListHome</home> <remote>shoppingBasket.CommoditiesListRemote</remote> <ejb-class>shoppingBasket.CommoditiesListBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> <session> <ejb-name>OrdersListBean</ejb-name> <home>shoppingBasket.OrdersListHome</home> <remote>shoppingBasket.OrdersListRemote</remote> <ejb-class>shoppingBasket.OrdersListBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> <session> <ejb-name>ShoppingBasketBean</ejb-name> <home>shoppingBasket.ShoppingBasketHome</home> <remote>shoppingBasket.ShoppingBasketRemote</remote> <ejb-class>shoppingBasket.ShoppingBasketBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar>
Клиентское приложение
В этом примере в качестве клиентского приложения будет выступать веб-приложение, написанное при помощи сервлетов и JSP.В данном пособии не ставиться цель научить с нуля программировать на сервлетах и JSP. Поэтому предполагается, что некоторые знания по этой теме у читателя уже есть.
Логика работы данного веб-приложения будет заключаться в следующем: пользователю отображается некоторая веб-страница, генерируемая при помощи JSP.После чего пользователь с этой веб-страницы может перейти на другую веб-страницу, либо послать данные на обработку некоторому сервлету (либо при помощи формы, либо просто посредством ссылки). Компоненты EJB хранятся в контексте JSP -сессии (Session).Помимо этого в контексте сессии хранится имя пользователя, под которым он вошел в систему. Для любого веб-магазина характерны следующие страницы:
- Страница входа. Здесь пользователь вводит свое имя и пароль. В этом примере в качестве этой страницы будет использоваться страница index.jsp.
- Страница со списком товаров для покупки. Здесь пользователь может выбрать среди списка всего доступного в магазине что-нибудь себе по вкусу. В примере это goodlist.jsp.
- Страница с корзиной. Здесь отображается текущее состояние корзины. Пользователь может пересчитать количество товаров в корзине или вообще удалить какой-то или какие-то товары из корзины. В примере это basket.jsp.
- Страница "Спасибо за покупку". Отображается, когда клиент сделал заказ. Предлагает посетить магазин еще раз. В примере это thankyou.jsp.
- Страница с информацией о предыдущих заказах. Здесь пользователь может узнать когда и какие заказы он уже делал в этом магазине. В примере это prevorders.jsp.
Помимо страниц, необходимы еще сервлеты, которые будут обрабатывать действия пользователя. Сервлеты необходимы для:
- Добавления товара в корзину, сервлет AddToCartServlet.
- Пересчета товаров в корзине, сервлет RecalculateServlet.
- Выполнения заказа, сервлет MakeOrderServlet.
- Входа в систему, сервлет LoginServlet.
- Выхода из системы, сервлет LogoutServlet.
Помимо сервлетов, будет использоваться фильтр сервлетов. Если пользователь не вошел в магазин, этот фильтр будет перенаправлять его на страницу входа index.jsp, в случае если он вдруг попытается запросить какую-либо другую страницу или сервлет. Фильтр называется AuthFilter.
Рассмотрим страницу входа в магазин.
<%@ page language="java" contentType="text/html; charset=cp1251" pageEncoding="cp1251"%> <%String username = (String) session.getAttribute("username"); // Пользователь уже вошел в магазин - отправляем его на страницу // со списком товаров if (username != null) { application.getRequestDispatcher("/goodlist.jsp").forward(request, response); } %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=cp1251"> <title>Login</title> </head> <body> // Данные отправляются сервлету LoginServlet. В URL-адресах ему поставлен // в соответствие адрес, заканчивающийся на login. // Стоит отметить, что мы не используем пароли для пользователей. // Каждый волен входить под тем именем, которое ему нравится. <form action="login" method="post"> <table> <tr> <td> Login: </td> <td> <input type="text" name="username"></input> </td> </tr> <tr> <td> <input type="SUBMIT" value="Login"></input> </td> </tr> </table> </form> </body> </html>
Страница входа в систему показана на Рис. 3.41.
Теперь рассмотрим сервлет входа в систему. Он обрабатывает только Р0SТ -запросы. Данный сервлет, получив данные формы, сохраняет имя пользователя в контексте сессии. Затем он получает удаленные интерфейсы трех ЕJB -компонентов и также сохраняет их в контексте сессии. Теперь они будут доступны на всех остальных страницах в магазине.
public class LoginServlet extends HttpServlet { private Context jndiContext = null; private static final long serialVersionUID = 4562488849398632419L; public LoginServlet() { super(); try { jndiContext = createJBossContext(); } catch (NamingException e) { e.printStackTrace(); } } private static Context createJBossContext() throws NamingException { Properties p = new Properties(); p.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); p.put("java.naming.provider.url", "jnp://127.0.0.1:1099"); p.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); Context jndiContext = new InitialContext(p); return jndiContext; } protected void doPost(HttpServletRequest req, HttpServletResponse res) { String loginName = req.getParameter("username"); HttpSession session = req.getSession(); // Если пользователь еще не вошел в магазин if (session.getAttribute("username") == null) { // Сохраняем имя пользователя в контексте сессии session.setAttribute("username", loginName); Object ref; try { // Получаем и сохраняем три удаленных интерфейса // компонентов EJB в сессии. ref = jndiContext.lookup("ShoppingBasketBean"); ShoppingBasketHome home = (ShoppingBasketHome) PortableRemoteObject.narrow (ref, ShoppingBasketHome.class); ShoppingBasketRemote remote = home.create(loginName); session.setAttribute("basketbean", remote); ref = jndiContext.lookup("CommoditiesListBean"); CommoditiesListHome homeCom = (CommoditiesListHome) PortableRemoteObject.narrow(ref, CommoditiesListHome.class); CommoditiesListRemote remoteCom = homeCom.create(); session.setAttribute("commoditiesbean", remoteCom); ref = jndiContext.lookup("OrdersListBean"); OrdersListHome homeOrd = (OrdersListHome) PortableRemoteObject.narrow(ref, OrdersListHome.class); OrdersListRemote remoteOrd = homeOrd.create(); session.setAttribute("ordersbean", remoteOrd); } catch (NamingException e) { e.printStackTrace(); } catch (CreateException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } // Отправляем пользователя на страницу с товарами RequestDispatcher reqDispatcher = getServletContext().getRequestDispatcher("/goodlist.jsp"); try { reqDispatcher.forward(req, res); } catch (java.io.IOException e) { e.printStackTrace(); } catch (javax.servlet.ServletException e) { e.printStackTrace(); } } }
Перейдем к странице с товарами. Здесь вся логика сводится к получению компонента CommoditiesListBean из контекста сессии, и отображения доступных товаров. Для каждого товара определена ссылка на сервлет добавления товара AddToCartServlet.В таблице COMMODITIESLIST у каждого объекта было определено такое поле как IMAGEPATH - в нем хранится путь до изображения, которое соответствует товару. При помощи Google™ находим фотографии различных пачек сигарет и поместим их в каталог img.
<%@ page language="java" contentType="text/html; charset=cp1251" pageEncoding="cp1251"%> <%@page import="shoppingBasket.CommoditiesListRemote"%> <%@page import="java.util.List"%> <%@page import="java.util.Iterator"%> <%@page import="dataObjects.Commodity"%> <%@page import="java.text.NumberFormat"%> <%@page import="java.util.Locale"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=cp1251"> <title>Cigarette store</title> </head> <body> <h1>Welcome to the finest internet cigarettes store!</h1> <h2>Here is the list of commodities available for purchase</h2> // Переход к корзине с товарами <a href="basket.jsp">Goto Basket</a><br> // Переход к предыдущим заказам <a href="prevorders.jsp">View previous orders</a><br> <table border="0" cellpadding="0" cellspacing="0"> <% // Получаем удаленный интерфейс ComoditiesListBean CommoditiesListRemote remote = (CommoditiesListRemote) session.getAttribute("commoditiesbean"); List list = remote.getAvailableCommodities(); NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US); for (Iterator iter = list.iterator(); iter.hasNext();) { Commodity commodity = (Commodity) iter.next(); %> <tr> <td style="padding-left:10px; padding-right:10px;"> <%=commodity.getName()%> </td> <td style="padding-left:10px; padding-right:10px;"> <%=commodity.getDescription()%> </td> <td style="padding-left:10px; padding-right:10px;"> <%=format.format(commodity.getPrice())%> </td> // Ссылка на сервлет AddToServlet <td style="padding-left:10px; padding-right:10px;"> <a href="addtocart?good id=<%=commodity.getId()%>">Add to cart</a> </td> <td style="padding-left:10px; padding-right:10px;"> <img src="<%=commodity.getImagePath()%>"/></td> </tr> <% } %> </table> // Переход к странице с корзиной для того, чтобы оформить заказ <a href="basket.jsp">Make order</a><br> // Выход из системы посредством LogoutServlet <a href="logout">Logout</a> </body> </html>
Страница с фотографиями товаров (сигарет) изображена на Рис. 3.42. Сервлет AddToCartServlet получает в качестве параметра ID товара, из контекста сессии берет удаленный интерфейс ShoppingListBean,а затем выполняет вызов addCommodity (goodId). Стоит отметить, что ни сервлет, не компонент не проверяют факта существования товара с таким ID. Поэтому пользователь может "обмануть" магазин передав заведомо неправильный good_id в сервлет.
public class AddToCartServlet extends HttpServlet { private static final long serialVersionUID = -666156591413576322L; public AddToCartServlet() { super(); } protected void doPost(HttpServletRequest req, HttpServletResponse res) { doGet(req, res); } protected void doGet(HttpServletRequest req, HttpServletResponse res) { HttpSession session = req.getSession(); ShoppingBasketRemote remote = (ShoppingBasketRemote) session.getAttribute("basketbean"); String strGoodId = req.getParameter("good id"); int goodId = 0; try { goodId = Integer.parseInt(strGoodId); } catch (NumberFormatException e) { goodId = 0; } if (goodId > 0 && remote != null) { try { remote.addCommodity(goodId); } catch (RemoteException e) { e.printStackTrace(); } } RequestDispatcher reqDispatcher = getServletContext().getRequestDispatcher("/goodlist.jsp"); try { reqDispatcher.forward(req, res); } catch (java.io.IOException e) { e.printStackTrace(); } catch (javax.servlet.ServletException e) { e.printStackTrace(); } } }