I need to return a DTO response with the entity's statistics pageable.
Current response:
[
{
"id": 1,
"name": "Customer 1",
"customerStats": {
"totalAmount": 950.0,
"countOrders": 3,
"countOrdersPending": 1,
"countOrdersCompleted": 2
}
},
{
"id": 2,
"name": "Customer 2",
"customerStats": {
"totalAmount": 1867.5,
"countOrders": 5,
"countOrdersPending": 2,
"countOrdersCompleted": 3
}
}
]
Expected response:
{
"content": [
{
"id": 1,
"name": "Customer 1",
"customerStats": {
"totalAmount": 950.0,
"countOrders": 3,
"countOrdersPending": 1,
"countOrdersCompleted": 2
}
},
{
"id": 2,
"name": "Customer 2",
"customerStats": {
"totalAmount": 1867.5,
"countOrders": 5,
"countOrdersPending": 2,
"countOrdersCompleted": 3
}
}
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageSize": 20,
"pageNumber": 0,
"paged": true,
"unpaged": false
},
"last": true,
"totalElements": 2,
"totalPages": 1,
"size": 20,
"number": 0,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"first": true,
"numberOfElements": 2,
"empty": false
}
I still need to do the conversion in the controller, how do I do the conversion in the CustomerController
?
My classes:
MODEL
Customer
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "customers")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Order
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "orders")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id", nullable = false, foreignKey = @ForeignKey(name = "fk_order_customer1"))
private Customer customer;
private Double amount;
@Enumerated(value = EnumType.STRING)
private OrderStatusType orderStatus;
}
Enum
public enum OrderStatusType {
PENDING,
COMPLETED
}
DTO
CustomerStatsDto
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
public class CustomerStatsDto {
private Double totalAmount;
private Long countOrders;
private Long countOrdersPending;
private Long countOrdersCompleted;
public CustomerStatsDto(Double totalAmount, Long countOrders, Long countOrdersPending, Long countOrdersCompleted) {
this.totalAmount = totalAmount;
this.countOrders = countOrders;
this.countOrdersPending = countOrdersPending;
this.countOrdersCompleted = countOrdersCompleted;
}
}
CustomerStatsResponse
public interface CustomerStatsResponse {
Long getId();
String getName();
Double getTotalAmount();
Long getCountOrders();
Long getCountOrdersPending();
Long getCountOrdersCompleted();
}
CustomerStatsResponseDto
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomerStatsResponseDto {
private Long id;
private String name;
private CustomerStatsDto customerStats;
public CustomerStatsResponseDto(CustomerStatsResponse customerStatsResponse) {
this.id = customerStatsResponse.getId();
this.name = customerStatsResponse.getName();
this.customerStats = new CustomerStatsDto(customerStatsResponse.getTotalAmount(), customerStatsResponse.getCountOrders(),
customerStatsResponse.getCountOrdersPending(), customerStatsResponse.getCountOrdersCompleted());
}
}
REPOSITORY
OrderRep
import com.example.demo.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;
public interface OrderRep extends JpaRepository<Order, Long> {
}
CustomerRep
import com.example.demo.dto.CustomerStatsResponse;
import com.example.demo.model.Customer;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface CustomerRep extends JpaRepository<Customer, Long> {
@Query(value = "SELECT c.id, c.name, "
"SUM(o.amount) AS totalAmount, "
"COUNT(o.id) AS countOrders, "
"(SELECT COUNT(ord.id) FROM orders ord "
"WHERE ord.customer_id = c.id AND ord.order_status = 'PENDING') as countOrdersPending, "
"(SELECT COUNT(ord.id) FROM orders ord "
"WHERE ord.customer_id = c.id AND ord.order_status = 'COMPLETED') as countOrdersCompleted "
"FROM customers c "
"INNER JOIN orders o ON c.id = o.customer_id "
"GROUP BY c.id, c.name"
, nativeQuery = true)
List<CustomerStatsResponse> customerStats();
@Query(value = "SELECT c.id, c.name, "
"SUM(o.amount) AS totalAmount, "
"COUNT(o.id) AS countOrders, "
"(SELECT COUNT(ord.id) FROM orders ord "
"WHERE ord.customer_id = c.id AND ord.order_status = 'PENDING') as countOrdersPending, "
"(SELECT COUNT(ord.id) FROM orders ord "
"WHERE ord.customer_id = c.id AND ord.order_status = 'COMPLETED') as countOrdersCompleted "
"FROM customers c "
"INNER JOIN orders o ON c.id = o.customer_id "
"GROUP BY c.id, c.name"
, nativeQuery = true)
Page<CustomerStatsResponse> customerStatsPageable(Pageable pageable);
}
SERVICE
CustomerService
import com.example.demo.dto.CustomerStatsResponse;
import com.example.demo.model.Customer;
import com.example.demo.repository.CustomerRep;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class CustomerService {
private final CustomerRep customerRep;
public List<Customer> findAll() {
return customerRep.findAll();
}
public List<CustomerStatsResponse> customerStats() {
return customerRep.customerStats();
}
public Page<CustomerStatsResponse> customerStatsPageable(Pageable pageable) {
return customerRep.customerStatsPageable(pageable);
}
}
CONTROLLER
CustomerController
import com.example.demo.dto.CustomerStatsResponseDto;
import com.example.demo.model.Customer;
import com.example.demo.service.CustomerService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("api/v1/customers")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerService customerService;
@GetMapping
public ResponseEntity<List<Customer>> findAll() {
return ResponseEntity.ok(customerService.findAll());
}
@GetMapping("/stats")
public ResponseEntity<List<CustomerStatsResponseDto>> customerStats() {
return ResponseEntity.ok(customerService.customerStats().stream()
.map(customerStatsResponse -> new CustomerStatsResponseDto(customerStatsResponse))
.collect(Collectors.toList()));
}
@GetMapping("/stats/pageable")
public ResponseEntity<Page<CustomerStatsResponseDto>> customerStatsPageable(Pageable pageable) {
//Return Customer Stats pageable
return null;
}
}
CodePudding user response:
You can do it easily with Page.map()
method (reference documentation):
@RestController
@RequestMapping("api/v1/customers")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerService customerService;
@GetMapping
public ResponseEntity<List<Customer>> findAll() {
return ResponseEntity.ok(customerService.findAll());
}
@GetMapping("/stats")
public ResponseEntity<List<CustomerStatsResponseDto>> customerStats() {
return ResponseEntity.ok(customerService.customerStats().stream()
.map(CustomerStatsResponseDto::new)
.collect(Collectors.toList()));
}
@GetMapping("/stats/pageable")
public ResponseEntity<Page<CustomerStatsResponseDto>> customerStatsPageable(Pageable pageable) {
return ResponseEntity.ok(customerService.customerStatsPageable()
.map(CustomerStatsResponseDto::new));
}
}