1. 项目需求
加入我们现在有这样一个小小项目,就是做一个注册模块,让注册的人员记录可以插入到数据库中,还可以做账号的唯一性判断,注册成功后可以进行邮件提醒功能。书上功能很简单,其实重点不是功能,而是借由此示例说明Maven的特性。这一节咱们主要说明一下坐标与依赖的特性。其余的特性也皆由此案例中衍生出来。
2. 模块划分
基本模块功能分为
验证码生成:包括生成随即验证数字以及数字图片。
发送邮件:注册成功后需要给注册的Email发一封email,以便激活注册信息。
激活账户:用于邮件激活用户之后,用户才可用。
登录:一切成功后可以登录系统。
系统比较简单了,但是我们也分模块进行开发。也好体现Maven模块强解耦合的管理思想。
3. 邮件模块的实现
这里和书中的讲解顺序不太一样,我们先来开发功能模块,之后通过Maven的坐标和以来的概念来分析咱们的邮件模块。整个系统是B/S架构,采用Spring帮助我们进行类的管理。为了放大这个微型系统的规模,我们单独为这个邮件功能建立一个项目,模拟一个很大系统的一个模块。我们先看邮件模块的实现类吧,接口就不给出了
package com.liuyan.account.mail.impl; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import com.liuyan.account.mail.AccountEmailService; public class AccountEmailServiceImpl implements AccountEmailService { private JavaMailSender javaMailSender; public JavaMailSender getJavaMailSender() { return javaMailSender; } public void setJavaMailSender(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } private String systemEmail; public String getSystemEmail() { return systemEmail; } public void setSystemEmail(String systemEmail) { this.systemEmail = systemEmail; } @Override public void sendMail(String to, String subject, String message) throws MessagingException { MimeMessage msg = javaMailSender.createMimeMessage(); MimeMessageHelper msgHelper = new MimeMessageHelper(msg); msgHelper.setFrom(systemEmail); msgHelper.setTo(to); msgHelper.setSubject(subject); msgHelper.setText(message); javaMailSender.send(msg); } }
之后在包/src/test/java编写测试用例
package com.liuyan.account.mail; import javax.mail.MessagingException; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; public class AccountEmailServiceTest { private GreenMail greenMail; @Before public void startTest() { greenMail = new GreenMail(ServerSetup.SMTP); greenMail.setUser("[email protected]", "1111"); greenMail.start(); } @Test public void sendMail() throws MessagingException { ApplicationContext ctx = new ClassPathXmlApplicationContext( "applicationContext.xml"); AccountEmailService accountEmailService = (AccountEmailService) ctx .getBean("accountEmailService"); String to = "[email protected]"; String subject = "测试"; String message = "内容"; accountEmailService.sendMail(to, subject, message); } @After public void stop() { greenMail.stop(); } }
单元测试也写完了,之后就是项目构建、打包了。
在这之前我们来看看Spring配置文件的内容
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"> <!-- 加载Properties文件 --> <bean id="configurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:mail.properties</value> </list> </property> </bean> <bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="defaultEncoding" value="UTF-8" /> <property name="host" value="${mail.host}" /> <property name="username" value="${mail.username}" /> <property name="password" value="${mail.password}" /> <property name="javaMailProperties"> <props> <!-- 设置认证开关 --> <prop key="mail.smtp.auth">true</prop> <!-- 启动调试开关 --> <prop key="mail.debug">true</prop> </props> </property> </bean> <bean id="accountEmailService" class="com.liuyan.account.mail.impl.AccountEmailServiceImpl"> <property name="javaMailSender" ref="javaMailSender"></property> <property name="systemEmail" value="[email protected]"></property> </bean> </beans>
mail.properties内容
mail.host=smtp.163.com [email protected] mail.password=111111 [email protected] [email protected]
下面就需要Maven出场了。
4. Maven的介入
其实上面的程序打包已经按照了Maven的规约了~我们再来看看这个项目模块的代码结构
通过MyEclipse插件很快写出pom.xml文件内容
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.liuyan.account</groupId> <artifactId>MavenAccount-email</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>2.5.6</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> <dependency> <groupId>com.icegreen</groupId> <artifactId>greenmail</artifactId> <version>1.3.1b</version> <scope>test</scope> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/resource</directory> </resource> </resources> </build> </project>
运行一下命令。
mvn clean test
自己的邮箱看看效果,多了一封邮件。Ok,再看本地仓库,唉~~~自己的c盘又添了不少东西。本地仓库会越来越大的。各位使用者要有心理准备,当然可以通过配置的方式转移本地仓库存储位置。
实际上是通过这个小例子说明坐标这个概念。在Maven中的坐标的意思就是各种构建引入的秩序,坐标是多维的。也就是groupId、artifactId、version、packaging这几个元素决定了其组建的唯一标识(classifier没有看到,如果后面看到了再补充进来)。
前面也稍带提过了groupId是项目组的标识、artifactId是模块标识、version是版本号标识、packaging是打包方式,默认是jar方式。如此看来这些元素描述了一个不能重复的标识,groupId+ artifactId+ version+”.”+packaging在整个儿仓库中是不应该重复的。
<groupId>com.liuyan.account</groupId> <artifactId>MavenAccount-email</artifactId> <version>0.0.1-SNAPSHOT</version>
而其他项目需要你的模块为其服务的时候,也是根据坐标找到你的模块的。这就引出了下面依赖项的配置。这个模块依赖了Spring,不怕,我们从maven仓库中去取依赖就可以了,下面的问题就是:我们需要哪些依赖?这些依赖的版本是什么?
通过已有组件的坐标,我们可以轻易从Maven中心库中获取依赖包
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>2.5.6</version> </dependency>
描述我们这个邮件模块依赖org.springframework.spring-context-support.2.5.6.jar这个东东。果然,运行后在本地仓库中找到了
项目依赖可以有以下几种配置范围
1:compile:默认值,这个代表在Maven项目周期的编译、测试、运行的3个classpath都生效,也就是说Maven自己在项目不同生命周期使用的classpath不一样,一旦配置了compile,那么在以上三个周期会将依赖jar放到不同周期classpath中。
2:test:测试期间有效,运行期间不必引入,就像junit包,在运行期间就没必要引入了。
3:provided:在编译、测试期间有效,其余周期都没用到,比如servlet-api.jar,web容器提供了此规范apijar和实现。
4:runtime:只在运行、测试期间生效,以JDK的JDBC规范为代表,哦,还有JavaEE的JPA规范。
5:system:与本机系统环境绑定,在编译、测试期间有效,往往和本机环境绑定,移植性不太好。
依赖传播:单丝不成线,孤木不成林。一个项目需要依赖很多辅助包,我们的spring也不例外。下面是本项目的依赖关系图
咱们就拿spring-core来说事儿吧,本项目直接依赖于它,它呢也不是吃素的,也需要别人的支持,他需要apache的commons-logging。那么就导致了如果我们想要使用spring-core的功能,必须得引入这个commons-logging包喽。没有Maven之前,我们一般都是先引入我们直接需要的包,之后根据错误信息加上我们自身的开发经验一个一个去网上下载我们核心包需要的其他包。造成的结果是,花了大量的时间在网上找包,好不容易将项目run起来了,执行一个操作后,又发现在运行的时候还需要别的jar包,如此根据错误信息往复在网上找相关jar包。最后发现自己一个很简单的项目怎么引入了那么多的包啊!
使用Maven管理项目的话,它会自动为您找这种传递性的依赖,因为在Maven中心仓库的项目描述中都已经严格阐述了各个开源项目的依赖关系。诚然,这种传递性依赖也存在范围的问题。我们就拿上面的举例子,本发送邮件模块项目依赖于spring-core依赖范围是compile,而spring-core依赖于commons-logging也是compile范围。那么通过传递性,本项目对commons-logging的依赖也是compile。看下表
直接依赖范围 |
compile |
test |
provided |
runtime |
compile |
compile |
- |
- |
runtime |
test |
test |
- |
- |
test |
provided |
provide |
- |
provided |
provided |
runtime |
runtime |
- |
- |
runtime |
这个表是嘛意思呢?就是说一个项目的第一直接依赖假如是compile范围,那么它的第二依赖包如果也是compile,那么本项目和第二依赖包的依赖范围就是compile。如果一个项目的第一直接依赖假如是compile范围,那么它的第二依赖包如果是test,那么本项目和第二依赖包不存在任何依赖关系,也是,第一直接依赖包和第二依赖包是测试的时候才用到的。无需影响到其他使用者。