java日常开发笔记

利用枚举进行业务逻辑抽象

2020-01-19  本文已影响0人  毁于一蛋

背景需求

用户管理模块,需要系统兼容本地用户架构和第三方的用户架构,比如淘宝,微信,或者其他的公司的ladp服务器的组织架构

何为抽象

java的三大特性,封装、继承、多态
封装:封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问。
继承:继承是类与类的一种关系,比较像集合中的从属于关系。
多态:对象的多种形态。多态有两种:引用多态和方法多态。继承是多态的实现基础。
搞清楚两点:引用多态、方法多态

如何针对这个业务抽象

定义枚举:

这里将用户的组织架构类型给抽象枚举出来,枚举的意思类似于举例,枚举是单实例的

/**
 * create by wuxuan.chai
 *
 * @since 4.7.3
 **/
public enum PlatCodeValue {
    /** 用于与crm的集成认证 */
    crm {
    },
    /** ldap */
    ldap {
        @Override
        public Role fetchOrgRole(ThirdOrg thirdOrg, ThirdUser thirdUserNickName) {
            String ldapDefaultRoleName = LdapConfiguration.getInstance().getLdapDefaultRoleName();
            return ApplicationContextHolder.getInstance(RoleService.class).fetchRoleByName(ldapDefaultRoleName);
        }
    },
    local {

    };

    public Role fetchOrgRole(ThirdOrg thirdOrg, ThirdUser thirdUserNickName) {
        return ApplicationContextHolder.getInstance(RoleService.class).fetchRoleByName(Role.NAME_ORG_MEMBER);
    }
}

定义接口

接口是定义业务通用的方法,如你你这个用户管理将要实现什么功能,需要做什么,接口定义的方法都将是通用的方法,即每一个枚举类中枚举的用户管理模块都具备的功能

/**
 * create by wuxuan.chai
 * at 2019/11/25 5:29 下午
 *
 * @since 4.7.3
 **/

public interface IUserResolver {

    //支持的类型
    PlatCodeValue supportType();

    //刷新用户的权限信息
    void refreshPermission(Long platUserId, Organization organization);

    //获取用户列表
    UserVO fetchUserList(UserVO queryUserVo);

    //获取组织架构节点
    OrgTagVO fetchOrgTagList(OrgTagVO queryOrgVo);


}

定义父类

父类的作用:给子类提供类引用、父类提供所有子类的实现模版方法,或者默认实现,一般父类中的抽象方法都是子类必须实现的,而非抽象方法则是父类给子类的提供的默认实现


/**
 * create by wuxuan.chai
 * at 2019/11/25 5:49 下午
 *
 * @since 4.7.3
 **/

public abstract class UserResolverSupport implements IUserResolver, InitializingBean {
    @Override
    public PlatCodeValue supportType() {
        return null;
    }

    @Override
    public abstract void refreshPermission(Long platUserId, Organization organization);

    @Override
    public abstract UserVO fetchUserList(UserVO queryUserVo);

    @Override
    public abstract OrgTagVO fetchOrgTagList(OrgTagVO queryOrgVo);


    @Override
    public void afterPropertiesSet() {
        PlatCodeValue platCodeValue = this.supportType();
        if(platCodeValue == null){
            return;
        }
        UserResolverRegistry.getInstance().registerUserResolver(platCodeValue,this);
    }
}

注册类

1、子类的注册类,这个类的作用就是将所有的子类实现和枚举进行绑定,在特定的调用位置时,可以通过这个类去获取到特定的枚举业务的实现类,执行特定的实现方法。当然直接调用具体的子类也可以,但是一旦业务场景由某个参数控制时,就不灵活了。
2、这个类是单实例的,使用的是恶汉式单示例的方式。在spring的bean初始化时完成所有子类的注入。详细可见这个类中的逻辑。

/**
 * create by wuxuan.chai
 * at 2019/11/25 5:55 下午
 *
 * @since
 **/

public class UserResolverRegistry {
    public static final UserResolverRegistry INSTANCE = new UserResolverRegistry();

    public Map<PlatCodeValue,IUserResolver> iUserResolverMap = Maps.newHashMap();

    public static UserResolverRegistry getInstance(){
        return INSTANCE;
    }

    public void registerUserResolver(PlatCodeValue platCodeValue,IUserResolver iUserResolver){
        iUserResolverMap.put(platCodeValue,iUserResolver);
    }

    public IUserResolver getUserResolver(PlatCodeValue platCodeValue){
        return iUserResolverMap.get(platCodeValue);
    }
}

实现类

针对Newbi的本地用户管理的特定实现

