java

位置:IT落伍者 >> java >> 浏览文章

serverAddressStringSMTP服务器的地址是比如SMTP服务的地址是authorizationRequiredboolean使用SMTP服务器发送邮件时是否需要提供安全信息否如果需要提供安全信息这个参数设为true否则设为falseprincipalString访问SMTP邮件服务器时使用的用户名否credentialsString访问SMTP邮件服务器时使用的密码否

被发送邮件的参数

要发送一个邮件我们需要提供的参数和相关要求如表所示

邮件参数表

fromString邮件发送者是toString邮件的接收者可以使用的形式传递多个接收者是比如我们可以使用  来设置邮件有两个接收者ccString邮件抄送的接收者可以使用的形式传递多个抄送的接收者否bccString邮件暗送的接收者可以使用的形式传递多个暗送的接收者否subjectString邮件的主题否contentTypeString被发送邮件的格式默认使用text/plain另外一种可选的类型是text/html你还可以在这个参数中加入字符集的设置否比如我们可以使用text/html;charset= GB来设置被发送的邮件使用html格式编码使用GBattachmentString邮件附件否ContentObject邮件内容否

注释设计实现

从以上两种参数常见的使用场景来看由于同一个应用中SMTP服务器通常是比较固定的所以SMTP服务器的参数也是比较固定的而被发送邮件的参数则随着业务的变化而不断发生变化充分考虑到这种不同点我们需要为上面这两种种情况提供不同的注释以及注释的使用范围

    SMTPServer注释

    SMTP服务器参数的注释名为SMTPServer它可以设计成一个类级别的注释用于为控件的继承类提供注释根据前面表 的分析SMTPServer必须提供四个参数serverAddressauthorizationRequiredprincipalcredentials

    由于和JavaMail控件结合非常紧密SMTPServer注释被设计成控件接口的内部类清单 的第行显示了SMTP注释的全部代码代码中为关键的内容提供了相应的提示信息

    Message注释

被发送邮件的参数对应的注释名为Message由于通常和业务方法密切相关因此我们Message注释被定义成为控件继承类中的业务方法提供注释

根据表 的分析Message对象必须提供个参数分别是fromtoccbccsubjectcontentTypeattachmentContent其中Content(被发送邮件的参数中邮件内容)比较特殊因为他会根据环境的不同而发生变化所以我们将它看作Object类型的变量在注释中定义Object这种类型没有必要因此设计时我们不把Content当作的Message注释的属性而是将它变成业务方法必须提供的参数

Message注释被设计成JavaMail控件接口的内部类Message注释的全部代码参见清单 的第~行代码

    控件接口

由于邮件发送的功能比较简单因此我们的控件接口类并不需要过多的提供接口方法唯一设计提供的接口方法名为getMailException它的功能是控件使用者调用时返回邮件发送过程中产生的最后一个违例清单 中提供了控件接口类的全部源代码

清单 src\org\vivianj\beehive\controls\examples\javamail\

JavaMailControljava

package orgntrolsexamplesjavamail;import javalangannotationElementType;import javalangannotationInherited;import javalangannotationRetention;import javalangannotationRetentionPolicy;import javalangannotationTarget;import orntrolsapibeanAnnotationConstraints;import orntrolsapibeanAnnotationMemberTypes;import orntrolsapibeanControlInterface;import orntrolsapipropertiesPropertySet;/** * JavaMailControl 是JavaMail控件的公共接口类 */@ControlInterfacepublic interface JavaMailControl {/** * 获取邮件发送过程中产生的最后一个违例 * @return返回邮件发送过程中产生的最后一个违例 */public Throwable getMailException();/** * 类级别的注释用于注释JavaMail控件中目标SMTP服务器的       相关信息 */@PropertySet(prefix = SMTPServer)    /* 使用@ Inherited注释表示该注释可以被自动继承 */@Inherited    /* 使用AllowExternalOverride表示定义的接口可以被覆盖 */@AnnotationConstraintsAllowExternalOverride@Retention(RetentionPolicyRUNTIME)    /* 使用TYPE和FIRELD表示该注释能够作用于类接口       以及类成员变量 */@Target( { ElementTypeTYPE ElementTypeFIELD })public @interface SMTPServer {/** * SMTP邮件发送服务器的地址这个属性是必须设置的 */String serverAddress();/** * 使用该SMTP服务器发送邮件是否需要安全认证

* true 需要安全认证

* false 不需要安全认证 */@AnnotationMemberTypesOptionalboolean authorizationRequired() default false;/** * 访问SMTP邮件服务器时使用的用户名 */@AnnotationMemberTypesOptionalString principal() default ;/** * 访问SMTP邮件服务器时使用的密码 */@AnnotationMemberTypesOptionalString credentials() default ;}/** * * Message 用于注释继承类中的业务方法描述被发送邮件的信息 */@PropertySet(prefix = Message)@Inherited@AnnotationConstraintsAllowExternalOverride@Retention(RetentionPolicyRUNTIME)@Target( { ElementTypeMETHOD })public @interface Message {/** * 邮件的发送者 */String from();/** * 邮件的接收者可以使用           形式传递多个接收者 */String to();/** * 邮件抄送的接收者可以使用             的形式传递多个抄送的接收者 */@AnnotationMemberTypesOptionalString cc() default ;/** * 邮件暗送的接收者可以使用           的形式传递多个暗送的接收者 */@AnnotationMemberTypesOptionalString bcc() default ;/** * 邮件的主题 */@AnnotationMemberTypesOptionalString subject() default ;/** * 被发送邮件的类型默认使用text/plain */@AnnotationMemberTypesOptionalString contentType()            default text/plain;charset=UTF;/** * 邮件附件 */@AnnotationMemberTypesOptionalString attachment() default ;}}

