从实体到 DTO 的转换
Posted
技术标签:
【中文标题】从实体到 DTO 的转换【英文标题】:Transition from Entity to DTO 【发布时间】:2018-03-09 11:53:09 【问题描述】:我想在所有类中使用 DTO 对象,但是当我从任何地方将 User> 更改为 UserDTO> 时出现错误。
我的错误日志是;
org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名为“userService”的 bean 时出错:不满足的依赖关系 通过字段“userRepository”表示;嵌套异常是 org.springframework.beans.factory.BeanCreationException:错误 创建名为“userRepository”的 bean:调用 init 方法 失败的;嵌套异常是 java.lang.IllegalArgumentException: Not a 托管类型:类 de.javatar81.examples.domain.UserDTO
引起:org.springframework.beans.factory.BeanCreationException: 创建名为“userRepository”的 bean 时出错:调用 init 方法失败;嵌套异常是 java.lang.IllegalArgumentException: 不是托管类型:类 de.javatar81.examples.domain.UserDTO
原因:java.lang.IllegalArgumentException:不是托管类型: 类 de.javatar81.examples.domain.UserDTO
User.class;
@Entity
@Table(name="USER")
public class User implements Serializable
private static final long serialVersionUID = -7860243025833384447L;
@Id
private Long id;
private String login;
private String firstName;
private String lastName;
private Date dayOfBirth;
@ManyToOne
private User manager;
//setters and getters
UserDTO.class;
public class UserDTO implements Serializable
private static final long serialVersionUID = -7860243025833384447L;
private Long id;
private String login;
private String firstName;
private String lastName;
private Date dayOfBirth;
private String city;
private String district;
//setters and getters
UserRepository.class;
public interface UserRepository extends PagingAndSortingRepository<UserDTO, Long>, JpaSpecificationExecutor<UserDTO>, JpaRepository<UserDTO, Long>, Repository<UserDTO, Long>
@Query(value = "select * from user where login like :filters% order by login \n-- #pageable\n",
countQuery = "select count(*) from user where login like :filters%",
nativeQuery = true)
Page<UserDTO> findByLogin(@Param("filters") String filters, Pageable pageable);
UserService.class;
@Service
public class UserService
@Autowired
private UserRepository userRepository;
public Page<UserDTO> findByFilter(Map<String, String> filters, Pageable pageable)
return userRepository.findAll(getFilterSpecification(filters), pageable);
public Page<UserDTO> findByLogin(String filters, Pageable pageable)
return userRepository.findByLogin(filters.toLowerCase(), pageable);
@Transactional
public void create(UserDTO user)
userRepository.save(user);
private Specification<UserDTO> getFilterSpecification(Map<String, String> filterValues)
return (Root<UserDTO> root, CriteriaQuery<?> query, CriteriaBuilder builder) ->
Optional<Predicate> predicate = filterValues.entrySet().stream()
.filter(v -> v.getValue() != null && v.getValue().length() > 0)
.map(entry ->
Path<?> path = root;
String key = entry.getKey();
if (entry.getKey().contains("."))
String[] splitKey = entry.getKey().split("\\.");
path = root.join(splitKey[0]);
key = splitKey[1];
return builder.like(path.get(key).as(String.class), "%" + entry.getValue() + "%");
)
.collect(Collectors.reducing((a, b) -> builder.and(a, b)));
return predicate.orElseGet(() -> alwaysTrue(builder));
;
private Predicate alwaysTrue(CriteriaBuilder builder)
return builder.isTrue(builder.literal(true));
UserBean.class;
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST)
public class UserBean
@Autowired
private UserService userService;
private UserLazyDataModel users;
@PostConstruct
private void init()
this.users = new UserLazyDataModel(userService);
public UserLazyDataModel getUsers()
return users;
UserLazyDataModel.class;
public class UserLazyDataModel extends LazyDataModel<UserDTO> implements SelectableDataModel<UserDTO>
private static final long serialVersionUID = -6123945723069023025L;
private final transient UserService userService;
private static final SortOrder DEFAULT_SORT_ORDER = SortOrder.ASCENDING;
private static final String DEFAULT_SORT_FIELD = "id";
private String columnName;
private String filter;
public UserLazyDataModel(UserService userService)
this.userService = userService;
@Override
public Object getRowKey(UserDTO user)
return user.getId();
@Override
public UserDTO getRowData(String rowKey)
Long rowId = Long.valueOf(rowKey);
@SuppressWarnings("unchecked")
List<UserDTO> users = (List<UserDTO>) super.getWrappedData();
return users.stream().filter(user -> user.getId().equals(rowId)).findAny().orElse(null);
@Override
public List<UserDTO> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters)
Sort sort = new Sort(getDirection(DEFAULT_SORT_ORDER), DEFAULT_SORT_FIELD);
if (multiSortMeta != null)
List<Order> orders = multiSortMeta.stream()
.map(m -> new Order(getDirection(m.getSortOrder() != null ? m.getSortOrder() : DEFAULT_SORT_ORDER),
m.getSortField()))
.collect(Collectors.toList());
sort = new Sort(orders);
return filterAndSort(first, pageSize, filters, sort);
@Override
public List<UserDTO> load(int first, int pageSize, String sortField, SortOrder sortOrder,
Map<String, Object> filters)
Sort sort = null;
if (sortField != null)
sort = new Sort(getDirection(sortOrder != null ? sortOrder : DEFAULT_SORT_ORDER), sortField);
else if (DEFAULT_SORT_FIELD != null)
sort = new Sort(getDirection(sortOrder != null ? sortOrder : DEFAULT_SORT_ORDER), DEFAULT_SORT_FIELD);
return filterAndSort(first, pageSize, filters, sort);
private List<UserDTO> filterAndSort(int first, int pageSize, Map<String, Object> filters, Sort sort)
Map<String, String> filtersMap = filters.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString()));
if (!filters.isEmpty())
filters.forEach((k, v) ->
columnName = new String(k.toString());
filter = new String(v.toString());
);
else
columnName = new String("login");
filter = new String("");
Page<UserDTO> page = userService.findByFilter(filtersMap, new PageRequest(first / pageSize, pageSize, sort));
Page<UserDTO> pageLogin = userService.findByLogin(filter, new PageRequest(first / pageSize, pageSize));
this.setRowCount(((Number) pageLogin.getTotalElements()).intValue());
this.setWrappedData(pageLogin.getContent());
return pageLogin.getContent();
private static Direction getDirection(SortOrder order)
switch (order)
case ASCENDING:
return Direction.ASC;
case DESCENDING:
return Direction.DESC;
case UNSORTED:
default:
return null;
index.xhtml;
<?xml version="1.0"?>
<ui:composition xmlns:f="http://java.sun.com/jsf/core"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:pe="http://primefaces.org/ui/extensions">
<h:head>
</h:head>
<h:body styleClass="login">
<f:view transient="true">
<h:form id="form">
<p:dataTable var="users" value="#userBean.users" paginator="true"
rows="10" sortMode="multiple"
paginatorTemplate="RowsPerPageDropdown FirstPageLink PreviousPageLink CurrentPageReport NextPageLink LastPageLink"
rowsPerPageTemplate="5,10,15" selectionMode="single" id="userTable"
lazy="true">
<p:column headerText="Id" sortBy="#users.id" filterBy="#users.id">
<h:outputText value="#users.id" />
</p:column>
<p:column headerText="Login" sortBy="#users.login"
filterBy="#users.login">
<h:outputText value="#users.login" />
</p:column>
<p:column headerText="Firstname" sortBy="#users.first_Name"
filterBy="#users.firstName">
<h:outputText value="#users.firstName" />
</p:column>
<p:column headerText="Lastname" sortBy="#users.lastName"
filterBy="#users.lastName">
<h:outputText value="#users.lastName" />
</p:column>
<p:column headerText="DayOfBirth" sortBy="#users.dayOfBirth"
filterBy="#users.dayOfBirth">
<h:outputText value="#users.dayOfBirth" />
</p:column>
<p:column headerText="Manager" sortBy="#users.manager.lastName"
filterBy="#users.manager.lastName">
<h:outputText value="#users.manager.lastName" />
</p:column>
</p:dataTable>
</h:form>
</f:view>
</h:body>
</ui:composition>
我还需要做什么?
【问题讨论】:
据我了解,您的存储库类使用 User 作为其实体而不是 UserDTO 如何将其转换为 DTO? @amRika 首先,检查它是否解决了您的beanNotFound异常问题 是的 .. 请在存储库类中使用 User 而不是 UserTO 尝试一次,让我知道它是否适合您。 它有效,谢谢!但它在我的 H2 控制台上创建了另一个名为 UserDTO 的表,这使得理解为我使用 DTO 的主要原因变得更加复杂。就我而言,DTO 应该使用与主实体对象相同的类。我错了吗? @amRika 【参考方案1】:public interface UserRepository extends PagingAndSortingRepository<UserDTO, Long>, JpaSpecificationExecutor<UserDTO>, JpaRepository<UserDTO, Long>, Repository<UserDTO, Long>
@Query(value = "select * from user where login like :filters% order by login \n-- #pageable\n",
countQuery = "select count(*) from user where login like :filters%",
nativeQuery = true)
Page<UserDTO> findByLogin(@Param("filters") String filters, Pageable pageable);
通过查看 UserRepository,似乎没有创建 UserRepository 的 bean,因为您忘记使用 @Repository
注释对存储库进行注释。
您必须使用@Repository
(为组件/类创建 Bean 的 Spring 原型)注释 UserRepository。因此,在创建 UserRepository 的 bean 之后,您将能够执行您的操作。
【讨论】:
但是在我创建 DTO 类之前,存储库类可以直接与实体类一起正常工作。【参考方案2】:我在这段代码中没有看到任何注释。你应该写它们:)
public class UserDTO implements Serializable
private static final long serialVersionUID = -7860243025833384447L;
private Long id;
private String login;
private String firstName;
private String lastName;
private Date dayOfBirth;
private String city;
private String district;
//setters and getters
【讨论】:
以上是关于从实体到 DTO 的转换的主要内容,如果未能解决你的问题,请参考以下文章
在 TypeScript 和 NestS 中将类转换为类/对象(实体到 DTO)