没有域名 有公网ip 建网站可以,网站推广找哪家公司好,wordpress标签页固定链接,wordpress 登录logo前言
最近一直在思考一个问题#xff0c;springboot的多模块项目到底是怎么运行和运作的#xff1f;
一般我们大部分的springboot项目都是单模块的项目#xff0c;但是如果后续有要求开发多模块的项目应该怎么处理#xff1f;于是基于这点进行了研究。
本次文章将会带大…前言
最近一直在思考一个问题springboot的多模块项目到底是怎么运行和运作的
一般我们大部分的springboot项目都是单模块的项目但是如果后续有要求开发多模块的项目应该怎么处理于是基于这点进行了研究。
本次文章将会带大家从头到尾搭建多模块项目讲解怎么去串接以及如何去运行
优缺点
️️️️️️️️️️️️️️️️ 多模块的项目一般也叫微服务项目微服务是一种架构模式或者说是一种架构风格,它提倡单一应用程序划分为一组小的服务,每个服务在其独立的自己的进程中,服务之间相互协调,互相配合,为用户提供最终价值 而我们的多模块的恰恰是这种思想 ️️️️️️️️️️️️️️️️ 优点 ❤️ 每个服务足够内聚足够小代码容易理解这样能聚焦一个指定的业务功能或业务需求 ❤️开发简单、开发效率提高一个服务可能就是专一的只干一件事 ❤️微服务是松耦合的是有功能意义的服务无论是在开发阶段或部署阶段都是独立的 以及其他… 缺点 开发人员要处理分布式系统的复杂性 多服务运维难度随着服务的增加运维的压力也在增大 维护分工合作困难
模块划分及依赖引用
模块划分
我的风格可能和别人不一样别人一上来就会教你步骤但是针对于这点我们首先得明确一点我们要搭建一个什么样的项目针对你要搭建的项目需要建立的模块也不一样
️️️️️ 以业务层划分为例也就是我们熟知的三层架构 也就是可以划分为数据库层web层和实现层对应可划分的框架明细如下 模块名称模块功能范围data实体类模块负责实体对象的构建config配置类模块负责springboot相关的基础配置dao数据库类模块负责数据库增删改查相关逻辑service业务实现类模块负责具体业务实现相关逻辑web项目启用类模块负责项目启用接口调用相关逻辑
️️️️️ 除了按照我们的三层架构的进行划分模块外我们也可以用我们具体的实际业务进行划分 举一个例子按照学校为例我们学校如果要记录数据可以按照这些进行划分
模块名称模块功能范围student学生信息类模块负责记录学生基本数据teacher老师信息类模块负责记录教师相关基本数据grade学生成绩类模块负责记录学生成绩数据 那么这里我只是简单的举一个例子那么为了演示方便本文章会按照三层架构的进行讲解 依赖引用
✏️✏️✏️✏️✏️
在正式搭建项目之前我们有一个比较重要的事情需要确认那就是我们的模块之间应该要怎么进行引用 因为这会涉及到一个问题那就是循环依赖 什么是循环依赖? 循环依赖即你A模块引入了B模块但是B模块也引入了A模块导致报错 循环依赖有什么影响? ✨第一点最重要会导致项目无法启动 ✨第二点如果前期不规划好怎么引入会导致出现一个问题假如有A,B,C三个模块你要在C模块开发逻辑但是需要引入A模块的代码目前的引入是A引入B和CB引入C因为C已经被A引入了但是C无法引入A如果强行引入会造成循环依赖但是假如你要在C拿到A的代码是无法拿到的因为没有引入对应模块无法调用对方的方法 感觉有点绕那么简单的说就是我们需要规范好怎么引入模块才能确保所有模块各司其职不会出现需要调用到对应的代码但是调用不到的情况 ✏️✏️✏️✏️✏️
按照我们的三层框架我们应该怎么引入? 首先config是配置应该是一个独立的模块其他模块可以依赖于它 data是一个实体类相关的那么它应该可以被任意的模块调用到 service 依赖于data,dao需要进行数据库的调用才能做到业务相关的逻辑 dao因为和数据库相关的进行交互而数据库连接相关逻辑一般会写在config所以dao依赖于config web是接口调用和启动相关的逻辑所以依赖于service 和config 模块 模块名称模块引入范围data无config无daodata, configservicedata,dao,servicewebconfig,service
✒️✒️✒️✒️✒️
搭建步骤
那么正式开始我们的搭建
首先我们选择新建项目 新建一个MAVEN项目填写项目名称组织等 PS: 我的IDEA为2024可能部分操作有些不一样但是建立的项目大差不差 初始项目搭建为如下 接下来把搭建的项目的src文件夹删掉只保留pom.xml 然后在该项目选择新建module NEW - Module.. 新建config模块 然后把config模块的Main的主入口文件删除 按照如上步骤把剩下的模块新建出来同样把Main入口删除,但是只保留web模块的Main入口文件 最终项目结构如下 这里为了方便标识我把web模块的Main修改为WebApplication 然后我们把父模块的pom.xml修改为如下: ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.hxc/groupIdartifactIdmultipleModuleDemo/artifactIdversion1.0-SNAPSHOT/versionpackagingpom/packagingnamemultipleModule/namedescription多module项目demo/descriptionmodulesmoduleconfig/modulemoduleweb/modulemoduledao/modulemoduleservice/modulemoduledata/module/modulespropertiesmaven.compiler.source8/maven.compiler.sourcemaven.compiler.target8/maven.compiler.targetproject.build.sourceEncodingUTF-8/project.build.sourceEncoding/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactIdversion2.6.2/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-jdbc/artifactIdversion2.6.2/version/dependencydependencygroupIdorg.junit.jupiter/groupIdartifactIdjunit-jupiter-api/artifactIdversion5.8.1/version !-- 根据需要调整版本 --scopetest/scope/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scopeversion2.6.2/version/dependencydependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.16.18/versionoptionaltrue/optional/dependency/dependencies/project 这里我引入了springboot相关的一些必要依赖后续可根据实际项目情况进行添加另外父模块的依赖是能够被子模块引入的有什么必要的也可以引入到父模块的pom或者新加一个common模块专门供其他子模块调用 config的pom.xml修改: ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.hxc/groupIdartifactIdmultipleModulesDemo/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdconfig/artifactIdnameconfig/nameversion1.0-SNAPSHOT/versiondescription配置模块/description/project data的pom.xml修改: ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.hxc/groupIdartifactIdmultipleModulesDemo/artifactIdversion1.0-SNAPSHOT/version/parentartifactIddata/artifactIdversion1.0-SNAPSHOT/versionnamedata/namedescription数据实体模块/description/projectdao的pom.xml ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.hxc/groupIdartifactIdmultipleModulesDemo/artifactIdversion1.0-SNAPSHOT/version/parentartifactIddao/artifactIdversion1.0-SNAPSHOT/versionnamedao/namedescription数据库/descriptiondependenciesdependencygroupIdcom.hxc/groupIdartifactIddata/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.hxc/groupIdartifactIdconfig/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.28/version/dependency/dependencies/projectservice的pom.xml修改: ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.hxc/groupIdartifactIdmultipleModulesDemo/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdservice/artifactIdversion1.0-SNAPSHOT/versionnameservice/namedescription逻辑层/descriptiondependenciesdependencygroupIdcom.hxc/groupIdartifactIddao/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.hxc/groupIdartifactIddata/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.hxc/groupIdartifactIdconfig/artifactIdversion1.0-SNAPSHOT/version/dependency/dependencies/projectweb的pom.xml修改: ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdcom.hxc/groupIdartifactIdmultipleModulesDemo/artifactIdversion1.0-SNAPSHOT/version/parentartifactIdweb/artifactIddependenciesdependencygroupIdcom.hxc/groupIdartifactIdconfig/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdcom.hxc/groupIdartifactIdservice/artifactIdversion1.0-SNAPSHOT/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdversion2.6.2/version/dependency/dependencies/project 那么为了能够正常的搭建一个可以启用的多模块项目我这里补充一个逻辑代码实现查询和新增接口正常调用和项目启动 在数据库新建一个用户表userData建表语句如下 CREATE TABLE userData (user_id varchar(100) NOT NULL COMMENT userId,nick_name varchar(100) NULL COMMENT 名称,sex varchar(10) NULL COMMENT 性别,age INT NULL COMMENT 年龄,CONSTRAINT userData_pk PRIMARY KEY (user_id)
)
ENGINEInnoDB
DEFAULT CHARSETutf8mb4
COLLATEutf8mb4_unicode_ci;在data模块新建一个实体UserData import lombok.Getter;
import lombok.Setter;
import lombok.ToString;Getter
Setter
ToString
public class UserData {private String userId;private String nickName;private String sex;private Integer age;
} 在dao模块新建一个jdbc数据库查询代码UserDataDao import com.hxc.user.UserData;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class UserDataDao {private static final String SQL_INS INSERT INTO userdata(user_id,nick_name,sex,age) VALUES (?,?,?,?);private static final String SQL_UPD UPDATE userdata SET nick_name?,sex?,age? WHERE userid?;private static final String SQL_SEL SELECT user_id,nick_name,sex,age FROM userdata ;private static final String SQL_DEL DELETE FROM userdata WHERE user_id ?;private final Connection conn;public UserDataDao(Connection conn) {this.conn conn;}public int insert(UserData data) {try (PreparedStatement ps this.conn.prepareStatement(SQL_INS)) {ps.setString(1, data.getUserId());ps.setString(2, data.getNickName());ps.setString(3, data.getSex());ps.setInt(4, data.getAge());return ps.executeUpdate();} catch (SQLException e) {throw new IllegalStateException(数据库查询错误, e.getMessage(), e);}}public int update(UserData data) {try (PreparedStatement ps this.conn.prepareStatement(SQL_UPD)) {ps.setString(1, data.getNickName());ps.setString(2, data.getSex());ps.setInt(3, data.getAge());ps.setString(4, data.getUserId());return ps.executeUpdate();} catch (SQLException e) {throw new IllegalStateException(数据库查询错误, e.getMessage(), e);}}public int delete(String userId) {try (PreparedStatement ps this.conn.prepareStatement(SQL_DEL)) {ps.setString(1, userId);return ps.executeUpdate();} catch (SQLException e) {throw new IllegalStateException(数据库查询错误, e.getMessage(), e);}}public ListUserData selectAll() {ArrayListUserData result new ArrayListUserData();try (PreparedStatement ps this.conn.prepareStatement(SQL_SEL)) {ResultSet rs ps.executeQuery();while (rs.next()) {result.add(convert(rs));}return result;} catch (SQLException e) {throw new IllegalStateException(数据库查询错误, e.getMessage(), e);}}public UserData selectByUserId(String userId) throws SQLException {UserData result null;try (PreparedStatement ps conn.prepareStatement(SQL_SEL WHERE user_id ?)) {ps.setString(1, userId);ResultSet rs ps.executeQuery();if (rs.next()) {result convert(rs);}return result;} catch (SQLException e) {throw new SQLException(e.getMessage());}}private UserData convert(ResultSet rs) throws SQLException {UserData data new UserData();int index 1;data.setUserId(rs.getString(index));data.setNickName(rs.getString(index));data.setSex(rs.getString(index));data.setAge(rs.getInt(index));return data;}
} 在config模块新建一个数据库连接配置DataSourceConfig和数据库连接实现类PrimeDB import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;/*** 数据库配置* */
Configuration
public class DataSourceConfig {Value(${spring.datasource.prime-data.driver-class-name})private String primeDataDriver;Value(${spring.datasource.prime-data.url})private String primeDataUrl;Value(${spring.datasource.prime-data.username})private String primeDataUsername;Value(${spring.datasource.prime-data.password})private String primeDataPassword;Beanpublic DriverManagerDataSource primeDataSource() {DriverManagerDataSource dataSource new DriverManagerDataSource();dataSource.setDriverClassName(primeDataDriver);dataSource.setUrl(primeDataUrl);dataSource.setUsername(primeDataUsername);dataSource.setPassword(primeDataPassword);return dataSource;}// 配置其他数据库连接待定占位Beanpublic DriverManagerDataSource otherDataSource() {DriverManagerDataSource dataSource new DriverManagerDataSource();dataSource.setDriverClassName(primeDataDriver);dataSource.setUrl(primeDataUrl);dataSource.setUsername(primeDataUsername);dataSource.setPassword(primeDataPassword);return dataSource;}
}import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;Component
public class PrimeDB {private final DataSource primeDataSource;Autowiredpublic PrimeDB(Qualifier(primeDataSource)DataSource primeDataSource) {this.primeDataSource primeDataSource;}public Connection create() throws SQLException {Connection connection null;try {connection primeDataSource.getConnection();return connection;} catch (SQLException e) {// 处理连接获取失败的异常情况throw new RuntimeException(连接数据库失败, e);}}
}那么为了可以实现测试类正常调用可在config的resource下建立一个application.yml为数据库连接配置但是为了正常启用项目需要在web模块的resource新建一个application.yml
如下为config的resource下建立一个application.yml
spring:application:name: multipleModuleBackdatasource:prime-data:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/primeData?useUnicodetruecharacterEncodingUTF-8useServerPrepStmtsfalserewriteBatchedStatementstrueuseCompressionfalseuseSSLfalseusername: rootpassword: root在我们的service模块新建一个UserService import com.hxc.dao.UserDataDao;
import com.hxc.user.UserData;
import java.sql.Connection;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;Service
public class UserService {public UserData findUser(Connection conn, String userId) throws Exception {try {UserDataDao userDataDao new UserDataDao(conn);UserData userData userDataDao.selectByUserId(userId);if (null userData) {throw new Exception(查无用户: userId);}return userData;} catch (Exception e) {throw new Exception(获取用户失败: e);}}public String insertUser(Connection conn, UserData userData) throws Exception {try {UserDataDao userDataDao new UserDataDao(conn);if (!StringUtils.hasText(userData.getUserId())) {throw new Exception(用户id不能为空!);}if (!StringUtils.hasText(userData.getNickName())) {throw new Exception(用户名称不能为空!);}UserData record userDataDao.selectByUserId(userData.getUserId());if (null ! record) {throw new Exception(用户: userData.getUserId() 已存在);}userDataDao.insert(userData);return 新增成功!;} catch (Exception e) {throw new Exception(新增用户失败: e);}}
}在web模块下建立一个接口调用文件UserWebServicer import com.hxc.configs.db.PrimeDB;
import com.hxc.user.UserData;
import java.sql.Connection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;RestController
RequestMapping(/user)
public class UserWebServicer {Autowiredprivate PrimeDB primeDB;GetMapping(/findUser)public UserData findUser(RequestParam(userId) String userId) throws Exception {System.out.println(Received request with userId: userId);try (Connection conn primeDB.create()) {return new UserService().findUser(conn, userId);} catch (Exception e) {throw new Exception(e);}}PostMapping(/insertUser)public String sendMessage(RequestBody UserData userData) throws Exception {try (Connection conn primeDB.create()) {return new UserService().insertUser(conn, userData);} catch (Exception e) {throw new Exception(e);}}
}
同时把webApplication的代码修改为
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
public class WebApplication {public static void main(String[] args) {System.out.println(多模块项目启动主入口);SpringApplication.run(WebApplication.class, args);}
}然后在web模块的resource下新建一个application.yml
server:port: 8082servlet:context-path: /multipleModulespring:application:name: multipleModuleBackdatasource:prime-data:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/primeData?useUnicodetruecharacterEncodingUTF-8useServerPrepStmtsfalserewriteBatchedStatementstrueuseCompressionfalseuseSSLfalseusername: rootpassword: root
这个时候我们就可以右键WebApplication启动我们的项目了 现在我的数据该表的数据有如下: 调用我的查询接口结果如下: 我们的项目正常运行
重要信息
以此我们的项目就正式搭建好了后续我们这个项目的调用情况是在data模块进行建立实体我们的dao模块调用data模块的实体和config的数据库连接进行数据库的增删改查然后我们的service模块进行业务逻辑的开发在web编写接口调用我们的业务逻辑按照这个顺序执行就能够正常的运行我们的项目不会出现循环依赖问题后续如果有新加别的模块也是按照这个思路进行添加
git项目demo
如下为本次教学的项目demo链接,可进行参考 SPRINGBOOT 多模块项目DEMO
结语
以上为springboot搭建多模块的方法和步骤如有遗漏将在本文章补充