从清单中提供的源代码中我们注意到SMTPServer接口的authorizationRequiredprincipalcredentials属性之前使用了@AnnotationMemberTypesOptional注释应用了@AnnotationMemberTypesOptional注释属性表示用户使用过程中可以不为这些属性提供内容没有提供@AnnotationMemberTypesOptional注释的属性(比如serverAddress)被视为必须设置的属性控件使用者使用该注释时必须提供对应的声明否则将无法通过编译

控件实现类

JavaMail控件要完成邮件发送的工作必须要完成获取目标SMTP服务器参数设置SMTP服务器参数获取用户业务方法调用中提供的注释和参数发送邮件等工作其中获取目标SMTP服务器参数设置SMTP服务器参数的动作通常只需要一次完成就行了我们设计成在控件初始化的时候完成反映到JavaMail控件的实现类中我们可以将这部分工作在onCreate方法中完成

在控件实现类中最主要的方法就是invoke(Method mObject[] args)这个方法中的两个参数为我们提供了用于调用业务方法时提供的注释内容和调用参数邮件发送的工作也被设计成在这个方法中完成

JavaMail控件实现类继承了JavaMail控件的接口类同时实现了orntrolsapibeanExtensible接口这样JavaMail控件的使用者就可以直接继承该控件清单中显示了JavaMail实现类的完整源代码如下源代码中在每一个关键点都提供了详细的说明帮助大家理解JavaMail实现类的实现原理请大家重点关注其中的onCreate和invoke两个方法

清单 src\org\vivianj\beehive\controls\examples\javamail\

JavaMailControlImpljava

