# SDK集成方案
应用远程调用模式,即集成SDK,应用集成SDK实际是发送rest请求远程调用AFCenter。
注:应用集成SDK前提是该应用项目为EOS项目且版本为8.1.2版本(包含)以上。
- 开发依赖包
<dependency>
<groupId>com.primeton.gocom</groupId>
<artifactId>com.primeton.gocom.afcenter.sdk</artifactId>
<version>8.2.1</version>
</dependency>
配置详情
网关集成AFCenter的SDK共有两种模式:
1.直接在项目配置文件中使用ip加端口模式完成AFCenter的SDK接口调用,如下所示:
afc.application.name=127.0.0.1:8081
afc.application.tenant=sys_tenant
afc.application.appCode=AFCenter
afc.application.appSecret=b771a0ad37c34baeab2b6f73fbebcabd
tenant为系统默认租户,appCode为系统初始化应用编码,appSecret为改应用密匙,都可使用admin账号登录AFCenter平台后获取。
- 在项目配置文件中使用nacos服务名模式完成AFCenter的SDK接口调用,如下所示:
afc.application.name=AFCENTER
afc.application.tenant=sys_tenant
afc.application.appCode=AFCenter
afc.application.appSecret=b771a0ad37c34baeab2b6f73fbebcabd
afc.application.name
的值为AFCenter服务启动后在nacos中注册的服务名。
注:使用nacos服务名模式集成AFCenter的SDK需要与AFCenter配置同一nacos地址。
接口说明
com.primeton.gocom.afcenter.sdk.api包中接口即可。
使用方式
直接使用@Autowired
方式注入IAFCClient,再get相应API类后再调用对应的API方法。
也可以使用AFCClientFactory去获取IAFCClient
IAFCClient afcClient=AFCClientFactory.getInstance().createAFCClient();
@RestController
public class TestController {
@Autowired
private IAFCClient afcClient;
@GetMapping(value = "/api/user")
public User getAfcApiUser() {
IUserAPI userApi = afcClient.getUserAPI();
User user = userApi.findUserByCode("sysadmin");
return user;
}
}
# 常见问题
应用集成AFCenter的SDK的过程中容易出现的问题:
1.AFCenter的SDK版本依赖问题:
目前版本已更新为8.2.1-SNAPSHOT
,后续版本变更文档中会及时更新。
2.应用项目集成SDK后,调用SDK接口出现401
状态码,AFCenter日志打印提示访问该接口前未登录问题:
首先确保AFCenter平台用户账号已登录,通过postman调用应用的接口(headers中传入Authorization,Authorization值是在afc登陆接口返回值中获取的)。
其次遇到session共享的问题,请排查以下几点:
a. 应用与AFCenter是否属于同系统。
b. redis是否使用同一个。
c. user-config.xml中是否开启系统内共享开关。
<group name="CacheForUserObject">
<configValue key="IsSystemCache">true</configValue>
<configValue key="CacheMode">REPL_ASYNC</configValue>
<configValue key="IsSystemShare">true</configValue>
</group>
d. 是否加入登录接口过滤白名单
注:afcenter的user-config.xml文件中登录过滤白名单要加入/api/afc/afc-proxy/*;
<group name="Login-Filter">
<!-- pages that can be accessed by any one including those not login -->
<configValue
key="Exclude">/api/afc/afc-proxy/*,/api/afc/oauth2/*,/api/afc/login/third-party/auth,/api/afc/login/third-party/qrConnect,/afc-proxy/*,/api/afc/validation-code,/swagger-ui.html,/v2/api-docs,/webjars/*,/swagger-resources/*,/afc,/afc/,/api/afc/login,/api/afc/login/password/key,/actuator/*,/om/*,/common.remote,
/jmxDefault.jmx,/common.download</configValue>
<!-- <configValue key="Include">*.flow,*.flowx,*.jsp,*.html,*.ajax,*.ext,*.action,*.beanx</configValue> -->
<configValue key="Include">/*</configValue>
<!-- the page to display when user not login -->
<configValue key="LoginPage"></configValue>
</group>
# SDK开发说明
# 公共方法说明
1、com.primeton.gocom.afcenter.common.sdk.SdkClientFactory:sdk客户端工厂
/**
* 注册本地sdk api实现
*
* @param sdkApiClass sdk接口类
* @param sdkApiLocalImpl sdk本地实现对象
*/
public static void registLocalSdkApiImpl(Class sdkApiClass, Object sdkApiLocalImpl);
/**
* 获取客户端
*
* @param clientClass 客户端类
* @param starterClassName starter配置的类名,用于判断是本地,还是远程
* @param sdkApiRemoteMethodInvocationHandler 远程实现的方法拦截对象
* @return 客户端类
*/
public static <T> T getClientProxy(Class<T> clientClass, String starterClassName, IMethodInvocationHandler sdkApiRemoteMethodInvocationHandler);
2、com.primeton.gocom.afcenter.common.sdk.AbstractSdkApiRemoteMethodInvocationHandler:sdk api 远程方法调用抽象实现
// 路径前缀
protected String pathPrefix = null;
// 服务名或者应用名(nacos对应)
protected String serviceName = null;
// header
protected Map<String, String> mapHeader = new HashMap<>();
# Afc sdk实现示例说明
1、afc sdk api,使用用户的IUserAPI示例
1) 接口定义(在sdk模块中):
要求:I+资源名+API
public interface IUserAPI {
User findUserByCode(String userCode);
。。。
}
2)本地实现(在sdk模块中)
public class UserLocalImpl implements IUserAPI {
private IUserService userService;
public UserLocalImpl() {
this.userService = EOS8ApplicationContext.INSTANCE.getBean(IUserService.class);
// 可以在这里注册本地实现,也可以在后续的factory中
// SdkClientFactory.registLocalSdkApiImpl(IUserAPI.class, this);
}
/**
* 根据用户code 查询用户信息
*
* @param userCode 用户code
* @return 用户实体
*/
@Override
public User findUserByCode(String userCode) {
return userService.findUserByCode(userCode, StatusEum.ENABLE.getCode());
}
。。。
}
3)远程实现(在restproxy模块中):
要求,httpPath是资源名(小写)/方法名(-连接), http方法是post,参数是MultiRequestBody类型。
@ApiIgnore
@RestController
@RequestMapping(value = SDK_URL_PREFIX + "/user", consumes = {APPLICATION_JSON_UTF8_VALUE}, produces = {APPLICATION_JSON_UTF8_VALUE})
public class UserProxyController implements IUserAPI {
@Autowired
private IUserService userService;
/**
* 根据用户code查询可用用户信息
*/
@PostMapping("/find-user-by-code")
@Override
public User findUserByCode(@ApiParam("用户code") @MultiRequestBody String userCode) {
return userService.findUserByCode(userCode, StatusEum.ENABLE.getCode());
}
。。。
}
2、afc sdk client
1)afc sdk client(在sdk模块中)
public interface IAFCClient {
IUserAPI getUserAPI();
。。。
}
2)远程调用AfcSdkApiRemoteMethodInvocationHandler(在sdk模块中)
public class AfcSdkApiRemoteMethodInvocationHandler extends AbstractSdkApiRemoteMethodInvocationHandler {
private static final long serialVersionUID = 1L;
public static final String APPCODE = "afc-appCode";
public static final String APPSECRET = "afc-appSecret";
public static final String TENANTID = "afc-tenantId";
public AfcSdkApiRemoteMethodInvocationHandler() {
// 路径前缀
this.pathPrefix = "api/afc/afc-proxy";
//服务名或者应用名
this.serviceName = EOS8ApplicationContext.INSTANCE.getProperty("afc.application.name");
// head相关参数
String tenant = EOS8ApplicationContext.INSTANCE.getProperty("afc.application.tenant");
String appCode = EOS8ApplicationContext.INSTANCE.getProperty("afc.application.appCode");
String appSecret = EOS8ApplicationContext.INSTANCE.getProperty("afc.application.appSecret");
Map<String, String> mapHeader = new HashMap<>();
if(StringUtils.isBlank(tenant)) {
HttpServletRequest httpRequest = DataContextService.current().getHttpRequest();
if (httpRequest != null) {
String tenantId = httpRequest.getHeader(CommonConstants.TENANT);
if(StringUtils.isBlank(tenantId)) {
tenantId = httpRequest.getParameter(CommonConstants.TENANT);
}
if (StringUtils.isNotBlank(tenantId)) {
mapHeader.put(TENANTID, tenantId);
}
}
} else {
mapHeader.put(APPCODE, appCode);
mapHeader.put(APPSECRET, appSecret);
mapHeader.put(TENANTID, tenant);
}
}
}
3)afc sdk client 工厂(在sdk模块中)
public class AFCClientFactory {
private static AFCClientFactory instance = null;
private AFCClientFactory() {
// 注册本地sdk api实现,如果在构造方法中注册,此处可以不用
SdkClientFactory.registLocalSdkApiImpl(IUserAPI.class, new UserLocalImpl());
...
}
public static AFCClientFactory getInstance() {
if(instance == null) {
instance = new AFCClientFactory();
}
return instance;
}
// 获取afc sdk 客户端
public IAFCClient createAFCClient() {
return SdkClientFactory.getClientProxy(IAFCClient.class,
"com.primeton.gocom.afcenter.starter.config.AFCServerAutoConfiguration",
new AfcSdkApiRemoteMethodInvocationHandler());
}
}
4)AFCSDKConfiguration:sdk中的配置类(在sdk模块中)
@Configuration
@ComponentScan(basePackages = "com.primeton.gocom.afcenter")
public class AFCSDKConfiguration {
@Bean
public IAFCClient afcClient() {// spring方式使用
return AFCClientFactory.getInstance().createAFCClient();
}
。。。
}
3、使用
1)直接使用
IUserAPI userApi = AFCClientFactory.getInstance().createAFCClient().getUserAPI();
2)spring方式使用
@Autowired
private IAFCClient afcClient;