<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.citydo</groupId>
<artifactId>vertxspringboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>vertxspringboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<vertex.version>3.9.1</vertex.version>
</properties>
<dependencies>
<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>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>${
vertex.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>${
vertex.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<version>${
vertex.version}</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
<version>${
vertex.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置:
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
启动:
package com.citydo.vertxspringboot;
import com.citydo.vertxspringboot.verticle.JpaProductVerticle;
import com.citydo.vertxspringboot.verticle.ProductServerVerticle;
import io.vertx.core.Vertx;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
@Slf4j
@SpringBootApplication
public class VertxspringbootApplication {
@Autowired
private ProductServerVerticle productServerVerticle;
@Autowired
private JpaProductVerticle jpaProductVerticle;
public static void main(String[] args) {
SpringApplication.run(VertxspringbootApplication.class, args);
}
@PostConstruct
public void deployVerticle() {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(productServerVerticle);
vertx.deployVerticle(jpaProductVerticle);
vertx.exceptionHandler(throwable -> log.error("exception happened: {}", throwable.toString()));
log.info("verticle deployed!!");
}
}
package com.citydo.vertxspringboot.verticle;
import com.citydo.vertxspringboot.utils.Constants;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author nick
*/
@Slf4j
@Component
public class ProductServerVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
super.start();
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.get("/products/:productID").handler(this::handleGetProduct);
router.put("/products/:productID").handler(this::handleAddProduct);
router.get("/products/").handler(this::handleListProducts);
router.delete("/products/:productID").handler(this::handleDeleteProduct);
router.patch("/products/:productID").handler(this::handlePatchProduct);
vertx.createHttpServer().requestHandler(router).listen(8080);
// .exceptionHandler(
// throwable -> log.error("HTTPServer error happened: {}", throwable.toString())
// );
}
private void getProductFailureHandler(RoutingContext failureRoutingContext){
HttpServerResponse response = failureRoutingContext.response();
response.end("something bad happened!");
}
private void handlePatchProduct(RoutingContext routingContext){
String productId = routingContext.request().getParam("productID");
log.info("productId used to patch product from request param: {}", productId);
if (productId == null) {
log.error("GET: the required productId is null!");
sendError(400, routingContext.response());
return;
}
JsonObject product = routingContext.getBodyAsJson();
vertx.eventBus().<JsonObject>send(Constants.PATCH_PRODUCT_ADDRESS, product, asyncResult -> {
log.info("result is: {}", asyncResult.result().body());
if (asyncResult.succeeded()) {
log.info("handle PATCH_PRODUCT_ADDRESS success!!");
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(String.valueOf(asyncResult.result().body()));
} else {
log.info("handle PATCH_PRODUCT_ADDRESS failed!!");
routingContext.response().setStatusCode(500).end();
}
});
}
private void handleDeleteProduct(RoutingContext routingContext){
Integer productId = Integer.valueOf(routingContext.request().getParam("productID"));
log.info("productId from request param: {}", productId);
vertx.eventBus()
.<Integer>send(Constants.DELETE_PRODUCT_ADDRESS, productId, result -> {
log.info("result is: {}", result.result().body());
if (result.succeeded()) {
log.info("handle DELETE_PRODUCT_ADDRESS success!!");
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(String.valueOf(result.result().body()));
} else {
log.info("handle DELETE_PRODUCT_ADDRESS failed!!");
routingContext.response().setStatusCode(500).end();
}
});
}
private void handleGetProduct(RoutingContext routingContext) {
String productId = routingContext.request().getParam("productID");
if (productId == null) {
log.error("GET: the required productId is null!");
sendError(400, routingContext.response());
return;
}
vertx.eventBus().<String>send(Constants.GET_ONE_PRODUCT_ADDRESS, productId, asyncResult -> {
log.info("Got one product by productId: {}", asyncResult);
if (asyncResult.succeeded()) {
String body = asyncResult.result().body();
if ("null".equals(body)){
log.info("No product found by the given productId: {}", productId);
routingContext.response().setStatusCode(404).end();
}else {
log.info("handle GET_ONE_PRODUCT_ADDRESS success!!");
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(body);
}
} else {
log.info("handle GET_ONE_PRODUCT_ADDRESS failed!!");
routingContext.response().setStatusCode(500).end();
}
});
}
private void handleAddProduct(RoutingContext routingContext) {
String productID = routingContext.request().getParam("productID");
if (productID == null) {
log.error("PUT: the productId is null!");
sendError(400, routingContext.response());
return;
}
JsonObject product = routingContext.getBodyAsJson();
vertx.eventBus().<JsonObject> send(Constants.ADD_PRODUCT_ADDRESS, product, asyncResult -> {
log.info("added one product: {}", asyncResult);
if (asyncResult.succeeded()) {
log.info("handle ADD_PRODUCT_ADDRESS success!!");
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(asyncResult.result().body().toString());
} else {
log.info("handle ADD_PRODUCT_ADDRESS failed!!");
routingContext.response().setStatusCode(500).end();
}
});
}
private void handleListProducts(RoutingContext routingContext) {
EventBus eventBus = vertx.eventBus();
eventBus.<String>send(Constants.ALL_PRODUCTS_ADDRESS, "", asyncResult -> {
log.info("result is: {}", asyncResult.result().body());
if (asyncResult.succeeded()) {
log.info("handle ALL_PRODUCTS_ADDRESS success!!");
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(asyncResult.result().body());
} else {
log.info("handle ALL_PRODUCTS_ADDRESS failed!!");
routingContext.response().setStatusCode(500).end();
}
});
log.info("ALL_PRODUCTS_ADDRESS Event already sent!");
}
private void sendError(int statusCode, HttpServerResponse response) {
response.setStatusCode(statusCode).end();
}
}
package com.citydo.vertxspringboot.verticle;
import com.citydo.vertxspringboot.dto.ProductResult;
import com.citydo.vertxspringboot.service.ProductService;
import com.citydo.vertxspringboot.utils.Constants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author nick
*/
@Slf4j
@Component
public class JpaProductVerticle extends AbstractVerticle {
private final static ObjectMapper objectMapper = Json.mapper;
@Autowired
private ProductService productService;
private Handler<Message<String>> allProductsHandler(ProductService productService) {
return msg -> vertx.<String>executeBlocking(future -> {
try {
future.complete(objectMapper.writeValueAsString(productService.getAllProduct()));
log.info("got all products from blocking...");
} catch (JsonProcessingException e) {
log.error("Failed to serialize result");
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
msg.reply(result.result());
} else {
msg.reply(result.cause().toString());
}
});
}
private Handler<Message<String>> getOneProductHandler(ProductService productService) {
return msg -> vertx.<String>executeBlocking(future -> {
try {
Integer productId = Integer.valueOf(msg.body());
log.info("productId from sender: {}", productId);
val productDTO = productService.findProductById(productId);
future.complete(objectMapper.writeValueAsString(productDTO));
log.info("got one product from blocking...");
} catch (Exception e) {
log.error("Failed to serialize result");
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
msg.reply(result.result());
} else {
msg.reply(result.cause().toString());
}
});
}
@Override
public void start() throws Exception {
super.start();
EventBus eventBus = vertx.eventBus();
eventBus.<String>consumer(Constants.ALL_PRODUCTS_ADDRESS).handler(allProductsHandler(productService));
eventBus.<String>consumer(Constants.GET_ONE_PRODUCT_ADDRESS).handler(getOneProductHandler(productService));
eventBus.<JsonObject>consumer(Constants.ADD_PRODUCT_ADDRESS).handler(addProductHandler(productService));
eventBus.<Integer>consumer(Constants.DELETE_PRODUCT_ADDRESS).handler(deleteProductHandler(productService));
eventBus.<JsonObject>consumer(Constants.PATCH_PRODUCT_ADDRESS).handler(patchProductHandler(productService));
}
private Handler<Message<Integer>> deleteProductHandler(ProductService productService) {
return message -> vertx.<Integer>executeBlocking(
future -> {
try {
Integer productId = message.body();
log.info("productId from sender: {}", productId);
future.complete(productService.deleteProduct(productId));
log.info("deleted one product from blocking...");
} catch (Exception e) {
log.error("Failed to serialize result");
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
message.reply(result.result());
} else {
message.reply(result.cause().toString());
}
}
);
}
private Handler<Message<JsonObject>> patchProductHandler(ProductService productService) {
return message -> vertx.<JsonObject>executeBlocking(
future -> {
try {
JsonObject product = message.body();
log.info("product to be patched from sender: {}", product);
future.complete(JsonObject.mapFrom(productService.patchProduct(product.mapTo(ProductResult.class))));
} catch (Exception e) {
log.error("Failed to serialize result");
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
message.reply(result.result());
} else {
message.reply(result.cause().toString());
}
}
);
}
private Handler<Message<JsonObject>> addProductHandler(ProductService productService) {
return message -> vertx.<JsonObject>executeBlocking(
future -> {
try {
JsonObject product = message.body();
log.info("product from sender: {}", product);
future.complete(JsonObject.mapFrom(productService.addProduct(product.mapTo(ProductResult.class))));
log.info("got one product from blocking...");
} catch (Exception e) {
log.error("Failed to serialize result");
future.fail(e);
}
},
result -> {
if (result.succeeded()) {
message.reply(result.result());
} else {
message.reply(result.cause().toString());
}
}
);
}
private Handler<Message<String>> getAllService() {
return msg -> vertx.<String>executeBlocking(future -> {
log.info("try to get json.....");
try {
log.info("get json success..");
future.complete(new JsonObject().put("name", "wade").toString());
} catch (Exception e) {
log.info("Failed to serialize result");
future.fail(e);
}
}, result -> {
if (result.succeeded()) {
msg.reply(result.result());
} else {
msg.reply(result.cause()
.toString());
}
});
}
}
package com.citydo.vertxspringboot.utils;
public class Constants {
public static final String ALL_PRODUCTS_ADDRESS = "all-products-address";
public static final String GET_ONE_PRODUCT_ADDRESS = "get-one-product-address";
public static final String ADD_PRODUCT_ADDRESS = "add-product-address";
public static final String DELETE_PRODUCT_ADDRESS = "delete-product-address";
public static final String PATCH_PRODUCT_ADDRESS = "patch-product-address";
}
package com.citydo.vertxspringboot.service;
import com.citydo.vertxspringboot.dto.ProductResult;
import com.citydo.vertxspringboot.entity.Product;
import com.citydo.vertxspringboot.repository.ProductRepository;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.transaction.Transactional;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @author nick
*/
@Slf4j
@Service
@Transactional
public class ProductService {
@Autowired
private ProductRepository productRepository;
/**
* 获取全部数据
* @return
*/
public List<ProductResult> getAllProduct() {
val entityList = productRepository.findAll();
if (CollectionUtils.isEmpty(entityList)){
return Collections.EMPTY_LIST;
}
return entityList.stream().map(Product::getProductResult).collect(Collectors.toList());
}
/**
* 查询单个数据Constants
* @param productId
* @return
*/
public ProductResult findProductById(Integer productId){
if (StringUtils.isEmpty(productId)){
return null;
}
val entity = productRepository.findById(productId);
return Objects.isNull(entity) ? null : entity.map(Product::getProductResult).get();
}
/**
* 添加
* @param productResult
* @return
*/
public ProductResult addProduct(ProductResult productResult){
Product toBeSavedEntity = new Product();
BeanUtils.copyProperties(productResult, toBeSavedEntity);
val savedEntity = productRepository.save(toBeSavedEntity);
return savedEntity.getProductResult();
}
/**
* 删除数据
* @param productId
* @return
*/
public Integer deleteProduct(Integer productId){
productRepository.deleteById(productId);
return productId;
}
public ProductResult patchProduct(ProductResult productResult) {
val entity = productRepository.findById(productResult.getProductId()).get();
entity.setProductName(productResult.getProductName());
entity.setDescription(productResult.getDescription());
val saved = productRepository.save(entity);
return saved.getProductResult();
}
}
package com.citydo.vertxspringboot.repository;
import com.citydo.vertxspringboot.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
package com.citydo.vertxspringboot.entity;
import com.citydo.vertxspringboot.dto.ProductResult;
import lombok.Data;
import lombok.val;
import org.springframework.beans.BeanUtils;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author nick
*/
@Data
@Entity
@Table(name = "product")
public class Product {
@Id
@Column(name = "product_id")
private Integer productId;
@Column(name = "product_name")
private String productName;
@Column(name = "description")
private String description;
/**
* 将数据对象转成返给前端对象
* @return
*/
public ProductResult getProductResult(){
val productDTO = new ProductResult();
BeanUtils.copyProperties(this, productDTO);
return productDTO;
}
}
package com.citydo.vertxspringboot.dto;
import lombok.Data;
@Data
public class ProductResult {
private Integer productId;
private String description;
private String productName;
}
sql:
-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product` (
`product_id` int(11) NOT NULL,
`product_name` varchar(45) NOT NULL,
`description` varchar(45) DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of product
-- ----------------------------
INSERT INTO `product` VALUES ('1', '张三', '测试中');