背景
传统的MVC架构中,业务逻辑一般在service层实现,但随着业务的发展,service层也在不断充斥、嵌入各种业务逻辑代码,导致service层代码过于臃肿、庞大,不利于代码的维护和业务的后续迭代发展。此时我们需要对service层进行瘦身,以达到职责分离、高内聚低耦合的效果。
下面以注册链路为例,讲述如何通过各种方式,对service层的注册逻辑进行瘦身,简化,从而降低代码复杂度,并达到职责分离的效果。
注册链路实现
我们以用户注册为例,对于用户注册,在业务逻辑方面,依次需要进行下列操作:
- 注册表单数据校验
- 账号冲突定位
- 密码加密处理
- 用户权限处理
- 创建用户
- 下发登录态
service层实现业务逻辑
实现
在传统的MVC架构中,对于注册逻辑,属于业务层逻辑,因此会在service层进行实现,具体实现内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| @Override public ResultT<String> register(RegisterRequest registerRequest) { // 注册表单参数校验 checkRegisterForm(registerRequest); // 账号冲突定位 checkUserConflict(registerRequest);
UserDO userDO = convert2DO(registerRequest); // 密码加密 richPassword(userDO); // 权限设置 richRole(userDO); if (userMapper.insert(userDO) > 0) { // 创建账号成功,下发登录态 String token = createLoginToken(userDO); return ResultT.success(token); } return ResultT.fail(); }
/** * 下发登录态 * @param userDO * @return */ private String createLoginToken(UserDO userDO) { // mock 下发登录态 return UUID.randomUUID().toString(); }
/** * 权限设置 * @param userDO */ private void richRole(UserDO userDO) { // mock 先使用默认权限 userDO.setRole(UserRoleConstant.DEFAULT_ROLE.toString()); }
/** * 密码加密 * @param userDO */ private void richPassword(UserDO userDO) { // mock 先不对密码做处理 userDO.setPassword(userDO.getPlainPassword()); }
/** * 账号冲突校验 * @param registerRequest */ private void checkUserConflict(RegisterRequest registerRequest) { if (StringUtils.isNotEmpty(registerRequest.getLoginId())) { LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserDO::getLoginId, registerRequest.getLoginId()); Integer count = userMapper.selectCount(queryWrapper); if (count > 0) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } } LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserDO::getEmail, registerRequest.getEmail()); Integer count = userMapper.selectCount(queryWrapper); if (count > 0) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } }
/** * 注册表单参数校验 * @param registerRequest */ private void checkRegisterForm(RegisterRequest registerRequest) { if (StringUtils.isEmpty(registerRequest.getEmail()) || StringUtils.isEmpty(registerRequest.getPassword())) { throw new UicException(ErrorCode.PARAM_VALIDATE_ERROR); } }
private UserDO convert2DO(RegisterRequest registerRequest) { UserDO userDO = new UserDO(); userDO.setLoginId(registerRequest.getLoginId()); if (StringUtils.isEmpty(userDO.getLoginId())) { userDO.setLoginId(UUID.randomUUID().toString().replaceAll("-", "")); } userDO.setEmail(registerRequest.getEmail()); userDO.setPlainPassword(registerRequest.getPassword()); userDO.setCreateTime(new Date()); userDO.setUpdateTime(new Date()); return userDO; }
|
缺点
在上述代码中,将每一个步骤都抽取为对应的方法,思路相对比较清晰,但这建立在业务逻辑相对稳定、简单的前提下,当后续业务逻辑开始改动,比如需要使用md5对密码进行加密、根据入参决定用户权限、通过jwt创建登录态token等等,此时我们虽然能在这些方法的基础上进行修改或新增,但是这些方法后续会越来越大,不利于后续的维护,此外,我们将这些步骤都堆积在service类中,不利于后续的职责分离。
抽象为执行类依次执行
实现
每一个方法对应一个职责,我们通过将这些逻辑,抽取为一个个执行类,并通过枚举将这些执行类的执行顺序进行编排。
交互图如下:
代码实现如下:
首先定义IFlow、IFlowExecutor、IFlowContext,然后定义AbstractFlow抽象类,实现流程执行器的增加、获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public interface IFlow { List<IFlowExecutor> getFlowExecutors();
default void execute(IFlowContext iFlowContext) { List<IFlowExecutor> flowExecutors = getFlowExecutors(); if (CollectionUtils.isEmpty(flowExecutors)) { return; } for (IFlowExecutor flowExecutor : flowExecutors) { flowExecutor.execute(iFlowContext); } } }
public interface IFlowContext { }
public interface IFlowExecutor { void execute(IFlowContext iFlowContext); }
public abstract class AbstractFlow implements IFlow { protected List<IFlowExecutor> iFlowExecutorList = new ArrayList<>();
public List<IFlowExecutor> getFlowExecutors() { return iFlowExecutorList; }
public void addFlowExecutor(IFlowExecutor executor) { this.iFlowExecutorList.add(executor); } }
|
然后依次实现表单校验、冲突校验、密码加密、权限设置、创建账号、登录态下发等执行器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
| @Component public class BuildUserTokenExecutor implements IFlowExecutor { @Autowired private JwtUtils jwtUtils;
@Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; UserDO userDO = registerFlowContext.getUserDO();
Map<String, Object> payloads = new HashMap<>(); payloads.put("email", userDO.getEmail()); payloads.put("id", userDO.getId()); payloads.put("loginId", userDO.getLoginId()); payloads.put("role", userDO.getRole());
String token = jwtUtils.encrypt(userDO.getId().toString(), payloads); registerFlowContext.setToken(token); } }
@Component public class CreateUserExecutor implements IFlowExecutor { @Autowired private UserMapper userMapper;
@Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; System.out.println(registerFlowContext); UserDO userDO = new UserDO(); userDO.setLoginId(registerFlowContext.getLoginId()); if (StringUtils.isEmpty(userDO.getLoginId())) { userDO.setLoginId(UUID.randomUUID().toString().replaceAll("-", "")); } userDO.setEmail(registerFlowContext.getEmail()); userDO.setPlainPassword(registerFlowContext.getPassword()); userDO.setPassword(registerFlowContext.getEncryptPassword()); userDO.setRole(registerFlowContext.getRoles()); userDO.setCreateTime(new Date()); userDO.setUpdateTime(new Date()); Map<String, String> featureMap = new HashMap<>(); featureMap.put(UserConstant.ENCRYPT_TYPE, registerFlowContext.getEncryptType()); userDO.setFeatures(FeatureUtils.convert2Feature(featureMap));
// 持久化数据库 int insert = userMapper.insert(userDO); if (insert <= 0) { throw new UicException(ErrorCode.PERSISTENCE_DATA_ERROR); } registerFlowContext.setUserDO(userDO); } }
@Component public class EncryptPasswordExecutor implements IFlowExecutor { @Autowired private EncryptHandlerFactory encryptHandlerFactory;
@Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; String encryptType = registerFlowContext.getEncryptType(); if (StringUtils.isEmpty(encryptType)) { encryptType = EncryptTypeEnum.MD5.getType(); registerFlowContext.setEncryptType(encryptType); } IEncryptHandler iEncryptHandler = encryptHandlerFactory.getEncryptHandlerByType(encryptType); EncryptRequest encryptRequest = new EncryptRequest(); encryptRequest.setPlainText(registerFlowContext.getPassword()); String encryptPassword = iEncryptHandler.encrypt(encryptRequest); registerFlowContext.setEncryptPassword(encryptPassword); } }
@Component public class RegisterFormCheckExecutor implements IFlowExecutor { @Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; if (StringUtils.isEmpty(registerFlowContext.getEmail()) || StringUtils.isEmpty(registerFlowContext.getPassword())) { throw new UicException(ErrorCode.PARAM_VALIDATE_ERROR); } } }
@Component public class UserConflictCheckExecutor implements IFlowExecutor { @Autowired private UserMapper userMapper;
@Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; if (StringUtils.isNotEmpty(registerFlowContext.getLoginId())) { LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserDO::getLoginId, registerFlowContext.getLoginId()); Integer count = userMapper.selectCount(queryWrapper); if (count > 0) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } } LambdaQueryWrapper<UserDO> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(UserDO::getEmail, registerFlowContext.getEmail()); Integer count = userMapper.selectCount(queryWrapper); if (count > 0) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } } }
@Component public class UserRoleRichExecutor implements IFlowExecutor { @Override public void execute(IFlowContext iFlowContext) { RegisterFlowContext registerFlowContext = (RegisterFlowContext) iFlowContext; UserRole userRole = new UserRole(); String isSeller = registerFlowContext.getExtend(UserConstant.IS_SELLER); if (StringUtils.isNotEmpty(isSeller) && Boolean.TRUE.toString().equals(isSeller)) { userRole.addRole(UserRoleConstant.SELLER_ROLE); }
String isBuyer = registerFlowContext.getExtend(UserConstant.IS_BUYER); if (StringUtils.isNotBlank(isBuyer) && Boolean.TRUE.toString().equals(isBuyer)) { userRole.addRole(UserRoleConstant.BUYER_ROLE); }
registerFlowContext.setRoles(userRole.getRoles()); } }
|
创建注册流程类
1 2
| public class RegisterFlow extends AbstractFlow { }
|
最后,创建配置类,将这些执行器按照顺序添加到RegisterFlow注册流程中,从而实现流程执行器在流程中的编排
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Configuration public class FlowConfiguration { @DependsOn({"registerFormCheckExecutor", "userConflictCheckExecutor", "encryptPasswordExecutor", "userRoleRichExecutor", "createUserExecutor", "buildUserTokenExecutor"}) @Bean public RegisterFlow registerFlow(@Qualifier("registerFormCheckExecutor")IFlowExecutor registerFormCheckExecutor, @Qualifier("userConflictCheckExecutor")IFlowExecutor userConflictCheckExecutor, @Qualifier("encryptPasswordExecutor")IFlowExecutor encryptPasswordExecutor, @Qualifier("userRoleRichExecutor")IFlowExecutor userRoleRichExecutor, @Qualifier("createUserExecutor")IFlowExecutor createUserExecutor, @Qualifier("buildUserTokenExecutor")IFlowExecutor buildUserTokenExecutor) { RegisterFlow registerFlow = new RegisterFlow(); registerFlow.addFlowExecutor(registerFormCheckExecutor); registerFlow.addFlowExecutor(userConflictCheckExecutor); registerFlow.addFlowExecutor(encryptPasswordExecutor); registerFlow.addFlowExecutor(userRoleRichExecutor); registerFlow.addFlowExecutor(createUserExecutor); registerFlow.addFlowExecutor(buildUserTokenExecutor); return registerFlow; } }
|
经过上述修改后,service层代码得到简化, 内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Component public class UserServiceImpl implements IUserService{ @Autowired private UserMapper userMapper;
@Autowired private RegisterFlow registerFlow;
@Override public UserDO getById(Integer id) { return userMapper.selectById(id); }
@Override public ResultT<String> register(RegisterRequest registerRequest) { RegisterFlowContext registerFlowContext = new RegisterFlowContext(); registerFlowContext.setLoginId(registerRequest.getLoginId()); registerFlowContext.setEmail(registerRequest.getEmail()); registerFlowContext.setPassword(registerRequest.getPassword()); if (registerRequest.getExtendMaps() != null) { registerRequest.getExtendMaps().forEach(registerFlowContext::putExtend); }
registerFlow.execute(registerFlowContext); return ResultT.success(registerFlowContext.getToken()); }
@Override public boolean updateUser(UserDO userDO) { return false; } }
|
缺点
上述方式虽然能将业务流程细分为不同的执行器,从而达到职责分离的作用,但是,当业务流程中,涉及分支判断,不同分支走不同业务逻辑时,上述实现方式较难支撑相关需求
流程引擎实现流程编排
对于市面上常用的几种流程引擎,都包含下列几种功能:
- 事件:开始事件、结束事件
- 活动activity:用户任务(User Task), 服务任务(Service Task) ,子流程(Sub Process)
- 网关GateWay:排他网关、并行网关、事件网关
在我们之前提到将业务流程抽象为执行类依次执行,这里的执行类其实就相当于流程引擎的服务任务(Service Task),而对于分支的判断,可以使用流程引擎的网关,此外,还可以通过用户任务,定位到当前节点,执行之前未完成、中断的流程。
实现
下面简单介绍注册流程如何通过流程引擎的服务任务编排实现。首先创建对应的流程文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <activiti id="register_flow"> <!--节点定义--> <startEvent id="startEvent"/> <serviceTask id="registerFormCheck" name="registerFormCheck" description="注册表单校验" class="com.yang.application.register.activiti.RegisterFormCheckActivity"/> <serviceTask id="userConflictCheck" name="userConflictCheck" description="用户冲突定位" class="com.yang.application.register.activiti.UserConflictCheckActivity"/> <serviceTask id="encryptPassword" name="encryptPassword" description="密码加密" class="com.yang.application.register.activiti.EncryptPasswordActivity"/> <serviceTask id="userRoleRich" name="userRoleRich" description="用户权限填充" class="com.yang.application.register.activiti.UserRoleRichActivity"/> <serviceTask id="createUser" name="createUser" description="创建用户" class="com.yang.application.register.activiti.CreateUserActivity"/> <serviceTask id="buildUserToken" name="buildUserToken" description="创建用户token" class="com.yang.application.register.activiti.BuildUserTokenActivity"/> <endEvent id="endEvent"/>
<!--节点执行顺序编排--> <sequenceFlow source="startEvent" target="registerFormCheck"/> <sequenceFlow source="registerFormCheck" target="userConflictCheck"/> <sequenceFlow source="userConflictCheck" target="encryptPassword"/> <sequenceFlow source="encryptPassword" target="userRoleRich"/> <sequenceFlow source="userRoleRich" target="createUser"/> <sequenceFlow source="createUser" target="buildUserToken"/> <sequenceFlow source="buildUserToken" target="endEvent"/> </activiti>
|
然后创建对应的服务任务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
| @Component public class RegisterFormCheckActivity implements IServiceTask { @Override public void doElse(ActivitiEngineRequest request, ActivitiEngineResponse response) { RegisterRequest registerRequest = (RegisterRequest) request.getBaseRequest(); if (StringUtils.isEmpty(registerRequest.getEmail()) || StringUtils.isEmpty(registerRequest.getPassword())) { throw new UicException(ErrorCode.PARAM_VALIDATE_ERROR); } } @Override public Object buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { return null; }
@Override public Object apply(Object o) { return null; }
@Override public void attachment(Object o, ActivitiEngineResponse response) {
} }
@Component public class UserConflictCheckActivity implements IServiceTask<UserQueryDomainRequest, UserQueryDomainResponse> { @Autowired private UserDomainService userDomainService;
@Override public UserQueryDomainRequest buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { return null; }
@Override public UserQueryDomainResponse apply(UserQueryDomainRequest userQueryDomainRequest) { return null; }
@Override public void doElse(ActivitiEngineRequest request, ActivitiEngineResponse response) { RegisterRequest registerRequest = (RegisterRequest) request.getBaseRequest(); if (StringUtils.isNotEmpty(registerRequest.getLoginId())) { UserQueryDomainRequest userQueryDomainRequest = new UserQueryDomainRequest.UserQueryDomainRequestBuilder() .userQueryType(UserQueryType.LOGIN_ID) .queryMessage(registerRequest.getLoginId()) .build(); UserQueryDomainResponse userQueryDomainResponse = userDomainService.query(userQueryDomainRequest); if (!CollectionUtils.isEmpty(userQueryDomainResponse.getUserAccountList())) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } } UserQueryDomainRequest userQueryDomainRequest = new UserQueryDomainRequest.UserQueryDomainRequestBuilder() .userQueryType(UserQueryType.EMAIL) .queryMessage(registerRequest.getEmail()) .build(); UserQueryDomainResponse userQueryDomainResponse = userDomainService.query(userQueryDomainRequest); if (!CollectionUtils.isEmpty(userQueryDomainResponse.getUserAccountList())) { throw new UicException(ErrorCode.USER_CONFLICT_ERROR); } }
@Override public void attachment(UserQueryDomainResponse userQueryDomainResponse, ActivitiEngineResponse response) {
} }
@Component public class EncryptPasswordActivity implements IServiceTask<UserPasswordEncryptDomainRequest, UserPasswordEncryptDomainResponse> { @Autowired private UserPasswordDomainService userPasswordDomainService;
@Override public UserPasswordEncryptDomainRequest buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { RegisterRequest registerRequest = (RegisterRequest) request.getBaseRequest(); UserPasswordEncryptDomainRequest userPasswordEncryptDomainRequest = new UserPasswordEncryptDomainRequest();
String encryptType = null; if (registerRequest.getExtendMaps() != null) { registerRequest.getExtendMaps().get("encryptType"); } EncryptTypeEnum encryptTypeEnum = EncryptTypeEnum.parseByType(encryptType); userPasswordEncryptDomainRequest.setEncryptType(encryptTypeEnum); userPasswordEncryptDomainRequest.setPlainPassword(registerRequest.getPassword()); return userPasswordEncryptDomainRequest; }
@Override public UserPasswordEncryptDomainResponse apply(UserPasswordEncryptDomainRequest userPasswordEncryptDomainRequest) { return userPasswordDomainService.encryptPassword(userPasswordEncryptDomainRequest); }
@Override public void attachment(UserPasswordEncryptDomainResponse userPasswordEncryptDomainResponse, ActivitiEngineResponse response) { UserModel userModel = (UserModel) response.getResponse(); if (userModel == null) { userModel = new UserModel(); response.setResponse(userModel); } userModel.setEncryptPassword(userPasswordEncryptDomainResponse.getEncryptPassword()); } }
@Component public class UserRoleRichActivity implements IServiceTask<UserRoleApplyDomainRequest, UserRoleApplyDomainResponse> { @Autowired private UserRoleDomainService userRoleDomainService;
@Override public UserRoleApplyDomainRequest buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { RegisterRequest registerRequest = (RegisterRequest) request.getBaseRequest(); UserRoleApplyDomainRequest userRoleApplyDomainRequest = new UserRoleApplyDomainRequest(); if (registerRequest.getExtendMaps() != null) { userRoleApplyDomainRequest.setFeatureMap(registerRequest.getExtendMaps()); } else { userRoleApplyDomainRequest.setFeatureMap(new HashMap<>()); } return userRoleApplyDomainRequest; }
@Override public UserRoleApplyDomainResponse apply(UserRoleApplyDomainRequest userRoleApplyDomainRequest) { return userRoleDomainService.applyUserRole(userRoleApplyDomainRequest); }
@Override public void attachment(UserRoleApplyDomainResponse userRoleApplyDomainResponse, ActivitiEngineResponse response) { UserModel userModel = (UserModel) response.getResponse(); userModel.setUserRole(userRoleApplyDomainResponse.getUserRole()); } }
@Component public class CreateUserActivity implements IServiceTask<UserCreateDomainRequest, UserCreateDomainResponse> { @Autowired private UserDomainService userDomainService;
@Override public UserCreateDomainRequest buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { RegisterRequest registerRequest = (RegisterRequest) request.getBaseRequest(); UserModel userModel = (UserModel) response.getResponse(); UserCreateDomainRequest userCreateDomainRequest = new UserCreateDomainRequest(); userCreateDomainRequest.setLoginId(registerRequest.getLoginId()); userCreateDomainRequest.setEmail(registerRequest.getEmail()); Map<String, String> featureMap = new HashMap<>(); if (userModel.getUserRole() != null) { userCreateDomainRequest.setRoles(userModel.getUserRole().getRoles()); } if (userModel.getEncryptPassword() != null) { userCreateDomainRequest.setPlainPassword(userModel.getEncryptPassword().getPlainPassword()); userCreateDomainRequest.setPassword(userModel.getEncryptPassword().getEncryptPassword()); featureMap.put("encryptType", userModel.getEncryptPassword().getEncryptType().getType()); } userCreateDomainRequest.setFeatureMap(featureMap);
UserAccount userAccount = convert2UserAccount(userCreateDomainRequest); userModel.setUserAccount(userAccount); return userCreateDomainRequest; }
private UserAccount convert2UserAccount(UserCreateDomainRequest userCreateDomainRequest) { UserAccount userAccount = new UserAccount(); userAccount.setLoginId(userCreateDomainRequest.getLoginId()); userAccount.setEmail(userCreateDomainRequest.getEmail()); userAccount.setFeatureMap(userCreateDomainRequest.getFeatureMap()); return userAccount; }
@Override public UserCreateDomainResponse apply(UserCreateDomainRequest userCreateDomainRequest) { if (StringUtils.isEmpty(userCreateDomainRequest.getLoginId())) { userCreateDomainRequest.setLoginId(UUID.randomUUID().toString().replaceAll("-", "")); } return userDomainService.createUser(userCreateDomainRequest); }
@Override public void attachment(UserCreateDomainResponse userCreateDomainResponse, ActivitiEngineResponse response) { if (userCreateDomainResponse.isSuccess()) { UserModel userModel = (UserModel) response.getResponse(); userModel.getUserAccount().setId(userCreateDomainResponse.getUserId()); return; } throw new UicException(ErrorCode.PERSISTENCE_DATA_ERROR); } }
@Component public class BuildUserTokenActivity implements IServiceTask<ApplyTokenDomainRequest, TokenDomainResponse> { @Autowired private UserTokenDomainService userTokenDomainService;
@Override public ApplyTokenDomainRequest buildDomainRequest(ActivitiEngineRequest request, ActivitiEngineResponse response) { UserModel userModel = (UserModel) response.getResponse(); ApplyTokenDomainRequest applyTokenDomainRequest = new ApplyTokenDomainRequest(); applyTokenDomainRequest.setUserId(userModel.getId()); UserAccount userAccount = userModel.getUserAccount(); Map<String, String> attachments = new HashMap<>(); attachments.put("email", userAccount.getEmail()); attachments.put("loginId", userAccount.getLoginId()); if (userModel.getUserRole() != null) { attachments.put("roles", userModel.getUserRole().getRoles()); } applyTokenDomainRequest.setAttachments(attachments); return applyTokenDomainRequest; }
@Override public TokenDomainResponse apply(ApplyTokenDomainRequest applyTokenDomainRequest) { return userTokenDomainService.applyToken(applyTokenDomainRequest); }
@Override public void attachment(TokenDomainResponse tokenDomainResponse, ActivitiEngineResponse response) { UserTokenModel userToken = tokenDomainResponse.getUserToken(); UserModel userModel = (UserModel) response.getResponse(); userModel.setUserToken(userToken); } }
|
然后我们修改service类,加上执行流程引擎的注册方法:
1 2 3 4 5 6 7 8 9 10 11 12
| @Override public ResultT<String> register2(RegisterRequest registerRequest) { ActivitiEngineRequest<RegisterRequest> activitiEngineRequest = new ActivitiEngineRequest<>(); activitiEngineRequest.setBaseRequest(registerRequest); ActivitiEngineResponse<UserModel> activitiEngineResponse = ActivitiFlowManager.startEngine("register_flow.xml", activitiEngineRequest); UserModel userModel = activitiEngineResponse.getResponse(); if (userModel != null && userModel.getUserToken() != null) { String token = userModel.getUserToken().getToken(); return ResultT.success(token); } return ResultT.fail(); }
|
添加测试方法:
1 2 3 4 5 6 7 8 9 10
| @Test public void testEngineRegister() { RegisterRequest registerRequest = new RegisterRequest(); registerRequest.setLoginId("test2"); registerRequest.setEmail("2827523201@qq.com"); registerRequest.setPassword("hello1234"); ResultT<String> resultT = userService.register2(registerRequest); System.out.println(resultT); System.out.println(resultT.getData()); }
|
执行结果如下:
缺点
- 学习成本高:流程引擎涉及的概念较多,包括流程设计、执行、监控和优化等,此外流程引擎对程序员业务逻辑的理解能力要求较高,如何对业务流程进行拆分?拆分的粒度是多少?都是值得考量的问题。
- 使用成本高:大多数流程引擎需要引入数据库来记录流程执行上下文,导致使用成本、维护成本增加。