Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created simple app for working with products and its categories #319

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
<maven.checkstyle.plugin.configLocation>
https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml
</maven.checkstyle.plugin.configLocation>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<lombok.mapstruct.binding.version>0.2.0</lombok.mapstruct.binding.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -30,7 +33,33 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
Expand Down Expand Up @@ -58,13 +87,43 @@
</execution>
</executions>
<configuration>
<sourceDirectories>
<sourceDirectory>**/target/generated-sources/**</sourceDirectory>
<sourceDirectory>**/target/generated-test-sources</sourceDirectory>
</sourceDirectories>
<configLocation>${maven.checkstyle.plugin.configLocation}</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<linkXRef>false</linkXRef>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok.mapstruct.binding.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package mate.academy.springboot.datajpa.config;

import org.mapstruct.InjectionStrategy;
import org.mapstruct.NullValueCheckStrategy;

@org.mapstruct.MapperConfig(
componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
implementationPackage = "<PACKAGE_NAME>.impl"
)
public class MapperConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package mate.academy.springboot.datajpa.controller;

import lombok.AllArgsConstructor;
import mate.academy.springboot.datajpa.dto.CategoryRequestDto;
import mate.academy.springboot.datajpa.dto.CategoryResponseDto;
import mate.academy.springboot.datajpa.model.Category;
import mate.academy.springboot.datajpa.service.CategoryService;
import mate.academy.springboot.datajpa.service.mapper.DtoMapper;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
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("/categories")
@AllArgsConstructor
public class CategoryController {
private final CategoryService categoryService;
private final DtoMapper<CategoryResponseDto, Category, CategoryRequestDto> dtoMapper;

@PostMapping
public CategoryResponseDto add(@RequestBody CategoryRequestDto categoryRequestDto) {
return dtoMapper.toDto(
categoryService.create(dtoMapper.toEntity(categoryRequestDto)));
}

@GetMapping("/{id}")
public CategoryResponseDto findById(@PathVariable Long id) {
return dtoMapper.toDto(categoryService.findById(id));
}

@PatchMapping("/{id}")
public CategoryResponseDto update(@PathVariable Long id,
@RequestBody CategoryRequestDto categoryRequestDto) {
return dtoMapper.toDto(categoryService.update(id,
dtoMapper.toEntity(categoryRequestDto)));
}

@DeleteMapping("/{id}")
public void deleteById(@PathVariable Long id) {
categoryService.deleteById(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package mate.academy.springboot.datajpa.controller;

import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import mate.academy.springboot.datajpa.dto.ProductRequestDto;
import mate.academy.springboot.datajpa.dto.ProductResponseDto;
import mate.academy.springboot.datajpa.model.Product;
import mate.academy.springboot.datajpa.service.ProductService;
import mate.academy.springboot.datajpa.service.mapper.DtoMapper;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
private final DtoMapper<ProductResponseDto, Product, ProductRequestDto> dtoMapper;

@PostMapping
public ProductResponseDto create(@RequestBody ProductRequestDto productRequestDto) {
return dtoMapper.toDto(
productService.create(dtoMapper.toEntity(productRequestDto)));
}

@GetMapping("/{id}")
public ProductResponseDto get(@PathVariable Long id) {
return dtoMapper.toDto(productService.findById(id));
}

@PatchMapping("/{id}")
public ProductResponseDto update(@PathVariable Long id,
@RequestBody ProductRequestDto productRequestDto) {
return dtoMapper.toDto(productService.update(id,
dtoMapper.toEntity(productRequestDto)));
}

@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.OK)
public void delete(@PathVariable Long id) {
productService.deleteById(id);
}

@GetMapping("/by-price")
public List<ProductResponseDto> getAllByPriceBetween(@RequestParam BigDecimal priceFrom,
@RequestParam BigDecimal priceTo) {
return productService.getAllByPriceBetween(priceFrom, priceTo).stream()
.map(dtoMapper::toDto)
.collect(Collectors.toList());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use short option

Suggested change
.collect(Collectors.toList());
.toList();

}

@GetMapping("/by-categories")
public List<ProductResponseDto> getAllByCategoryIds(@RequestParam Set<Long> categoryIds) {
List<Product> allByCategoryIds = productService.getAllByCategoryIds(categoryIds);
return allByCategoryIds.stream()
.map(dtoMapper::toDto).collect(Collectors.toList());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.map(dtoMapper::toDto).collect(Collectors.toList());
.map(dtoMapper::toDto).toList();

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. But I'm not using toList() in homework cos this method appears in Java 16 but most of our homework uses Java 11. I missed that this task is using Java 17. Also, I had some problems before with List immutability after using the "toList()" method, so...

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mate.academy.springboot.datajpa.dto;

import lombok.Data;

@Data
public class CategoryRequestDto {
private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package mate.academy.springboot.datajpa.dto;

import lombok.Data;

@Data
public class CategoryResponseDto {
private Long id;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need send id in response?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I want to return the ID of the saved element

private String name;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mate.academy.springboot.datajpa.dto;

import java.math.BigDecimal;
import lombok.Data;

@Data
public class ProductRequestDto {
private String title;
private BigDecimal price;
private Long categoryId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package mate.academy.springboot.datajpa.dto;

import java.math.BigDecimal;
import lombok.Data;

@Data
public class ProductResponseDto {
private Long id;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same, do you realy need send id in Response?

private String title;
private BigDecimal price;
private Long categoryId;
}
20 changes: 20 additions & 0 deletions src/main/java/mate/academy/springboot/datajpa/model/Category.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mate.academy.springboot.datajpa.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name = "categories")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
25 changes: 25 additions & 0 deletions src/main/java/mate/academy/springboot/datajpa/model/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mate.academy.springboot.datajpa.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
Comment on lines +13 to +14

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use one annotation Data

Suggested change
@Getter
@Setter
@Data

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read some topics, that were specified in the common mistakes file, about avoiding @DaTa annotation in Entity classes. I do not agree with all suggestions, however, I do find myself aligning with a majority of them, that's why I don't use @DaTa annotation here

@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private BigDecimal price;
@ManyToOne
private Category category;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package mate.academy.springboot.datajpa.repository;

import mate.academy.springboot.datajpa.model.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package mate.academy.springboot.datajpa.repository;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import mate.academy.springboot.datajpa.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> getAllByPriceBetween(BigDecimal priceFrom, BigDecimal priceTo);

List<Product> getAllByCategoryIdIn(Collection<Long> categoryId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package mate.academy.springboot.datajpa.service;

import mate.academy.springboot.datajpa.model.Category;

public interface CategoryService {
Category create(Category category);

Category findById(Long id);

Category update(Long id, Category category);

void deleteById(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package mate.academy.springboot.datajpa.service;

import java.util.NoSuchElementException;
import lombok.AllArgsConstructor;
import mate.academy.springboot.datajpa.model.Category;
import mate.academy.springboot.datajpa.repository.CategoryRepository;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class CategoryServiceImpl implements CategoryService {
private final CategoryRepository categoryRepository;

@Override
public Category create(Category category) {
return categoryRepository.save(category);
}

@Override
public Category findById(Long id) {
return categoryRepository.findById(id).orElseThrow(() ->
new NoSuchElementException("Can't get category with id " + id));
}

@Override
public Category update(Long id, Category category) {
if (category == null) {
throw new IllegalArgumentException("Category cannot be null");
}
Category categoryFromDb = categoryRepository.findById(id).orElseThrow(() ->
new NoSuchElementException("Can't get category with id " + id));
categoryFromDb.setName(category.getName());
return categoryRepository.save(categoryFromDb);
}

@Override
public void deleteById(Long id) {
categoryRepository.deleteById(id);
}
}
Loading
Loading