组织与人员同步 #

  • 组织与人员同步有以下三种方式,其中RPC,HTTP在集成系统中实现,DB方式由Yo信实现,下面将详细讲述它们的实现方式。
  • 其中rpc和http方式提供集成源码供开发者参照。

RPC #

RPC框架使用的是UPush中的URPC,其性能在推送系统高并发的场景中得到了充分的验证,而且上手难度低,无需搭建额外的运行环境。 下载 (opens new window)UPush的最新版本,在libs文件夹中找到upush2-api.jar,upush2-rpc.jar复制到集成系统项目的libs文件夹,把yoxin-integration.jar放入libs, 在pom.xml中引用依赖:

<dependency>
  <groupId>com.cmcim.yoxin</groupId>
  <artifactId>yoxin-integration</artifactId>
  <version>3.0.0</version>
  <scope>system</scope>
  <systemPath>${project.basedir}/libs/yoxin-integration.jar</systemPath>
</dependency>
<dependency>
  <groupId>com.cmcim.upush</groupId>
  <artifactId>upush2-api</artifactId>
  <scope>system</scope>
  <version>2.2.6</version>
  <systemPath>${project.basedir}/libs/upush2-api.jar</systemPath>
</dependency>
<dependency>
  <groupId>com.cmcim.upush</groupId>
  <artifactId>upush2-rpc</artifactId>
  <scope>system</scope>
  <version>2.2.6</version>
  <systemPath>${project.basedir}/libs/upush2-rpc.jar</systemPath>
</dependency>
  • 在集成系统项目中包service下创建三个类用来实现同步接口,分别是YoUserServiceImpl用于用户同步,YoOrgServiceImpl用于组织同步,YoAppServiceImpl对用户可使用的集成系统应用进行鉴权,这三个类是同步的核心实现,但都是CURD并不复杂。接口参照
@Service
public class YoUserServiceImpl implements YoUserService {
  ...
}

@Service
public class YoOrgServiceImpl implements YoOrgService {
  ...
}

@Service
public class YoAppServiceImpl implements YoAppService {
  ...
}

  • 在集成系统项目中创建上面三个类对应的UPRC代理类
public class YoUserServiceRpcProxy extends URpcProvider implements YoUserService {

    private YoUserService userService;

    public YoUserServiceRpcProxy(YoUserService userService) {
        this.userService = userService;
    }

    // 方法实现举例,即把YoUserServiceImpl中在这里调用一遍
    @Override
    public YoUserDto getUserDto(String userId) throws Exception {
        return userService.getUserDto(userId);
    }

    // ... 其他方法同上
}

public class YoOrgServiceRpcProxy extends URpcProvider implements YoOrgService {
    private YoOrgService orgService;

    public YoOrgServiceRpcImpl(YoOrgService service) {
        this.orgService = service;
    }

    // 方法实现举例,即把YoOrgServiceImpl中在这里调用一遍
    @Override
    public YoPageInfo<YoOrgMemberDto> getOrgMembers(String orgId, Integer page, Integer count, Boolean hasSubOrg, String filter) throws Exception {
        return orgService.getOrgMembers(orgId, page, count, hasSubOrg, filter);
    }

    // ... 其他方法同上
}

public class YoAppServiceRpcProxy extends URpcProvider implements YoAppService {

    private YoAppService yoAppService;

    public YoAppServiceRpcProxy(YoAppService yoAppService) {
        this.yoAppService = yoAppService;
    }

    @Override
    public List<YoAppDto> getWorkbenchApps(List<YoAppDto> list) throws Exception {
        return yoAppService.getWorkbenchApps(list);
    }
}

  • 初始化URPC服务,需要在Springboot启动后,所有Bean都加载完之后再初始化URPC,所以在集成系统中创建如下类:
@Slf4j
@Component
public class AppLifeCycleConfig implements CommandLineRunner, DisposableBean {

    // 注入三个同步实现类,用来构造代理对象
    @Autowired
    YoUserService yoUserService;
    @Autowired
    YoOrgService yoOrgService;
    @Autowired
    YoAppService yoAppService;

    // 配置注入
    @Autowired
    UPushConfig upushConfig;

    // rpc服务
    private URpcServer rpcServer;

    // 程序结束会执行destroy,停止rpc服务
    @Override
    public void destroy() {
        rpcServer.stop();
    }

