文章目录
- 父项目microcloud
- 本地模拟RPC调用
- common-api子模块
- 创建dto类
- 创建服务接口
- 创建一个对象拷贝的工具类
- provider-dept-8001 子模块
- bootstrap.yml
- application.yml
- logback-spring.xml
- Swagger配置
- 创建MyBatisPlus配置类
- 部门 数据库创建脚本
- 创建Dept映射类
- 创建IDeptDAO数据接口
- 在生产端需要提供有业务接口的实现子类
- 启动类
- 测试
- controller
- common-api子模块修改
- consumer-springboot-80 子模块
- application.yml
- controller
- 启动类
父项目microcloud
添加common-api子模块
添加 provider-dept-8001 子模块
添加 consumer-springboot-80 子模块
New Module
Gradle版本:
版本组合:
springboot : ‘2.2.5.RELEASE’, // SpringBoot版本号
springcloud : ‘Hoxton.SR3’, // SpringCloud版本号
alibabacloud : ‘2.2.1.RELEASE’, // SpringCloudAlibaba版本号
gradle.properties
project_group=com.yootk
project_version=1.0.0
project_jdk=11
dependencies.gradle
ext.versions = [ // 定义全部的依赖库版本号springboot : '2.2.5.RELEASE', // SpringBoot版本号springcloud : 'Hoxton.SR3', // SpringCloud版本号alibabacloud : '2.2.1.RELEASE', // SpringCloudAlibaba版本号lombok : '1.18.20', // Lombok版本号junit : '5.6.3', // 配置JUnit测试工具的版本编号junitPlatformLauncher: '1.6.3', // JUnit测试工具运行平台版本编号mybatisPlus : '3.4.3', // MyBatisPlus的版本号mysql : '8.0.25', // MySQL数据库驱动版本druid : '1.2.6', // Druid版本号swagger : '3.0.0', // Swagger版本号nacos : '2.0.2', // Nacos版本号
]
ext.libraries = [ // 依赖库引入配置'spring-boot-gradle-plugin' :"org.springframework.boot:spring-boot-gradle-plugin:${versions.springboot}",'spring-cloud-dependencies' :"org.springframework.cloud:spring-cloud-dependencies:${versions.springcloud}",'spring-cloud-alibaba-dependencies':"com.alibaba.cloud:spring-cloud-alibaba-dependencies:${versions.alibabacloud}",// 以下的配置为与项目用例测试有关的依赖'junit-jupiter-api' :"org.junit.jupiter:junit-jupiter-api:${versions.junit}",'junit-vintage-engine' :"org.junit.vintage:junit-vintage-engine:${versions.junit}",'junit-jupiter-engine' :"org.junit.jupiter:junit-jupiter-engine:${versions.junit}",'junit-platform-launcher' :"org.junit.platform:junit-platform-launcher:${versions.junitPlatformLauncher}",'junit-platform-engine' :"org.junit.platform:junit-platform-engine:${versions.junitPlatformLauncher}",'junit-jupiter-params' :"org.junit.jupiter:junit-jupiter-params:${versions.junit}",'junit-bom' : "org.junit:junit-bom:${versions.junit}",'junit-platform-commons' :"org.junit.platform:junit-platform-commons:${versions.junitPlatformLauncher}",// 以下的配置为Lombok组件有关的依赖'lombok' : "org.projectlombok:lombok:${versions.lombok}",// 以下的配置为数据库开发有关的依赖'mybatis-plus-boot-starter' : "com.baomidou:mybatis-plus-boot-starter:${versions.mybatisPlus}",'mysql-connector-java' : "mysql:mysql-connector-java:${versions.mysql}",'druid' : "com.alibaba:druid:${versions.druid}",// 以下的配置为Swagger有关的依赖库'springfox-boot-starter' : "io.springfox:springfox-boot-starter:${versions.swagger}",// 以下的配置为Nacos有关的依赖库'nacos-client' : "com.alibaba.nacos:nacos-client:${versions.nacos}"
]
build.gradle
buildscript { // 定义脚本使用资源apply from: 'dependencies.gradle' // 引入所需要的依赖库文件repositories { // 脚本资源仓库maven { url 'https://maven.aliyun.com/repository/public' }}dependencies { // 依赖库classpath libraries.'spring-boot-gradle-plugin' // SpringBoot插件}
}
group project_group // 组织名称
version project_version // 项目版本apply from: 'dependencies.gradle' // 导入依赖配置
def env = System.getProperty("env") ?: 'dev' // 获取env环境属性
subprojects { // 配置子项目apply plugin: 'java' // 子模块插件apply plugin: 'org.springframework.boot' // 引入SpringBoot插件apply plugin: 'io.spring.dependency-management' // 版本号管理sourceCompatibility = project_jdk // 源代码版本targetCompatibility = project_jdk // 生成类版本repositories { // 配置Gradle仓库mavenLocal()maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }mavenCentral()jcenter()}dependencyManagement {// 版本控制插件imports {mavenBom libraries.'spring-cloud-dependencies' // SpringCloud依赖管理mavenBom libraries.'spring-cloud-alibaba-dependencies' // SpringCloudAlibaba依赖管理}}dependencies { // 公共依赖库管理compile('org.springframework.boot:spring-boot-devtools') // 项目热部署// 以下为测试环境的相关依赖配置testImplementation('org.springframework.boot:spring-boot-starter-test') {exclude group: 'junit', module: 'junit' // 移除Junit4}testImplementation(enforcedPlatform(libraries.'junit-bom')) // 绑定为JUnit5运行testImplementation(libraries.'junit-platform-commons') // Junit5测试组件testImplementation(libraries.'junit-platform-engine') // Junit5测试组件testImplementation(libraries.'junit-jupiter-api') // Junit5测试组件testImplementation(libraries.'junit-vintage-engine') // Junit5测试组件testImplementation(libraries.'junit-jupiter-engine') // Junit5测试组件testImplementation(libraries.'junit-platform-launcher') // Junit5测试组件// 以下为Lombok插件的相关依赖配置compileOnly(libraries.'lombok') // 编译时生效annotationProcessor(libraries.'lombok') // 注解时生效}sourceSets { // 源代码目录配置main { // main及相关子目录配置java { srcDirs = ['src/main/java'] }resources { srcDirs = ['src/main/resources', "src/main/profiles/$env"] }}test { // test及相关子目录配置java { srcDirs = ['src/test/java'] }resources { srcDirs = ['src/test/resources'] }}}test { // 配置测试任务useJUnitPlatform() // 使用JUnit测试平台}task sourceJar(type: Jar, dependsOn: classes) { // 源代码的打包任务archiveClassifier = 'sources' // 设置文件的后缀from sourceSets.main.allSource // 所有源代码的读取路径}task javadocTask(type: Javadoc) { // JavaDoc文档打包任务options.encoding = 'UTF-8' // 设置文件编码source = sourceSets.main.allJava // 定义所有的Java源代码}task javadocJar(type: Jar, dependsOn: javadocTask) { // 先生成JavaDoc再打包archiveClassifier = 'javadoc' // 文件标记类型from javadocTask.destinationDir // 通过JavadocTask任务中找到目标路径}tasks.withType(Javadoc) { // 文档编码配置options.encoding = 'UTF-8' // 定义编码}tasks.withType(JavaCompile) { // 编译编码配置options.encoding = 'UTF-8' // 定义编码}artifacts { // 最终的打包的操作任务archives sourceJar // 源代码打包archives javadocJar // javadoc打包}gradle.taskGraph.whenReady { // 在所有的操作准备好后触发tasks.each { task -> // 找出所有的任务if (task.name.contains('test')) { // 如果发现有test任务// 如果将enabled设置为true表示要执行测试任务,如果设置为false表示不执行测试任务task.enabled = true}}}[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'// 编码配置
}
project(":common-api") { // 进行子模块的配置dependencies { // 配置模块所需要的依赖库compile("org.springframework.boot:spring-boot-starter-web") // SpringBoot依赖compile('org.springframework.cloud:spring-cloud-starter-openfeign')}
}
project(":provider-dept-8001") { // 部门微服务dependencies {implementation(project(":common-api")) // 导入公共的子模块implementation(libraries.'mybatis-plus-boot-starter')implementation(libraries.'mysql-connector-java')implementation(libraries.'druid')implementation(libraries.'springfox-boot-starter')// 以下的依赖库为Nacos注册中心所需要的依赖配置implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery') {exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖}implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config') {exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖}implementation(libraries.'nacos-client') // 引入与当前的Nacos匹配的依赖库}
}
project(":consumer-springboot-80") { // 消费端模块dependencies {implementation(project(":common-api")) // 导入公共的子模块implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery') {exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖}implementation(libraries.'nacos-client') // 引入与当前的Nacos匹配的依赖库}
}
本地模拟RPC调用
配置文件路径:C:\Windows\System32\driversletc\hosts
服务提供者主机名称: 127.0.0.1 provider-dept-8001
服务消费者主机名称: 127.0.0.1 consumer-springboot-80
common-api子模块
创建dto类
package com.yootk.common.dto;import lombok.Data;import java.io.Serializable;
// 该类主要实现部门数据结构的映射,实现数据的远程传输
@Data // Lombok注解,自动生成所需要的类结构
public class DeptDTO implements Serializable { // 定义数据传输类private Long deptno; // 部门编号private String dname; // 部门名称private String loc; // 部门位置
}
创建服务接口
package com.yootk.service;import com.yootk.common.dto.DeptDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;import java.util.List;
import java.util.Map;
@FeignClient("dept.provider") // 定义要访问的微服务实例名称
public interface IDeptService { // 业务接口/*** 根据部门的编号获取部门的完整信息* @param id 要查询的部门编号* @return 编号存在则以DTO对象的形式返回部门数据,如果不存在返回null*/@GetMapping("/provider/dept/get/{deptno}") // 远程REST接口public DeptDTO get(@PathVariable("deptno") long id);/*** 增加部门对象* @param dto 保存要增加部门的详细数据* @return 增加成功返回true,否则返回false*/@PostMapping("/provider/dept/add")public boolean add(DeptDTO dto);/*** 列出所有的部门数据信息* @return 全部数据的集合, 如果没有任何的部门数据则集合为空(size() == 0)*/@GetMapping("/provider/dept/list")public List<DeptDTO> list();/*** 进行部门的分页数据加载操作* @param currentPage 当前所在页* @param lineSize 每页加载的数据行数* @param column 模糊查询的数据列* @param keyword 模糊查询关键字* @return 部门集合数据以及统计数据,返回的数据项包括:* 1、key = allDepts、value = List集合(部门的全部数据对象)* 2、key = allRecorders、value = 总记录数;* 3、key = allPages、value = 页数。*/@GetMapping("/provider/dept/split")public Map<String, Object> split(@RequestParam("cp") int currentPage,@RequestParam("ls") int lineSize,@RequestParam("col") String column,@RequestParam("kw") String keyword);
}
创建一个对象拷贝的工具类
在Spring 开发框架内部提供有一个BeanUJtils工具类,这个工具类有一个最大的特点就是可以直接实现对象的数据的拷贝操作,可是这个拷贝操作不包含有集合数据的拷贝处理。
package com.yootk.common.util;import org.springframework.beans.BeanUtils;import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;public class DeepBeanUtils extends BeanUtils { // 扩充已有的Bean工具类private DeepBeanUtils() {}/*** 实现List集合对象的拷贝处理* @param sources 原始对象集合* @param target 目标对象集合* @param <S> 源对象类型* @param <T> 目标对象类型* @return 拷贝后的List集合*/public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {List<T> list = new ArrayList<>(sources.size()); // 开辟一个新的List集合for (S source : sources) { // 集合迭代T obj = target.get(); // 获取数据copyProperties(source, obj); // 由父类所提供的拷贝方法list.add(obj); // 增加集合数据}return list; // 返回集合}
}
provider-dept-8001 子模块
bootstrap.yml
spring: # Spring配置项cloud: # SpringCloud配置项nacos: # Nacos注册中心的配置config: # gRPC通讯配置server-addr: nacos-server:8848 # Nacos地址 代理nacos-proxy:8848namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanCluster # 配置集群名称
application.yml
server: # 服务端配置port: 8001 # 8001端口
mybatis-plus: # MyBatisPlus配置type-aliases-package: com.yootk.provider.vo # 别名配置
spring:application: # 配置应用信息name: dept.provider # 是微服务的名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务service: ${spring.application.name} # 使用微服务的名称作为注册的服务名称server-addr: nacos-server:8848 # Nacos服务地址 代理nacos-proxy:8848namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanCluster # 配置集群名称metadata: # 根据自身的需要配置元数据version: 1.0 # 自定义元数据项company: 沐言科技 # 自定义元数据项url: www.yootk.com # 自定义元数据项author: 李兴华(爆可爱的小李老师) # 自定义元数据项datasource: # 数据源配置type: com.alibaba.druid.pool.DruidDataSource # 数据源类型driver-class-name: com.mysql.cj.jdbc.Driver # 驱动程序类url: jdbc:mysql://localhost:3306/yootk8001 # 连接地址username: root # 用户名password: mysqladmin # 连接密码druid: # druid相关配置initial-size: 5 # 初始化连接池大小min-idle: 10 # 最小维持连接池大小max-active: 50 # 最大支持连接池大小max-wait: 60000 # 最大等待时间time-between-eviction-runs-millis: 60000 # 关闭空闲连接间隔min-evictable-idle-time-millis: 30000 # 连接最小生存时间validation-query: SELECT 1 FROM dual # 状态检测test-while-idle: true # 空闲时检测连接是否有效test-on-borrow: false # 申请时检测连接是否有效test-on-return: false # 归还时检测连接是否有效pool-prepared-statements: false # PSCache缓存max-pool-prepared-statement-per-connection-size: 20 # 配置PS缓存filters: stat, wall, slf4j # 开启过滤stat-view-servlet: # 监控界面配置enabled: true # 启用druid监控界面allow: 127.0.0.1 # 访问白名单login-username: muyan # 用户名login-password: yootk # 密码reset-enable: true # 允许重置url-pattern: /druid/* # 访问路径web-stat-filter:enabled: true # 启动URI监控url-pattern: /* # 跟踪全部服务exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*" # 跟踪排除filter:slf4j: # 日志enabled: true # 启用SLF4j监控data-source-log-enabled: true # 启用数据库日志statement-executable-sql-log-enable: true # 执行日志result-set-log-enabled: true # ResultSet日志启用stat: # SQL监控merge-sql: true # 合并统计log-slow-sql: true # 慢执行记录slow-sql-millis: 1 # 慢SQL执行时间wall: # SQL防火墙enabled: true # SQL防火墙config: # 防火墙规则multi-statement-allow: true # 允许执行批量SQLdelete-allow: false # 禁止执行删除语句aop-patterns: "com.yootk.provider.action.*,com.yootk.provider.service.*,com.yootk.provider.dao.*" # Spring监控
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false"><contextName>logback</contextName><!-- 定义控制台输出匹配格式 --><substitutionProperty name="logging.pattern.console"value="%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%X{requestId}]) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ewtpc}"/><!-- 定义日志文件输出匹配格式 --><substitutionProperty name="logging.pattern.file"value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} %clr([%X{requestId}]) ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ewtpc}"/><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wtpc" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><conversionRule conversionWord="ewtpc" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/><appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!-- 控制台输出 --><layout class="ch.qos.logback.classic.PatternLayout"> <!-- 使用layout节点 --><pattern>${logging.pattern.console}</pattern> <!-- 格式引用 --></layout></appender><!-- 将每天的日志保存在一个文件之中 --><appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"><Prudent>true</Prudent><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 设置日志保存路径,本次按照月份创建日志目录,而后每天的文件归档到一组 --><FileNamePattern>muyan-logs/%d{yyyy-MM}/yootk_%d{yyyy-MM-dd}.log</FileNamePattern><MaxHistory>365</MaxHistory><!-- 删除超过365天的日志文件 --></rollingPolicy><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>INFO</level> <!-- 保存ERROR及以上级别的日志 --></filter><encoder><Pattern>${logging.pattern.file}</Pattern> <!-- 格式引用 --></encoder></appender><appender name="druidSqlFile" class="ch.qos.logback.core.rolling.RollingFileAppender"><Prudent>true</Prudent><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 设置日志保存路径,本次按照月份创建日志目录,而后每天的文件归档到一组 --><FileNamePattern>druid-logs/%d{yyyy-MM}/yootk_druid_slow_sql_%d{yyyy-MM-dd}.log</FileNamePattern><MaxHistory>365</MaxHistory><!-- 删除超过365天的日志文件 --></rollingPolicy><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ERROR</level> <!-- 保存ERROR及以上级别的日志 --></filter><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern><charset>utf-8</charset></encoder></appender><logger name="com.alibaba.druid.filter.stat.StatFilter" level="ERROR"><appender-ref ref="druidSqlFile"/></logger><logger name="com.yootk.provider.dao" level="DEBUG"/> <!-- 局部日志级别 --><root level="INFO"> <!-- 全局日志级别 --><appender-ref ref="console"/><appender-ref ref="file"/></root>
</configuration>
Swagger配置
package com.yootk.provider.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;@Configuration
public class SwaggerConfig { // Swagger配置类private ApiInfo getApiInfo() { // 文档之中的头部的信息项return new ApiInfoBuilder().title("【沐言科技】部门微服务").description("实现部门数据的统一管理,包括:增加部门信息、查询部门信息、部门列表显示等,此处省略5000字...").termsOfServiceUrl("https://www.yootk.com").contact(new Contact("爆可爱的小李老师", "edu.yootk.com", "784420216@qq.com")).license("沐言科技 - 授权管理").version("1.0.0").build();}@Beanpublic Docket getDocker() { // 所有的详细描述在此类中定义return new Docket(DocumentationType.SWAGGER_2) // 使用的文档版本类型.apiInfo(this.getApiInfo()).select() // 所有的接口一定要放在指定的包中.apis(RequestHandlerSelectors.basePackage("com.yootk.provider.action")).paths(PathSelectors.any()).build();}
}
swagger安全配置
虽然当前已经成功的实现了所需要的REST接口描述文档显示,但是这个文档显示本身会存在有一些设计上的缺陷,他没有提供安全保护,只要是个人,可以访问到你的服务器,那么就都可以进行服务调用。.
如果要想解决这种文档的安全访问的问题,唯一的做法就是使用SpringSecurity 来实现开发,因为这个框架是与SpringBoot深入绑定在一起的,那么使用它进行开发是最佳的做法。
父项目的build.gradle配置
project(":provider-dept-8001") { // 部门微服务dependencies {implementation(project(":common-api")) // 导入公共的子模块implementation(libraries.'mybatis-plus-boot-starter')implementation(libraries.'mysql-connector-java')implementation(libraries.'druid')implementation(libraries.'springfox-boot-starter')implementation('org.springframework.boot:spring-boot-starter-security')// 以下的依赖库为Nacos注册中心所需要的依赖配置implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery') {exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖}implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config') {exclude group: 'com.alibaba.nacos', module: 'nacos-client' // 移除旧版本的Nacos依赖}implementation(libraries.'nacos-client') // 引入与当前的Nacos匹配的依赖库}
}
启用安全配置之前需要进行密码的加密处理,本次使用的密码明文“yootk"
package com.yootk.test;import org.springframework.security.crypto.factory.PasswordEncoderFactories;public class TestCreatePassword {public static void main(String[] args) {String pwd = PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("yootk");System.out.println(pwd);}
}
SwaggerWebSecurityConfig
如果要想进行安全的启用,肯定要配置访问路径以及账户信息。
package com.yootk.provider.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;@Configuration
public class SwaggerWebSecurityConfig extends WebSecurityConfigurerAdapter { // Swagger安全配置// 如果有其他的需要,你可以继续进行数据库的连接配置,具体的讲解已经提供过了private static final String DEFAULT_PASSWORD ="{bcrypt}$2a$10$bvOY6ixvY5DmgiNW.Z79qeV9abQM9a6NbM1n9sejeUnB98C0kKAMu";@Beanpublic PasswordEncoder getPasswordEncoder() {return PasswordEncoderFactories.createDelegatingPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("swagger") // 默认用户名.password(DEFAULT_PASSWORD) // 默认密码.roles("USER", "ADMIN");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/swagger-ui/**", "/v2/api-docs").hasRole("ADMIN").and().httpBasic().and().formLogin().permitAll().and().csrf().disable();}
}
Swagger所提供的地址
http://provider-dept-8001:8001/swagger-ui
创建MyBatisPlus配置类
package com.yootk.provider.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisPlusConfig { // MybatisPlus配置类@Beanpublic MybatisPlusInterceptor getMybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 拦截器interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页处理return interceptor;}
}
部门 数据库创建脚本
DROP DATABASE IF EXISTS yootk8001;
CREATE DATABASE yootk8001 CHARACTER SET UTF8;
USE yootk8001;
CREATE TABLE dept (deptno BIGINT AUTO_INCREMENT,dname VARCHAR(50),loc VARCHAR(50),CONSTRAINT pk_deptno PRIMARY KEY(deptno)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO dept(dname,loc) VALUES ('开发部', database());
INSERT INTO dept(dname,loc) VALUES ('财务部', database());
INSERT INTO dept(dname,loc) VALUES ('市场部', database());
INSERT INTO dept(dname,loc) VALUES ('后勤部', database());
INSERT INTO dept(dname,loc) VALUES ('公关部', database());
COMMIT;
创建Dept映射类
package com.yootk.provider.vo;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@TableName("dept")
@Data // Lombok代码生成
public class Dept { // 这个类所需要追加MBP所需要的注解@TableId(type = IdType.AUTO) // 采用自动增长列配置private Long deptno; // 与deptno字段映射private String dname;private String loc;
}
创建IDeptDAO数据接口
package com.yootk.provider.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yootk.provider.vo.Dept;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface IDeptDAO extends BaseMapper<Dept> { // DAO接口开发完成
}
在生产端需要提供有业务接口的实现子类
package com.yootk.provider.service.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yootk.common.dto.DeptDTO;
import com.yootk.common.util.DeepBeanUtils;
import com.yootk.provider.dao.IDeptDAO;
import com.yootk.provider.vo.Dept;
import com.yootk.service.IDeptService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class DeptServiceImpl implements IDeptService {@Autowiredprivate IDeptDAO deptDAO;@Overridepublic DeptDTO get(long id) {DeptDTO dto = new DeptDTO(); // 实例化传输对象// 在本地端通过了VO类实现了数据的加载,随后将此数据拷贝到DTO对象之中BeanUtils.copyProperties(this.deptDAO.selectById(id), dto); // 属性拷贝return dto;}@Overridepublic boolean add(DeptDTO dto) {Dept dept = new Dept(); // 数据层最终需要的是一个VO类型BeanUtils.copyProperties(dto, dept);return this.deptDAO.insert(dept) > 0; // 更新行数大于0}@Overridepublic List<DeptDTO> list() {QueryWrapper<Dept> wrapper = new QueryWrapper<>();List<DeptDTO> allDepts = DeepBeanUtils.copyListProperties(this.deptDAO.selectList(wrapper), DeptDTO::new); // 集合数据拷贝return allDepts;}@Overridepublic Map<String, Object> split(int currentPage, int lineSize, String column, String keyword) {QueryWrapper<Dept> wrapper = new QueryWrapper<>();wrapper.like(column, keyword); // 设置模糊查询操作int count = this.deptDAO.selectCount(wrapper); // 统计个数// 实现数据的查询处理IPage<Dept> page = this.deptDAO.selectPage(new Page<>(currentPage, lineSize, count), wrapper);Map<String, Object> map = new HashMap<>(); // 包装返回结果map.put("allDepts", DeepBeanUtils.copyListProperties(page.getRecords(), DeptDTO::new));map.put("allRecorders", page.getTotal());map.put("allPages", page.getPages());return map;}
}
启动类
package com.yootk.provider;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartProviderDept8001Application {public static void main(String[] args) {SpringApplication.run(StartProviderDept8001Application.class, args);}
}
测试
package com.yootk.test;import com.yootk.common.dto.DeptDTO;
import com.yootk.provider.StartProviderDept8001Application;
import com.yootk.service.IDeptService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;import java.util.Map;@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@SpringBootTest(classes = StartProviderDept8001Application.class)
public class TestDeptService {@Autowiredprivate IDeptService deptService; // 注入业务接口对象@Testpublic void testGet() {System.out.println(this.deptService.get(1));}@Testpublic void testList() {System.out.println(this.deptService.list());}@Testpublic void testAdd() {DeptDTO dto = new DeptDTO();dto.setDname("公益部");dto.setLoc("洛阳");System.out.println(this.deptService.add(dto));}@Testpublic void testSplit() {Map<String, Object> map = this.deptService.split(1, 2, "dname", "");System.out.println(map);}
}
controller
package com.yootk.provider.action;import com.yootk.common.dto.DeptDTO;
import com.yootk.service.IDeptService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;@RestController
@RequestMapping("/provider/dept/*") // 微服务提供者父路径
@Slf4j // 使用一个注解
public class DeptAction {@Autowiredprivate IDeptService deptService;@ApiOperation(value="部门查询", notes = "根据部门编号查询部门详细信息")@GetMapping("get/{id}")public Object get(@PathVariable("id") long id) {return this.deptService.get(id);}@ApiOperation(value="部门增加", notes = "增加新的部门信息")@ApiImplicitParams({@ApiImplicitParam(name = "deptDTO", required = true,dataType = "DeptDTO", value = "部门传输对象实例")})@PostMapping("add")public Object add(@RequestBody DeptDTO deptDTO) { // 后面会修改参数模式为JSONreturn this.deptService.add(deptDTO);}@ApiOperation(value="部门列表", notes = "查询部门的完整信息")@GetMapping("list")public Object list() {return this.deptService.list();}@ApiOperation(value="部门分页查询", notes = "根据指定的数据库参数实现部门数据的分页加载")@ApiImplicitParams({@ApiImplicitParam(name="cp", value = "当前所在页", required = true, dataType = "int"),@ApiImplicitParam(name="ls", value = "每页显示的数据行数", required = true, dataType = "int"),@ApiImplicitParam(name="col", value = "模糊查询列", required = true, dataType = "String"),@ApiImplicitParam(name="kw", value = "模糊查询关键字", required = true, dataType = "String")})@GetMapping("split")public Object split(int cp, int ls, String col, String kw) {return this.deptService.split(cp, ls, col, kw);}
}
common-api子模块修改
由于该模块需要被其他子模块所使用,那么这个时候就需要对代码进行编译.
build.gradle:
jar { enabled = true} // 允许打包为jar文件
bootJar { enabled = false } // 不允许打包为Boot执行文件
javadocTask { enabled = false } // 不需要打包为doc文件
Gradle编译:
gradle build
【provider-dept-8001子模块】启动当前的部门微服务测试
consumer-springboot-80 子模块
application.yml
server: # 服务端配置port: 80 # 这个接口可以随意,反正最终都是由前端提供服务
spring:application: # 配置应用信息name: consumer # 是微服务的名称cloud: # Cloud配置nacos: # Nacos注册中心配置discovery: # 发现服务server-addr: nacos-server:8848 # Nacos服务地址 代理nacos-proxy:8848 namespace: 96c23d77-8d08-4648-b750-1217845607ee # 命名空间IDgroup: MICROCLOUD_GROUP # 一般建议大写cluster-name: MuyanCluster # 配置集群名称register-enabled: false # 消费端不注册
controller
package com.yootk.consumer.action;import com.yootk.common.dto.DeptDTO;
import com.yootk.service.IDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/consumer/dept/*") // 两个不同的服务路径
public class DeptConsumerAction { // 消费端Action@Autowired // 由容器帮助用户自动实例化接口对象private IDeptService deptService;@GetMapping("add") // 消费端接口名称public Object addDept(DeptDTO dto) {return this.deptService.add(dto);}@GetMapping("get")public Object get(Long deptno) {return this.deptService.get(deptno);}@GetMapping("list")public Object list() {return this.deptService.list();}@GetMapping("split")public Object split(int cp, int ls, String col, String kw) {return this.deptService.split(cp, ls, col, kw);}
}
启动类
package com.yootk.consumer;import muyan.yootk.config.ribbon.DeptProviderRibbonConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.yootk.service") // Feign扫描包
public class StartConsumerApplication {public static void main(String[] args) {SpringApplication.run(StartConsumerApplication.class, args);}
}