映射结构实现
Mapstruct Implementation
我正在使用 mapstruct 将我的模型映射到我的 DTO。
我想按全名搜索记录。
我不明白为什么会出现以下错误:
Error creating bean with name 'customerController'
Error creating bean with name 'customerServiceImpl'
Error creating bean with name 'customerRepository'
No property name found for type Customer!
这是我的项目
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);
@Mapping(source = "lastName", target = "lastName")
CustomerDTO customerToCustomerDTO(Customer customer);
}
@Data
public class CustomerDTO {
private String firstName;
private String lastName;
}
@Data
@Entity
@Getter
@Setter
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerListDTO {
List<CustomerDTO> categories;
}
@Controller
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("{name}")
public ResponseEntity<CustomerDTO> getCustomerByName(@PathVariable String name) {
return new ResponseEntity<>(
customerService.getCustomerByName(name), HttpStatus.OK
);
}
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByName(String x);
}
public interface CustomerService {
CustomerDTO getCustomerByName(String name);
}
@AllArgsConstructor
@Service
public class CustomerServiceImpl implements CustomerService {
CustomerMapper customerMapper;
CustomerRepository customerRepository;
@Override
public CustomerDTO getCustomerByName(String lastName) {
return customerMapper.customerToCustomerDTO(customerRepository.findByName(lastName));
}
}
这是一个潜在的修复方法:将在 CustomerMapper 中映射以下内容,但对我来说感觉不对。
@Mapping(source = "name", target = "lastName")
@Mapping(source = "firstName", target = "firstName")
在文档中,据说您可以将模型中的任何字段映射到 DTO,我认为我的代码可能有问题。
我尝试在回购、服务、控制器中实施的方式。
编辑:
也许解决方案是在存储库中使用 DTO?
更新:
@Override
public CustomerDTO getCustomerByName(String lastName) {
return customerRepository.findByName(lastName).map(customerMapper::customerToCustomerDTO);
}
.map无法使用
要使用 .map 我应该使用这样的代码
.findAll()
.stream()
.map(customerMapper::customerToCustomerDTO)
.collect(Collectors.toList());
我正在使用 findByName 方法,但是它无法访问 .map。
我该如何解决这个问题?
编辑
我认为我的客户应该是这样的
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerDTO {
private String id;
private String firstName;
private String lastName;
}
“未找到 属性 类型客户的名称!”
在您的 table 客户中,您有一个名称为“name”的列?
下面我对您的代码做了一些更改,但是如果您需要按名称查找,您的存储库需要找到正确的搜索。当您仅使用 findByName 时 return 行,其中名称等于参数中传递的名称。示例:findByName("Scilla") 只有 return 列名称等于“Scilla”的行,如果列名称的值类似于“scilla”(较低)或“Scilla abc”,则此条目不是 return由查询编辑。
值为“Scilla”的 findByName 方法生成此查询:
select * from customer where name = 'Scilla';
代码更改
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByLastName(String lastName);
List<Customer> findByLastNameContainingIgnoreCase(String name);
List<Customer> findByLastNameContaining(String name);
}
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);
CustomerDTO customerToCustomerDTO(Customer customer);
Customer toDomain(CustomerDTO customerDTO);
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@NoArgsConstructor
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
}
import lombok.Data;
@Data
public class CustomerDTO {
private String firstName;
private String lastName;
}
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("{name}")
public ResponseEntity<CustomerDTO> getCustomerByName(@PathVariable String name) {
return new ResponseEntity<>(
customerService.getCustomerByName(name), HttpStatus.OK
);
}
@PostMapping
public ResponseEntity<CustomerDTO> getCustomerByName(@RequestBody CustomerDTO customerDTO ) {
return new ResponseEntity<>(
customerService.save(customerDTO), HttpStatus.OK
);
}
}
重要
下面放Spring数据查询和翻译查询。
List<Customer> findByLastNameContainingIgnoreCase(String name)
select * from customer where last_name ilike = '%name%';
pom.xml定义
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
<release>11</release>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
要将您的客户实体映射到 DTO 并在 Spring 应用程序中使用它,您应该使用以下映射器(参数 componentModel
= "spring"):
@Mapper(
componentModel = "spring",
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
)
public interface CustomerMapper {
@Mapping(target = "lastName", source = "name")
CustomerDto toDto(Customer customer);
}
MapStruct 不知道如何将实体中的 name
属性 映射到 DTO 中的 lastName
属性,因此您必须在 @Mapping 中指定它注释。
(我还建议使用 'strategy' 参数的指定值 - 您可以在 javadoc 中查看它们的用途。)
在这种情况下,MapStruct 会生成一个适当的 Spring bean 并实现您的映射器,如下所示:
@Component
public class CustomerMapperImpl {
public CustomerDto toDto(Customer customer) {
CustomerDto dto = new CustomerDto();
if (customer != null) {
if (customer.getFirstName() != null) {
dto.setFirstName(customer.getFirstName());
}
if (customer.getName() != null) {
dto.setLastName(customer.getName());
}
}
return dto;
}
}
因此 Spring 将能够在您的服务中注入该 bean(不要忘记将您的回购协议的 findByName
方法更正为 return Optional
):
@RequiredArgsConstructor
@Service
public class CustomerServiceImpl implement CustomerService {
private final CustomerRepo repo;
private final CustomerMapper mapper;
@Override
public Optional<CustomerDto> getByName(@NonNull String name) {
return repo.findByName(name).map(mapper::toDto)
}
@Override
public List<CustomerDto> getAll() {
return repo.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
}
}
然后在您的 REST 控制器中使用此服务:
@RequiredArgsConstructor
@RestController
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService service;
@GetMapping("/{name}")
public CustomerDto getByName(@PathVariable String name) {
return service.getByName()
.orElseThrow(() -> new ResponseStatusException("Customer not found"));
}
@GetMapping
public List<CustomerDto> getAll() {
return service.getAll();
}
}
不要忘记配置您的项目以同时使用 MapStruct 和 Lombok:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
我正在使用 mapstruct 将我的模型映射到我的 DTO。 我想按全名搜索记录。 我不明白为什么会出现以下错误:
Error creating bean with name 'customerController'
Error creating bean with name 'customerServiceImpl'
Error creating bean with name 'customerRepository'
No property name found for type Customer!
这是我的项目
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);
@Mapping(source = "lastName", target = "lastName")
CustomerDTO customerToCustomerDTO(Customer customer);
}
@Data
public class CustomerDTO {
private String firstName;
private String lastName;
}
@Data
@Entity
@Getter
@Setter
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerListDTO {
List<CustomerDTO> categories;
}
@Controller
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("{name}")
public ResponseEntity<CustomerDTO> getCustomerByName(@PathVariable String name) {
return new ResponseEntity<>(
customerService.getCustomerByName(name), HttpStatus.OK
);
}
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByName(String x);
}
public interface CustomerService {
CustomerDTO getCustomerByName(String name);
}
@AllArgsConstructor
@Service
public class CustomerServiceImpl implements CustomerService {
CustomerMapper customerMapper;
CustomerRepository customerRepository;
@Override
public CustomerDTO getCustomerByName(String lastName) {
return customerMapper.customerToCustomerDTO(customerRepository.findByName(lastName));
}
}
这是一个潜在的修复方法:将在 CustomerMapper 中映射以下内容,但对我来说感觉不对。
@Mapping(source = "name", target = "lastName")
@Mapping(source = "firstName", target = "firstName")
在文档中,据说您可以将模型中的任何字段映射到 DTO,我认为我的代码可能有问题。 我尝试在回购、服务、控制器中实施的方式。
编辑:
也许解决方案是在存储库中使用 DTO?
更新:
@Override
public CustomerDTO getCustomerByName(String lastName) {
return customerRepository.findByName(lastName).map(customerMapper::customerToCustomerDTO);
}
.map无法使用
要使用 .map 我应该使用这样的代码
.findAll()
.stream()
.map(customerMapper::customerToCustomerDTO)
.collect(Collectors.toList());
我正在使用 findByName 方法,但是它无法访问 .map。
我该如何解决这个问题?
编辑
我认为我的客户应该是这样的
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomerDTO {
private String id;
private String firstName;
private String lastName;
}
“未找到 属性 类型客户的名称!”
在您的 table 客户中,您有一个名称为“name”的列?
下面我对您的代码做了一些更改,但是如果您需要按名称查找,您的存储库需要找到正确的搜索。当您仅使用 findByName 时 return 行,其中名称等于参数中传递的名称。示例:findByName("Scilla") 只有 return 列名称等于“Scilla”的行,如果列名称的值类似于“scilla”(较低)或“Scilla abc”,则此条目不是 return由查询编辑。
值为“Scilla”的 findByName 方法生成此查询:
select * from customer where name = 'Scilla';
代码更改
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
Customer findByLastName(String lastName);
List<Customer> findByLastNameContainingIgnoreCase(String name);
List<Customer> findByLastNameContaining(String name);
}
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper(CustomerMapper.class);
CustomerDTO customerToCustomerDTO(Customer customer);
Customer toDomain(CustomerDTO customerDTO);
}
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@NoArgsConstructor
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
}
import lombok.Data;
@Data
public class CustomerDTO {
private String firstName;
private String lastName;
}
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("{name}")
public ResponseEntity<CustomerDTO> getCustomerByName(@PathVariable String name) {
return new ResponseEntity<>(
customerService.getCustomerByName(name), HttpStatus.OK
);
}
@PostMapping
public ResponseEntity<CustomerDTO> getCustomerByName(@RequestBody CustomerDTO customerDTO ) {
return new ResponseEntity<>(
customerService.save(customerDTO), HttpStatus.OK
);
}
}
重要
下面放Spring数据查询和翻译查询。
List<Customer> findByLastNameContainingIgnoreCase(String name)
select * from customer where last_name ilike = '%name%';
pom.xml定义
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.4.1.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<forceJavacCompilerUse>true</forceJavacCompilerUse>
<release>11</release>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
要将您的客户实体映射到 DTO 并在 Spring 应用程序中使用它,您应该使用以下映射器(参数 componentModel
= "spring"):
@Mapper(
componentModel = "spring",
nullValueMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE
)
public interface CustomerMapper {
@Mapping(target = "lastName", source = "name")
CustomerDto toDto(Customer customer);
}
MapStruct 不知道如何将实体中的 name
属性 映射到 DTO 中的 lastName
属性,因此您必须在 @Mapping 中指定它注释。
(我还建议使用 'strategy' 参数的指定值 - 您可以在 javadoc 中查看它们的用途。)
在这种情况下,MapStruct 会生成一个适当的 Spring bean 并实现您的映射器,如下所示:
@Component
public class CustomerMapperImpl {
public CustomerDto toDto(Customer customer) {
CustomerDto dto = new CustomerDto();
if (customer != null) {
if (customer.getFirstName() != null) {
dto.setFirstName(customer.getFirstName());
}
if (customer.getName() != null) {
dto.setLastName(customer.getName());
}
}
return dto;
}
}
因此 Spring 将能够在您的服务中注入该 bean(不要忘记将您的回购协议的 findByName
方法更正为 return Optional
):
@RequiredArgsConstructor
@Service
public class CustomerServiceImpl implement CustomerService {
private final CustomerRepo repo;
private final CustomerMapper mapper;
@Override
public Optional<CustomerDto> getByName(@NonNull String name) {
return repo.findByName(name).map(mapper::toDto)
}
@Override
public List<CustomerDto> getAll() {
return repo.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
}
}
然后在您的 REST 控制器中使用此服务:
@RequiredArgsConstructor
@RestController
@RequestMapping("api/v1/customers")
public class CustomerController {
private final CustomerService service;
@GetMapping("/{name}")
public CustomerDto getByName(@PathVariable String name) {
return service.getByName()
.orElseThrow(() -> new ResponseStatusException("Customer not found"));
}
@GetMapping
public List<CustomerDto> getAll() {
return service.getAll();
}
}
不要忘记配置您的项目以同时使用 MapStruct 和 Lombok:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>