Как сделать редирект в 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

