ziyi.liu 4 gadi atpakaļ
vecāks
revīzija
9a0f8cad28

+ 111 - 0
graphql-api/src/main/java/com/remy/graphql/builder/GraphqlContextBuilder.java

@@ -0,0 +1,111 @@
+package com.remy.graphql.builder;
+
+import com.remy.common.module.GoodsDTO;
+import com.remy.common.module.OrderDTO;
+import com.remy.common.module.UserDTO;
+import com.remy.graphql.evn.RestAPIEnv;
+import graphql.kickstart.execution.context.DefaultGraphQLContext;
+import graphql.kickstart.execution.context.GraphQLContext;
+import graphql.kickstart.servlet.context.DefaultGraphQLServletContext;
+import graphql.kickstart.servlet.context.DefaultGraphQLWebSocketContext;
+import graphql.kickstart.servlet.context.GraphQLServletContextBuilder;
+import org.dataloader.DataLoader;
+import org.dataloader.DataLoaderRegistry;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.client.RestTemplate;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.websocket.Session;
+import javax.websocket.server.HandshakeRequest;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
+@Configuration
+public class GraphqlContextBuilder implements GraphQLServletContextBuilder {
+
+    @Autowired
+    RestAPIEnv apiEnv;
+
+    @Override
+    public GraphQLContext build(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
+        return DefaultGraphQLServletContext.createServletContext(buildDataLoaderRegistry(), null)
+                .with(httpServletRequest)
+                .with(httpServletResponse)
+                .build();
+    }
+
+    @Override
+    public GraphQLContext build(Session session, HandshakeRequest handshakeRequest) {
+        return DefaultGraphQLWebSocketContext.createWebSocketContext(buildDataLoaderRegistry(), null)
+                .with(session)
+                .with(handshakeRequest)
+                .build();
+    }
+
+    @Override
+    public GraphQLContext build() {
+        return new DefaultGraphQLContext(buildDataLoaderRegistry(), null);
+    }
+
+    private DataLoaderRegistry buildDataLoaderRegistry() {
+        DataLoaderRegistry dataLoaderRegistry = new DataLoaderRegistry();
+        dataLoaderRegistry.register("goodsDataLoader", goodsDataLoader());
+        dataLoaderRegistry.register("userDataLoader", userDataLoader());
+        dataLoaderRegistry.register("orderGoodsDataLoader", orderGoodsDataLoader());
+        dataLoaderRegistry.register("orderUserDataLoader", orderUserDataLoader());
+        return dataLoaderRegistry;
+    }
+
+    private DataLoader<String, GoodsDTO> goodsDataLoader() {
+        RestTemplate restTemplate = new RestTemplate();
+        return new DataLoader<>(
+                goodsSerialNos -> supplyAsync(
+                        () -> goodsSerialNos.stream().map(goodsSerialNo -> restTemplate.getForObject(
+                                apiEnv.getGoodsEndpoint() + goodsSerialNo, GoodsDTO.class))
+                                .collect(Collectors.toList())));
+    }
+
+    private DataLoader<Long, UserDTO> userDataLoader() {
+        RestTemplate restTemplate = new RestTemplate();
+        return new DataLoader<>(
+                userIDs -> supplyAsync(
+                        () -> userIDs.stream().map(userID -> restTemplate.getForObject(
+                                apiEnv.getUsersEndpoint() + userID, UserDTO.class))
+                                .collect(Collectors.toList())));
+    }
+
+    private DataLoader<String, List<OrderDTO>> orderGoodsDataLoader() {
+        RestTemplate restTemplate = new RestTemplate();
+        return new DataLoader<>(
+                goodsSerialNos -> supplyAsync(
+                        () -> goodsSerialNos.stream().map(goodsSerialNo ->
+                                restTemplate.exchange(
+                                        apiEnv.getOrdersEndpoint() + "query?goodsSerialNo={goodsSerialNo}",
+                                        HttpMethod.GET,
+                                        new HttpEntity(null),
+                                        new ParameterizedTypeReference<List<OrderDTO>>() {
+                                        }, goodsSerialNo).getBody())
+                                .collect(Collectors.toList())));
+    }
+
+    private DataLoader<Long, List<OrderDTO>> orderUserDataLoader() {
+        RestTemplate restTemplate = new RestTemplate();
+        return new DataLoader<>(
+                userIDs -> supplyAsync(
+                        () -> userIDs.stream().map(userID ->
+                                restTemplate.exchange(
+                                        apiEnv.getOrdersEndpoint() + "query?userID={userID}",
+                                        HttpMethod.GET,
+                                        new HttpEntity(null),
+                                        new ParameterizedTypeReference<List<OrderDTO>>() {
+                                        }, userID).getBody())
+                                .collect(Collectors.toList())));
+    }
+}

