Service层瘦身思考

背景

传统的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());
}

执行结果如下:

缺点
  • 学习成本高:流程引擎涉及的概念较多,包括流程设计、执行、监控和优化等,此外流程引擎对程序员业务逻辑的理解能力要求较高,如何对业务流程进行拆分?拆分的粒度是多少?都是值得考量的问题。
  • 使用成本高:大多数流程引擎需要引入数据库来记录流程执行上下文,导致使用成本、维护成本增加。

Service层瘦身思考
https://cxydhi.github.io/2024/10/04/Service层瘦身思考/
作者
沉河不浮
发布于
2024年10月4日
许可协议