org.springframework.mail.cos.CosMailSenderImpl
和
org.springframework.mail.javamail.JavaMailSenderImpl
实现。appfuse使用的是后者。
MainEngine其中的两个方法:
1setMailSender(MailSender mailSender)
2setVelocityEngine(VelocityEngine velocityEngine)
在配置文件applicationContext-Server.xml中
1<bean id="mailEngine" class="org.appfuse.service.MailEngine">
2 <property name="mailSender" ref="mailSender"/>
3 <property name="velocityEngine" ref="velocityEngine"/>
4</bean>
通过这个把mailSender和velocityEngine赋予MainEngine。
1 :Bean mainSender的定义:
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}"/>
<property name="username" value="${mail.username}"/>
<property name="password" value="${mail.password}"/>
</bean>
可以看到mailSender的实现为org.springframework.mail.javamail.JavaMailSenderImpl,它有三个属性
:
1host
2username
3password
它们的值是读配置文件mail.properties读到的。具体看web/WEB-INF/applicationContext-resources.xml中的Bean
propertyConfigurer,如下:
1<!-- For mail settings and future properties files -->
2<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
3 <property name="locations">
4 <list>
5 <value>classpath:mail.properties</value>
6 </list>
7 </property>
8</bean>
2 :Bean velocityEngine的定义:
1<!-- Configure Velocity for sending e-mail -->
2<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
3 <property name="velocityProperties">
4 <props>
5 <prop key="resource.loader">class</prop>
6 <prop key="class.resource.loader.class">
7 org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
8 </prop>
9 <prop key="velocimacro.library"></prop>
10 </props>
11 </property>
12</bean>
解释一下:Velocity是一种java模版引擎技术,允许任何人使用简单而强大的模版语言来引用定义在java代码中的对象。在spring中对它的支持是VelocityEngineFactoryBean。
3 :MailEngine中的其他方法:
1send(SimpleMailMessage msg)
2sendMessage(SimpleMailMessage msg, String templateName,Map model)
3sendMessage(String[] emailAddresses,ClassPathResource resource, String bodyText,String subject, String attachmentName)
3.1 :send(SimpleMailMessage msg)调用mailSender把msg发出去。
3.2 :sendMessage(SimpleMailMessage msg, String templateName,Map
model)把model中的值通过velocityEngine写到 templateName里的相应位置。把结果放到msg的文本区。然后调用send方法把msg发出去。
3.3 :sendMessage(String[] emailAddresses,
ClassPathResource
resource, String bodyText,
String subject, String attachmentName) 此方法的作用为;
把mailSender强制转换成JavaMailSenderImpl,然后调用它的createMimeMessage()方法。创建一个类型为MimeMessage的message,根据他创建一个类型为MimeMessageHelper的类helper.然后把message的主题设为subject,text设为bodyText,attachment(附件)的文件为resource,名为attachmentName。
然后用mailSender把它发出去。
三 : UserExistsException
:
继承于 Exception的异常类,当数据库中此用户存在抛出此异常。参考UserManager
中的方法:
saveUser(User user) throws UserExistsException;
四 : UserSecurityAdvice :
public class UserSecurityAdvice implements MethodBeforeAdvice, AfterReturningAdvice
这里使用了spring的aop工具,spring提供的aop装备有以下几种 :
1MethodBeforeAdvice(实现before装备)
2AfterReturningAdvice(实现After装备)
3ThrowsAdvice(Throw装备)
4Methodinterceptor(Around装备).
appfuse在这里使用的是MethodBeforeAdvice ,AfterReturningAdvice
五 :在applicationContext-server.xml中定义了一个名为txProxyTemplate的bean,它是个抽象bean
1<bean id="txProxyTemplate" abstract="true"
2 class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
3 <property name="transactionManager" ref="transactionManager"/>
4 <property name="transactionAttributes">
5 <props>
6 <prop key="save*">PROPAGATION_REQUIRED</prop>
7 <prop key="remove*">PROPAGATION_REQUIRED</prop>
8 <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
9 </props>
10 </property>
11</bean>
他的类型是个事务代理工厂,
org.springframework.transaction.interceptor.TransactionProxyFactoryBean
它有两个属性 :
1 :transactionManager,依赖与bean transactionManager.
2 :transactionAttributes,它定义了在处理事务时的规则.
1如果代理对象的方法以save开头,则ROPAGATION_REQUIRED
既事务类型为required,
2以remove开头的方法的事务类型为则PROPAGATION_REQUIRED,事务类型为required.
3其他为PROPAGATION_REQUIRED,readOnly.
解释一下事务的概念:
在EJB中,容器提供了声明性事务的支持.EJB 支持7中不同的声明性事务.
1Required(如果存在事务就在事务中运行,如果没有事务生成一个新事务),
2RequiredNew(无论有没有事务都要生成新事务,在自己的事务中运行),
3Mandatory(事务是必须的,如果没有事务报异常),
4Supports(有事务使用事物,没有事务不使用事务),
5NotSupports(不能在事务中运行),
6Never(不能在另一个事务意境中调用此方法)
7Bean-Managed(由Bean类自己管理事务)
在spring中与它们对应的是在接口org.springframework.transaction.TransactionDefinition中定义的:
1int PROPAGATION_REQUIRED = 0;
2int PROPAGATION_SUPPORTS = 1;
3int PROPAGATION_MANDATORY = 2;
4int PROPAGATION_REQUIRES_NEW = 3;
5int PROPAGATION_NOT_SUPPORTED = 4;
6int PROPAGATION_NEVER = 5;
7int PROPAGATION_NESTED = 6;
可以看到spring没有ejb的 Bean-Magaged事务,但是它新增一个PROPAGATION_NESTED事务.
如果现在存在一个事务,就在一个嵌套的事务里运行.这个只有在spring使用基于jdbc3.0的DataSourceTransactionManager时才使用.
六 :在applicationContext-service.xml中定义的三个bean:
1manager
2roleManager
3userManager
都是从txProxyTemplate继承下来的.
1 :manager 的定义为:
1<bean id="manager" parent="txProxyTemplate">
2 <property name="target">
3 <bean class="org.appfuse.service.impl.BaseManager">
4 <property name="DAO" ref="dao"/>
5 </bean>
6 </property>
7</bean>
可以看到它与lookupManager
1<bean id="lookupManager" class="org.appfuse.service.impl.LookupManagerImpl">
2 <property name="lookupDao" ref="lookupDao"/>
3</bean>
的区别:前者继承txProxyTemplate,
1<bean id="txProxyTemplate" abstract="true"
2 class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
3 <property name="transactionManager" ref="transactionManager"/>
4 <property name="transactionAttributes">
5 <props>
6 <prop key="save*">PROPAGATION_REQUIRED</prop>
7 <prop key="remove*">PROPAGATION_REQUIRED</prop>
8 <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
9 </props>
10 </property>
11</bean>
txProxyTemplate的class是
org.springframework.transaction.interceptor.TransactionProxyFactoryBean
manager 的 target为
org.appfuse.service.impl.BaseManager
所以相对于loopupManager来说通过TransactionProxyFactoryBean实现了事务管理.roleManager
与Manager类似.
2 :userManager的定义如下:
继续看before方法,
1 :它通过Authentication 实例取的用户授权角色集roles,然后遍历授权角色集
如果授权角色集里有名为Constants.ADMIN_ROLE的角色,令boolean administrator
= true.
2 :接下来是:User user = (User) args[0];然后把user的的名字放在String
username里。
3 :如果auth.getPrincipal()类型为UserDetails,则currentUser的值为
auth.getPrincipal()).getUsername(),否则为String.valueOf(auth.getPrincipal())。
此时分情况判断:
1。如果username和currentUser不等
新建一个resolver对象:
AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
通过它判断此用户类型:
如果是非匿名用户:
如果不是administrator 抛出AccessDeniedException
异常。
2。如果username和currentUser相等,此用户不是administrator.
把user的角色集放到一个Set userRoles里。把授权角色放到一个Set authorizedRoles里。
`如果授权角色集和角色集不等的话,抛出异常 AccessDeniedException.
总之这个类的作用是是保证用户只能更新自己,而不是其他人。
applicationContext-server.xml是上述类的spring文件的配置片段。主要与邮件服务,和与数据库操作相关的bean.
org.appfuse.service.impl:
此包下是org.appfuse.server包定义的接口的具体实现。
org.appfuse.service.util:
此包下的类是在具体操作过程中使用到一些对象转换类。
ConvertUtil:
它有如下方法:
convertBundleToMap,
convertListToMap,
convertBundleToProperties,
populateObject(Object obj, ResourceBundle rb)--把rb转换成Map
map,然后把map组装到obj里然后返回obj.
getOpposingObject(Object o) 此方法是处理hibernate的pojo对象与struts的form之间的转换。
convert(Object o) 调用getOpposingObject取到与o想对的对象target,然后把o的所有属性值赋给target.返回target.
convertLists(Object o) 此方法的作用是如果o的属性里有一个类型为list的属性,对此属性的每一个元素调用convert方法,把转换后的对象放到一个list里,然后用list重新设置此属性。返回
o.
CurrencyConverter是与钱相关的转换实用类。它实现Converter接口的convert方法。
定义了金钱的格式为“###,###.00”convert方法,可以把String,或Double类型的value转换成格式为“###,###.00”的double类型数返回。
DateUtil:它有以下属性:
String defaultDatePattern:
String timePattern = "HH:mm";
方法:
String getDatePattern()---从ApplicationContext...里根据locale取得“date.format”的值。做为日期格式,放到defaultDatePattern里,如果没有“date.format”,defaultDatePattern
= "MM/dd/yyyy"。
getDate(Date aDate)---以defaultDatePattern的格式把aDate转换成字符串返回。
convertStringToDate(String aMask, String strDate)---以aMask的格式把SstrDate转换成日期返回。
getDateTime(String aMask, Date aDate)----以aMask的格式返回aDate的字符串表示形式。
getTimeNow(Date theTime)---以timePattern的形式返回时间。
Calendar getToday()---以Calendar的方式返回当时时间。
getDateTime(String aMask, Date aDate)---以aMask的格式返回aDate的字符串表达。
convertDateToString(Date aDate)---以“date.format”定义的格式返回aDate的字符串表达。
convertStringToDate(String strDate)---以“date.format”定义的格式把strDate转换成日期返回。
DateConverter继承实现了Converter的convert方法,此方法调用此类中定义的另外两个方法实现
字符串到Date/Timestamp,或则Date/Timpstamp到String的转换。其中timestamp的格式:
TS_FORMAT = DateUtil.getDatePattern() + " HH:mm:ss.S";
encodePassword(String password, String algorithm)
此方法的流程如下:先得到password的字节码放到字节数组 unencodedPassword里。
根据algorithm得到一个MessageDigest对象。
md.reset();
md.update(unencodedPassword);
byte[] encodedPassword = md.digest();
StringBuffer buf = new StringBuffer();
对encodedPassword进行循环判断,如果某一位的值小于0x10,buf添加一个0.
否则把encodedPassword这一位转换成16进制数,然后添加到buf上。
返回buf.toString().
encodeString(String str)
此方法通过sun.misc.BASE64Encoder 把str用base64编码。
decodeString(String str)
此方法通过sun.misc.BASE64Encoder解码。
TimestampConverter继承了DateConverter.
重构了convertToString(Class type, Object value)---此方法相对父类只是少了一步判断。
新建了一个方法convertToDate(Class type, Object value)。
这个方法相对于父类少了一个参数(格式),此类的日期格式为TS_FORMAT = DateUtil.getDatePattern()
+ " HH:mm:ss.S"。它与同名父类方法的作用一样。
|