java-mirror-server/ReadMe.md

413 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Spring微服务模板
每个服务下都有`Dockerfile`文件,几乎是写好的模板,如果要添加在这基础上即可。
- 基础包有
- 微服务基础功能openFein
- 邮件发送
- WebSocket
- Minio
- Redis
- rabbitMq
- velocity
- IP地址查询
- knife4j
- 数据库多源配置
- 启动类一共有两个,网关是必不可少的
1. web端
2. admin端
3. gateway网关
## 基础配置
### 微服务模块
微服务请求其它模块无法从线程中获取到值将用户Token放在请求头中这样从请求头中获取Token即可
`common/common-service/src/main/java/cn/bunny/common/service/interceptor/UserTokenFeignInterceptor.java`
```java
/**
* * 微服务请求其它模块找不到Token无法从线程中获取值
* 传递请求头,在微服务中
*/
public class UserTokenFeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
HttpServletRequest request = requestAttributes.getRequest();
String token = request.getHeader("token");
requestTemplate.header("token", token);
}
}
```
### 配置文件详情
### 打包命令
命令解释:清理之前内容,打包,使用生产环境,跳过测试
```shell
mvn clean package -Pprod -DskipTests
```
#### SpringBoot配置文件
在开发中需要使用到开发环境、上线需要生产环境,在环境中设置`@profiles.active@`可以根据不同环境切换
```yaml
spring:
profiles:
active: @profiles.active@
application:
name: service-admin
```
只需要在IDE中勾选相关环境即可
![image-20240822093552802](./images/image-20240822093552802.png)
> 注意!!!
>
> 因为Java每次启动都需要生成target有缓存在里面很有可能明明选择了配置但是没有生效的情况。
>
> 解决办法就是,每次改变环境执行`mvn clean`或者点击IDE中`mvn clean`
>
> ![image-20240822093803078](./images/image-20240822093803078.png)
### Dockerfile配置
如果需要访问宿主机文件目录这个是Docker内部地址
```dockerfile
# 程序内部挂在目录
VOLUME /home/server/uploads
```
#### IDE中配置
![image-20240822094021339](./images/image-20240822094021339.png)
![image-20240822094000542](./images/image-20240822094000542.png)
### 整体返回响应
整体返回响应如下
```java
// 状态码
private Integer code;
// 返回消息
private String message;
// 返回数据
private T data;
```
![image-20240822092441020](./images/image-20240822092441020.png)
和分页返回
```java
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ResultPage<T> implements Serializable {
// 当前页
private Integer pageNo;
// 每页记录数
private Integer pageSize;
// 总记录数
private long total;
// 当前页数据集合
private List<T> list;
}
```
以及常用的枚举状态码(展示部分)
![image-20240822092510151](./images/image-20240822092510151.png)
### 多数据库源配置
开发中有时会使用到多个数据库源这个配置也是来自MybatisPlus官方推荐的库
```xml
<!-- 多数据库源插件 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.3.1</version>
</dependency>
```
#### 配置简介
如果不需要多数据库,移除包之后将注释的部分放开,删除`dynamic`节点以下内容
```java
datasource:
# type: com.zaxxer.hikari.HikariDataSource
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://${bunny.datasource.host}:${bunny.datasource.port}/${bunny.datasource.sqlData}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
# username: ${bunny.datasource.username}
# password: ${bunny.datasource.password}
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
grace-destroy: false #是否优雅关闭数据源默认为false设置为true时关闭数据源时如果数据源中还存在活跃连接至多等待10s后强制关闭
datasource:
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${bunny.datasource.host}:${bunny.datasource.port}/${bunny.datasource.sqlData}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: ${bunny.datasource.username}
password: ${bunny.datasource.password}
aop:
enabled: true
```
## 中间件配置
### mybatis-plus
#### 配置详情
配置乐观锁、防止全表删除、最大分页100页
`common/service-utils/src/main/java/cn/bunny/common/service/config/MybatisPlusConfig.java`
```java
/**
* Mybatis-Plus配置类
*/
@EnableTransactionManagement
@Configuration
@Slf4j
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
paginationInnerInterceptor.setMaxLimit(100L);// 设置最大分页为100
interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 乐观锁
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防止全表删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
```
如果如要插入和修改时,自定义时间或者其它可以在这设置
`common/service-utils/src/main/java/cn/bunny/common/service/config/MyBatisPlusFieldConfig.java`
```java
/**
* 配置MP在修改和新增时的操作
*/
@Component
public class MyBatisPlusFieldConfig implements MetaObjectHandler {
/**
* 使用mp做添加操作时候这个方法执行
*/
@Override
public void insertFill(MetaObject metaObject) {
// 设置属性值
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("deleteStatus", 1, metaObject);
if (BaseContext.getUsername() != null) {
this.setFieldValByName("createBy", BaseContext.getUsername(), metaObject);
this.setFieldValByName("updateBy", BaseContext.getUsername(), metaObject);
}
}
/**
* 使用mp做修改操作时候这个方法执行
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("updateBy", BaseContext.getUsername(), metaObject);
}
}
```
### Redis
#### 配置详情
分别设置了过期30天、1小时、3分钟
`common/service-utils/src/main/java/cn/bunny/common/service/config/RedisConfiguration.java`
```java
/**
* * 配置Redis过期时间30天
* 解决cache(@Cacheable)把数据缓存到redis中的value是乱码问题
*/
@Bean
@Primary
@SuppressWarnings("all")
public CacheManager cacheManagerWithMouth(RedisConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer()))
.entryTtl(Duration.ofDays(30));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
/**
* * 配置redis过期时间3分钟
*
* @param factory
* @return
*/
@Bean
@SuppressWarnings("all")
public CacheManager cacheManagerWithMinutes(RedisConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(3));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
/**
* * 配置Redis过期时间1小时
*
* @param factory
* @return
*/
@Bean
@SuppressWarnings("all")
public CacheManager cacheManagerWithHours(RedisConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer()))
.entryTtl(Duration.ofHours(1));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
```
#### 使用详情
如果需要指定Redis配置`cacheManager="Redis配置中方法名"`
使用springCache只需要在方法上加上下面代码
```java
@Cacheable(value = "TaskStatistics", key = "'ByDepartment::'+#departmentName",
cacheManager = "cacheManagerWithMinutes")
```
### Minio
#### 配置详情
Minio没有给出SpringBoot的配置文件下面是自定义实现
`module/module-minio/src/main/java/cn/bunny/module/minio/properties/MinioProperties.java`
在配置文件中有这4个配置字段
```java
@Configuration
@ConfigurationProperties(prefix = "bunny.minio")
@ConditionalOnProperty(name = "bunny.minio.bucket-name")// 当属性有值时这个配置才生效
@Data
@Slf4j
public class MinioProperties {
private String endpointUrl;
private String accessKey;
private String secretKey;
private String bucketName;
@Bean
public MinioClient minioClient() {
log.info("注册MinioClient...");
return MinioClient.builder().endpoint(endpointUrl).credentials(accessKey, secretKey).build();
}
}
```
在项目中加入了Minio常用工具方法对Minio二次封装
![image-20240822091720866](./images/image-20240822091720866.png)
### 邮箱发送
邮箱发送配置的是动态邮件,发件人是动态的不是写死在配置文件中
![image-20240822091810597](./images/image-20240822091810597.png)
#### 配置文件
如果不需要动态配置可以在`SpringBoot`配置文件中加入下面的配置
```properties
mail:
host: smtp.qq.com # 邮箱地址
port: 465 # 邮箱端口号
username: xxx@qq.com # 设置发送邮箱
password: xx # 如果是纯数字要加引号
default-encoding: UTF-8 # 设置编码格式
protocol: smtps
properties:
mail:
debug: true # 是否开启debug模式发送邮件
smtp:
auth: true
connectionTimeout: 5000 # 设置连接延迟
timeout: 5000 # 延迟时间
writeTimeout: 5000 # 写入邮箱延迟
allow8BitMime: true
sendPartial: true
ssl:
enabled: true # 是否开启SSL连接
socketFactory:
class: javax.net.ssl.SSLSocketFactory # 必要设置!!!
```
### SpringSecurity
因为项目做的是开发模板在admin模板中集成了安全框架
`module/spring-security/src/main/java/cn/bunny/security/config/WebSecurityConfig.java`
在这个文件最下面是排除路径不需要Security检测的路径根据自己需求进行修改因为整合了knife4j在测试时需要放开swagger配置响应请求等。
```java
/**
* * 排出鉴定路径
*
* @return WebSecurityCustomizer
*/
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
String[] annotations = {"/", "/test/**", "/diagram-viewer/**", "/editor-app/**", "/*.html",
"/*/*/noAuth/**", "/*/noAuth/**", "/favicon.ico", "/swagger-resources/**", "/webjars/**",
"/v3/**", "/swagger-ui.html/**", "/doc.html"};
return web -> web.ignoring().requestMatchers(annotations);
}
```