建立 NewsApp 企業應用,包含 EJB 模組與 Web 模組。使用消息驅動 Bean (MDB) 接收 Servlet 發送的 JMS 訊息,持久化至資料庫,並由另一 Servlet 顯示訊息列表。展示 EJB 3.0 註解式開發如何簡化企業應用建構。
File → New Project → Enterprise → Enterprise ApplicationNewsApp,伺服器選 GlassFish,Java EE 版本 Java EE 5。Create EJB Module、Create Web Application Module,完成。New → Persistence → Persistence Unit。TopLink,Data Source jdbc/sample,Table Generation Create。persistence.xml。@Entity
public class NewsEntity implements Serializable {
@Id @GeneratedValue
private Long id;
private String title;
private String body;
// Getter/Setter...
}
@MessageDriven(mappedName = "jms/NewMessage",
activationConfig = {
@ActivationConfigProperty(propertyName="acknowledgeMode", propertyValue="Auto-acknowledge"),
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue")
})
public class NewMessage implements MessageListener {
@Resource private MessageDrivenContext mdc;
@PersistenceContext private EntityManager em;
public void onMessage(Message message) {
ObjectMessage msg = null;
try {
if (message instanceof ObjectMessage) {
msg = (ObjectMessage) message;
NewsEntity e = (NewsEntity) msg.getObject();
em.persist(e); // 持久化
}
} catch (JMSException e) {
mdc.setRollbackOnly(); e.printStackTrace();
} catch (Throwable te) { te.printStackTrace(); }
}
}
關鍵點:@Resource 注入 MDB 上下文,@PersistenceContext 注入 EntityManager,mappedName 對應 JMS Queue JNDI 名稱。
New → Persistence → Session Beans for Entity Classes。NewsEntity,產生 @Stateless Session Bean 及 Local 介面。@PersistenceContext EntityManager,提供 findAll() 等查詢方法。@WebServlet("/ListNews")
public class ListNews extends HttpServlet {
@EJB private NewsEntityFacadeLocal newsEntityFacade;
protected void processRequest(HttpServletRequest req, HttpServletResponse res) {
List<NewsEntity> news = newsEntityFacade.findAll();
PrintWriter out = res.getWriter();
out.println("News List
");
for (NewsEntity e : news) {
out.println("" + e.getTitle() + "
" + e.getBody() + "
");
}
out.println("Add new message");
}
}
@WebServlet("/PostMessage")
public class PostMessage extends HttpServlet {
@Resource(mappedName="jms/NewMessageFactory") private ConnectionFactory cf;
@Resource(mappedName="jms/NewMessage") private Queue queue;
protected void processRequest(HttpServletRequest req, HttpServletResponse res) {
String title = req.getParameter("title");
String body = req.getParameter("body");
if (title != null && body != null) {
try {
Connection conn = cf.createConnection();
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sess.createProducer(queue);
ObjectMessage msg = sess.createObjectMessage();
NewsEntity e = new NewsEntity(); e.setTitle(title); e.setBody(body);
msg.setObject(e);
prod.send(msg);
prod.close(); conn.close();
res.sendRedirect("ListNews");
} catch (JMSException ex) { ex.printStackTrace(); }
}
// 顯示 HTML 表單...
}
}
Properties → Run,Relative URL 設 /ListNews。Run Project,瀏覽器開啟訊息列表。Add new message 填寫標題與內容送出,訊息經 MDB 非同步持久化,重導回列表頁。
伺服器日誌出現 JMS resource not created : jms/Queue,透過管理主控台檢查/建立:
jms/NewMessage,Type javax.jms.Queuejms/NewMessageFactory,Type javax.jms.QueueConnectionFactory管理主控台:IDE Runtime 視窗右鍵伺服器 View Admin Console,預設帳密 admin/adminadmin。
本教學完整展示 Java EE 5 核心技術整合:EJB 3.0 註解式 Session Bean、MDB、JPA 實體、JMS 非同步訊息、Servlet 控制器,全程零 XML 部署描述符,體現「慣例優於配置」的開發體驗。