关于搭建springcloud + springboot 的分布式项目框架
一 、 整体架构设计,如下:
具体划分为:
1. 前台用户功能:
portal - provider 服务提供者
portal - consumer 服务消费者
2. 后台管理功能:
manager-provider 服务提供者
manager-consumer 服务消费者
3. 注册中心模块
eureka-server-reg-center
4. 远程接口提供者
feign-api
5. 实体类 及 通用功能
common
6. 流程服务提供者
activiti - provider
二 、聚合工程与子工程搭建
1 、 工程清单 :
- sp-parent (父工程)
- sp-common(子工程)
- sp-feign-api(子工程)
- sp-eureka-reg-center(子工程)
- sp-portal-provider(子工程)
- sp-portal-consumer(子工程)
- sp-manager-provider(子工程)
- sp-manager-consumer(子工程)
- sp-activiti-provider(子工程)
以上工程,除了sp-parent 是 pom 工程外,其他的都是 jar 工程
2 、工程依赖关系建立
根据架构图的内容进行依赖关系的配置
3 、项目基础设定
3.1 包名 (基于主启动类的自动包扫描,所以要对包名进行规范的定义)
主启动类所在包:com.webcode.sp
实体类:com.webcode.sp.entities
工具类:com.webcode.sp.utils
Mapper接口:com.webcode.sp.mapper
Service接口:com.webcode.sp.service
Service实现类:com.webcode.sp.service.impl
Controller类:com.webcode.sp.controller
工厂类:com.webcode.sp.factory
3.2 端口号
- sp-parent
不需要
- sp-common
不需要
- sp-feign-api
不需要
- sp-eureka-reg-center
10000
- sp-portal-provider
10001
- sp-manager-provider
10002
- sp-activiti-provider
10003
- sp-protal-consumer
80
- sp-manager-consumer
10004
三 、 t_user 表结构分析与数据库表建立
字段作用 字段名称 字段类型 字段长度
主键 member_id int
登录账号 login_acc varchar 100
登录密码 login_pwd varchar 100
欢迎信息中显示的昵称 nick_name varchar 100
真实姓名 real_name varchar 100
身份证号 card_num varchar 100
手机号 phone_num varchar 20
Email地址 email_addr varchar 100
账户类型 acc_type tinyint
备用字段1 extral_field_a varchar 300
备用字段2 extral_field_b varchar 300
备用字段3 extral_field_c varchar 300
备用字段4 extral_field_d varchar 300
CREATE TABLE `t_user` (
`member_id` int NOT NULL AUTO_INCREMENT ,
`login_acc` varchar(100) NULL ,
`login_pwd` varchar(100) NULL ,
`nick_name` varchar(100) NULL ,
`real_name` varchar(100) NULL ,
`card_num` varchar(100) NULL ,
`phone_num` varchar(20) NULL ,
`email_addr` varchar(100) NULL ,
`acc_type` tinyint NULL ,
`extral_field_a` varchar(300) NULL ,
`extral_field_b` varchar(300) NULL ,
`extral_field_c` varchar(300) NULL ,
`extral_field_d` varchar(300) NULL ,
PRIMARY KEY (`member_id`)
)
四、Mapper及实体类Bean的创建
使用 逆向工程生成对应的实体类、mapper
使用工程注意事项:
- 修改mbg.xml中的 23行,也就是所要生成的数据库实体类所对应的数据库的URL地址
- 再修改64行的 tableName 表名 及对应的 domainObjectName 实体类Bean的名称
- 如果不止生成一个实体类,只需要复制<table>列并修改对应的参数即可。
- 执行生成逆向工程数据:
- 启动com.webcode.main中的Runner.java中的main方法即可
逆向工程工具包百度云链接地址:
链接:https://pan.baidu.com/s/1XkGJ7WVNgtZ6xdnRaMpnQA
提取码:4tch
将生成的BEAN和Mapper.java、Mapper.xml添加到项目中,具体位置如下图:
五、Service 及其实现类 ServiceImpl 及Controller层的创建
根据 项目基础设定创建 Service 、 ServiceImpl对应的包名,并创建UserService 、 UserServiceImpl 类
UserService 中创建 CURD 基本的单表操作,在UserServiceImpl中实现UserServcie接口的方法,并调用UserMapper的实例bean注入进来,对CURD 调用对应的Mapper层CURD操作。
注意: 为了便于排错 , 在 UserService中的CURD方法名要与Mapper中的区别开来 :
示例:
- UserService : get 、save 、 update、 remove
- UserMapper : select 、 insert 、update 、 delete
根据项目基础设定创建 Controller层,并创建 UserController.java ,并调用 UserService 业务功能
六 、加入SpringCloud环境
1. sp-parent
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2. sp-portal-provider工程
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 加入Eureka客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.webcode.sp.springcloud</groupId>
<artifactId>sp-feign-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
将provider 中的parent 版本修改为父工程的 sp-parent 版本,并添加对其他模块 的依赖
<parent> <groupId>com.webcode.sp.springcloud</groupId> <artifactId>sp-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
七 、主启动类与实务配置
1. 创建 主启动类 :
@SpringBootApplication
@EnableEurekaClient
@MapperScan("com.webcode.sp.mapper")
@EnableTransactionManagement
public class PortalProviderMainType {
public static void main(String[] args) {
SpringApplication.run(PortalProviderMainType.class, args);
}
}
2 . 为项目配置事务管理
在主启动类添加 @EnableTransactionManagement 注解,以引入SpringBoot的事务
在 UserServiceImpl 的方法上添加 @Transactional(readOnly = true) 注解,将当前实现类加入到事务中管理
在 需要进行事务管理的 方法 前添加 @Transactional(readOnly=false,rollbackFor=Exception.class,propagation=Propagation.REQUIRES_NEW)
注解,当前注解为: readOnly = false 等于 “不仅仅是只读,可写”
rollbackFor=Exception.class 是对异常情况进行回滚,propagation=Propagation.REQUIRES_NEW 是指事务的传播特性,当前给定的传播特性为:每一个当前的方法被其他包的类调用时,或者被本类中的其他方法调用时,都会开启一个新的事务。
3 . Controller类
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/portal/provider/user/{id}")
public ResultEntity<User> getUserById(@PathVariable("id") Integer id ){
User user = userService.getById(id);
return new ResultEntity<User>(ResultEntity.SUCCES,ResultEntity.NO_MSG,user);
}
}
- 创建ResultEntity工具类,将Controller层方法,进行统一异常处理,如没有异常,成功的请求根据情况对后台数据进行封装,并返回给前端页面。
- 为了减少代码量,为当前项目添加 lombok 来优雅编码
- Lombok 插件安装:
ResultEntity 效果:
@Data
public class ResultEntity<T> {
public static final String SUCCES= "SUCCESS"; //成功回调函数
public static final String FAILED= "FAILED"; //失败回调函数
public static final String NO_MSG= "NO_MSG"; //默认成功,没有异常
public static final String NO_DATA= "NO_DATA"; //没有数据返回
//响应结果: 可选值只有SUCCESS和FAILED
private String result;
//在响应结果为FAILED 是的提示消息
private String message = NO_MSG;
//在响应结果为SUCCESS时返回的数据
private T data;
public ResultEntity(String result, String message, T data) {
super();
this.result = result;
this.message = message;
this.data = data;
}
}
4. yml配置文件
server:
port: 10001 #配置当前服务的端口号
spring:
application:
name: PortalProvider # 配置的是这个微服务的名字,将来在注册中心中显示的和消费端引用的都是这个名字。
datasource: # 配置数据源
name: druid-source #配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this)
type: com.alibaba.druid.pool.DruidDataSource # 配置的数据源类型,这里是阿里的数据源
driver-class-name: org.gjt.mm.mysql.Driver #根据url自动识别,这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下)
url: jdbc:mysql://127.0.0.1:3306/springdemo?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8 #连接数据库的url,不同数据库不一样。
username: root #连接数据库的用户名
password: root #连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
dbcp:
min-idle: 5 #最小连接池数量
initial-size: 5 #初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
max-total: 5 # 最大连接池数量
max-wait-millis: 200 # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
mybatis:
mapper-locations:
- classpath:mappers/*Mapper.xml #配置扫描的 *Mapper.xml文件地址
eureka:
client:
service-url:
defaultZone: http://localhost:10000/eureka # 指定客户端访问Eureka服务端的URL地址
#DRUID连接池的使用 配置详情 :
八 、 注册中心 sp - eureka-reg-center 配置
1. 依赖添加:
<dependencies>
<!-- eureka-server服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
将provider 中的parent 版本修改为父工程的 sp-parent 版本,并添加热部署
<parent> <groupId>com.webcode.sp.springcloud</groupId> <artifactId>sp-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
2. 主启动类创建
@SpringBootApplication
@EnableEurekaServer //把当前微服务标记为Eureka注册中心,接受其他微服务的注册
public class EurekaRegCentMainType {
public static void main(String[] args) {
SpringApplication.run(EurekaRegCentMainType.class, args);
}
}
3.yml 配置文件
server:
port: 10000
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka #指定客户端访问Eureka服务端的URL地址
九 、 静态资源
1. 存放目录
2. 路径问题
static目录下的文件,部署到服务器上后会放在Web应用的根目录下,所以页面上路径根据是否配置了server.context-path,有两种情况:
- 配置了server.context-path
/contextPath/xxx/xxx
- 没有配置server.context-path
/xxx/xxx
十 、 Maven的依赖原则
当根据依赖的传递性会在同一个工程中引入同一个jar包的不同版本时,Maven参照下面两个原则:
①路径最短者优先
②路径相同时,先声明者优先
解决jar包冲突的另外一个办法
<!-- Activiti场景启动器 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>5.21.0</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>