关于搭建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  (父工程)

分布式架构开源项目 分布式项目架构设计_SpringCloud _02

  • sp-common(子工程)

分布式架构开源项目 分布式项目架构设计_分布式架构开源项目_03

  • sp-feign-api(子工程)

分布式架构开源项目 分布式项目架构设计_SpringBoot_04

  • sp-eureka-reg-center(子工程)

分布式架构开源项目 分布式项目架构设计_分布式架构开源项目_05

  • sp-portal-provider(子工程)

分布式架构开源项目 分布式项目架构设计_SpringCloud _06

  • sp-portal-consumer(子工程)

分布式架构开源项目 分布式项目架构设计_分布式架构_07

  • sp-manager-provider(子工程)

分布式架构开源项目 分布式项目架构设计_分布式架构_08

  • sp-manager-consumer(子工程)

分布式架构开源项目 分布式项目架构设计_分布式架构_09

  • sp-activiti-provider(子工程)

分布式架构开源项目 分布式项目架构设计_框架_10

以上工程,除了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

分布式架构开源项目 分布式项目架构设计_框架_11

使用工程注意事项:

  • 修改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添加到项目中,具体位置如下图:

分布式架构开源项目 分布式项目架构设计_分布式架构开源项目_12

五、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.  存放目录

分布式架构开源项目 分布式项目架构设计_SpringBoot_13

分布式架构开源项目 分布式项目架构设计_SpringCloud _14

2. 路径问题

static目录下的文件,部署到服务器上后会放在Web应用的根目录下,所以页面上路径根据是否配置了server.context-path,有两种情况:

  • 配置了server.context-path

/contextPath/xxx/xxx

  • 没有配置server.context-path

/xxx/xxx

十 、  Maven的依赖原则

 

分布式架构开源项目 分布式项目架构设计_分布式架构_15

 

当根据依赖的传递性会在同一个工程中引入同一个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>