- 参考
- 开发环境
- 测试表-t_rbt_test
- 组件引用说明
- 项目源代码
- 创建父模块-test-invoice-cloud
- 创建子模块-test-invoice-eureka
- 创建子模块-test-invoice-common
- 创建子模块-test-invoice-contract
- 创建子模块-test-invoice-service
- 创建子模块-test-invoice-web
- 项目开发过程中遇到的问题及解决
- 项目总类图
- 项目总结构图
- 扩展-负载均衡
- 项目调用关系图
参考
开发环境
| 名称 | 版本 |
|---|---|
| 操作系统 | Windows 10 X64 |
| JDK | JDK1.8(jdk-8u151-windows-x64) |
| IntelliJ IDEA | IntelliJ IDEA 2018.3 |
| Maven | Maven 3.6.0 |
测试表-t_rbt_test
位于本地 MySql 数据库 luoma_test 下
SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for t_rbt_test-- ----------------------------DROP TABLE IF EXISTS `t_rbt_test`;CREATE TABLE `t_rbt_test` (`id` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL COMMENT '主键',`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '名称',`version` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '版本号',`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '创建人',`create_time` timestamp(0) NULL DEFAULT NULL COMMENT '创建时间',`update_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '修改人',`update_time` timestamp(0) NULL DEFAULT NULL COMMENT '修改时间',`is_delete` int(1) NULL DEFAULT NULL COMMENT '是否删除',`biz_time` timestamp(0) NULL DEFAULT NULL COMMENT '系统时间戳',PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
组件引用说明
由于篇幅有限,加上侧重点的问题。本文中引用的组件请参考
项目源代码
见附件
创建父模块-test-invoice-cloud
文件-New-项目
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
依次补全下面的信息,点击 下一个
| 节点 | 描述 |
|---|---|
| groupId | 代表组织和整个项目的唯一标志,是项目组织唯一的知标识符,实际对应 JAVA 的包的结构 |
| artifactId | 项目的唯一的标识符,实际对应项目的名称 |
| version | 用于说明目前项目的版本 |
输入项目名称 test-invoice-cloud ,我们主要是在这个项目下创建我们的子模块
这样我们就创建好了一个普通项目,因为该项目是作为一个解决方案存在的,可以直接删除 src 文件夹
创建好的项目如下
项目文件名称及含义
| 目录/文件 | 含义 |
|---|---|
| .idea | 创建项目的时候自动创建一个 .idea 的项目配置目录来保存项目的配置信息。这是默认选项。 子目录包含一系列XML文件,包括:compiler.xml、encodings.xml、modules.xml等。这些文件记录工程本身的核心信息,包括:模块组件的名称和位置、编译器设置等,可以存放到VCS。一个例外是workspace.xml,该文件存储个人设置(例如窗口位置)以及其它附属于开发环境的信息,不应该存放到VCS |
| pom.xml | Maven 项目配置文件。POM( Project Object Model,项目对象模型 ) 是 Maven 工程的基本工作单元,是一个XML文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。执行任务或目标时,Maven 会在当前目录中查找 POM。它读取 POM,获取所需的配置信息,然后执行目标。 |
| .iml | 模块是工程中一个可以独立编译、运行、调试、测试的单元。模块的配置信息默认存放在其内容根目录(Content root folder)下的 .iml 文件中,该文件一般存放到VCS。 |
设置 Maven 引用地址
注意,这里的设置是必须的。相关组件的下载就需要这里的配置。
pom.xml
<?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"><!--父级:Spring Boot--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><!--<version>2.0.1.RELEASE</version>--><!--<version>2.0.3.RELEASE</version>--><!--解决循环引用对象问题mybatis https://github.com/heikehuan/springboot-multiple-dataSources/issues/2--><version>2.0.9.RELEASE</version></parent><modelVersion>4.0.0</modelVersion><groupId>com-test-invoice</groupId><artifactId>test-invoice-cloud</artifactId><version>1.0-SNAPSHOT</version><name>test-invoice-cloud</name><packaging>pom</packaging><modules><module>test-invoice-common</module><module>test-invoice-contract</module><module>test-invoice-service</module><module>test-invoice-web</module><module>test-invoice-eureka</module></modules><properties><springCloud.version>Finchley.RELEASE</springCloud.version><fastjson.version>1.2.38</fastjson.version><swagger.version>2.7.0</swagger.version><lombok.version>1.18.6</lombok.version><HikariCP.version>3.3.1</HikariCP.version><mybatis-plus-spring-boot-starter.version>3.1.0</mybatis-plus-spring-boot-starter.version><swagger-ui.version>2.7.0</swagger-ui.version></properties><!--Spring Cloud 版本序列配置--><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${springCloud.version}</version><type>pom</type><scope>import</scope><exclusions><exclusion><groupId>redis.clients</groupId><artifactId>jedis</artifactId></exclusion></exclusions></dependency></dependencies></dependencyManagement><dependencies><!--Spring Boot 执行器组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--Spring Cloud 基础--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter</artifactId></dependency><!--Spring Cloud 服务注册组件--><dependency><groupId>org.springframework.cloud</groupId><!--此处的依赖是SpringBoot2.0以后专用的,如果您使用的SpringBoot版本低于2.0请使用spring-cloud-starter-eureka-server--><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><!--Spring Boot 测试组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Spring Boot Web组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 从依赖信息里移除 Tomcat配置 --><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!-- 参数校验信息 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><!-- 添加 Undertow依赖 start--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency><!-- 添加 Undertow依赖 end--><!-- spring aop start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- spring aop end --><!--lombok start--><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><!--lombok end--><!--fastJson start--><!--Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--fastJson end--><!--swagger start--><!--springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful API,swagger主要用于展示springfox生成的API文档--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${swagger.version}</version></dependency><!--swagger end--></dependencies><!--注意:这里必须要添加,否则各种依赖有问题--><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/libs-milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories><build><plugins><plugin><!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 --><source>1.8</source> <!-- 源代码使用的JDK版本 --><target>1.8</target> <!-- 需要生成的目标class文件的编译版本 --><encoding>UTF-8</encoding><!-- 字符集编码 --><!--<skipTests>true</skipTests><!– 跳过测试 –><verbose>true</verbose><showWarnings>true</showWarnings><fork>true</fork><!– 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 –><executable><!– path-to-javac –></executable><!– 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> –><compilerVersion>1.3</compilerVersion><!– 指定插件将使用的编译器的版本 –><meminitial>128m</meminitial><!– 编译器使用的初始内存 –><maxmem>512m</maxmem><!– 编译器使用的最大内存 –><compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>--><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 --></configuration></plugin><plugin><groupId>org.sonarsource.scanner.maven</groupId><artifactId>sonar-maven-plugin</artifactId><version>3.5.0.1254</version></plugin></plugins></build></project>
创建子模块-test-invoice-eureka
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-eureka
模块名称 test-invoice-eureka
创建类和文件
模块简介
这个模块对应的是 Eureka Server
Eureka Server 提供服务注册服务,各个节点启动后,会在 Eureka Server 中进行注册,这样 EurekaServer 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
这里只是作为项目中的一个模块,详细的了解可参考下面的内容
pom.xml
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-eureka</artifactId><name>test-invoice-eureka</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-netflix-eureka-server</artifactId><version>2.0.0.M7</version><scope>compile</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins><resources><resource><directory>src/main/resources</directory><includes><include>**/*</include></includes></resource></resources></build></project>
yml
application.yml
spring:# 节点1的标签profiles:active: devactiviti:check-process-definitions: false #校验流程文件,默认校验resources下的processes文件夹里的流程文件# 服务名保持一致application:name: eureka-ha
application-dev.yml
server:port: 8772# 配置Eureka Server 信息eureka:client:# 表示是否将自己注册到Eureka Server,不进行注册(当服务注册中心是单点而非高可用时的配置方式)registerWithEureka: false# 表示是否从Eureka Server获取注册信息,不获取注册信息(当服务注册中心是单点而非高可用时的配置方式)fetchRegistry: false#设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。默认是http://localhost:8761/eureka ;多个地址可使用 , 分隔service-url:defaultZone: http://localhost:${server.port}/eureka/# 自定义实例编号instance:instance-id: ${spring.application.name}:${server.port}# 配置使用主机名注册服务#hostname: peer1# 优先使用IP地址方式进行注册服务prefer-ip-address: true# 配置使用指定IPip-address: 127.0.0.1
入口类-EurekaHaApplication
package com.test.eurekaha;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;/*** EurekaHaApplication** @author:* @version:* @date: 2019-08-13 15:26*///排除掉数据库配置项目@SpringBootApplication( exclude = {DataSourceAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class,RedisAutoConfiguration.class,RedisRepositoriesAutoConfiguration.class})@EnableEurekaServerpublic class EurekaHaApplication {public static void main(String[] args) {SpringApplication.run(EurekaHaApplication.class, args);}}
测试
创建成功后,启动项目,访问 http://localhost:8772/
创建子模块-test-invoice-common
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-common
模块名称 test-invoice-common
模块简介
test-invoice-common 这个模块主要是创建一些公共类,实体提供给其它模块使用
新建测试类-TRbtTestData
新建包 com.test.invoice
再新建类 TRbtTestData
属性私有,行为公有
所以这里我们把属性设置为 private,通过 get 和 set 来获取设置值
package com.test.invoice.data;import com.alibaba.fastjson.annotation.JSONField;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.experimental.Accessors;@Data@Accessors(chain = true)public class TRbtTestData {@ApiModelProperty("名称")@JSONField(name = "name")private String name;@ApiModelProperty("版本号")@JSONField(name = "version")private String version;}
这个类引入了很多包,需要在 pom.xml 引入
父模块 pom.xml 引入包子模块 pom.xml 无法解析问题
问题描述
TRbtTestData 类需要引入一些包,我们再最外层 test-invoice-cloud 的 pom.xml 中引入包
这个 pom.xml 中使用到了自定义变量,可以参考
<?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"><!--父级:Spring Boot--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><!--<version>2.0.1.RELEASE</version>--><!--<version>2.0.3.RELEASE</version>--><!--解决循环引用对象问题mybatis https://github.com/heikehuan/springboot-multiple-dataSources/issues/2--><version>2.0.9.RELEASE</version></parent><modelVersion>4.0.0</modelVersion><groupId>com-test-invoice</groupId><artifactId>test-invoice-cloud</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><name>test-invoice-cloud</name><modules><module>test-invoice-common</module></modules><properties><fastjson.version>1.2.38</fastjson.version><swagger.version>2.7.0</swagger.version><lombok.version>1.18.6</lombok.version></properties><dependencies><!--Spring Boot 执行器组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--Spring Cloud 基础--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter</artifactId></dependency><!--Spring Cloud 服务注册组件--><dependency><groupId>org.springframework.cloud</groupId><!--此处的依赖是SpringBoot2.0以后专用的,如果您使用的SpringBoot版本低于2.0请使用spring-cloud-starter-eureka-server--><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><!--Spring Boot 测试组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Spring Boot Web组件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 从依赖信息里移除 Tomcat配置 --><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><!-- spring aop start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- spring aop end --><!--fastJson start--><!--Fastjson是一个Java语言编写的高性能功能完善的JSON库。它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!--fastJson end--><!--swagger start--><!--springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful API,swagger主要用于展示springfox生成的API文档--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${swagger.version}</version></dependency><!--swagger end--><!--lombok start--><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><!--lombok end--></dependencies></project>
test-invoice-common 的 pom.xml 中不引入,因为是父子模块,子模块就不用再引用了
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-common</artifactId><name>test-invoice-common</name></project>
构建,报下面的错误
程序包 xx 不存在
问题解决
原因是子模块没有引入对应包内容
打开右边的 Maven 选项卡,发现 test-invoice-common 没有 Dependencies 内容
在 test-invoice-common 的 pom.xml 中加入下面的内容
<properties><mybatisplus.version>3.1.0</mybatisplus.version></properties><dependencies><!--MyBatis-Plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatisplus.version}</version></dependency></dependencies>
完整 pom.xml
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-common</artifactId><name>test-invoice-common</name><properties><mybatisplus.version>3.1.0</mybatisplus.version></properties><dependencies><!--MyBatis-Plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatisplus.version}</version></dependency></dependencies></project>
重新导入
导入成功后重新构建项目,成功
打开右边的 Maven 选项卡,Dependencies 内容出现
问题原因
去掉 在 test-invoice-common 的 pom.xml 中的内容
<properties><mybatisplus.version>3.1.0</mybatisplus.version></properties><dependencies><!--MyBatis-Plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatisplus.version}</version></dependency></dependencies>
重新构建项目,也成功。
说明这个问题的原因是 IDE 不够智能引起的,有时候会加载不到对应的包引用,需要再重新构建才可以。
创建下图中的类和文件
类图
pom.xml
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-common</artifactId><name>test-invoice-common</name><properties><mybatisplus.version>3.1.0</mybatisplus.version></properties><dependencies><!--MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>${mybatisplus.version}</version></dependency><!--Dozer是一个JavaBean映射工具库。它支持简单的属性映射,复杂类型映射,双向映射,隐式显式的映射,以及递归映射--><dependency><groupId>com.github.dozermapper</groupId><artifactId>dozer-core</artifactId><version>6.1.0</version></dependency><!--JUnit 是一个Java编程语言的单元测试框架--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><!--bouncy castle(轻量级密码术包)是一种用于 Java 平台的开放源码的轻量级密码术包;它支持大量的密码术算法,并提供JCE 1.2.1的实现--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.55</version></dependency><!--密码加密框架--><dependency><groupId>com.madgag.spongycastle</groupId><artifactId>core</artifactId><version>1.54.0.0</version></dependency></dependencies></project>
基础实体类-SuperEntity
package com.test.invoice.model.base;import com.baomidou.mybatisplus.annotation.FieldFill;import com.baomidou.mybatisplus.annotation.IdType;import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableId;import com.baomidou.mybatisplus.extension.activerecord.Model;import com.fasterxml.jackson.annotation.JsonFormat;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;import java.io.Serializable;import java.util.Date;/*** 基础实体类** @author:* @version:* @date: 2019-08-09 14:26*/@EqualsAndHashCode(callSuper = true)@Data@Accessors(chain = true)public class SuperEntity<T extends Model> extends Model<T> {@TableId(type = IdType.UUID)@ApiModelProperty(value = "主键")private String id;@ApiModelProperty(value="创建时间",hidden = true)@TableField(value="create_time",fill = FieldFill.INSERT)@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)@ApiModelProperty(value = "修改时间", hidden = true)@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;@ApiModelProperty(value = "创建人", hidden = true)@TableField(value = "create_by", fill = FieldFill.INSERT)private String createBy;@ApiModelProperty(value = "修改人", hidden = true)@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)private String updateBy;@ApiModelProperty(value = "是否删除(0:未删除;1:已删除)", hidden = true)@TableField(value = "is_delete", fill = FieldFill.INSERT)private Integer isDelete;@ApiModelProperty(value = "系统时间戳", hidden = true)@TableField(value = "biz_time", fill = FieldFill.INSERT_UPDATE)@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")private Date bizTime;@Overrideprotected Serializable pkVal() { return this.id; }}
t_rbt_test 表对应实体类-TRbtTestEntity
package com.test.invoice.model;import com.baomidou.mybatisplus.annotation.TableName;import com.test.invoice.model.base.SuperEntity;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.ToString;import lombok.experimental.Accessors;/*** t_rbt_test 表对应实体类-TRbtTestEntity** @author:* @version:* @date: 2019-08-09 14:25*/@Data@EqualsAndHashCode(callSuper = true)@Accessors(chain = true)@ToString@TableName("t_rbt_test")public class TRbtTestEntity extends SuperEntity {@ApiModelProperty("名称")private String name;@ApiModelProperty("版本号")private String version;}
TRbtTestData 参数类
package com.test.invoice.data;import com.alibaba.fastjson.annotation.JSONField;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.experimental.Accessors;/*** TRbtTestData 参数类** @author:* @version:* @date: 2019-08-09 08:57*/@Data@Accessors(chain = true) //@Accessors 注解用来配置lombok如何产生和显示getters和setters的方法。public class TRbtTestData {@ApiModelProperty("id")@JSONField(name = "id")private String id;@ApiModelProperty("名称")@JSONField(name = "name")private String name;@ApiModelProperty("版本号")@JSONField(name = "version")private String version;}
TRbtTestData 分页对象类
package com.test.invoice.data;import com.alibaba.fastjson.annotation.JSONField;import com.test.invoice.model.base.SuperEntity;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.experimental.Accessors;/*** TRbtTestData 分页对象类** @author:* @version:* @date: 2019-08-15 16:49*/@Data@Accessors(chain = true) //@Accessors 注解用来配置lombok如何产生和显示getters和setters的方法。public class TRbtTestDataParam extends SuperEntity {@ApiModelProperty("当前页")@JSONField(name = "page")private Integer page;@ApiModelProperty("页面大小")@JSONField(name = "pageSize")private Integer pageSize;@ApiModelProperty("名称")@JSONField(name = "name")private String name;}
响应码枚举对象-ResponseCode
package com.test.invoice.enums;/*** 响应码枚举对象。** @author*/public enum ResponseCode {//通用OK(2000, "Success"),INSERT_ERROR(-108, "新增失败"),DELETE_ERROR(-109, "数据删除失败,请刷新重试"),UPDATE_ERROR(-107, "更新失败,请刷新重试"),OPERATE_ERROR(5500, "操作失败"),PARAM_INVALID(1000, "缺失参数或无效"),THIRD_PARTY_EXCEPTION(3000, "第三方接口异常"),SYSTEM_EXCEPTION(5000, "系统异常"),SYSTEM_EXCEPTION_4(8004, "解析回调的xml出现异常"),SYSTEM_EXCEPTION_8(8008, "JSON转换错误"),SYSTEM_EXCEPTION_9(8009, "HTTP请求异常"),SYSTEM_EXCEPTION_10(8010, "用户权限不够"),SYSTEM_EXCEPTION_11(8011, "获取用户信息失败"),SYSTEM_EXCEPTION_13(8013, "查询用户出现异常"),SYSTEM_EXCEPTION_14(8014, "获取用户信息失败,请核实用户id"),SYSTEM_EXCEPTION_16(8888, "获取用户信息失败,请核实用户id"),SYSTEM_EXCEPTION_18(8888, "用户权限不够"),SYSTEM_EXCEPTION_20(8888, "获取用户信息失败"),SYSTEM_EXCEPTION_21(8888, "调用失败"),ACCESS_TOKEN_EXCEPTION(9000, "获取token失败"),AUTH_INVALID(4000, "身份验证失败"),TOKEN_MISSING(4001, "token缺失"),TOKEN_INVALID(4002, "token Fail"),;private final int value;private final String description;ResponseCode(int value, String description) {this.value = value;this.description = description;}public int value() {return this.value;}public String getDescription() {return this.description;}public static ResponseCode valueOf(int code) {for (ResponseCode responseCode : values()) {if (responseCode.value == code) {return responseCode;}}throw new IllegalArgumentException("No matching constant for [" + code + "]");}@Overridepublic String toString() {return Integer.toString(this.value);}}
服务异常类-ServiceException
package com.test.invoice.excepiton;import com.test.invoice.enums.ResponseCode;/*** 服务异常类** @author:* @version:* @date: 2019-08-09 10:28*/public class ServiceException extends RuntimeException {private int code;public ServiceException(ResponseCode responseCode,Throwable cause){super(responseCode.getDescription(),cause);this.code = responseCode.value();}public ServiceException(ResponseCode responseCode){super(responseCode.getDescription());this.code = responseCode.value();}public int getCode() { return code; }public void setCode(int code) { this.code = code; }}
响应实体-ResponseVO
VO:value object 值对象/ view object 表现层对象
1.主要对应页面显示(web 页面 / swt 、swing 界面)的数据对象
2.可以和表对应,也可以不对应,根据业务需要。
package com.test.invoice.vo;import com.fasterxml.jackson.annotation.JsonInclude;import com.test.invoice.enums.ResponseCode;import com.test.invoice.excepiton.ServiceException;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;import java.io.Serializable;/** * 响应实体 * * @author: * @version: * @date: 2019-08-09 10:40 */@Data@AllArgsConstructor@NoArgsConstructor@JsonInclude(JsonInclude.Include.NON_NULL)@ApiModel("响应实体")@Accessors(chain = true)public class ResponseVO<T> implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty("编码 200:成功,其他异常") private Integer code; @ApiModelProperty("消息") private String msg; @ApiModelProperty("数据结果集") private T data; @ApiModelProperty("服务器时间戳") private Long timestamp; public ResponseVO(ResponseCode responseCode){ this.code = responseCode.value(); this.msg = responseCode.getDescription(); this.timestamp = System.currentTimeMillis(); } public ResponseVO(ResponseCode responseCode,T data){ this.code = responseCode.value(); this.msg = responseCode.getDescription(); this.timestamp = System.currentTimeMillis(); this.data = data; } public ResponseVO(ServiceException e){ this.code = e.getCode(); this.msg = e.getMessage(); } public ResponseVO(int code, String msg){ this.code = code; this.msg = msg; this.timestamp = System.currentTimeMillis(); }}
VO:value object 值对象/ view object 表现层对象
1.主要对应页面显示(web 页面 / swt 、swing 界面)的数据对象
2.可以和表对应,也可以不对应,根据业务需要。
package com.test.invoice.vo;import com.fasterxml.jackson.annotation.JsonInclude;import com.test.invoice.enums.ResponseCode;import com.test.invoice.excepiton.ServiceException;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.experimental.Accessors;import java.io.Serializable;/*** 响应实体** @author:* @version:* @date: 2019-08-09 10:40*/@Data@AllArgsConstructor@NoArgsConstructor@JsonInclude(JsonInclude.Include.NON_NULL)@ApiModel("响应实体")@Accessors(chain = true)public class ResponseVO<T> implements Serializable {private static final long serialVersionUID = 1L;@ApiModelProperty("编码 200:成功,其他异常")private Integer code;@ApiModelProperty("消息")private String msg;@ApiModelProperty("数据结果集")private T data;@ApiModelProperty("服务器时间戳")private Long timestamp;public ResponseVO(ResponseCode responseCode){this.code = responseCode.value();this.msg = responseCode.getDescription();this.timestamp = System.currentTimeMillis();}public ResponseVO(ResponseCode responseCode,T data){this.code = responseCode.value();this.msg = responseCode.getDescription();this.timestamp = System.currentTimeMillis();this.data = data;}public ResponseVO(ServiceException e){this.code = e.getCode();this.msg = e.getMessage();}public ResponseVO(int code, String msg){this.code = code;this.msg = msg;this.timestamp = System.currentTimeMillis();}}
创建子模块-test-invoice-contract
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-contract
模块名称 test-invoice-contract
创建包重复问题
新建包 com.test.invoice.service
再建一个子包 db
再建一个和 db 包同级的包 test
这时候发现并不同级
解决
新建好包 com.test.invoice.service 之后创建类 Test,再创建包
新建类-TRbtTestConsumer
package com.test.invoice.service.consumer;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.*;import com.test.invoice.data.TRbtTestData;/*** TRbtTestConsumer** @author:* @version:* @date: 2019-08-08 14:45*/@FeignClient(value = "service-producer")public class TRbtTestConsumer {public void Test(){TRbtTestData data = new TRbtTestData();}}
pom.xml 引用
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-contract</artifactId><name>test-invoice-contract</name><dependencies><dependency><groupId>com.test.invoice</groupId><artifactId>test-invoice-common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--feign start--><dependency><groupId>org.springframework.cloud</groupId><!--spring boot 2.0.3版本解决方案:spring-cloud-starter-feign--><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--feign end--></dependencies><build></build><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>
报错-Dependency ‘xxx’ not found 及解决
Dependency 'com.test.invoice:test-invoice-common:1.0-SNAPSHOT' not found
参考文档
我对比三个 pom.xml 文件
test-invoice-cloud
pom.xml
<modelVersion>4.0.0</modelVersion><groupId>com-test-invoice</groupId><artifactId>test-invoice-cloud</artifactId><version>1.0-SNAPSHOT</version><name>test-invoice-cloud</name><packaging>pom</packaging>
test-invoice-common
pom.xml
<parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-common</artifactId><name>test-invoice-common</name>
test-invoice-contract
pom.xml
<parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-contract</artifactId><name>test-invoice-contract</name><dependency><groupId>com.test.invoice</groupId><artifactId>test-invoice-common</artifactId><version>1.0-SNAPSHOT</version></dependency>
问题原因
<dependency><groupId>com.test.invoice</groupId>
问题解决,修改为
<dependency><groupId>com-test-invoice</groupId>
创建下图中的类和文件
模块简介
主要用于提供接口,还有 Feign-api 接口
类图
pom.xml
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-contract</artifactId><name>test-invoice-contract</name><dependencies><dependency><groupId>com-test-invoice</groupId><artifactId>test-invoice-common</artifactId><version>1.0-SNAPSHOT</version></dependency><!--feign start--><dependency><groupId>org.springframework.cloud</groupId><!--spring boot 2.0.3版本解决方案:spring-cloud-starter-feign--><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--feign end--></dependencies><build></build><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>
接口定义-ITRbtTestService
package com.test.invoice.service.producer;import com.test.invoice.data.TRbtTestData;import com.test.invoice.data.TRbtTestDataParam;import com.test.invoice.vo.ResponseVO;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.*;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;/*** 接口定义-ITRbtTestService*/public interface ITRbtTestService {ResponseVO<String> Add(@RequestBody TRbtTestData data);ResponseVO<Boolean> Update(@RequestBody TRbtTestData data);ResponseVO<Boolean> Del(@RequestParam(value="name",required = true) String name,@RequestParam(value="version",required = true) String version);ResponseVO<TRbtTestData> Get(@RequestBody TRbtTestData data);ResponseVO<Page<TRbtTestData>> Query(@RequestBody TRbtTestDataParam param);}
Feign-api 接口定义——TRbtTestConsumer
package com.test.invoice.service.consumer;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.test.invoice.vo.ResponseVO;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.*;import com.test.invoice.data.TRbtTestData;import com.test.invoice.data.TRbtTestDataParam;/*** Feign-api 接口定义——TRbtTestConsumer** @author:* @version:* @date: 2019-08-08 14:45*/@FeignClient(value = "service-producer")public interface TRbtTestConsumer {@PostMapping("/Test/Add")ResponseVO<String> Add(@RequestBody TRbtTestData data);@PostMapping("Test/Update")ResponseVO<Boolean> Update(@RequestBody TRbtTestData data);@RequestMapping(value="Test/Del",method=RequestMethod.GET)ResponseVO<Boolean> Del(@RequestParam(value="name",required = true) String name,@RequestParam(value="version",required = true) String version);@PostMapping("/Test/Get")ResponseVO<TRbtTestData> Get(@RequestBody TRbtTestData data);@PostMapping("/Test/Query")ResponseVO<Page<TRbtTestData>> Query(@RequestBody TRbtTestDataParam param);}
创建子模块-test-invoice-service
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-service
模块名称 test-invoice-service
创建下图中的类和文件
模块简介
作为一个 Eureka Client 模块
实现 test-invoice-contract 项目中定义的接口
类图
pom.xml
<?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"><parent><artifactId>test-invoice-cloud</artifactId><groupId>com-test-invoice</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>test-invoice-service</artifactId><name>test-invoice-service</name><dependencies><dependency><groupId>com-test-invoice</groupId><artifactId>test-invoice-contract</artifactId><version>1.0-SNAPSHOT</version></dependency><!--Apache PDFbox 是一个开源的、基于 Java 的、支持 PDF 文档生成的工具库--><dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.1</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.4</version></dependency><!--iText是一个能够快速产生PDF文件的java类库--><dependency><groupId>com.lowagie</groupId><artifactId>itext</artifactId><version>2.1.7</version></dependency><!--mysql start--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mysql end--><!--保存到数据库需要如下依赖--><!--<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency>--><!--db start--><!--号称性能最好的JDBC连接池--><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>${HikariCP.version}</version></dependency><!--db end--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus-spring-boot-starter.version}</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!--redis start--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--redis end--><!--分布式链路追踪三个依赖--><!--<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-sleuth</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zipkin</artifactId></dependency><!--activiti start--><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>6.0.0</version></dependency><!--activiti end--></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork></configuration><!--如果要访问info接口想获取maven中的属性内容请记得添加如下内容--><executions><execution><goals><goal>build-info</goal></goals></execution></executions></plugin></plugins><resources><resource><directory>src/main/resources</directory><includes><include>**/*</include></includes></resource></resources></build></project>
Resources
自定义分页映射xml-TRbtTestMapper.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.test.invoice.mapper.TRbtTestRepository"><select id="selectPageVO" resultType="com.test.invoice.data.TRbtTestData"parameterType="com.test.invoice.data.TRbtTestDataParam">select id,name,version from t_rbt_test where name = #{param.name}</select></mapper>
application.yml
server:port: 18800spring:profiles:active: dev # 指定配置文件http:encoding:force: true # 默认编码,即 utf8activiti:check-process-definitions: false # 校验流程文件,默认校验resources下的processes文件夹里的流程文件# 服务名称,即serviceIdapplication:name: service-producersleuth:web:client:enabled: true # 启用为分布式web client 客户端sampler:probability: 1.0 # 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1
application-dev.yml
spring:datasource:type: com.zaxxer.hikari.HikariDataSource #数据源类型url: jdbc:mysql://localhost:3306/luoma_test?serverTimezone=UTC&characterEncoding=utf-8&useSSL=false #数据库urlusername: root #数据库用户名password: luoma_LUOMA #数据库密码driver-class-name: com.mysql.jdbc.Driver #数据库驱动hikari:pool-name: pool-vscloudconnectionTestQuery: SELECT 1maximum-pool-size: 50minimum-idle: 10#mybatismybatis-plus:mapper-locations: classpath:/mapper/*Mapper.xml #mybatis-plus mapper xml 文件地址#实体扫描,多个package用逗号或者分号分隔typeAliasesPackage:typeEnumsPackage:global-config:id-type: 4#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"field-strategy: 2#驼峰下划线转换db-column-underline: true#刷新mapper 调试神器refresh-mapper: true#数据库大写下划线转换#capital-mode: true#序列接口实现类配置#key-generator:#逻辑删除配置logic-delete-value: 0logic-not-delete-value: 1configuration:map-underscore-to-camel-case: truecache-enabled: false# 服务注册与发现相关配置eureka:#自定义实例编号instance:instance-id: ${spring.application.name}:${server.port}# 优先使用IP地址方式进行注册服务prefer-ip-address: true# 配置使用指定IPclient:# 服务注册地址serviceUrl:defaultZone: http://127.0.0.1:8772/eureka/
application-test.yml
#springspring:datasource:type: com.zaxxer.hikari.HikariDataSourceurl: jdbc:mysql://localhost:3306/luoma_test?serverTimezone=UTC&characterEncoding=utf-8&useSSL=falseusername: rootpassword: luoma_ai_LEIMUdriver-class-name: com.mysql.jdbc.Driverhikari:pool-name: pool-vscloudconnectionTestQuery: SELECT 1maximum-pool-size: 50minimum-idle: 10#mybatismybatis-plus:mapper-locations: classpath:/mapper/*Mapper.xml#实体扫描,多个package用逗号或者分号分隔typeAliasesPackage:typeEnumsPackage:global-config:#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";id-type: 0#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"field-strategy: 2#驼峰下划线转换db-column-underline: true#刷新mapper 调试神器refresh-mapper: true#数据库大写下划线转换#capital-mode: true#序列接口实现类配置#key-generator:#逻辑删除配置logic-delete-value: 0logic-not-delete-value: 1# #自定义填充策略接口实现# meta-object-handler:configuration:map-underscore-to-camel-case: truecache-enabled: false
bootstrap.properties
#由于 logback-spring.xml的加载在 application.properties之前,所以之前的配置 logback-spring.xml无法获取到 spring.application.name属性,因此这里将该属性移动到最先加载的 bootstrap.properties配置文件中。#https://cloud.tencent.com/developer/article/1067431spring.application.name=service-producer
MybatisPlus 配置类-MybatisPlusConfig
package com.test.invoice.config;import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;import org.mybatis.spring.mapper.MapperScannerConfigurer;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Profile;/*** 从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。*/@Configurationpublic class MybatisPlusConfig {/*** mybatis-plus SQL执行效率插件【生产环境可以关闭】*/@Bean//@Profile({"dev", "test"})// 设置 dev test 环境开启@Profile({"dev"})// 设置 dev test 环境开启public PerformanceInterceptor performanceInterceptor() {return new PerformanceInterceptor();}/*** mybatis-plus分页插件<br>* 文档:http://mp.baomidou.com<br>*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();// paginationInterceptor.setLimit(你的最大单页限制数量,默认 500 条,小于 0 如 -1 不受限制);return paginationInterceptor;}/*** 相当于顶部的:* {@code @MapperScan("com.baomidou.springboot.mapper*")}* 这里可以扩展,比如使用配置文件来配置扫描Mapper的路径*/@Beanpublic MapperScannerConfigurer mapperScannerConfigurer() {MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();scannerConfigurer.setBasePackage("com.test.invoice.mapper*");return scannerConfigurer;}}
MybatisPlus 配置类-MyMetaObjectHandler
package com.test.invoice.config;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;import lombok.extern.slf4j.Slf4j;import org.apache.ibatis.reflection.MetaObject;import org.springframework.stereotype.Component;import java.util.Date;/*** mybatis公共字段自动填充**/@Slf4j@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {String user="luoma";try {log.info("【填充数据 --开始】");this.setFieldValByName("createTime", new Date(), metaObject);this.setFieldValByName("updateTime", new Date(), metaObject);this.setFieldValByName("bizTime", new Date(), metaObject);this.setFieldValByName("isDelete", 0, metaObject);this.setFieldValByName("createBy", user, metaObject);this.setFieldValByName("updateBy", user, metaObject);log.info("【填充数据 --完毕】");} catch (Exception e) {log.info("填充错误" + e.getMessage());}}/*** description 更新自动填充*/@Overridepublic void updateFill(MetaObject metaObject) {String user="luoma";this.setFieldValByName("updateTime", new Date(), metaObject);this.setFieldValByName("bizTime", new Date(), metaObject);this.setFieldValByName("updateBy", user, metaObject);log.info("【填充数据 --完毕】");}}
自定义接口-TRbtTestRepository
package com.test.invoice.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.baomidou.mybatisplus.core.metadata.IPage;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.test.invoice.data.TRbtTestData;import com.test.invoice.data.TRbtTestDataParam;import com.test.invoice.model.TRbtTestEntity;import org.springframework.stereotype.Repository;@Repositorypublic interface TRbtTestRepository extends BaseMapper<TRbtTestEntity> {IPage<TRbtTestData> selectPageVO(Page<TRbtTestData> page, TRbtTestDataParam param);}
接口实现-TRbtTestServiceImpl
package com.test.invoice.service.impl;import com.test.invoice.data.TRbtTestDataParam;import com.test.invoice.enums.ResponseCode;import com.test.invoice.vo.ResponseVO;import com.test.invoice.data.TRbtTestData;import com.test.invoice.mapper.TRbtTestRepository;import com.test.invoice.model.TRbtTestEntity;import com.test.invoice.service.producer.ITRbtTestService;import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;import com.baomidou.mybatisplus.core.metadata.IPage;import com.baomidou.mybatisplus.core.toolkit.Wrappers;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestParam;import java.util.List;/*** TRbtTestServiceImpl** @author:* @version:* @date: 2019-08-12 10:23*/@Slf4j@Servicepublic class TRbtTestServiceImpl extends ServiceImpl<TRbtTestRepository, TRbtTestEntity> implements ITRbtTestService {@Overridepublic ResponseVO<String> Add(@RequestBody TRbtTestData data){TRbtTestEntity entity = new TRbtTestEntity();entity.setName(data.getName()).setVersion(data.getVersion());if(baseMapper.insert(entity) > 0){return new ResponseVO<>(ResponseCode.OK);}return new ResponseVO<>(ResponseCode.OPERATE_ERROR,"ERROR");}@Overridepublic ResponseVO<Boolean> Update(@RequestBody TRbtTestData data){UpdateWrapper<TRbtTestEntity> wrapper = new UpdateWrapper<>();wrapper.set("name",data.getName()).set("version",data.getVersion());wrapper.eq("id",data.getId());return new ResponseVO<>(ResponseCode.OK,update(wrapper));}@Overridepublic ResponseVO<Boolean> Del(@RequestParam(value="name",required = true) String name, @RequestParam(value="version",required = true) String version){UpdateWrapper<TRbtTestEntity> wrapper = new UpdateWrapper<>();wrapper.eq("name",name);wrapper.eq("version",version);return new ResponseVO<>(ResponseCode.OK, baseMapper.delete(wrapper) > 0);}@Overridepublic ResponseVO<TRbtTestData> Get(@RequestBody TRbtTestData data){List<TRbtTestEntity> list = baseMapper.selectList(Wrappers.<TRbtTestEntity>lambdaQuery().eq(TRbtTestEntity::getName, data.getName()));if(!list.isEmpty()){TRbtTestEntity entity = list.get(0);data.setName(entity.getName());data.setVersion(entity.getVersion());return new ResponseVO<>(ResponseCode.OK, data);}else{return new ResponseVO<>(ResponseCode.PARAM_INVALID, data);}}@Overridepublic ResponseVO<Page<TRbtTestData>> Query(@RequestBody TRbtTestDataParam param){Page<TRbtTestData> page = new Page<>();page.setCurrent(param.getPage());page.setSize(param.getPageSize());//return new ResponseVO<>(ResponseCode.OK, baseMapper.selectPageVO(page, param));IPage<TRbtTestData> ipageData = baseMapper.selectPageVO(page, param);//IPage<TRbtTestData> 转换为 Page<TRbtTestData>Page<TRbtTestData> pageData = new Page<>();pageData.setRecords(ipageData.getRecords());pageData.setCurrent(ipageData.getCurrent());pageData.setSize(ipageData.getSize());pageData.setTotal(ipageData.getTotal());return new ResponseVO<>(ResponseCode.OK, pageData);}}
生产者:业务微服务-测试框架系统控制类-TRbtTestController
package com.test.invoice.contorller;import com.test.invoice.data.TRbtTestData;import com.test.invoice.data.TRbtTestDataParam;import com.test.invoice.service.producer.ITRbtTestService;import com.test.invoice.vo.ResponseVO;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.RestController;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.*;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import javax.annotation.Resource;/**** 生产者:业务微服务-测试框架系统控制类** @author:* @version:* @date: 2019-08-12 09:53*/@RestController@Api(description = "测试框架系统控制类")public class TRbtTestController {@Resourceprivate ITRbtTestService testService;@PostMapping("/Test/Add")@ApiOperation(value="系统框架测试-新增数据",httpMethod = "POST",response = ResponseVO.class,notes = "系统框架测试-新增数据")public ResponseVO Add(@RequestBody TRbtTestData data){return testService.Add(data);}@PostMapping("Test/Update")@ApiOperation(value="系统框架测试-修改数据",httpMethod = "POST",response = ResponseVO.class,notes = "系统框架测试-修改数据")public ResponseVO<Boolean> Update(@RequestBody TRbtTestData data){return testService.Update(data);}@RequestMapping(value="Test/Del",method = RequestMethod.GET)@ApiOperation(value="系统框架测试-删除数据",httpMethod = "GET",response = ResponseVO.class,notes = "系统框架测试-删除数据")public ResponseVO<Boolean> Del(@RequestParam(value="name",required = true) String name,@RequestParam(value="version",required = true) String version){return testService.Del(name,version);}@PostMapping("/Test/Get")@ApiOperation(value="系统框架测试-获取单个数据",httpMethod = "POST",response = ResponseVO.class,notes = "系统框架测试-获取单个数据")public ResponseVO<TRbtTestData> Get(@RequestBody TRbtTestData data){return testService.Get(data);}@PostMapping("/Test/Query")@ApiOperation(value="系统框架测试-查询分页数据",httpMethod = "POST",response = ResponseVO.class,notes = "系统框架测试-查询分页数据")public ResponseVO<Page<TRbtTestData>> Query(@RequestBody TRbtTestDataParam param){return testService.Query(param);}}
入口类-ServerApplication
package com.test.invoice;import org.activiti.spring.boot.SecurityAutoConfiguration;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.web.bind.annotation.RestController;/*** 启动类** @author:* @version:* @date: 2019-08-12 09:53*/@SpringBootApplication(exclude = SecurityAutoConfiguration.class) //禁用 security 验证@RestController@EnableEurekaClient //Eureka Clientpublic class ServerApplication {public static void main(String[] args){SpringApplication.run(ServerApplication.class,args);}}
测试结果
启动项目 test-invoice-eureka
启动项目 test-invoice-service
启动多个项目参考
首先访问 http://localhost:8772/ ,看 Instances currently registered with Eureka 是否能看到 test-invoice-service 项目
接着使用 Postman 调用 test-invoice-service 接口 Add
结果
创建子模块-test-invoice-web
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-web
模块名称 test-invoice-web
创建下图中的类和文件
模块简介
作为一个 Eureka 客户端,提供调用接口
类图
pom.xml
server:port: 8080servlet:context-path: /enta/apispring:application:# 服务名,即serviceIdname: service-feign-websleuth:web:client:enabled: true # 启用为分布式web client 客户端sampler:probability: 1.0 # 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1# 服务注册与发现相关配置eureka:#自定义实例编号instance:instance-id: ${spring.application.name}:${server.port}# 优先使用IP地址方式进行注册服务prefer-ip-address: true# 配置使用指定IP# ip-address: 127.0.0.1client:# 服务注册地址serviceUrl:# defaultZone: http://127.0.0.1:8772/eureka/defaultZone: http://127.0.0.1:8772/eureka/#配置actuator的相关配置# 描述信息info:blog-url: http://luoma.proauthor: luoma# 加载所有的端点/默认只加载了 info / healthmanagement:endpoints:web:exposure:include: "*"endpoint:health:show-details: alwaysshutdown:enabled: false # 可以关闭制定的端点
bootstrap.properties
#由于 logback-spring.xml的加载在 application.properties之前,所以之前的配置 logback-spring.xml无法获取到 spring.application.name属性,因此这里将该属性移动到最先加载的 bootstrap.properties配置文件中。#https://cloud.tencent.com/developer/article/1067431spring.application.name=service-feign-web
消费者,通过 Feign-api 调用-TRbtTestController
package com.test.invoice.controller;import com.test.invoice.data.TRbtTestData;import com.test.invoice.data.TRbtTestDataParam;import com.test.invoice.service.consumer.TRbtTestConsumer;import com.test.invoice.vo.ResponseVO;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.*;import org.springframework.beans.factory.annotation.Autowired;/*** 消费者,通过 Feign-api 调用** @author:* @version:* @date: 2019-08-12 14:49*/@RestController@Api(description = "测试框架系统控制类")@RequestMapping("/Inv/Api")public class TRbtTestController {//@Resource@Autowiredprivate TRbtTestConsumer testConsumer;@PostMapping("Test/Add")@ApiOperation(value = "系统框架测试-新增数据", httpMethod = "POST", response = ResponseVO.class, notes = "系统框架测试-新增数据")public ResponseVO Add(@RequestBody TRbtTestData data){return testConsumer.Add(data);}@PostMapping("Test/Update")@ApiOperation(value = "系统框架测试-修改数据", httpMethod = "POST", response = ResponseVO.class, notes = "系统框架测试-修改数据")public ResponseVO Update(@RequestBody TRbtTestData data){return testConsumer.Update(data);}@RequestMapping(value="Test/Del",method=RequestMethod.GET)@ApiOperation(value = "系统框架测试-删除数据", httpMethod = "POST", response = ResponseVO.class, notes = "系统框架测试-删除数据")public ResponseVO Del(@RequestParam(value="name",required = true) String name,@RequestParam(value="version",required = true) String version){return testConsumer.Del(name,version);}@PostMapping("/Test/Get")@ApiOperation(value = "系统框架测试-获取单个数据", httpMethod = "POST", response = ResponseVO.class, notes = "系统框架测试-获取单个数据")public ResponseVO Get(@RequestBody TRbtTestData data){return testConsumer.Get(data);}@PostMapping("/Test/Query")@ApiOperation(value = "系统框架测试-获取分页数据", httpMethod = "POST", response = ResponseVO.class, notes = "系统框架测试-获取分页数据")public ResponseVO Query(@RequestBody TRbtTestDataParam param){return testConsumer.Query(param);}}
启动类-WebApplication
package com.test.invoice;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.cloud.openfeign.EnableFeignClients;/*** 启动类** @author:* @version:* @date: 2019-08-12 14:43*///禁用 security 验证@SpringBootApplication(exclude = org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class)@EnableFeignClients //使用feign客户端,https://blog.csdn.net/andy_zhang2007/article/details/86680622@EnableEurekaClient //启用服务注册与发现public class WebApplication { //extends SpringBootServletInitializerpublic static void main(String[] args){SpringApplication.run(WebApplication.class,args);}}
测试
启动项目 test-invoice-eureka
启动项目 test-invoice-service
启动项目 test-invoice-web
启动多个项目参考
首先访问 http://localhost:8772/ ,看 Instances currently registered with Eureka 是否能看到
test-invoice-service 项目test-invoice-web 项目
测试-Add
使用 Postman 访问 http://localhost:8080/enta/api/Inv/Api/Test/Add
参数
{"id":"","name":"luoma","version":"1.0.6"}
结果
测试-Update
使用 Postman 访问 http://localhost:8080/enta/api/Inv/Api/Test/Update
参数
{"id":"11d1dd6b2bbe1d9a729986f5c2f62b42","name":"测试数据-菲克-1","version":"1.0.1"}
结果
测试-Del
使用 Postman 访问 http://localhost:8080/enta/api/Inv/Api/Test/Del?name=luoma&version=1.0.1
结果
测试-Get
使用 Postman 访问 http://localhost:8080/enta/api/Inv/Api/Test/Get
参数
{"id":"","name":"测试数据-菲克-1","version":""}
测试-Query
使用 Postman 访问 http://localhost:8080/enta/api/Inv/Api/Test/Query
参数
{"page":2,"pageSize":3,"name":"luoma"}
项目开发过程中遇到的问题及解决
父模块 pom.xml 引入包子模块 pom.xml 无法解析问题
访问接口-提示 Unsupported Media Type
项目总类图
项目总结构图
扩展-负载均衡
创建子模块-test-invoice-service-1
test-invoice-cloud 上右键,新建模块
左侧面板选择 Maven,不勾选 Create from archetype 选项,如下图,点击 下一个 即可。
artifactId test-invoice-service-1
模块名称 test-invoice-service-1
复制 test-invoice-service 模块的所有内容到 test-invoice-service-1
修改启动类为 ServerApplication_1
package com.test.invoice;import org.activiti.spring.boot.SecurityAutoConfiguration;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.web.bind.annotation.RestController;/*** 启动类** @author:* @version:* @date: 2019-08-12 09:53*/@SpringBootApplication(exclude = SecurityAutoConfiguration.class) //禁用 security 验证@RestController@EnableEurekaClient //Eureka Clientpublic class ServerApplication_1 {public static void main(String[] args){SpringApplication.run(ServerApplication_1.class,args);}}
修改 TRbtTestServiceImpl 的 Add 方法
原 Add 方法添加代码 data.setName(data.getName()+"_18801"); 以示区分
@Overridepublic ResponseVO<String> Add(@RequestBody TRbtTestData data){data.setName(data.getName()+"_18801");TRbtTestEntity entity = new TRbtTestEntity();entity.setName(data.getName()).setVersion(data.getVersion());if(baseMapper.insert(entity) > 0){return new ResponseVO<>(ResponseCode.OK);}return new ResponseVO<>(ResponseCode.OPERATE_ERROR,"ERROR");}
修改 application.yml 端口号
端口号从 18800 修改为 18801,其它不变
server:port: 18801spring:profiles:active: dev # 指定配置文件http:encoding:force: true # 默认编码,即 utf8activiti:check-process-definitions: false # 校验流程文件,默认校验resources下的processes文件夹里的流程文件# 服务名称,即serviceIdapplication:name: service-producersleuth:web:client:enabled: true # 启用为分布式web client 客户端sampler:probability: 1.0 # 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1
启动项目
依次启动
启动项目 `test-invoice-eureka`启动项目 `test-invoice-service`启动项目 `test-invoice-service-1`启动项目 `test-invoice-web`
查看 Eureka 是否注册
使用 Postman 调用接口
快速的多次点击添加
URL:http://localhost:8080/enta/api/Inv/Api/Test/Add
参数:{"id":"","name":"五哥","version":"1.0.6"}
数据库查询结果
SELECT * FROM `t_rbt_test`where name like '五哥%'
可以看到有些是正常的数据,有些是带后缀 _18801 的数据
说明两个服务中心 test-invoice-service,test-invoice-service-1 自动提供了服务均衡负载的功能
项目调用关系图