    // 所有Bean初始化完成后会执行run方法,初始化并启动rpc服务
    @Override
    public void run(String... args) throws Exception {
        rpcServer = new URpcServer();
        // 注册rpc 代理对象
        rpcServer.register(new YoUserServiceRpcProxy(yoUserService));
        rpcServer.register(new YoOrgServiceRpcProxy(yoOrgService));
        rpcServer.register(new YoAppServiceRpcProxy(yoAppService));

        // 对请求和应答的拦截,可在这里输入日志,添加上下文
        rpcServer.setInterceptor(new IURpcServerInterceptor() {
            @Override
            public void beginReturn(IoSession ioSession, URpcReturn uRpcReturn) {
                // 应答/返回
                log.debug("[URpc Rsp] {}", uRpcReturn.toString());
            }

            @Override
            public void beginInvoke(IoSession ioSession, URpcFunction uRpcFunction) {
                // 请求/调用
                log.debug("[URpc Req] {}, {}", uRpcFunction.getMethod(), uRpcFunction.getParams());
            }
        });

        // 启动rpc服务,第一个参数为服务名,任意起名即可,第二个参数是rpc服务端口
        rpcServer.start("urpc", upushConfig.getUrpcPort());
        log.info("urpc server start success");
    }

}

HTTP #

  • http方式同样需要引入依赖,但只需要引入yoxin-integration即可
<dependency>
  <groupId>com.cmcim.yoxin</groupId>
  <artifactId>yoxin-integration</artifactId>
  <version>3.0.0</version>
  <scope>system</scope>
  <systemPath>${project.basedir}/libs/yoxin-integration.jar</systemPath>
</dependency>

  • http方式同样需要实现,YoUserService,YoOrgService,YoAppService这三个接口,具体可参照上面rpc方式

  • http方式需要集成系统提供restful api接口。请按照下面的接口规范创建接口,接口参数说明参照
@RestController
// 请求的前缀可任何设置,但下面的Mapping路径保持固定
@RequestMapping(value = "/integration")
public class IntegrationController {

    // 注入三个同步实现类,在接口中直接调用
    @Autowired
    YoOrgService orgService;
    @Autowired
    YoUserService userService;
    @Autowired
    YoAppService appService;

    /**
     * BaseResponseInfo 结构为:
     * {
     *  code: 0, // 应该状态码 0 表示正确
     *  msg: "", // 错误内容
     *  data: {} // 应答内容 
     * }  
     * 
     * 实际集成时类名可任意定义,保持上面一样的数据结构即可
     */

