EJB中有三种Bean,EntityBean,SessionBean,MessageBean,其中MessageBean就是用来发送消息的。
服务器:JBoss 4.2
EJB中支持两种类型的消息,一种是Topic,一种是Queue。
Topic:基于发布/订阅的方式,允许有多个接受者,消息生产者将消息发送到主题上,接受者必须先订阅该主题。
Queue:点对点的方式,只能被一个接受者接受一次,消息生产者把消息发送到队列中,不需订阅。
要在JBoss中使用JMS,需要配置一些文件
1.%JBOSS_HOME%\server\default\deploy 下mail-service.xml,该文件用于配置发送email的一些参数(例子中使用gmail服务器)
<?xml version="1.0" encoding="UTF-8"?> <server> <mbean code="org.jboss.mail.MailService" name="jboss:service=Mail"> <attribute name="JNDIName">java:/Mail</attribute> <attribute name="User">zoucailong</attribute> <attribute name="Password">******</attribute> <attribute name="Configuration"> <!-- A test configuration --> <configuration> <!-- Change to your mail server prototocol --> <property name="mail.store.protocol" value="pop3"/> <property name="mail.transport.protocol" value="smtp"/> <!-- Change to the user who will receive mail --> <property name="mail.user" value="zoucailong"/> <!-- Change to the mail server --> <property name="mail.pop3.host" value="pop3.gmail.com"/> <!-- Change to the SMTP gateway server --> <property name="mail.smtp.host" value="smtp.gmail.com"/> <property name="mail.smtp.socketFactory.class" value="javax.net.ssl.SSLSocketFactory"/> <property name="mail.smtp.socketFactory.fallback" value="false"/> <property name="mail.smtp.auth" value="true"/> <!-- The mail server port --> <property name="mail.smtp.port" value="465"/> <!-- Change to the address mail will be from --> <property name="mail.from" value="[email protected]"/> <!-- Enable debugging output from the javamail classes --> <property name="mail.debug" value="false"/> </configuration> </attribute> <depends>jboss:service=Naming</depends> </mbean> </server>
如果邮件发送不成功,可以把"mail.debug"的值改为true调试。
2.%JBOSS_HOME%\server\default\deploy\jms 下jbossmq-destinations-service.xml,该文件用于配置Topic和Queue
<mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Topic,name=testTopic"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends> <attribute name="SecurityConf"> <security> <role name="guest" read="true" write="true"/> <role name="publisher" read="true" write="true" create="false"/> <role name="durpublisher" read="true" write="true" create="true"/> </security> </attribute> </mbean> <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=fmQueue"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> <depends optional-attribute-name="SecurityManager">jboss.mq:service=SecurityManager</depends> <attribute name="MessageCounterHistoryDayLimit">-1</attribute> <attribute name="SecurityConf"> <security> <role name="guest" read="true" write="true"/> <role name="publisher" read="true" write="true" create="false"/> <role name="noacc" read="false" write="false" create="false"/> </security> </attribute> </mbean>
启动JBoss,可以在控制台看到自己配置的Topic或Queue的名字。
定义一个实体,用来封装发送邮件所需要的参数,包括接收人邮件地址、主题、内容、附件地址等。
import java.io.Serializable; import java.util.Date; public class EmailEntity implements Serializable { private static final long serialVersionUID = 3436776941158302904L; private String from; private String to; private String subject; private String content; private String multiPartFile; private Date sendDate; public EmailEntity() { } public EmailEntity(String to, String subject, String content, String multiPartFile) { this.to = to; this.subject = subject; this.content = content; this.multiPartFile = multiPartFile; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getMultiPartFile() { return multiPartFile; } public void setMultiPartFile(String multiPartFile) { this.multiPartFile = multiPartFile; } public Date getSendDate() { return sendDate; } public void setSendDate(Date sendDate) { this.sendDate = sendDate; } }
写一个Message Producer,一个普通的Java类,在这个类中使用到JMS的API
import java.util.Properties; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.ObjectMessage; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSession; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import org.apache.log4j.Logger; public class MsgProducerService { private static Logger logger = Logger.getLogger(MsgProducerService.class); private static InitialContext context; private static Queue queue; private static QueueConnectionFactory connectionFactory; private static InitialContext getInitialContext() throws NamingException { if(context == null) { Properties env = new Properties(); env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); env.setProperty(Context.PROVIDER_URL, "localhost"); context = new InitialContext(env); } return context; } static { try { connectionFactory = (QueueConnectionFactory) getInitialContext().lookup("ConnectionFactory"); queue = (Queue) getInitialContext().lookup("queue/fmQueue"); } catch (NamingException e) { e.printStackTrace(); } } public static void sendMail(EmailEntity emailEntity) { QueueConnection connection = null; QueueSession session = null; MessageProducer producer; try { connection = connectionFactory.createQueueConnection(); session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(queue); ObjectMessage msg = session.createObjectMessage(); msg.setObject(emailEntity); producer.send(msg); } catch (JMSException e) { logger.error("Send email error:"+e); e.printStackTrace(); } finally { try { if(session != null) session.close(); if(connection != null) connection.close(); } catch (JMSException e) { e.printStackTrace(); } } } }
以上代码中,ObjectMessage根据你的消息类型而定,有
StreamMessage:一种主体中包含Java基本值流的消息。其填充和读取均按顺序进行。
MapMessage:一种主体中包含一组名-值对的消息。(没有定义条目顺序)
TextMessage:一种主体中包含Java字符串的消息(例如:XML消息)
ObjectMessage:一种主体中包含序列化Java对象的消息。
BytesMessage:一种主体中包含连续字节流的消息。
下面定义一个消息接受者,该类实现MessageListener接口,自动监听消息的状态,当有消息到达时,就会触发onMessage方法
import java.io.File; import java.util.Date; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import javax.mail.Message; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.naming.Context; import javax.naming.InitialContext; //指定destination的类型和名字,以下用的是Queue,用到上面的配置文件中定义的fmQueue @MessageDriven(activationConfig ={ @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/fmQueue") }) public class EmailBean implements MessageListener { @Override public void onMessage(javax.jms.Message msg) { try { if(msg != null && msg instanceof ObjectMessage) { ObjectMessage objMsg = (ObjectMessage)msg; EmailEntity emailEntity = (EmailEntity) objMsg.getObject(); sendMail(emailEntity); } } catch (Exception e) { e.printStackTrace(); } } //发送邮件的方法 private void sendMail(EmailEntity emailEntity) throws Exception { if(emailEntity == null) return; Context context = new InitialContext(); Session session = (Session) context.lookup("java:/Mail"); MimeMessage msg = new MimeMessage(session); msg.setFrom(); if(emailEntity.getTo() != null && emailEntity.getTo().trim().length() > 0) { String[] toArr = emailEntity.getTo().split(","); if(toArr.length > 0) { InternetAddress[] addressArr = new InternetAddress[toArr.length]; for(int i = 0; i < toArr.length; i++) { addressArr[i] = new InternetAddress(toArr[i]); } msg.addRecipients(Message.RecipientType.TO, addressArr); } } if(emailEntity.getSubject() != null) msg.setSubject(emailEntity.getSubject(), "UTF-8"); if(emailEntity.getMultiPartFile() != null) { File file = new File(emailEntity.getMultiPartFile()); if(file.exists()) { //添加附件 Multipart multipart = new MimeMultipart(); MimeBodyPart bodyPart = new MimeBodyPart(); FileDataSource fds = new FileDataSource(emailEntity.getMultiPartFile()); bodyPart.setDataHandler(new DataHandler(fds)); bodyPart.setFileName(fds.getName()); multipart.addBodyPart(bodyPart); if(emailEntity.getContent() != null) { MimeBodyPart bodyPartText = new MimeBodyPart(); bodyPartText.setText(emailEntity.getContent(), "UTF-8"); multipart.addBodyPart(bodyPartText); } msg.setContent(multipart); } else return; } msg.setSentDate(new Date()); msg.saveChanges(); Transport.send(msg, msg.getRecipients(Message.RecipientType.TO)); } }
这样就可以实现邮件的异步发送了。