【spring微服务】spring-boot基于idea实现多模块项目搭建
一、创建spring-boot项目
参考信息:https://blog.csdn.net/zcf980/article/details/83040029
1、项目介绍
spring-trade
->spring-trade-web
->spring-trade-service
->spring-trade-dao
2、项目搭建思路
先创建一个spring-trade的父工程,然后在父工程再建三个子Moudle
3、项目搭建过程
3.1、社区版本idea添加springboot的安装插件
打开IDEA中的setting(设置)–> Plugins(插件下载中心) -->选择MarketPlace(下载中心)里面搜索 (Spring Initializr and Assistant)
使用插件创建项目时,出现网站访问超时的情况
解决办法,将项目的地址替换成阿里云:https://start.aliyun.com/
(1)创建一个spring-trade的工程
(2)创建一个spring-trade-dao模块(spring-trade-service模块创建方式一样)
(3)创建一个spring-trade-web模块
(4)项目整理
- 删除dao,service模块的启动类,resource目录下的文件清空
- 保留web模块的启动类
- web模块添加service模块依赖,service模块添加dao模块依赖
(5)配置slf4j,log4j2的日志框架
在web模块的pom文件中,排除spring-boot默认的日志配置,添加log4j2的日志配置
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!--父项目声明--> <parent> <groupId>com.sxf.study</groupId> <artifactId>spring-trade</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <!--自身坐标--> <groupId>com.spring.sxf.study</groupId> <artifactId>spring-trade-web</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-trade-web</name> <packaging>jar</packaging> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.spring.sxf.study</groupId> <artifactId>spring-trade-service</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <!--spring-boot默认使用slf4j+logback进行日志记录,则排除,使用log4j2--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!--引入log4j2启动日志打印--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
在web模块的resources目录下添加log4j2.xml配置
<?xml version="1.0" encoding="UTF-8"?> <!-- configuration 节点的属性: status:用来指定log4j本身的打印日志的级别. monitorinterval:用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s. --> <!-- 日志级别以及优先级排序(由高到低): OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <configuration status="DEBUG" monitorinterval="60"> <!--声明属性--> <Properties> <!--这里的log.path是定义日志存放的地方,此处是存放于项目根路径下的/Users/shangxiaofei文件夹中--> <Property name="log.path">/Users/shangxiaofei</Property> </Properties> <!--声明日志输出位置--> <Appenders> <!-- Console节点用来定义输出到控制台的Appender name : 指定Appender的名字,用于Logger节点引用 target : SYSTEM_OUT 或 SYSTEM_ERR,一般设置为:SYSTEM_OUT PatternLayout : 指定日志输出格式,默认为%m%n --> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] [%t] - %l - %m%n"/> </Console> <!-- File节点用来定义输出到指定位置的文件 name:指定Appender的名字. fileName:指定输出日志的目的文件带全路径的文件名. PatternLayout:输出格式,不设置默认为:%m%n. --> <File name="LogFile" fileName="${log.path}/spring-trade.log"> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] [%t] - %l - %m%n"/> <!--只输出info级别以上的日志--> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> </File> <!-- RollingFile 节点用来定义超过指定大小自动删除旧的创建新的的Appender name:指定Appender的名字. fileName:指定输出日志的目的文件带全路径的文件名. PatternLayout:输出格式,不设置默认为:%m%n. filePattern:指定新建日志文件的名称格式. Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志. ThresholdFilter : 日志过滤器(如果存在多个日志过滤器,则使用<Filters></Filters>包含住) TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am. SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小. DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。 --> <RollingFile name="RollingFile" fileName="${log.path}/spring-trade-rolling.log" filePattern="${log.path}/logs/${date:yyyy-MM}/info-%d{yyyy-MM-dd}.log.zip"> <!--只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) DENY(拒绝),NEUTRAL(中立),ACCEPT(允许)--> <!--该RollingFile的Filters 代表的意思是,只输出info级别的日志,【先拒绝日志,后接受日志】顺序不能颠倒--> <Filters> <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/> <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/> </Filters> <PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] [%t] - %l - %m%n"/> <Policies> <TimeBasedTriggeringPolicy modulate="true" interval="1"/> </Policies> </RollingFile> </Appenders> <!-- Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出 level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF. AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender. Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。 level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF. name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点. AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。 --> <Loggers> <!--过滤掉spring和mybatis的一些无用的All,Trace,Debug级别的日志信息--> <logger name="org.springframework" level="INFO"/> <logger name="com.spring" level="INFO"/> <!-- additivity设置成false:org.mybatis包下的日志,只会打印到LogFile的appender中,不会再打到Root中定义的appender中 additivity设置成true或不设置:日志除了打到LogFile的appender中,还会打印到Root中定义的appender的中 --> <logger name="org.mybatis" level="INFO" additivity="false"> <appender-ref ref="LogFile"/> </logger> <!--level代表只输出info级别以上的日志--> <root level="info"> <appender-ref ref="Console"/> <appender-ref ref="RollingFile"/> </root> </Loggers> </configuration>
(6)配置数据库和mybatis框架,编写测试demo
在resources目录下的application.yml文件下添加数据库配置信息和mybatis的整合信息
#数据库配置 spring: datasource: url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8 username: root password: shangxiaofei coresize: 60 maxsize: 60 dirverclassname: com.mysql.jdbc.Driver #和mybatis整合 mybatis: mapper-locations: classpath:mapper/*/*.xml
数据源bean的加载信息
package com.spring.sxf.study.springtradedao.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import javax.sql.DataSource; /** * @author * @date 3:51 PM 2019/9/26 */ @Configuration public class DataSourcesConfig { @Autowired private Environment environment; @Bean public DataSource getDataSouces() { DruidDataSource dataSource = new DruidDataSource(); String url = environment.getProperty("spring.datasource.url"); String name = environment.getProperty("spring.datasource.username"); String pwd = environment.getProperty("spring.datasource.password"); String coreSize = environment.getProperty("spring.datasource.coresize"); String maxSize = environment.getProperty("spring.datasource.maxsize"); String dirverClassName=environment.getProperty("spring.datasource.dirverclassname"); System.out.println("数据库url=" + url); System.out.println("数据库用户名=" + name); System.out.println("数据库密码=" + pwd); System.out.println("数据库核心连接池初始化个数=" + coreSize); System.out.println("数据库核心连接池最大个数=" + maxSize); dataSource.setUrl(url); dataSource.setUsername(name); dataSource.setPassword(pwd); dataSource.setInitialSize(Integer.valueOf(coreSize)); dataSource.setMaxActive(Integer.valueOf(maxSize)); dataSource.setDriverClassName(dirverClassName); dataSource.setDbType("mysql"); return dataSource; } }
在启动类上配置项目启动扫描
package com.spring.sxf.study.springtradeweb; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @MapperScan("com.spring.sxf.study.springtradedao.mapper") @SpringBootApplication(scanBasePackages="com.spring.sxf") public class SpringTradeWebApplication { public static void main(String[] args) { SpringApplication.run(SpringTradeWebApplication.class, args); } }
dao模块的pom.xml配置spring-mybatis整合配置和事务配置
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!--声明父项目--> <parent> <groupId>com.sxf.study</groupId> <artifactId>spring-trade</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <!--项目自身坐标--> <groupId>com.spring.sxf.study</groupId> <artifactId>spring-trade-dao</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-trade-dao</name> <packaging>jar</packaging> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- 添加Druid依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <!--mybatis和spring框架整合自动化配置依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!--mysql连接依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!--mybatis自动生成代码模块--> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <verbose>true</verbose> <overwrite>true</overwrite> <configurationFile>src/main/resources/generatorConfig.xml</configurationFile> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.36</version> </dependency> <dependency> <groupId>com.github.harawata</groupId> <artifactId>mybatis-generator-plugin</artifactId> <version>0.0.2-SNAPSHOT</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
二、搭建spring-boot项目遇到的问题
1、spring-boot项目打包非执行jar报错
【报错详情】
Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.1.8.RELEASE:repackage failed: Unable to find main class -> [Help 1]
【解决办法】
1、将父pom中的下述打包组件移除,并将不需要执行jar模块pom文件移除如下组件
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
2、spring-boot空项目启动报错信息如下
【报错信息如下】
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
Process finished with exit code 1
【解决办法】
未配置数据库连接信息,配置数据库信息
三、spring-boot配置log4j2日志,基于@Slf4j 失效的问题。
【项目启动日志提示信息】
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/shangxiaofei/sxfwork/local/org/slf4j/slf4j-log4j12/1.7.2/slf4j-log4j12-1.7.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/shangxiaofei/sxfwork/local/org/apache/logging/log4j/log4j-slf4j-impl/2.11.2/log4j-slf4j-impl-2.11.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
【原因】
- 系统依赖多个日志实现方案,其中slf4j-log4j12是log4j的实现,log4j-slf4j-impl是log4j2的实现。
- slf4j是根据org/slf4j/impl/StaticLoggerBinder.class 这个类决定使用哪个logFactory的
【解决办法】
- 找出项目中那个jar依赖了slf4j-log4j12,并将其排除掉。
四、spring-boot项目配置不同环境使用不同配置文件
1、项目结构
2、在项目的pom.xml文件中配置profiles和resources
<!--配置各个环境的信息--> <profiles> <profile> <id>dev</id> <properties> <profiles.active>dev</profiles.active> </properties> <!--当执行项目打包时,未传递环境信息,则默认使用该配置--> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>pro</id> <properties> <profiles.active>pro</profiles.active> </properties> </profile> </profiles> <build> <resources> <resource> <directory>src/main/resources</directory> <!--项目打包需要将resources目录下的这些文件排除掉--> <excludes> <exclude>dev/*</exclude> <exclude>pro/*</exclude> </excludes> </resource> <resource> <!--将指定的配置文件移动到resources目录下--> <directory>src/main/resources/${profiles.active}</directory> </resource> </resources> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
3、项目打包时传递不同的环境参数,激活不同的配置文件
#激活dev环境 mvn -U clean install -Dmaven.test.skip=true #激活pro环境 mvn -U -P pro clean install -Dmaven.test.skip=true
4、配置加载文件
package com.spring.sxf.study.springtradeweb; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; @PropertySource(value = "classpath:env.properties", encoding="utf-8") @MapperScan("com.spring.sxf.study.springtradedao.mapper") @SpringBootApplication(scanBasePackages="com.spring.sxf") @ConfigurationProperties() public class SpringTradeWebApplication { public static void main(String[] args) { SpringApplication.run(SpringTradeWebApplication.class, args); } }
5、测试是否生效
@Slf4j @Controller @RequestMapping("/blog") public class BlogController { @Value("${env.envDesc}") private String envDesc; @Autowired private BlogService blogService; @RequestMapping("/env") @ResponseBody public String testEnv(){ log.info("current envDesc:{}",envDesc); return envDesc; } }