added rocketmq

This commit is contained in:
Jincheng Lu 2025-09-16 23:40:14 +08:00
parent 17ba0a8226
commit be78b6dd27
13 changed files with 247 additions and 41 deletions

11
pom.xml
View File

@ -44,6 +44,17 @@
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.4</version>
</dependency>
<dependency> <dependency>
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>

View File

@ -1,8 +1,9 @@
package com.ljc42.product.Controller; package com.ljc42.product.Controller;
import com.ljc42.product.DTO.ProductDTO;
import com.ljc42.product.DTO.ResponseDTO;
import com.ljc42.product.Exceptions.ProductExitsException; import com.ljc42.product.Exceptions.ProductExitsException;
import com.ljc42.product.Exceptions.ProductNotFoundException; import com.ljc42.product.Exceptions.ProductNotFoundException;
import com.ljc42.product.Model.Product;
import com.ljc42.product.Service.ProductService; import com.ljc42.product.Service.ProductService;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -22,40 +23,34 @@ public class ProductController {
} }
@GetMapping("/api/v1/product/{name}") @GetMapping("/api/v1/product/{name}")
public ResponseEntity<Map<String,Object>> getProducts(@PathVariable String name) { public ResponseEntity<ResponseDTO> getProducts(@PathVariable String name) {
try { try {
Product product = this.productService.getProductByName(name); ProductDTO productDTO = this.productService.getProductByName(name);
JSONObject jsonProduct = new JSONObject(); return new ResponseEntity<>(new ResponseDTO(200,"Product retrieved", productDTO), HttpStatus.OK);
jsonProduct.put("name", product.getName());
jsonProduct.put("price", product.getPrice());
jsonProduct.put("stock", product.getStock());
JSONObject responseBody = new JSONObject();
responseBody.put("code", 200);
responseBody.put("product", jsonProduct);
responseBody.put("message", "Product retrieved");
return new ResponseEntity<>(responseBody.toMap(), HttpStatus.OK);
} catch (ProductNotFoundException e) { } catch (ProductNotFoundException e) {
JSONObject responseBody = new JSONObject(); return new ResponseEntity<>(new ResponseDTO(404,e.getMessage()), HttpStatus.NOT_FOUND);
responseBody.put("code", 404);
responseBody.put("message", e.getMessage());
return new ResponseEntity<>(responseBody.toMap(), HttpStatus.NOT_FOUND);
} }
} }
@PostMapping("/api/v1/product/create") @PostMapping("/api/v1/product/create")
public ResponseEntity<Map<String, Object>> createProducts(@RequestBody Product product) { public ResponseEntity<ResponseDTO> createProducts(@RequestBody ProductDTO productDTO) {
try { try {
this.productService.createProduct(product); ProductDTO createdDTO = this.productService.createProduct(productDTO);
JSONObject responseBody = new JSONObject(); return new ResponseEntity<>(new ResponseDTO(201,"Product created",createdDTO),HttpStatus.CREATED);
responseBody.put("code", 201);
responseBody.put("name", product.getName());
responseBody.put("message", "Product created");
return new ResponseEntity<>(responseBody.toMap(),HttpStatus.CREATED);
} catch (ProductExitsException e) { } catch (ProductExitsException e) {
JSONObject responseBody = new JSONObject(); return new ResponseEntity<>(new ResponseDTO(409,e.getMessage()),HttpStatus.CONFLICT);
responseBody.put("code", 409);
responseBody.put("message", e.getMessage());
return new ResponseEntity<>(responseBody.toMap(),HttpStatus.CONFLICT);
} }
} }
@PutMapping("/api/v1/product/update")
public ResponseEntity<ResponseDTO> updateProducts(@RequestBody ProductDTO productDTO){
try {
ProductDTO updatedDTO = this.productService.updateProduct(productDTO);
return new ResponseEntity<>(new ResponseDTO(200,"Product updated",updatedDTO),HttpStatus.OK);
} catch (ProductNotFoundException e) {
return new ResponseEntity<>(new ResponseDTO(404,e.getMessage()),HttpStatus.NOT_FOUND);
}
}
} }

View File

@ -0,0 +1,4 @@
package com.ljc42.product.DTO;
public class DTO {
}

View File

