Как сделать редирект в Jboss Seam фреймворке
Описание задачи
Допустим, у нас есть база данных товаров магазина отечественной сантехники. Мы знаем JBoss и Seam достаточно хорошо, чтобы спроектировать, спрограммировать и развернуть online магазин. Что мы и сделали. Все прекрасно работает. Вот так будет выглядеть адрес стиральной машинки: http://www.super-best-sanitary.ru/household/washer/producer/ct1243.html
Покупатели покупают, веб сайт процветает, база данных обновляется, склады с товаром опустошаются. Прошло время. Поставщик этих прекрасных стиральных машинок запустил собственный веб сайт с каталогом и решил сделать с каждой страницы с описанием девайса сделать ссылку на страницу нашего магазина. К сожалению, он не захотел вникать в логику формирования наших ссылок, а сделал просто вот так: http://www.super-best-sanitary.ru/?id=987251. И встала перед нами задача сделать перенаправление на человеческую страницу нашего сайта.
Есть у нас таблица, которая связывает идентификационный номер девайса производителя с самим девайсом и производителем и категорией товара в нашем магазине. Чтобы было проще - изобразим ее так:
Вот такой Entity bean получится из этой таблицы:
package com.shop; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Goods { @Id @GeneratedValue private Integer id; private String producer_link_name; private String category_link_name; private String device_link_name; private Integer device_producer_id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getProducer_link_name() { return producer_link_name; } public void setProducer_link_name(String producer_link_name) { this.producer_link_name = producer_link_name; } public String getCategory_link_name() { return category_link_name; } public void setCategory_link_name(String category_link_name) { this.category_link_name = category_link_name; } public String getDevice_link_name() { return device_link_name; } public void setDevice_link_name(String device_link_name) { this.device_link_name = device_link_name; } public Integer getDevice_producer_id() { return device_producer_id; } public void setDevice_producer_id(Integer device_producer_id) { this.device_producer_id = device_producer_id; } }
Теперь идем на http://tuckey.org/urlrewrite/ и скачиваем последнюю версию Url Rewrite фильтра. Как написано на этой странице – распаковываем Jar библиотеку фильтра в web-inf, добавляем следующую запись в web.inf:
<filter-name>UrlRewriteFilter</filter-name> <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class> <!-- set the amount of seconds the conf file will be checked for reload can be a valid integer (0 denotes check every time, empty/not set denotes no reload check) --> <init-param> <param-name>confReloadCheckInterval</param-name> <param-value>60</param-value> </init-param> <!-- sets up log level (will be logged to context log) --> <init-param> <param-name>logLevel</param-name> <param-value>log4j</param-value> </init-param> <!-- you can disable status page if desired can be: true, false (default true) --> <init-param> <param-name>statusEnabled</param-name> <param-value>true</param-value> </init-param> <!-- you can change status path so that it does not conflict with your installed apps (note, defaults to /rewrite-status) note, must start with / --> <init-param> <param-name>statusPath</param-name> <param-value>/my_rewrite_status</param-value> </init-param> </filter>
Страница my_rewrite_status покажет статус текущих настроек фильтра и массу другой полезной отладочной информации.
Готово. Осталось написать свой настроечный файл и бин, который будет обрабатывать запрос. В настроечный файл фильтра добавим такую запись:
<rule> <from>^/?id=([0-9+])$</from> <set name="producer_id">$1</set> <run class="com.shop.ProducerRewriteAction" method="doDevice" neweachtime="false"/> <to type="permanent-redirect">%{attribute:url}</to> </rule>
Как видно из настроек мы будем делать редирект со статусом 301. Класс обработчик называется com.shop.ProducerRewriteAction. Осталось его создать и имплементировать.
package com.shop; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.shop.bean.Device; public class ProducerRewriteAction { private static final String DEVICE_JNDI_NAME = "super-best-sanitary/DeviceBean/local"; public void doDevice(HttpServletRequest request, HttpServletResponse response){ int producer_id = (Integer)request.getAttribute("producer_id"); String url = "/"; try { Device device = (Device) (new InitialContext()).lookup(DEVICE_JNDI_NAME); url = device.getURLByProducerId(producer_id); } catch (NamingException e) { return; } request.setAttribute("url", url); } }
Интерфейс бина:
package com.shop.bean; public interface Device { public String getURLByProducerId(int producer_id); }
Имплементация:
package com.shop.bean; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.jboss.seam.annotations.Name; import com.shop.Goods; @Name("Device") @Stateless public class DeviceBean implements Device { @PersistenceContext private EntityManager em; public String getURLByProducerId(int producer_id) { Goods selectedDevice = (Goods)em.createQuery("select n from Goods n where n.device_producer_id = :id").setParameter("id", producer_id).getSingleResult(); return "/household/" + selectedDevice.getCategory_link_name() + "/" + selectedDevice.getProducer_link_name() + "/"+selectedDevice.getDevice_link_name() + ".html"; } }
Единственный комментарий – чтобы использовать таким образом dependency injection для EntityManager соединение с базой данных должно быть настроено заранее.
Таким образом, все входящие запросы вида /?id=987251 будут перенаправлены на вполне приличный URL: /household/washer/producer/ct1243.html
Санкт-Петербург Зима 2008