    @PostMapping("/apps")
    public BaseResponseInfo getWorkbenchApps(@RequestBody List<YoAppDto> list) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = appService.getWorkbenchApps(list);
        return res;
    }

    @GetMapping("/org/{orgId}/members")
    public BaseResponseInfo getOrgMembers(@PathVariable("orgId") String orgId,
                                          @RequestParam("page") Integer page,
                                          @RequestParam("count") Integer count,
                                          @RequestParam("hasSubOrg") Boolean hasSubOrg,
                                          @RequestParam("filter") String filter) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.getOrgMembers(orgId, page, count, hasSubOrg, filter);
        return res;
    }

    @GetMapping("/org/{orgId}/member/{memberId}/exist")
    public BaseResponseInfo isMemberInOrg(@PathVariable("orgId") String orgId,
                                          @PathVariable("memberId") String memberId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.isMemberInOrg(orgId, memberId);
        return res;
    }

    @GetMapping("/org/member/{userId1}/and/{userId2}/in/same/company")
    public BaseResponseInfo isInSameCompany(@PathVariable("userId1") String userId1,
                                            @PathVariable("userId2") String userId2) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.isInSameCompany(userId1, userId2);
        return res;
    }

    @GetMapping("/org/customer/service")
    public BaseResponseInfo getCustomerServiceAgent(@RequestBody String str) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.getCustomerServiceAgent(str);
        return res;
    }

    @GetMapping("/org/{orgId}/all/parents")
    public BaseResponseInfo parentOrgIds(@PathVariable("orgId") String orgId,
                                         @RequestParam("companyId") String companyId,
                                         @RequestParam("containCompany") Boolean containCompany) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.parentOrgIds(orgId, companyId, containCompany);
        return res;
    }

    @GetMapping("/org/{orgId}/base")
    public BaseResponseInfo getOrgBase(@PathVariable("orgId") String orgId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.getOrgBase(orgId);
        return res;
    }

    @GetMapping("/org/{orgId}")
    public BaseResponseInfo getOrg(@PathVariable("orgId") String orgId,
                                   @RequestParam("hasSubOrg") Boolean hasSubOrg,
                                   @RequestParam("hasSubCompany") Boolean hasSubCompany,
                                   @RequestParam("hasMemberNum") Boolean hasMemberNum) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.getOrg(orgId, hasSubOrg, hasSubCompany, hasMemberNum);
        return res;
    }

    @GetMapping("/org/user/{userId}/company")
    public BaseResponseInfo getUserCompany(@PathVariable("userId") String userId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.getUserCompany(userId);
        return res;
    }

    @GetMapping("/org/{orgId}/parent/{parentId}/exist")
    public BaseResponseInfo isSubOrg(@PathVariable("orgId") String orgId, @PathVariable("parentId") String parentId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.isSubOrg(orgId, parentId);
        return res;
    }

    @GetMapping("/org/{orgId}/user/{userId}/role/exist")
    public BaseResponseInfo isUserHasOrgRole(@PathVariable("orgId") String orgId,
                                             @PathVariable("userId") String userId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = orgService.isUserHasOrgRole(orgId, userId);
        return res;
    }

    @GetMapping("/user/{userId}")
    public BaseResponseInfo getUserDto(@PathVariable("userId") String userId) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = userService.getUserDto(userId);
        return res;
    }

    @GetMapping("/user/{username}/category/{category}")
    public BaseResponseInfo getUserBaseDto(@PathVariable("username") String username,
                                           @PathVariable("category") String category) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = userService.getUserBaseDto(username, category);
        return res;
    }

    @PutMapping("/user/{userId}/gender/{gender}")
    public BaseResponseInfo updateUserGender(@PathVariable("userId") String userId,
                                             @PathVariable("gender") Integer gender) throws Exception {
        userService.updateUserGender(userId, gender);
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = null;
        return res;
    }

    @PutMapping("/user/{userId}/phone/{phone}")
    public BaseResponseInfo updateUserPhone(@PathVariable("userId") String userId,
                                            @PathVariable("phone") String phone) throws Exception {
        userService.updateUserPhone(userId, phone);
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = null;
        return res;
    }

    @PutMapping("/user/{userId}/email/{email}")
    public BaseResponseInfo updateUserEmail(@PathVariable("userId") String userId, @PathVariable("email") String email) throws Exception {
        userService.updateUserEmail(userId, email);
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = null;
        return res;
    }

    @PutMapping("/user/{userId}/password/{password}")
    public BaseResponseInfo updateUserPassword(@PathVariable("userId") String userId, @PathVariable("password") String password) throws Exception {
        userService.updateUserPassword(userId, password);
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = null;
        return res;
    }

    @PostMapping("/user")
    public BaseResponseInfo addUser(@RequestBody YoUserBaseDto baseDto) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = userService.addUser(baseDto);
        return res;
    }

    @GetMapping("/user/{userId}/password/{password}")
    public BaseResponseInfo checkUserPassword(@PathVariable("userId") String userId, @PathVariable("password") String password) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = userService.checkUserPassword(userId, password);
        return res;
    }

    @GetMapping("/user/sync")
    public BaseResponseInfo getUserSyncList(@RequestParam("page") Integer page,
                                            @RequestParam("count") Integer count) throws Exception {
        BaseResponseInfo res = new BaseResponseInfo();
        res.code = 0;
        res.data = userService.getUserSyncList(page, count);
        return res;
    }
}

DB #

  • 前两种方式都是在集成系统中实现,通过网络调用,DB方式在Yo信服务端实现,直接读取数据库,是三种方式效率最高的方式
  • DB方式直接连接到集成系统的数据库,通过读取用户,组织表来实现这个三个接口类(YoUserService,YoOrgService,YoAppService)
  • DB方式需要集成系统提供相关的表结果说明
  • DB可以在集成系统无源码,集成系统的开发团队无法继续开发时使用

同步效果展示 #

下面以PC端展示,移动端效果一致。

组织架构 #

  • 集成系统组织架构

  • Yo信组织架构

人员 #

  • 集成系统人员

  • Yo信人员

通过聊天选人功能来查看公司所有人