@ -0,0 +1,40 @@
package com.ljc42.product.DTO;
public class ProductDTO extends DTO{
private String name;
private Double price;
private Integer stock;
public ProductDTO() {
}
public ProductDTO(String name, Double price, Integer stock) {
this.name = name;
this.price = price;
this.stock = stock;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
}

View File

@ -0,0 +1,36 @@
package com.ljc42.product.DTO;
public class ResponseDTO extends DTO{
private int code;
private String message;
private DTO data;
public ResponseDTO(int code, String message, DTO data) {
this.code = code;
this.message = message;
this.data = data;
}
public ResponseDTO(int code, String message) {
this.code = code;
this.message = message;
this.data = null;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
public void setCode(int code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
public void setData(DTO data) {
this.data = data;
}
}

View File

@ -0,0 +1,17 @@
package com.ljc42.product;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;
@Service
@RocketMQMessageListener(
topic = "PRODUCT_CREATE_TOPIC",
consumerGroup = "PRODUCT_CREATE_GROUP"
)
public class Listener implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("downstream service is creating index for product: " + s);
}
}

View File

@ -0,0 +1,22 @@
package com.ljc42.product.Mapper;
import com.ljc42.product.DTO.ProductDTO;
import com.ljc42.product.Model.Product;
public class ProductMapper {
public static ProductDTO ProductToDTO(Product product) {
ProductDTO productDTO = new ProductDTO();
productDTO.setName(product.getName());
productDTO.setPrice(product.getPrice());
productDTO.setStock(product.getStock());
return productDTO;
}
public static Product DTOtoProduct(ProductDTO productDTO) {
Product product = new Product();
product.setName(productDTO.getName());
product.setPrice(productDTO.getPrice());
product.setStock(productDTO.getStock());
return product;
}
}

View File

@ -4,19 +4,21 @@ import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import java.io.Serializable;
@Entity @Entity
public class Product { public class Product implements Serializable {
private @Id private @Id
@GeneratedValue Long id; @GeneratedValue Long id;
private String name; private String name;
private double price; private Double price;
private int stock; private Integer stock;
public Product() { public Product() {
} }
public Product(String name, double price, int stock) { public Product(String name, Double price, Integer stock) {
this.name = name; this.name = name;
this.price = price; this.price = price;
this.stock = stock; this.stock = stock;
@ -30,19 +32,19 @@ public class Product {
this.name = name; this.name = name;
} }
public double getPrice() { public Double getPrice() {
return price; return price;
} }
public void setPrice(double price) { public void setPrice(Double price) {
this.price = price; this.price = price;
} }
public int getStock() { public Integer getStock() {
return stock; return stock;
} }
public void setStock(int stock) { public void setStock(Integer stock) {
this.stock = stock; this.stock = stock;
} }
} }

View File

@ -0,0 +1,23 @@
package com.ljc42.product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class RedisConfig {
@Bean
LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory();
}
@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;
}
}

View File

@ -0,0 +1,9 @@
package com.ljc42.product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RocketMQConfig {
}

View File

@ -1,31 +1,72 @@
package com.ljc42.product.Service; package com.ljc42.product.Service;
import com.ljc42.product.DTO.ProductDTO;
import com.ljc42.product.Exceptions.ProductNotFoundException; import com.ljc42.product.Exceptions.ProductNotFoundException;
import com.ljc42.product.Mapper.ProductMapper;
import com.ljc42.product.Model.Product; import com.ljc42.product.Model.Product;
import com.ljc42.product.Repository.ProductRepository; import com.ljc42.product.Repository.ProductRepository;
import com.ljc42.product.Exceptions.ProductExitsException; import com.ljc42.product.Exceptions.ProductExitsException;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@Service @Service
public class ProductService { public class ProductService {
@Autowired @Autowired
private ProductRepository productRepository; private ProductRepository productRepository;
public void createProduct(Product product) throws ProductExitsException{ @Autowired
if(productRepository.existsByName(product.getName())) { private RedisTemplate<String, Object> redisTemplate;
@Autowired
private RocketMQTemplate rocketMQTemplate;
public ProductDTO createProduct(ProductDTO productDTO) throws ProductExitsException{
if(productRepository.existsByName(productDTO.getName())) {
throw new ProductExitsException("Product with the same name already exists"); throw new ProductExitsException("Product with the same name already exists");
} else { } else {
this.productRepository.save(product); redisTemplate.delete(productDTO.getName());
this.productRepository.save(ProductMapper.DTOtoProduct(productDTO));
rocketMQTemplate.getProducer().setSendMsgTimeout(10000);
rocketMQTemplate.convertAndSend("PRODUCT_CREATE_TOPIC", productDTO.getName());
return productDTO;
} }
} }
public Product getProductByName(String name) throws ProductNotFoundException { public ProductDTO getProductByName(String name) throws ProductNotFoundException {
if(redisTemplate.hasKey(name)) {
return ProductMapper.ProductToDTO((Product) Objects.requireNonNull(redisTemplate.opsForValue().get(name)));
}
if(productRepository.existsByName(name)) { if(productRepository.existsByName(name)) {
return productRepository.findByName(name); Product product = productRepository.findByName(name);
redisTemplate.opsForValue().set(name, product);
redisTemplate.expire(name,5, TimeUnit.MINUTES);
return ProductMapper.ProductToDTO(product);
} else { } else {
throw new ProductNotFoundException("Product not found"); throw new ProductNotFoundException("Product not found");
} }
} }
public ProductDTO updateProduct(ProductDTO productDTO) throws ProductNotFoundException {
if(productRepository.existsByName(productDTO.getName())) {
redisTemplate.delete(productDTO.getName());
Product product = productRepository.findByName(productDTO.getName());
if(productDTO.getPrice() != null) {
product.setPrice(productDTO.getPrice());
}
if(productDTO.getStock() != null) {
product.setStock(productDTO.getStock());
}
productRepository.save(product);
return ProductMapper.ProductToDTO(product);
} else {
throw new ProductNotFoundException("Product not found");
}
}
} }

View File

@ -5,3 +5,9 @@ spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa spring.datasource.username=sa
spring.datasource.password=password spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.redis.host=localhost
spring.redis.port=6379
rocketmq.name-server=localhost:9876
rocketmq.producer.group=my_producer_group