
在许多web应用程序中,controller层负责接收http请求、协调业务逻辑并返回响应。然而,一个常见的模式是,controller方法内部会包含大量的样板代码,例如:
以下是一个典型的Controller层代码示例,展示了这种重复性:
public class Controller {
private Mapper mapper; // 假设有一个通用的对象映射器
private Service1 service1;
private Service2 service2;
public Response1 test1(Request1 request1){
// 请求DTO映射
ServiceInputDto1 serviceInputDto1 = mapper.map(request1, ServiceInputDto1.class);
// 业务服务调用
ServiceOutputDto1 serviceOutputDto1 = service1.test(serviceInputDto1);
// 响应DTO映射
Response1 response1 = mapper.map(serviceOutputDto1, Response1.class);
return response1;
}
public Response2 test2(Request2 request2){
// 请求DTO映射
ServiceInputDto2 serviceInputDto2 = mapper.map(request2, ServiceInputDto2.class);
// 业务服务调用
ServiceOutputDto2 serviceOutputDto2 = service2.test(serviceInputDto2);
// 响应DTO映射
Response2 response2 = mapper.map(serviceOutputDto2, Response2.class);
return response2;
}
}随着API数量的增加,这种模式会导致Controller层变得臃肿,充斥着重复的映射逻辑,降低了代码的可读性和可维护性。因此,有必要引入一个中间层来抽象和封装这些通用操作。
为了解决Controller层的样板代码问题,我们可以引入一个专门的中间件层。这个中间件的主要职责是:
通过这种方式,Controller层将变得极其简洁,只关注请求的接收和委托,而将具体的处理流程交由中间件完成。
为了实现上述中间件,我们可以设计一个泛型化的 InputOutputMapping 类,它能够处理不同类型的数据转换和业务服务调用。
import java.util.function.Function;
public class InputOutputMapping {
private Mapper mapper; // 假设有一个通用的对象映射器,如MapStruct或ModelMapper
public InputOutputMapping(Mapper mapper) {
this.mapper = mapper;
}
/**
* 通用处理方法,封装了请求DTO映射、业务服务调用和响应DTO映射。
*
* @param requestObject 原始请求对象 (例如:Controller接收的RequestX)
* @param inDtoClass 业务服务输入DTO的Class类型 (例如:ServiceInputDtoX.class)
* @param serviceFunction 业务服务函数,接受输入DTO并返回输出DTO
* @param responseClass 最终响应对象的Class类型 (例如:ResponseX.class)
* @param <REQ> 原始请求对象类型
* @param <IN_DTO> 业务服务输入DTO类型
* @param <OUT_DTO> 业务服务输出DTO类型
* @param <RESP> 最终响应对象类型
* @return 最终响应对象
*/
public <REQ, IN_DTO, OUT_DTO, RESP> RESP apply(
REQ requestObject,
Class<IN_DTO> inDtoClass,
Function<IN_DTO, OUT_DTO> serviceFunction,
Class<RESP> responseClass
) {
// 1. 请求对象映射为业务输入DTO
final IN_DTO inputDto = mapper.map(requestObject, inDtoClass);
// TODO: 在这里可以添加通用的输入数据校验逻辑
// 例如:validate(inputDto);
// 2. 调用业务服务函数
final OUT_DTO outputDto = serviceFunction.apply(inputDto);
// 3. 业务输出DTO映射为最终响应对象
final RESP response = mapper.map(outputDto, responseClass);
return response;
}
}在这个 InputOutputMapping 类中:
通过引入 InputOutputMapping,Controller层的代码将变得异常简洁和一致:
public class Controller {
private Service1 service1;
private Service2 service2;
private InputOutputMapping mapping; // 注入通用映射器
// 假设通过构造函数或Spring @Autowired注入
public Controller(Service1 service1, Service2 service2, InputOutputMapping mapping) {
this.service1 = service1;
this.service2 = service2;
this.mapping = mapping;
}
public Response1 test1(Request1 request1){
return mapping.apply(
request1,
ServiceInputDto1.class,
// 使用Lambda表达式传递业务服务调用逻辑
serviceInputDto1 -> service1.test(serviceInputDto1),
Response1.class
);
}
public Response2 test2(Request2 request2){
return mapping.apply(
request2,
ServiceInputDto2.class,
// 使用Lambda表达式传递业务服务调用逻辑
serviceInputDto2 -> service2.test(serviceInputDto2),
Response2.class
);
}
}可以看到,Controller中的每个方法现在都只包含一行核心逻辑,大大减少了重复代码,提高了可读性。
这种中间件的设计可以被视为一种通用处理模板或流程抽象器。它不是严格意义上的“门面模式”(Facade Pattern),因为门面模式通常用于为复杂的子系统提供一个简化的接口,而这里我们主要是抽象了一个通用的“请求-处理-响应”流程。
它与以下设计模式有相似之处:
因此,我们可以将其理解为一种结合了模板方法和策略模式思想的通用流程处理器。
这种模式特别适用于那些具有大量API接口,且这些接口的请求-处理-响应流程高度相似的系统。
通过在Controller层和业务服务层之间引入一个通用的输入输出映射器 (InputOutputMapping),我们能够有效地将重复的DTO映射和业务服务调用逻辑抽象出来。这种设计不仅减少了Controller层的样板代码,提升了代码的可读性和可维护性,还为统一处理流程(如校验、日志、异常)提供了便利的切入点。在构建大型、多接口的Web应用程序时,这种模式是一种值得考虑的优化策略。
以上就是优化Controller层:构建通用业务处理中间件的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号