+ 27 - 0
graphql-api/src/main/java/com/remy/graphql/resolvers/dataloader/GoodsDataLoaderResolver.java

@@ -0,0 +1,27 @@
+package com.remy.graphql.resolvers.dataloader;
+
+import com.remy.common.module.GoodsDTO;
+import com.remy.common.module.OrderDTO;
+import com.remy.common.module.UserDTO;
+import graphql.kickstart.execution.context.GraphQLContext;
+import graphql.kickstart.tools.GraphQLResolver;
+import graphql.schema.DataFetchingEnvironment;
+import org.dataloader.DataLoader;
+import org.dataloader.DataLoaderRegistry;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+@Component
+public class GoodsDataLoaderResolver implements GraphQLResolver<GoodsDTO> {
+
+    public CompletableFuture<List<OrderDTO>> orders(GoodsDTO goodsDTO, DataFetchingEnvironment env){
+        DataLoaderRegistry registry = ((GraphQLContext) env.getContext()).getDataLoaderRegistry();
+        DataLoader<String, List<OrderDTO>> orderGoodsDataLoader = registry.getDataLoader("orderGoodsDataLoader");
+        if (orderGoodsDataLoader != null) {
+            return orderGoodsDataLoader.load(goodsDTO.getSerialNo());
+        }
+        throw new IllegalStateException("No order data loader found");
+    }
+}

+ 35 - 0
graphql-api/src/main/java/com/remy/graphql/resolvers/dataloader/OrderDataLoaderResolver.java

@@ -0,0 +1,35 @@
+package com.remy.graphql.resolvers.dataloader;
+
+import com.remy.common.module.GoodsDTO;
+import com.remy.common.module.OrderDTO;
+import com.remy.common.module.UserDTO;
+import graphql.kickstart.execution.context.GraphQLContext;
+import graphql.kickstart.tools.GraphQLResolver;
+import graphql.schema.DataFetchingEnvironment;
+import org.dataloader.DataLoader;
+import org.dataloader.DataLoaderRegistry;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.CompletableFuture;
+
+@Component
+public class OrderDataLoaderResolver implements GraphQLResolver<OrderDTO> {
+
+    public CompletableFuture<GoodsDTO> goods(OrderDTO orderDTO, DataFetchingEnvironment env){
+        DataLoaderRegistry registry = ((GraphQLContext) env.getContext()).getDataLoaderRegistry();
+        DataLoader<String, GoodsDTO> goodsDataLoader = registry.getDataLoader("goodsDataLoader");
+        if (goodsDataLoader != null) {
+            return goodsDataLoader.load(orderDTO.getGoodsSerialNo());
+        }
+        throw new IllegalStateException("No goods data loader found");
+    }
+
+    public CompletableFuture<UserDTO> user(OrderDTO orderDTO, DataFetchingEnvironment env){
+        DataLoaderRegistry registry = ((GraphQLContext) env.getContext()).getDataLoaderRegistry();
+        DataLoader<Long, UserDTO> userDataLoader = registry.getDataLoader("userDataLoader");
+        if (userDataLoader != null) {
+            return userDataLoader.load(orderDTO.getUserID());
+        }
+        throw new IllegalStateException("No user data loader found");
+    }
+}

+ 28 - 0
graphql-api/src/main/java/com/remy/graphql/resolvers/dataloader/UserDataLoaderResolver.java

@@ -0,0 +1,28 @@
+package com.remy.graphql.resolvers.dataloader;
+
+import com.remy.common.module.GoodsDTO;
+import com.remy.common.module.OrderDTO;
+import com.remy.common.module.UserDTO;
+import graphql.kickstart.execution.context.GraphQLContext;
+import graphql.kickstart.tools.GraphQLResolver;
+import graphql.schema.DataFetchingEnvironment;
+import org.dataloader.DataLoader;
+import org.dataloader.DataLoaderRegistry;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+@Component
+public class UserDataLoaderResolver implements GraphQLResolver<UserDTO> {
+
+    public CompletableFuture<List<OrderDTO>> orders(UserDTO userDTO, DataFetchingEnvironment env){
+        DataLoaderRegistry registry = ((GraphQLContext) env.getContext()).getDataLoaderRegistry();
+        DataLoader<Long, List<OrderDTO>> orderUserDataLoader = registry.getDataLoader("orderUserDataLoader");
+        if (orderUserDataLoader != null) {
+            return orderUserDataLoader.load(userDTO.getId());
+        }
+        throw new IllegalStateException("No goods data loader found");
+    }
+
+}