/**
 * create by wuxuan.chai
 * at 2019/11/25 6:04 下午
 *
 * @since 4.7.3
 **/
@Service
public class NewBIUserResolver extends UserResolverSupport {
    @Resource
    private RbacUserService rbacUserService;
    @Resource
    private OrgTagService orgTagService;


    @Override
    public PlatCodeValue supportType() {
        return PlatCodeValue.local;
    }

    @Override
    public void refreshPermission(Long platUserId, Organization organization) {
        //nothing
    }

    @Override
    public UserVO fetchUserList(UserVO userVO) {
        //模糊查询(email/nickname)
        CRMUserParamVO queryUserVo = userVO.getQueryUserVo();
        Page page = userVO.getPage();
        String kw = queryUserVo.getKw();
        //获取某个节点下的直属用户
        Integer tagId = queryUserVo.getOrgId();
        List<Tag> filterTags = Lists.newArrayList();
        if(tagId != null) {
            Tag singleTag = Tag.fetch(Long.valueOf(tagId));
            filterTags.add(singleTag);
        }
        //获取某个节点下的所有子节点的所有用户
        Integer topTagId = queryUserVo.getTopOrgId();
        if(!ObjectUtils.isLogicalNull(topTagId)) {
            Tag topTag = Tag.fetch(Long.valueOf(topTagId));
            List<Tag> childrenTags = orgTagService.fetchChildTags(orgTagService.list(OrgUtils.fetchOrgId()), topTag.getId());
            filterTags.add(topTag);
            filterTags.addAll(childrenTags);
        }
        List<Long> filterTagIds = Lists.transform(filterTags, Tag::getId);
        List<User> users = rbacUserService.fuzzyQueryUsers(kw, page,filterTagIds)
                                .stream()
                                .peek(user->user.attr("isLocal","true"))
                                .collect(Collectors.toList());
        return UserVO.builder()
                .users(users)
                .page(page)
                .build();
    }

    @Override
    public OrgTagVO fetchOrgTagList(OrgTagVO orgTagVO) {
        //模糊查询
        CRMOrgTagParamVO queryOrgVo = orgTagVO.getQueryOrgVo();
        String kw = queryOrgVo.getKw();
        Integer integer = Optional.ofNullable(queryOrgVo.getParentId()).orElse(0);
        Long parentId = Long.valueOf(integer);
        Page page = orgTagVO.getPage();
        List<Tag> tagList = orgTagService.fuzzyQueryTags(kw, parentId, page);
        return OrgTagVO.builder()
                .tags(tagList)
                .page(page)
                .build();
    }
}

针对于公司的crm的用户的特定实现

/**
 * create by wuxuan.chai
 * at 2019/11/25 6:05 下午
 *
 * @since 4.7.3
 **/
@Service
public class CrmUserResolver extends UserResolverSupport {

    @Resource
    private ThirdUserService thirdUserService;

    @Resource
    private UserRoleService userRoleService;
    @Resource
    private UserAttrService userAttrService;

    @Override
    public PlatCodeValue supportType() {
        return PlatCodeValue.crm;
    }