package orgntrolsexamplesjavamail;import javalangreflectMethod;import javautilProperties;import javaxactivationDataHandler;import javaxactivationFileDataSource;import javaxmailAddress;import javaxmailBodyPart;import javaxmailMultipart;import javaxmailSession;import javaxmailTransport;import javaxmailinternetInternetAddress;import javaxmailinternetMimeBodyPart;import javaxmailinternetMimeMessage;import javaxmailinternetMimeMultipart;import orntrolsapibeanControlImplementation;import orntrolsapibeanExtensible;import orntextContext;import orntextControlBeanContext;import orntextResourceContext;import orntextControlBeanContextLifeCycle;import orntrolsapieventsEventHandler;/** * JavaMailControlImpl 用于封装访问SMTP邮件服务器发送邮件的操作 */@ControlImplementationpublic class JavaMailControlImpl implements JavaMailControl ExtensiblejavaioSerializable {static final long serialVersionUID = L;@ContextControlBeanContext context;@ContextResourceContext resourceContext;private Throwable lastException;private Session session;private Properties props;private String serverAddress;private boolean authorizationRequired;private String principal;private String credentials;private MimeMessage mimeMessage;private Multipart multipart;@EventHandler(field = context         eventSet = LifeCycleclass eventName = onCreate)public void onCreate() {SMTPServer server = (SMTPServer) contextgetControlPropertySet(SMTPServerclass);/* 获取SMTP服务器的地址 */serverAddress = serverserverAddress();/* 目标SMTP服务器发送邮件时是否需要安全认证 */authorizationRequired =              serverauthorizationRequired();/* 访问目标SMTP服务器时的用户名 */principal = serverprincipal();/* 访问目标SMTP服务器时的密码 */credentials = servercredentials();if (props == null)props = SystemgetProperties();/* 初始化SMTP服务器地址 */propsput(mailsmtphost serverAddress);/* 初始化访问目标SMTP服务器时是否需要提供安全信息 */setAuthorizationRequired(authorizationRequired);}/** * 返回邮件发送过程中的最后一个违例对象 */public Throwable getMailException() {return lastException;}/** * 根据用户提供的注释和调用方法时传入的参数完成邮件发送的       动作 * * @param m *            被调用的业务方法 * @param args *            调用业务方法时传递的参数 */public Object invoke(Method m Object[] args)         throws Throwable {Message message = (Message) context             getMethodPropertySet(mMessageclass);/* 获取邮件的接收者 */String to = messageto();/* 获取邮件的发送者 */String from = messagefrom();/* 获取邮件抄送的接收者 */String cc = ();/* 获取邮件暗送的接收者 */String bcc = messagebcc();/* 获取邮件格式 */String contentType = ntentType();/* 获取邮件附件 */String attachment = messageattachment();/* 获取邮件主题 */String subject = messagesubject();/* 获取邮件内容 */Object body = null;/* 如果业务方法没有提供发送方法抛出违例信息 */if (argslength < ) {body = ;throw new IllegalArgumentException(At most one parameter may be defined as the                  + body of the Mail message);} elsebody = args[];/* 创建邮件对象 */createMimeMessage();/* 设置邮件对象的发送者 */setFrom(from);/* 设置邮件对象的接收者 */setTo(to);/* 设置邮件对象的抄送接收者 */setCC(cc);/* 设置邮件对象的暗送接收者 */setBCC(bcc);/* 设置邮件主题 */setSubject(subject);/* 设置邮件内容和格式 */setBody(body contentType);/* 设置邮件附件 */setAttachment(attachment);/* 发送邮件 */sendMail();return null;}/** * 设置访问SMTP服务器时是否需要提供 * * @param need *            访问SMTP服务器时是否需要提供安全信息                  true 需要 false 不需要 */private void setAuthorizationRequired(boolean need) {if (props == null)props = SystemgetProperties();if (need) {propsput(mailsmtpauth true);} else {propsput(mailsmtpauth false);}}/** * 创建用于发送的邮件对象 */private void createMimeMessage() throws Exception {try {/* 获得邮件发送上下文 */session = SessiongetDefaultInstance(props null);} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}try {/* 创建邮件发送消息对象 */mimeMessage = new MimeMessage(session);/* 创建邮件发送对象 */multipart = new MimeMultipart();} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置被发送邮件的内容 * * @param body *            被发送邮件的内容 * @param contentType *            被发送邮件的类型 */public void setBody(Object body String contentType)         throws Exception {try {BodyPart bodyPart = new MimeBodyPart();bodyPartsetContent(body contentType);multipartaddBodyPart(bodyPart);} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置被发送邮件的主题 * * @param subject *            被发送邮件的主题 */public void setSubject(String subject) throws Exception {try {mimeMessagesetSubject(subject);} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 为被发送邮件增加附件 * * @param attachment *            附件的文件路径 */public void setAttachment(String attachment)         throws Exception {try {BodyPart bp = new MimeBodyPart();FileDataSource fileds =                  new FileDataSource(attachment);bpsetDataHandler(new DataHandler(fileds));bpsetFileName(filedsgetName());multipartaddBodyPart(bp);} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置邮件的发送者 * * @param from *            邮件的发送者email地址 */public void setFrom(String from) throws Exception {try {mimeMessagesetFrom(new InternetAddress(from));} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置邮件的接收者 * * @param to *            邮件的接收者字符串 */public void setTo(String to) throws Exception {try {mimeMessagesetRecipients(                javaxmailMessageRecipientTypeTOInternetAddressparse(to));} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置邮件抄送的接收者 * * @param cc *            邮件抄送的接收者字符串 */public void setCC(String cc) throws Exception {try {mimeMessagesetRecipients(                javaxmailMessageRecipientTypeCC(Address[]) InternetAddressparse(cc));} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 设置邮件暗送的接收者 * * @param bcc *            邮件暗送接收者字符串 */public void setBCC(String bcc) throws Exception {try {mimeMessagesetRecipients(                javaxmailMessageRecipientTypeBCC(Address[]) InternetAddressparse(bcc));} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}/** * 发送邮件 * */private void sendMail() throws Exception {try {/* 设置邮件发送消息对象 */mimeMessagesetContent(multipart);/* 保存邮件发送消息对象 */mimeMessagesaveChanges();/* 获取邮件发送上下文 */Session mailSession =                 SessiongetInstance(props null);/* 根据SMTP服务器对于安全的不同要求连接SMTP服务器 */      Transport transport =               mailSessiongetTransport(smtp);if (authorizationRequired)nnect((String) propsget(                 mailsmtphost)principal credentials);elsennect((String) propsget(                mailsmtphost) );/* 发送邮件给所有接收者 */Address[] tos = mimeMessage    getRecipients(javaxmailMessageRecipientTypeTO);if (tos != null && toslength > ) {Systemoutprintln(toslength =                + toslength);transportsendMessage(mimeMessage tos);}/* 发送邮件给所有抄收的接收者 */Address[] ccs = mimeMessagegetRecipients(                       javaxmailMessageRecipientTypeCC);if (ccs != null && ccslength > ) {transportsendMessage(mimeMessage ccs);Systemoutprintln(ccslength =                     + ccslength);}/* 发送邮件给所有暗送的接收者 */Address[] bccs = mimeMessagegetRecipients(                   javaxmailMessageRecipientTypeBCC);if (bccs != null && bccslength > ) {transportsendMessage(mimeMessage bccs);Systemoutprintln(bccslength =                      + bccslength);}/* 断开与SMTP服务器的连接 */transportclose();} catch (Exception e) {eprintStackTrace();lastException = e;throw e;}}}

经过上面的这些步骤以后JavaMail控件的主体部分就已经全部完成了我们可以将它编译打包成jar文件在另外的应用中使用它下面的内容将介绍如何使用JavaMail控件完成JavaMail资源访问

使用JavaMail控件访问JavaMail资源

JavaMail控件本身并不能直接用于发送邮件控件使用者必须继承该控件提供对应的注释后才能够完成邮件发送的工作本章节中将给大家讲解如何继承JavaMail控件来完成邮件发送的工作

使用JavaMail控件连接到需要提供安全认证的SMTP服务器

网易(NEASE)公司是我个人比较喜欢的提供免费邮箱服务的网络公司网易(NEASE)公司提供的免费邮箱对应的SMTP服务器()需要提供安全认证才能够发送邮件

我们将编写一段代码调用已经完成的JavaMail控件访问需要提供安全信息的网易公司的SMTP服务器为了简化例子我们假设仅仅需要通过这段代码将邮件发送给唯一的一个接收者不需要暗送或者抄送给其他人要发送的邮件也没有附件

清单 中显示了符合要求的一个例子

清单 src\org\vivianj\beehive\controls\examples\

NeaseJavaMailControljava

package orgntrolsexamples;import orntrolsapibeanControlExtension;import orgntrolsexamplesjavamailJavaMailControl;/** * NeaseJavaMailControl 用于继承JavaMail控件完成邮件发送的

* 功能使用邮件服务器

* 使用该SMTP服务器需要提供安全信息 */@ControlExtension@JavaMailControlSMTPServer(serverAddress =     authorizationRequired = true principal = principal     credentials = credentials)public interface NeaseJavaMailControl      extends JavaMailControl {/** * 完成发送邮件的功能

* 邮件发送者的邮箱是

* 邮件接收者的邮箱是

* 邮件主题是hello

* 邮件的内容由控件使用者在调用时使用参数body传入

* * @param body *            邮件的内容 */@JavaMailControlMessage(from =         to = subject = hello)public void sendMail(String body);}

使用Java控件连接到不需要提供安全认证的SMTP服务器

是我创建的唯J族组织负责维护的一个网站它同时能够为唯J族组织的部分用户提供SMTP服务它所使用的SMTP服务器()在发送邮件时不需要用户提供安全认证信息

我们将编写一段代码调用已经完成的JavaMail控件连接到不需要提供安全信息的SMTP服务器—后发送邮件为了简化例子我们假设仅仅需要通过这段代码将邮件发送给唯一的一个接收者不需要暗送或者抄送给其他人要发送的邮件也没有附件

清单 中显示了符合要求的一个例子

清单 src\org\vivianj\beehive\controls\examples\

VivianjJavaMailControljava

package orgntrolsexamples;import orntrolsapibeanControlExtension;import orgntrolsexamplesjavamailJavaMailControl;/** * VivianjJavaMailControl 用于继承JavaMail控件

* 实现通过邮件服务器发送邮件的功能

* 使用该SMTP服务器不需要提供安全信息 */@ControlExtension@JavaMailControlSMTPServer(    serverAddress =     authorizationRequired = false principal = username     credentials = password)public interface VivianjJavaMailControl     extends JavaMailControl {/** * 完成发送邮件的功能

* 邮件发送者的邮箱是p

* 邮件接收者的邮箱是

* 邮件主题是hello

* 邮件的内容由控件使用者在调用时使用参数body传入

* * @param body *            邮件的内容 */@JavaMailControlMessage(from = p          to = subject = hello)public void sendMail(String body);}

结束语

Beehive发布的时候只是提供了三种系统控件JDBC控件EJB控件和JMS控件分别用于访问JDBC数据源EJB和JMS然而实际应用情况下我们通常需要访问更多类型的企业资源所以我们必须要根据实际情况编写符合实际要求的控件

本文中作者选择JEE中常见的JavaMail资源作为例子详细地介绍了如何基于控件架构分析设计实现和访问JavaMail控件的过程读者可以根据上面的步骤结合自己的实际需求编写更多的控件简化企业应用开发

参考资源

Beehive在线资源

下载资源

本文中例子下载地址

JMSControlExampleszip

作者简介

肖菁肖菁 是唯J族()创始人BEA 杭州User Group负责人自由撰稿人开源项目BuildFileDesigner(buildfilede)和VSecurity(vsecu)创始人

               

基于控件构架开发访问JavaMail的控件


发布日期:2019年12月09日
 
基于控件构架开发访问JavaMail的控件

Beehive只是提供了三种访问企业资源的系统控件现实情况下我们需要访问更多类型的企业资源所以我们需要自己来开发符合自己需要的控件在这篇文章里作者将介绍如何基于控件架构开发访问JavaMail资源的控件简化对JavaMail资源的访问

从前面的文章中我们已经学习了Beehive中提供的三种访问企业资源的控件JDBC控件EJB控件和JMS控件而这也是Beehive中目前已经提供的全部系统控件然而JEE标准中提供的企业资源类型远不止这三种开发者选择等待Beehive开发组提供更多的控件显然是不明智的我们必须自己动手来解决控件的开发

本文中就将给大家介绍如何基于控件架构提供的API来开发自己的控件我们选择开发者经常需要访问的企业资源——JavaMail作为目标资源按照控件的命名规则我们暂且叫做JavaMail控件吧

要完成一个控件的设计通常需要完成如下的工作

    确定控件要完成的功能

    分析要完成控件的功能确定没有使用控件之前我们通常需要提供哪些参数这些参数是否可能组合成集合使用参数是否必须提供参数的类型等

    根据分析结果设计和实现对应于这些参数的注释这些注释能够完整地体现第二步中分析的结果

    定义和实现控件公共类

    根据控件的使用情况确定控件公共接口类中需要对外提供的接口方法要确定这些接口方法可能会比较困难因为有些时候控件设计者可能难于确定是否为控件使用者提供低级接口以便使用者能够深入的控制控件的行为

    提供控件实现类

控件实现类通常被设计成可扩展(实现orntrolsapibeanExtensible接口)的这样方便使用者扩展该实现类控件实现类中最主要的方法是invoke(Method mObject[] args)方法这个方法的参数 m 代表控件使用者调用的业务方法而 args 数组则对应着控件使用者调用该业务方法时提供的调用参数控件实现类需要根据使用者提供的注释和调用业务时提供的参数完成控件主体功能的实现

下面的章节中我们将详细地讲解如果依照上面的步骤来完成JavaMail控件的设计和开发本文中所有例子的源代码可以在通过资源下载区中的连接完成下载

控件功能定义

JavaMail控件的开发目标是完成访问SMTP服务器发送邮件的封装提供足够的注释满足开发者在发送邮件时需要设置的参数同时提供邮件发送的实现方法使开发者在使用控件后无需编写访问SMTP服务器设置邮件发送者/接收者等参数发送邮件的代码而只需要将精力集中到业务逻辑上

需要提供的注释

在开发控件之前我们需要确定向开发者提供哪些注释才能够满足他们定制控件的实际需求因此我们首先要分析开发者使用这些控件时通常需要提供哪些参数要访问SMTP服务器发送邮件开发需要提供的参数分为两类

目标SMTP服务器的参数

目标SMTP服务器的参数包括目标SMTP服务器的地址访问SMTP服务器是否需要提供安全信息以及访问SMTP服务器所需要的用户名和密码其中目标SMTP服务器的地址是必须的我们需要提供的参数和相关要求如表所示

SMTP服务器参数表

参数名参数类型参数说明是否必须提供说明参数名参数类型参数说明是否必须提供例子

上一篇:用Javamail写的解析MimeMessage的程序

下一篇:JSR-223(Scripting for the Java&nbs