+ 3 - 1
graphql-api/src/main/java/com/remy/graphql/resolvers/mutation/GoodsMutation.java

@@ -11,6 +11,8 @@ import org.springframework.web.client.RestTemplate;
 
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class GoodsMutation implements GraphQLMutationResolver {
@@ -20,7 +22,7 @@ public class GoodsMutation implements GraphQLMutationResolver {
 
     CompletableFuture<GoodsDTO> createGoods(GoodsDTO goodsDTO) {
         log.info("start create goods: " + BeanHelper.toJSON(goodsDTO));
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().postForObject(apiEnv.getGoodsEndpoint(),
                         goodsDTO, GoodsDTO.class));
     }

+ 3 - 1
graphql-api/src/main/java/com/remy/graphql/resolvers/mutation/OrderMutation.java

@@ -11,6 +11,8 @@ import org.springframework.web.client.RestTemplate;
 
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class OrderMutation implements GraphQLMutationResolver {
@@ -20,7 +22,7 @@ public class OrderMutation implements GraphQLMutationResolver {
 
     CompletableFuture<OrderDTO> createOrder(OrderDTO orderDTO) {
         log.info("start create order: " + BeanHelper.toJSON(orderDTO));
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().postForObject(apiEnv.getOrdersEndpoint(),
                         orderDTO, OrderDTO.class));
     }

+ 3 - 1
graphql-api/src/main/java/com/remy/graphql/resolvers/mutation/UserMutation.java

@@ -11,6 +11,8 @@ import org.springframework.web.client.RestTemplate;
 
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class UserMutation implements GraphQLMutationResolver {
@@ -20,7 +22,7 @@ public class UserMutation implements GraphQLMutationResolver {
 
     CompletableFuture<UserDTO> createUser(UserDTO userDTO) {
         log.info("start create user: " + BeanHelper.toJSON(userDTO));
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().postForObject(apiEnv.getUsersEndpoint(),
                         userDTO, UserDTO.class));
     }

+ 4 - 2
graphql-api/src/main/java/com/remy/graphql/resolvers/query/GoodsQuery.java

@@ -14,6 +14,8 @@ import org.springframework.web.client.RestTemplate;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class GoodsQuery implements GraphQLQueryResolver {
@@ -23,7 +25,7 @@ public class GoodsQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<List<GoodsDTO>> goodsList() {
         log.info("start query goods list");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().exchange(
                         apiEnv.getGoodsEndpoint(),
                         HttpMethod.GET,
@@ -34,7 +36,7 @@ public class GoodsQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<GoodsDTO> goods(String serialNo) {
         log.info("start query goods by serialNo");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().getForObject(apiEnv.getGoodsEndpoint() + serialNo, GoodsDTO.class));
     }
 }

+ 7 - 3
graphql-api/src/main/java/com/remy/graphql/resolvers/query/OrderQuery.java

@@ -1,6 +1,8 @@
 package com.remy.graphql.resolvers.query;
 
+import com.remy.common.module.GoodsDTO;
 import com.remy.common.module.OrderDTO;
+import com.remy.common.module.UserDTO;
 import com.remy.graphql.evn.RestAPIEnv;
 import graphql.kickstart.tools.GraphQLQueryResolver;
 import lombok.extern.slf4j.Slf4j;
@@ -14,6 +16,8 @@ import org.springframework.web.client.RestTemplate;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class OrderQuery implements GraphQLQueryResolver {
@@ -23,7 +27,7 @@ public class OrderQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<List<OrderDTO>> orderList() {
         log.info("start query orderList");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().exchange(
                         apiEnv.getOrdersEndpoint(),
                         HttpMethod.GET,
@@ -34,7 +38,7 @@ public class OrderQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<List<OrderDTO>> orderQuery(String goodsSerialNo) {
         log.info("start query order by goods serial no");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().exchange(
                         apiEnv.getOrdersEndpoint() + "query?goodsSerialNo=" + goodsSerialNo,
                         HttpMethod.GET,
@@ -45,7 +49,7 @@ public class OrderQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<OrderDTO> orderInfo(String orderNo) {
         log.info("start query order by order no");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().getForObject(apiEnv.getOrdersEndpoint() + orderNo, OrderDTO.class));
     }
 }

+ 9 - 12
graphql-api/src/main/java/com/remy/graphql/resolvers/query/UserQuery.java

@@ -14,6 +14,8 @@ import org.springframework.web.client.RestTemplate;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
+import static java.util.concurrent.CompletableFuture.supplyAsync;
+
 @Component
 @Slf4j
 public class UserQuery implements GraphQLQueryResolver {
@@ -23,7 +25,7 @@ public class UserQuery implements GraphQLQueryResolver {
 
     public CompletableFuture<List<UserDTO>> userList() {
         log.info("start query orderList");
-        return CompletableFuture.supplyAsync(() ->
+        return supplyAsync(() ->
                 new RestTemplate().exchange(
                         apiEnv.getUsersEndpoint(),
                         HttpMethod.GET,
@@ -32,20 +34,15 @@ public class UserQuery implements GraphQLQueryResolver {
                         }).getBody());
     }
 
-    public CompletableFuture<List<UserDTO>> userQuery(String username) {
+    public CompletableFuture<UserDTO> userQuery(String username) {
         log.info("start query order by goods serial no");
-        return CompletableFuture.supplyAsync(() ->
-                new RestTemplate().exchange(
-                        apiEnv.getUsersEndpoint() + "query?username=" + username,
-                        HttpMethod.GET,
-                        new HttpEntity(null),
-                        new ParameterizedTypeReference<List<UserDTO>>() {
-                        }).getBody());
+        return supplyAsync(() ->
+                new RestTemplate().getForObject(apiEnv.getUsersEndpoint() + "query?username=" + username, UserDTO.class));
     }
 
     public CompletableFuture<UserDTO> userInfo(Long userID) {
-        log.info("start query order by order no");
-        return CompletableFuture.supplyAsync(() ->
-                new RestTemplate().getForObject(apiEnv.getOrdersEndpoint() + userID, UserDTO.class));
+        log.info("start query user by user id");
+        return supplyAsync(() ->
+                new RestTemplate().getForObject(apiEnv.getUsersEndpoint() + userID, UserDTO.class));
     }
 }

+ 2 - 2
graphql-api/src/main/resources/graphqls/query.graphqls

@@ -6,7 +6,7 @@ type Query{
     orderList: [Order]
     orderQuery(goodsSerialNo: String!): [Order]
 
-    userInfo(userID: ID!): User!
+    userInfo(userID: ID!): User
     userList: [User]
-    userQuery(username: String!): [User]
+    userQuery(username: String!): User
 }

+ 8 - 2
order-service/src/main/java/com/remy/order/controller/OrderController.java

@@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 @RestController
 @RequestMapping("orders")
@@ -26,8 +28,12 @@ public class OrderController {
     }
 
     @RequestMapping("query")
-    public List<Order> findALlByGoodsSerialNo(@RequestParam("goodsSerialNo") String goodsSerialNo){
-        return orderService.findAllByGoodsSerialNo(goodsSerialNo);
+    public List<Order> findAllByCondition(@RequestParam Map<String,String> params) {
+        return orderService.findByCondition(
+                Order.builder()
+                        .goodsSerialNo(params.get("goodsSerialNo"))
+                        .userID(params.get("userID") == null ? null : Long.parseLong(params.get("userID")))
+                        .build());
     }
 
     @PostMapping()

+ 1 - 0
order-service/src/main/java/com/remy/order/dao/OrderDAO.java

@@ -10,4 +10,5 @@ public interface OrderDAO extends JpaRepository<Order, Long> {
     Order findOrderByOrderNo(String orderNo);
 
     List<Order> findAllByGoodsSerialNo(String goodsSerialNo);
+
 }

+ 2 - 0
order-service/src/main/java/com/remy/order/service/OrderService.java

@@ -10,6 +10,8 @@ public interface OrderService {
 
     List<Order> findAllByGoodsSerialNo(String goodsSerialNo);
 
+    List<Order> findByCondition(Order order);
+
     List<Order> findAll();
 
     Order save(Order order);

+ 6 - 0
order-service/src/main/java/com/remy/order/service/impl/OrderServiceImpl.java

@@ -4,6 +4,7 @@ import com.remy.order.dao.OrderDAO;
 import com.remy.order.entity.Order;
 import com.remy.order.service.OrderService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -24,6 +25,11 @@ public class OrderServiceImpl implements OrderService {
         return orderDAO.findAllByGoodsSerialNo(goodsSerialNo);
     }
 
+    @Override
+    public List<Order> findByCondition(Order order) {
+        return orderDAO.findAll(Example.of(order));
+    }
+
     @Override
     public List<Order> findAll() {
         return orderDAO.findAll();