    @Override
    public void refreshPermission(Long platUserId,Organization organization) {
        long orgId = organization.getId();
        ThirdUser thirdUser = thirdUserService.lookUp(String.valueOf(platUserId), orgId);
        if(thirdUser == null) {
            return;
        }
        User user = thirdUser.fetchUser();
        List<Permission> permissions = EPassportApiUtils.fetchCrmUserPermission(platUserId);
        //刷新用户的角色
        List<Role> roles = permissions
                .stream()
                .map(p -> {
                    String code = p.getCode();
                    DefaultPermissionTypeValue byCode = DefaultPermissionTypeValue.getByCode(code);
                    return byCode.fetchRole();
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        List<Role> resultRoles = Lists.newArrayList();
        //判断是否有系统角色
        roles.forEach(role -> {
            if(role.getRestrictType() == RoleRestrictTypeValue.system) {
                resultRoles.add(role);
            }
        });
        //获取最大的组织角色
        OptionalLong min = roles.stream().filter(role -> role.getId() > 0).mapToLong(Role::getId).min();
        Asserts.assertTrue(min.isPresent(), "用户为配置组织角色,请在epassport的角色配置中关联。");
        assert min.isPresent();
        long roleId = min.getAsLong();
        resultRoles.add(Role.fetchRole(roleId));
        userRoleService.refreshUserRole(resultRoles, user, organization);
        //刷新用户的个人权限
        List<UserAttr> userAttrs = permissions
                .stream()
                .map(p -> {
                    String code = p.getCode();
                    DefaultPermissionTypeValue permissionTypeValue = DefaultPermissionTypeValue.getByCode(code);
                    UserAttr userAttr = permissionTypeValue.fetchUserAttr();
                    if(userAttr == null){
                        return null;
                    }
                    userAttr.setUserId(user.getId());
                    userAttr.setUpdateDate(new Date());
                    return userAttr;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        userAttrService.refreshUserAttrs(userAttrs,organization.getId(),user.getId());

    }

    @Override
    public UserVO fetchUserList(UserVO userVo) {
        CRMUserParamVO crmUserParamVO = userVo.getQueryUserVo();
        if(crmUserParamVO == null) {
            crmUserParamVO = new CRMUserParamVO();
        }
        crmUserParamVO.buildBy(userVo.getPage());
        userVo.setQueryUserVo(crmUserParamVO);
        CRMUserVO crmUserVO = EPassportApiUtils.fetchUserList(crmUserParamVO);
        List<CrmUser> crmUsers = crmUserVO.getData();
        Long orgId = OrgUtils.fetchOrgId();
        List<ThirdUser> thirdUsers = CrmUtils.convertToThirdUser(crmUsers, orgId.toString());

        //刷新用户,兼容配置初始化项目,数据权限,后面可能会出现这种问题
        syncThirdPartyUser(thirdUsers);

        List<User> users = thirdUsers.stream()
                .map(thirdUser -> thirdUserService.lookUp(thirdUser.getPlatUserNick(), this.supportType()))
                .map(thirdUser -> {
                    User user = thirdUser.fetchUser();
                    user.attr("isLocal", "false");
                    user.attr("thirdUserId", thirdUser.getPlatUserId());
                    return user;
                })
                .collect(Collectors.toList());

        //构建前端分页信息
        int page = crmUserVO.getPage();
        int pageSize = crmUserVO.getPageSize();
        int total = crmUserVO.getTotal();

        Page build = Page.builder()
                .currentPage(page)
                .pageSize(pageSize)
                .totalCount(total)
                .build();

        return UserVO.builder()
                .users(users)
                .page(build)
                .build();
    }

    @Override
    public OrgTagVO fetchOrgTagList(OrgTagVO queryOrgVo) {
        CRMOrgTagParamVO crmOrgTagParamVO = queryOrgVo.getQueryOrgVo();
        if(crmOrgTagParamVO == null) {
            crmOrgTagParamVO = new CRMOrgTagParamVO();
        }
        crmOrgTagParamVO.buildBy(queryOrgVo.getPage());
        queryOrgVo.setQueryOrgVo(crmOrgTagParamVO);
        CRMOrgVO crmOrgVO = Optional.ofNullable(EPassportApiUtils.fetchOrgList(crmOrgTagParamVO)).orElse(new CRMOrgVO());
        ;
        List<CrmOrg> crmOrgs = crmOrgVO.getData();
        //epassport的组织架构节点不入库,这里取得实时的
        List<Tag> tagList = crmOrgs.stream().map(Tag::buildBy).peek(tag -> tag.setOrgId(OrgUtils.fetchOrgId())).collect(Collectors.toList());
        int page = crmOrgVO.getPage();
        int pageSize = crmOrgVO.getPageSize();
        int total = crmOrgVO.getTotal();

        Page pageObject = Page.builder()
                .totalCount(total)
                .pageSize(pageSize)
                .currentPage(page)
                .build();
        return OrgTagVO.builder()
                .tags(tagList)
                .page(pageObject)
                .build();
    }

    @Transactional(rollbackFor = Exception.class)
    private void syncThirdPartyUser(List<ThirdUser> thirdUsers) {
        Organization organization = OrgUtils.fetchOrg();
        ThirdPartySyncResolverRegister.getInstance().getThirdPartySyncResolver(ThirdPartyTypeValue.crm).refreshThirdPartyUser(thirdUsers, organization);
    }
}

如何调用

只举例刷新权限,其他的都一样

public static void refreshPermission(String securityProfile){
    PlatCodeValue platCodeValue = PlatCodeValue.valueOf(securityProfile);
    IUserResolver userResolver = UserResolverRegistry.getInstance().getUserResolver(platCodeValue);
    ThirdUser thirdUser = thirdUserService.getByUserId(user.getId());
    userResolver.refreshPermission(Long.valueOf(thirdUser.getPlatUserId()),OrgUtils.fetchOrg());
}

总结

这个代码模版很简单:
一个枚举,一个接口,一个父类,一个注册器,若干枚举子类实现
其中注册器是我们的门面,后面的调用都直接从注册器中拿就行了。

这里面应用到的设计模式有:单例模式、原型模式、模版方法模式

上一篇下一篇

猜你喜欢

热点阅读