首页 > 解决方案 > 为什么 dto 被转换为 Map?

问题描述

我一直在试图理解为什么将 searchDto 转换为 Map。调用以下函数来获取与来自 Angular 表单的给定搜索词匹配的客户。

 public Page<Customer> getCustomerFromCustomerLoan(Object searchDto, Pageable pageable) {
        List<Customer> customerList = new ArrayList<>();
        final ObjectMapper objectMapper = new ObjectMapper();
        Map<String, String> s = objectMapper.convertValue(searchDto, Map.class);
        s.put("distinctByCustomer", "true");
        s.values().removeIf(Objects::isNull);
        logger.info("search param for customer in customerLoan {}", s);
        final CustomerLoanSpecBuilder customerLoanSpecBuilder = new CustomerLoanSpecBuilder(s);
        final Specification<CustomerLoan> specification = customerLoanSpecBuilder.build();
        Page<CustomerLoan> customerLoanPage = customerLoanRepository
            .findAll(specification, pageable);
        customerLoanPage.getContent().forEach(customerLoan -> {
            if (!customerList.contains(customerLoan)) {
                customerList.add(customerLoan.getCustomerInfo());
            }
        });
        List<Customer> finalList = customerList.stream().filter(distinctByKey(Customer::getId))
            .collect(
                Collectors.toList());

        Page<Customer> pages = new PageImpl<Customer>(finalList, pageable,
            customerLoanPage.getTotalElements());
        return pages;
    }

标签: java

解决方案


好吧,当问到为什么有人以特定方式做某事时,我们所能做的就是做出有根据的猜测——除非有一些文档说明这背后的原因。在这种情况下,我的猜测是,因为searchDto它的类型Object实际上可能是几种类型之一,例如普通的 json 字符串、已经解析的 pojo 等 - 将其转换为地图可以使该 dto 中的信息在相当通用方式。

想想那些实际使用共享某些属性的不同 pojo 的 api,CustomerLoan假设这些可能是 customerNumber,loanAmountcustomerName
现在可以使用只有customerNumberandloanAmount而另一个具有customerNumberand的 DTO customerName。如果您将这些 DTO 转换为映射,您将获得一个可以传递给该类的通用结构,CustomerLoanSpecBuilder然后该类可以检查这些属性是否存在值。

当然,您可能可以同时使用接口,instanceof但这也可能很乏味。

我将尝试用一个例子来澄清:

使用地图可能如下所示:

Map<String, String> props = ...;
if( props.get("customerNumber") != null ) {
   //add predicate for customer number
}
if( props.get("customerName") != null ) {
   //add predicate for customer name
}
if( props.get("loanAmount") != null ) {
   //add predicate for loan amount
}

如果您想使用接口提供一个干净的 api,则需要 3 个单独的接口,例如, ICustomerNumber(我实际上并不喜欢这些名称,但它们应该使它们的含义有些清晰):ICustomerNameILoanAmount

class DTO1 implements ICustomerNumber, ILoanAmount { ... }
class DTO1 implements ICustomerNumber, ICustomerName { ... }

现在使用这些可能如下所示:

Object inputDto = ...;
if( inputDto instanceof ICustomerNumber ) {
   //cast to ICustomerNumber, get the value and add predicate for customer number
}
if( inputDto instanceof ICustomerName ) {
   //cast to ICustomerName , get the value and add predicate for customer name
}
if( inputDto instanceof ILoanAmount ) {
   //cast to ILoanAmount , get the value and add predicate for loan amount
}

另一种选择是使用反射来检查是否有一个方法被调用getCustomerNumber(),如果是调用它,但你不想走那条路。


推荐阅读