前言
大型Java项目都需要根据项目功能进行工程的细化;
Maven项目多模块是用项目层次的划分,替代简单的包层次的划分,遵循了高内聚,低耦合的设计模式;
工程细化的思想:分Java文件-------》分包-------》分模块-------》分工程(微服务);
我们可以借助Maven实现Java项目的分模块化开发:
- 父工程和子模块之间的依赖会继承
- 管理模块之间的依赖关系
一、Maven基础(回顾)
回顾之前学过的maven基础知识;
1.maven作用
- 依赖管理:pom.xml添加依赖
- 一键构建:点击按钮完成项目构建
2.maven常用命令
clean: 删除target目录(清理上一次构建过程产生的临时文件)
compile:编译src/mian/java目录下的java文件为.class文件
test: 编译src/mian/test目录下的java文件为.class文件并运行
packaage:打包编译src/mian/包含java、resources、webapp目录
install: 包部署到本地仓库
deploy:包部署到私服
3.maven生命周期
每一个生命周期就是一系列命令的集合
清理:clean
默认:compile--->test--->pakage--->install-deploy
站点:site
4.maven仓库种类
本地仓库:开发者电脑
私服:公司内网服务器
远程/中央仓库:公网服务器
5.maven主要标签
groupId : com.itheima 公司域名倒写
artifactId : spring 项目名称
version : 1.0-SNAPSHOT SNAPSHOT(快照) 测试版本 、 RELEASE(发行) 稳定版本
packing : 打包方式有 jar包 java、 war: web、 pom: 父工程
二、分模块开发(理论)
当1个大型Java项目中,我们可以把1个项目拆分成多个子模块,借助maven给每个当前项目中各个子模块,产生1个唯一的GAV坐标;(拆分)
把当前项目/模块安装到本地仓库中;
多个子模块之间就可以通过Maven的dependency标签引入当前模块依赖的其他模块,以完成模块之间的相互调用 ; (聚合)
1.2.聚合:
3.父子工厂搭建
把1个SSM项目拆分成 ssm-web----------->ssm-service-----------> ssm-dao这3个子模块,建立依赖关系,完成模块之间功能调用;
3.1.创建父工程
删除父工程的src目录;
编译阶段2个模块之间建立依赖:可以通过源码建立依赖;
运行阶段2个模块之间建立依赖:必须把依赖的模块部署(package)到本地仓库中,才能被依赖;
两个模块是否建立依赖成功,可以从maven的Dependencies中查看;
3.5.1.ssm-service和ssm-dao模建立依赖
<dependency> <groupId>com.zhanggen</groupId> <artifactId>ssm-dao</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
3.5.2.ssm-web 和ssm-service模块建立依赖
<dependencies> <!--引入ssm-service模块的依赖--> <dependency> <groupId>com.zhanggen</groupId> <artifactId>ssm-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
3.6.1.父子工程之间继承关系
当父工程中的引入了Junit依赖之后,父工程中所有子模块也会继承Junit依赖,都可以使用的Junit功能;
3.6.2.依赖关系传递
package com.heima.behavior; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import javax.sql.DataSource; //排除model模块传递的DataSource数据库依赖 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableDiscoveryClient public class BehaviorApplication { public static void main(String[] args) { SpringApplication.run(BehaviorApplication.class, args); } }
---------------------------
3.8.依赖冲突解决
我们可以使用以下方法选择出1个唯一的版本的依赖;
dependencyManagement标签进行
<!--版本锁定--> <dependencyManagement> <dependencies> <!-- 给Feign、Gateway、Eureka等提供版本支持 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR10</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 给Nacos、Sentinel、Dubbo等提供版本支持 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
dependencies和dependencyManagement标签的区别
- dependencyManagement标签:在父项目中进行依赖版本的统一,不会真正引入依赖,避免出现依赖冲突;
Error:java: Annotation processing is not supported for module cycles.
Please ensure that all modules from cycle [wzhfunding-admin-webUI01,wzhfunding-admin-componet] are excluded from annotation processing
2.模块循环解决方法
如果A模块和B模块相互(循环)依赖,
A<-->B
可以抽取出相互依赖的类,封装到C模块;
A-->C
B-->C
-- 创建学生表 CREATE TABLE student( number VARCHAR(10) UNIQUE, -- 学号 NAME VARCHAR(10), -- 姓名 birthday DATE, -- 生日 address VARCHAR(200) -- 地址 ); INSERT INTO student VALUES ('hm001','张弢','1995-05-05','北京市昌平区'); INSERT INTO student VALUES ('hm002','少林圣神','1996-06-06','北京市海淀区'); INSERT INTO student VALUES ('hm003','易云','1997-07-07','北京市朝阳区'); INSERT INTO student VALUES ('hm004','易天行','1998-08-08','北京市丰台区'); INSERT INTO student VALUES ('hm005','易继风','1999-09-09','北京市顺义区'); INSERT INTO student VALUES ('hm006','飞龙将军','2000-01-01','北京市西城区'); INSERT INTO student VALUES ('hm007','逍遥王','2001-02-02','北京市延庆区'); INSERT INTO student VALUES ('hm008','张君宝','2002-03-03','北京市东城区'); INSERT INTO student VALUES ('hm009','张启樵','2003-04-04','北京市东城区'); student.sql
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhanggen</groupId> <artifactId>ssm-project</artifactId> <!--打包方式声明为pom:代表当前这是父工程的pom文件--> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <!--声明当前父工程管理的子模块有哪些--> <modules> <module>ssm-dao</module> <module>ssm-service</module> <module>ssm-web</module> </modules> <dependencies> <!--mybatis相关的坐标--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.15</version> </dependency> <!--spring相关的坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.6.RELEASE</version> </dependency> <!--springmvc相关的坐标--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <!--mybatis-spring--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.1</version> </dependency> <!--辅助坐标--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> </project>
package com.zhanggen.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @NoArgsConstructor @AllArgsConstructor public class Student { private String number; private String name; private Date birthday; private String address; }
package com.zhanggen.mapper; import com.zhanggen.domain.Student; import org.apache.ibatis.annotations.Select; import java.util.List; public interface StudentMapper { //查询所有 @Select("select * from student") List<Student> findAll(); }
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8
jdbc.username=zhanggen
jdbc.password=123.com
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--配置:引入properties配置文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置:DruidDataSource数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!--配置:SqlSessionFactoryBean工厂--> <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置:Mybatis扫描的mapper接口--> <bean id="configurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.zhanggen.mapper"></property> </bean> </beans>
1.4.测试
package com.zhanaggen; import com.zhanggen.domain.Student; import com.zhanggen.mapper.StudentMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-dao.xml") public class StudentMapperTest { @Autowired private StudentMapper studentMapper; @Test public void testFindAll() { List<Student> studentList = studentMapper.findAll(); for (Student student : studentList) { System.out.println(student); } } }
package com.zhanggen.service; import com.zhanggen.domain.Student; import java.util.List; public interface StudentService { //查询所有 List<Student> findAll(); }
2.2.
package com.zhanggen.service.impl; import com.zhanggen.domain.Student; import com.zhanggen.mapper.StudentMapper; import com.zhanggen.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @Transactional public class StudentServiceImpl implements StudentService { @Autowired private StudentMapper studentMapper; //查询所有 public List<Student> findAll() { return studentMapper.findAll(); } }
2.3.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--注解扫描--> <context:component-scan base-package="com.zhanggen"> <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/> </context:component-scan> <!--<!–导入applicationContext-dao.xm配置文件–>--> <!--<import resource="applicationContext-dao.xml"/>--> <!--事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--事务注解驱动--> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
2.4.测试
分模块开发的项目,spring容器启动之后,如何加载各个子模块下的配置文件?
监听器:监听到tomcat启动
classpath*:搜索的时候既要搜索当前项目,又要搜索当前项目依赖的jar包中的类路径
@ContextConfiguration("classpath*:applicationContext-*.xml")
package com.zhanggen; import com.zhanggen.domain.Student; import com.zhanggen.service.StudentService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) //@ContextConfiguration({"classpath:applicationContext-service.xml", "classpath:applicationContext-dao.xml"}) //classpath*:搜索的时候既要搜索当前项目,又要搜索当前项目依赖的jar包中的类路径 @ContextConfiguration("classpath*:applicationContext-*.xml") public class StudentServiceTest { @Autowired private StudentService studentService; @Test public void testFindAll() { List<Student> studentList = studentService.findAll(); for (Student student : studentList) { System.out.println(student); } } }
3.1.创建controller层处理器
package com.zhanggen.controller; import com.zhanggen.domain.Student; import com.zhanggen.service.StudentService; import com.zhanggen.vo.ResultInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class StudentController { @Autowired private StudentService studentService; //查询所有 @GetMapping("/student") public ResultInfo findAll() { List<Student> studentList = studentService.findAll(); return ResultInfo.success(studentList); } }
3.2.创建结果信息类
统一后端响应信息格式;
package com.zhanggen.controller; import com.zhanggen.domain.Student; import com.zhanggen.service.StudentService; import com.zhanggen.vo.ResultInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class StudentController { @Autowired private StudentService studentService; //查询所有 @GetMapping("/student") public ResultInfo findAll() { List<Student> studentList = studentService.findAll(); return ResultInfo.success(studentList); } }
3.3.添加springMVC配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--注解扫描--> <context:component-scan base-package="com.zhanggen.controller"/> <!--注解驱动--> <mvc:annotation-driven/> <!--释放静态资源--> <mvc:resources mapping="/index.html" location="/"/> <mvc:resources mapping="/css/*" location="/css/"/> <mvc:resources mapping="/fonts/*" location="/fonts/"/> <mvc:resources mapping="/img/*" location="/img/"/> <mvc:resources mapping="/js/*" location="/js/"/> <!--释放静态文件--> <!--文件上传解析器--> <!--类型转换--> </beans>
3.4.配置web.xml
spring监听器:当Tomcat启动时自动装配当前项目下所有子模块下的配置文件,启动spring
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!--1.spring监听器:当Tomcat启动时自动装配当前项目下所有子模块下的配置文件,启动spring--> <context-param> <param-name>contextConfigLocation</param-name> <!--注意加载当前项目里所有模块下的配置文件--> <param-value>classpath*:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--2.springMMV前端控制器--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--3.spring中文乱码过滤器:--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
参考