Skip to content

Commit edb6b26

Browse files
committed
Lecture 9, 10 and 11 : Command Handlers
1 parent 0ed3f3a commit edb6b26

7 files changed

Lines changed: 199 additions & 22 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.example.demo;
2+
3+
import org.springframework.http.ResponseEntity;
4+
5+
6+
public interface Command <E, T> {
7+
// <E, T> = Entity, T is generic type in java
8+
9+
ResponseEntity <T> execute(E entity);
10+
// we can also name the method handle.. since its a handler.. but execute is also used..
11+
12+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.example.demo.Product.Model;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class UpdateProductCommand {
7+
private int id;
8+
private Product product;
9+
10+
public UpdateProductCommand(int id, Product product) {
11+
this.id = id;
12+
this.product = product;
13+
}
14+
}

Initial_Projects/NoBS/src/main/java/com/example/demo/Product/ProductController.java

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.example.demo.Product;
22

33
import com.example.demo.Product.Model.Product;
4+
import com.example.demo.Product.Model.UpdateProductCommand;
5+
import com.example.demo.Product.commandHandlers.CreateProductCommandHandler;
6+
import com.example.demo.Product.commandHandlers.DeleteProductCommandHandler;
7+
import com.example.demo.Product.commandHandlers.UpdateProductCommandHandler;
48
import com.example.demo.Product.queryHandlers.GetAllProductsQueryHandler;
59
import com.example.demo.Product.queryHandlers.GetProductQueryHandler;
610
import org.apache.coyote.Response;
@@ -75,39 +79,67 @@ public ResponseEntity<Product> getProduct(@PathVariable Integer id) {
7579
return getProductQueryHandler.execute(id);
7680
}
7781

78-
// Lecture - 5: POST, PUT and DELETE MAPPING
82+
// // Lecture - 5: POST, PUT and DELETE MAPPING
83+
// @PostMapping
84+
// // @RequestBody will tell that in the HTTP request body look for a product.
85+
// public ResponseEntity createProduct(@RequestBody Product product) {
86+
// // Accept a product through JSON
87+
// // Convert it to a Product
88+
// // Save it in the database
89+
// productRepository.save(product); // Currently we do not have any data validation.
90+
// return ResponseEntity.ok().build(); // This wont return anything in the body for now. Only returns a 200
91+
// // response code.
92+
// }
93+
94+
// Lecture 9 : Command Handler
95+
@Autowired
96+
private CreateProductCommandHandler createProductCommandHandler;
7997
@PostMapping
8098
// @RequestBody will tell that in the HTTP request body look for a product.
81-
public ResponseEntity createProduct(@RequestBody Product product) {
82-
// Accept a product through JSON
83-
// Convert it to a Product
84-
// Save it in the database
85-
productRepository.save(product); // Currently we do not have any data validation.
86-
return ResponseEntity.ok().build(); // This wont return anything in the body for now. Only returns a 200
87-
// response code.
99+
public ResponseEntity<String> createProduct(@RequestBody Product product) {
100+
return createProductCommandHandler.execute(product);
88101
}
89102

90103
// PUT is kind of a combination of GET AND POST.
104+
// @PutMapping("/{id}")
105+
// public ResponseEntity updateProduct(@PathVariable Integer id, @RequestBody Product product) {
106+
// // We would require the id to update the product
107+
// // Again we are not doing any validation here.
108+
// // We are doing this id thing manually just to see. We could have passed the ID
109+
// // in the product itself.
110+
// product.setId(id); // Helps set the id so that retrieval / update becomes easy.
111+
// productRepository.save(product); // updates the given product for the id set above.
112+
// return ResponseEntity.ok().build();
113+
// }
114+
115+
// Lecture 10 : Command Handler 2
116+
@Autowired
117+
UpdateProductCommandHandler updateProductCommandHandler;
91118
@PutMapping("/{id}")
92119
public ResponseEntity updateProduct(@PathVariable Integer id, @RequestBody Product product) {
93-
// We would require the id to update the product
94-
// Again we are not doing any validation here.
95-
// We are doing this id thing manually just to see. We could have passed the ID
96-
// in the product itself.
97-
product.setId(id); // Helps set the id so that retrieval / update becomes easy.
98-
productRepository.save(product); // updates the given product for the id set above.
99-
return ResponseEntity.ok().build();
120+
UpdateProductCommand updateProductCommand = new UpdateProductCommand(id, product);
121+
return updateProductCommandHandler.execute(updateProductCommand);
100122
}
101123

124+
// @DeleteMapping("/{id}")
125+
// public ResponseEntity deleteProduct(@PathVariable Integer id) {
126+
// Product product = productRepository.findById(id).get();
127+
// productRepository.delete(product);
128+
//
129+
// // OR..
130+
// // productRepository.deleteById(id);
131+
//
132+
// return ResponseEntity.ok().build();
133+
// }
134+
135+
// Lecture 11 : Command Handler 3
136+
@Autowired
137+
private DeleteProductCommandHandler deleteProductCommandHandler;
102138
@DeleteMapping("/{id}")
103139
public ResponseEntity deleteProduct(@PathVariable Integer id) {
104-
Product product = productRepository.findById(id).get();
105-
productRepository.delete(product);
106-
107-
// OR..
108-
// productRepository.deleteById(id);
109-
110-
return ResponseEntity.ok().build();
140+
// Not fully done yet as we have not handled the Optional (nullable) yet... in case we don't find the product with the given id.
141+
// It'd be done in further classes with custom exception...
142+
return deleteProductCommandHandler.execute(id);
111143
}
112144

113145
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.example.demo.Product.commandHandlers;
2+
3+
import com.example.demo.Command;
4+
import com.example.demo.Product.Model.Product;
5+
import com.example.demo.Product.ProductRepository;
6+
import io.micrometer.common.util.StringUtils;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.stereotype.Service;
10+
11+
// Lecture 9 : Command Handler
12+
@Service
13+
public class CreateProductCommandHandler implements Command<Product, String> {
14+
15+
@Autowired // allows us to inject the product repository and access it in the command handler.
16+
private ProductRepository productRepository;
17+
@Override
18+
public ResponseEntity<String> execute(Product product) {
19+
// Validate then save...
20+
checkValidation(product);
21+
22+
// Validation provides the safety for our app here...
23+
// The validation won't allow to save a wrong product and will throw an exception and stop execution.
24+
25+
productRepository.save(product);
26+
return ResponseEntity.ok().build();
27+
}
28+
29+
private void checkValidation(Product product) {
30+
// name
31+
if (StringUtils.isBlank(product.getName())) { // micrometer utils... check import
32+
throw new RuntimeException("Product name cannot be empty");
33+
}
34+
// description
35+
if(StringUtils.isBlank(product.getDescription())) {
36+
throw new RuntimeException("Description cannot be empty");
37+
}
38+
// price
39+
if(product.getPrice() <= 0.0) {
40+
throw new RuntimeException("Price cannot be negative or 0");
41+
}
42+
// quantity
43+
if(product.getQuantity() <= 0) {
44+
throw new RuntimeException("Quantity cannot be negative or 0");
45+
}
46+
}
47+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.example.demo.Product.commandHandlers;
2+
3+
import com.example.demo.Command;
4+
import com.example.demo.Product.Model.Product;
5+
import com.example.demo.Product.ProductRepository;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.stereotype.Service;
9+
10+
@Service
11+
public class DeleteProductCommandHandler implements Command<Integer, ResponseEntity> {
12+
13+
@Autowired
14+
private ProductRepository productRepository;
15+
@Override
16+
public ResponseEntity<ResponseEntity> execute(Integer id) {
17+
Product product = productRepository.getReferenceById(id);
18+
productRepository.delete(product);
19+
return ResponseEntity.ok().build();
20+
}
21+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.example.demo.Product.commandHandlers;
2+
3+
import com.example.demo.Command;
4+
import com.example.demo.Product.Model.Product;
5+
import com.example.demo.Product.Model.UpdateProductCommand;
6+
import com.example.demo.Product.ProductRepository;
7+
import io.micrometer.common.util.StringUtils;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.http.ResponseEntity;
10+
import org.springframework.stereotype.Service;
11+
12+
@Service
13+
public class UpdateProductCommandHandler implements Command<UpdateProductCommand, ResponseEntity> {
14+
15+
@Autowired
16+
private ProductRepository productRepository;
17+
@Override
18+
public ResponseEntity execute(UpdateProductCommand command) {
19+
Product product = command.getProduct();
20+
// validate product
21+
checkValidation(product);
22+
product.setId(command.getId());
23+
// If this is not done and the entry does not already exist in the database
24+
// then it will work just like POST command else it will create a new entry.
25+
productRepository.save(product);
26+
return ResponseEntity.ok().build();
27+
}
28+
29+
// This method could be abstracted even more as it is being used in multiple classes...
30+
// by making something like another utility class
31+
private void checkValidation(Product product) {
32+
// name
33+
if (StringUtils.isBlank(product.getName())) { // micrometer utils... check import
34+
throw new RuntimeException("Product name cannot be empty");
35+
}
36+
// description
37+
if(StringUtils.isBlank(product.getDescription())) {
38+
throw new RuntimeException("Description cannot be empty");
39+
}
40+
// price
41+
if(product.getPrice() <= 0.0) {
42+
throw new RuntimeException("Price cannot be negative or 0");
43+
}
44+
// quantity
45+
if(product.getQuantity() <= 0) {
46+
throw new RuntimeException("Quantity cannot be negative or 0");
47+
}
48+
}
49+
}

Initial_Projects/db/NoBS.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
use nobs;
44

5+
/*
56
CREATE TABLE product (
67
id INT AUTO_INCREMENT PRIMARY KEY,
78
name VARCHAR(255),
89
description VARCHAR(255),
910
price double,
1011
quantity int
1112
);
13+
*/
1214

1315
select * from product;
1416

0 commit comments

Comments
 (0)