bladex 开发手册

发布于 2021-10-20  49.89k 次阅读


约定大于配置!!!
约定大于配置!!!
约定大于配置!!!

1、 针对本机多网卡/虚拟机IP/代理IP/docker 容器启动等情况,需指定注册段IP

  • pom 加入依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
        </dependency>
  • application.yml加入配置
spring.cloud.inetutils.preferred-networks: '172.16.'

2、日志调用

  • 落库 -> 日志独立库(nacos->balde-dev.yaml->blade.datasource.dev.log.url、blade.datasource.dev.log.username、blade.datasource.dev.log.password,【blade-log】->application.yml对应配置) private BladeLogger dblog; dblog.info("title", "data");

  dblog.info -> spring event异步订阅事件 -> 最终调ILogClient -> saveUsualLog("Info") -> blade_log_usual表

  dblog.warn-> spring event异步订阅事件 -> 最终调ILogClient -> saveUsualLog("Warn") -> blade_log_usual表

  dblog.error -> spring event异步订阅事件 -> 最终调ILogClient -> saveUsualLog("Error") -> blade_log_usual表


@ApiLog("Blog详情")
@GetMapping("/detail")
@ApiOperation(value = "查看详情", notes = "传入主键")
public R<Blog> detail(@ApiParam(value = "主键值") @RequestParam Integer id) {   
    Blog detail = service.getById(id);   return R.data(detail);
}

@ApiLog -> spring event异步订阅事件 -> 最终调ILogClient -> saveApiLog() -> blade_log_api表


public class BladeRestExceptionTranslator {
    @ExceptionHandler({Throwable.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R handleError(Throwable e) {
        log.error("服务器异常", e);
        ErrorLogPublisher.publishEvent(e, UrlUtil.getPath(WebUtil.getRequest().getRequestURI()));
        return R.fail(ResultCode.INTERNAL_SERVER_ERROR, Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage());
    }

 服务器未知异常 -> 异步订阅事件 -> 最终调ILogClient -> saveErrorLog() -> blade_log_api表

  • ELFK -> 日志系统 @Slf4j public class ...{ public void ....{ log.info("收到消息: {}", message); } }

3、分布式事务

  • 基于seata at模式
  • serviceImpl 类 stage 1 方法上标注全局事务
<dependency>
  <groupId>org.springblade</groupId>
  <artifactId>blade-starter-transaction</artifactId>
</dependency>
@GlobalTransactional
@Transactional(rollbackFor = Exception.class)
public void xxx(...){

}

4、代码结构/命名规范

  • 代码结构

├── controller

│   ├── api  #api接口
│   └── manage  #后台管理接口
├── entity
│   ├── dto    #数据传输模型
│   └── vo     #返回前端视图模型
├── feign      #内部接口
├── mapper  #xml
└── service

    └── impl #service实现

api目录命名规则,XxxApiController,路径("/api/xxx")

manage目录命名规则,XxxApiController,路径("/manage/xxx")

feign目录命名规则,IXxxClient

dto目录命名规则,XxxDto

vo目录命名规则,XxxVo

nacos配置网关可以动态修改路径,pbkdf2('blade-auth',128,1024,3) = f0c8d543bfd2d5b9a90e6a68fe7a310e

http://172.16.0.200/f0c8d543bfd2d5b9a90e6a68fe7a310e/api/order/detail

  • 数据库规则

每张表都必须建字段,

bladex 开发手册

需要实现租户时继承:TenantEntity,其他继承:BaseEntity,

主键配置如下

// IdType.ASSIGN_ID 为mybatis plus 3.x 的雪花算法
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;

application.yml

# 关闭日志配置
blade: 
  mybatis-plus: 
    sql-log: false

5、框架相关

  • 接口放行,网关不做鉴权(nacos->blade.yml)
blade:
 secure:
    skip-url:
      - /test/**
      - /weixin_return_url/**
  • 接口验签,(nacos->blade.yml)
blade:
  secure:
    sign:
      - method: ALL
        pattern: /api/order/**
        crypto: "sha1"
      - method: ALL
        pattern: /manage/**
        crypto: "md5"
  • Client客户端认证机制,(nacos->blade.yml)
blade:    #多终端认证配置,AntPatternMatch规则,ClientInterceptor.class/SecureConfiguration.class
    client:
      - client-id: sword
        path-patterns:
          - /sword/**
      - client-id: saber
        path-patterns:
          - /saber/**
      - client-id: sword/saber
        path-patterns:
          - /**/manage/**
      - client-id: android/ios/h5
        path-patterns:
          - /**/api/**

这里做了重构,

目的是为了 让 /**/api/** 的路径请求 只允许 android/ios/h5 的client token 才能访问,

已经提了MR和Issue,主要是Spring Security 的路径监听规则导致Blade的ClientInterceptor.java逻辑冲突,目前先构建本地依赖

eg: curl --location --request GET 'http://172.16.0.200/blade-demo/manage/test' \
--header 'blade-auth: bearer {{token}}' \
--header 'Authorization: Basic aW9zOjI2OTE2MDNjMWE1MGE5OTlhZjE4N2I0ZWM5M2I3YTI1'

  • 配置单人登录(nacos->blade.yaml)
blade:
  #token配置
  token:
    #单人登录
    single: true
  • 踢出已登录用户
JwtUtil.removeAccessToken(String tenantId, String userId)
  • 获取用户信息
SecureUtil.xxx()
  • Redis分布式锁(nacos->blade-dev.yaml)
#项目模块集中配置
blade:
  #分布式锁配置
  lock:
    enabled: true
    address: redis://172.16.0.201:6379
<dependency>
  <groupId>org.springblade</groupId>
  <artifactId>blade-starter-redis</artifactId>
</dependency>
@RequestMapping("/test")
@RedisLock(value = "lock:api:test")
public String test() {

}
  • Redis缓存(nacos->blade.yaml)
blade:
  #redis序列化方式,参见BladeRedisProperties.SerializerType
  redis:
    serializer-type: json
@Autowired
private BladeRedis bladeRedis;
@RequestMapping("/test")
public String test() {
    bladeRedis.set("a:b", bean);
}

6、权限模块

  • 功能权限 -> 即菜单按钮权限,参见RBAC
  • 接口权限 -> 注解@PreAuth,个别敏感接口,只允许管理员或特定角色访问,具体参见Spring security
#引入 secure
<dependency>
    <groupId>org.springblade</groupId>
    <artifactId>blade-core-auto</artifactId>
</dependency>


@PreAuth("hasAnyRole('opsPrivileger','admin')")
//修改系统参数值(手续费/商户号/...)
public boolean updateOpsParam(...){

}
  • 数据权限 -> 注解@DataAuth,具体参见dsf,租户模式实现数据权限 -> tenant_id字段,@DataAuth数据权限 -> create_dept字段,eg:租户A下面的销售角色只能看到本部及下属机构的销售统计数据

动态数据权限部分只扫描了包含Page、List的mapper方法,其他方法需要在blade.yml配置

#引入 secure
<dependency>
    <groupId>org.springblade</groupId>
    <artifactId>blade-starter-datascope</artifactId>
</dependency>

<dependency>
    <groupId>org.springblade</groupId>
    <artifactId>blade-scope-api</artifactId>
</dependency>


@DataAuth(column = "user_id", type = DataScopeEnum.OWN_DEPT_CHILD,value = "where scope.create_dept !='a' and scope.create_dept in (${deptId})")
//${deptId} -> BladeUser类属性
//column -> 可自定数据权限字段
public R saleMetricsReport(...){

}