GraphQL实现前后端分离(二):用真实项目手把手教你使用SpringBoot集成GraphQL服务,并进行流程开发。

本文中搭建的项目是在参考company的真实项目基础上简化而来,主要简化了许多业务逻辑、一些数据源(比如OTS redis在项目中的使用以及web权限验证等等,,),项目变得简单清晰,突出使用SpringBoot集成GraphQL服务,并进行流程开发。虽然是简化后的,但是开发架构基本贴近我们工作中的架构环境和架构原则,所以你要是第一次使用Granphql,可以参考本文进行实际开发环境搭建。

一、创建一个Spring boot 工程

1、本次构建的工程环境:

JDK1.8

Spring boot 2.1.6

Spring web Start   :构建Web服务,包括RESTful,使用SpringMVC的应用程序,使用ApacheTomcat作为默认的嵌入式容器。

MySQL

Mybatis

Graphql-java

fastjson

Lombok

Maven

2、项目创建方法参考:

IDEA 使用Spring Initializr 构建springboot项目

到下面这一步时,选择以下插件和框架支持:

工程创建完,删除掉自动生成的一些无用的文件、文件夹后,工程目录如下:

二、搭建集成开发环境

1、配置pom文件:

配置启动路径、增加fastjson依赖、增加Graphql-java依赖。

配置完成后pom文件如下:

<?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 http://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.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aigov</groupId>
    <artifactId>graphql_java</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>graphql_java</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--增加json依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>

        <!-- 添加Graphql依赖 -->
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphql-spring-boot-starter</artifactId>
            <version>5.10.0</version>
        </dependency>

        <!-- 添加 GraphiQL 依赖 -->
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphiql-spring-boot-starter</artifactId>
            <version>5.10.0</version>
            <scope>runtime</scope>
        </dependency>

        <!-- 添加 graphql-java-tools 软件包 -->
        <dependency>
            <groupId>com.graphql-java-kickstart</groupId>
            <artifactId>graphql-java-tools</artifactId>
            <version>5.5.0</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--配置启动路径-->
                <configuration>
                    <mainClass>com.aigov.graphql_java.GraphqlJavaApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

此处对graphq-java依赖方式参考了源码文件:https://github.com/graphql-java-kickstart/graphql-spring-boot#documentation

但是不是完全照搬,Altair、Voyager 等几个Graphql的可视化工具、插件、IED啥的没有引入。

添加了上述Graphql 部分的依赖后,maven会导入下面几个jar包:

  • graphiql-spring-boot-autoconfigure: 开发者工具graphiql的自动配置
  • graphiql-spring-boot-starter: 开发者工具graphiql的实现
  • graphql-java: graphql的java实现
  • graphql-java-servlet: 封装graphql服务为servlet,处理graphql的request和response
  • graphql-java-tools: 自动加载*.graphqls文件,并屏蔽graphql-java的底层实现细节
  • graphql-spring-boot-autoconfigure: graphql-spring-boot的自动配置
  • graphql-spring-boot-starter: starter

有空我会参考gitHub源码,解释一下这三个依赖包。

2、改application.properties文件为application.yml。配置项目信息:

server:
  port: 6001
spring:
  datasource:
    name: test
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/aigov_core?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
    username: root
    password: 123456
graphql:
  servlet:
    mapping: /graphql
    enabled: true
    corsEnabled: true
  tools:
    schemaLocationPattern: "**/*.graphqls"
graphiql:
  mapping: /graphiql
  endpoint:
    graphql: /graphql
    subscriptions: /subscriptions
  static:
    basePath: /
  enabled: true
  pageTitle: GraphiQL
  cdn:
    enabled: false
    version: 0.11.11
  props:
    resources:
      query: testquery.query
      defaultQuery: testquery.query
    variables:
      editorTheme: "solarized light"
  headers:
    Authorization: "Bearer vdff3344ffs v"

到这一步,项目基本的资源环境都配置好了。

3、建几个包文件夹,最终包和代码结构如下:

4、mysql建表-车辆信息表(clxx)

三、使用Granphql api 实现前后端分离

在resources文件夹下的granphql包下新建一些 .granphiql 文件,方法如下:

1、在granphql包下面新建query.graphqls文件

query.graphqls里可以包含了你需要的所有查询请求接口,这就是第一节里面讲的Query,所有查询的入口,这里的查询是个宏观概念,实际上我在项目中,增删改查都在这个Query入口下实现了。

clxx:ClxxRoot ——clxx你可以理解为这是一个子查询的入口名字 ,前端所需要的后端对车辆信息(clxx)所做的所有数据处理,都将定义在ClxxRoot里面,比如这里面可以实现查询并返回车辆信息数据给前端的api、、

type Query {

    #车辆信息
    clxx:ClxxRoot
}

2、在granphql包下新建clxx.graphqls文件

clxx.graphqls里面会实现一些针对车辆信息的增删改查API,同时也会定义一些“对象”,像java一样。比如像下面add API中需要传入一个ClxxVoAdd对象,这时我们需要在.graphqls文件中定义他。

  • 输入对象定义格式为 input  xxxx
  • 返回值对象定义格式为 type xxxx。
type ClxxRoot{

    #新增 cldm必传
    add(clxx:ClxxVoAdd):Result
    #删除 根据车牌号删除
    delete(cph:String!):Result
    #修改 cldm必传
    edit(clxx:ClxxVoEdit):Result
    #查询 根据cph模糊查询
    find(cph:String!):[ClxxVo]
}

input ClxxVoAdd{
    #车辆代码
    cldm:String!
    #车牌号
    cph:String
    #车牌颜色
    cpys:Int
    #车辆vin码
    vin:String
}

input ClxxVoEdit{
    #车辆代码
    cldm:String!
    #车牌号
    cph:String
    #车牌颜色
    cpys:Int
    #车辆vin码
    vin:String
}

type ClxxVo{
    #车辆代码
    cldm:String
    #车牌号
    cph:String
    #车牌颜色
    cpys:Int
    #车辆vin码
    vin:String
}

3、定义特殊graphql对象

上面这个graphql文件中有个 Result 对象,上面没有提及,并不是因为它是graphql的自带对象,实际上这是需要我们自己根据自己需求定义的,这里将用到枚举,是的graphql也是支持枚举的。

新建一个scalar.graphqls文件,定义一个Result响应对象:

type Result{
    result:  ResultCode!
    msg:String
}

enum ResultCode {
    #成功
    success
    #失败
    fail
    #异常
    error
}

到这里graphql的描述文件(也就是schema)差不多写完了,后面就要需要把schema里面定义过的graphql对象在java文件里定义成java对象。

4、定义java bean对象

这里的bean对象就是对应上面graphql对象的。

  • 4.1 创建ClxxVoAdd.java
package com.aigov.graphql_java.entity;

import lombok.Data;

/**
 * @author : aigoV
 * @date :2019/8/19
 * 车辆信息新增vo对象
 **/
@Data
public class ClxxVoAdd {

    /** 车辆代码 **/
    private String cldm;
    
    /** 车牌号 **/
    private String cph;

    /** 车牌颜色 **/
    private Integer cpys;

    /** 车辆vin **/
    private String vin;
}

4.2 创建 ClxxVoEdit.java

package com.aigov.graphql_java.entity;

import lombok.Data;

/**
 * @author : aigoV
 * @date :2019/8/19
 * 车辆信息修改对象
 **/
@Data
public class ClxxVoEdit {

    /** 车辆代码 **/
    private String cldm;

    /** 车牌号 **/
    private String cph;

    /** 车牌颜色 **/
    private Integer cpys;

    /** 车辆vin码 **/
    private String vin;
}

4.3 ClxxVo.java

package com.aigov.graphql_java.entity;

import lombok.Data;

/**
 * @author : aigoV
 * @date :2019/8/19
 * 车辆信息bean对象
 **/
@Data
public class ClxxVo {

    /** 车辆代码 **/
    private String cldm;

    /** 车牌号 **/
    private String cph;

    /** 车牌颜色 **/
    private Integer cpys;

    /** 车辆vin码 **/
    private String vin;
}

4.4 定义scalar.graphqls文件中的特殊 Result 对象

  • 4.4.1 创建一个java文件定义 ResultCode 枚举对象
package com.aigov.graphql_java.entity;

/**
 * @author : aigoV
 * @date :2019/8/26
 * ResultCode 枚举
 **/
public enum  ResultCodeEnum {
    success,
    fail,
    error
}
  • 4.4.2 创建一个java文件,定义Result java对象
package com.aigov.graphql_java.entity;

/**
 * @author : aigoV
 * @date :2019/8/26
 * 接口调用结果
 **/
public class ResultScalar {
    
    private ResultScalar(){ }
    private ResultCodeEnum result;
    private String msg;
    public  static ResultScalar error(String msg){
        ResultScalar rs = new ResultScalar();
        rs.result =  ResultCodeEnum.error;
        rs.setMsg(msg);
        return rs;
    }
    public  static ResultScalar error(){
        ResultScalar rs = new ResultScalar();
        rs.result =  ResultCodeEnum.error;
        rs.setMsg("程序内部错误");
        return rs;
    }
    public  static ResultScalar success(String msg){
        ResultScalar rs = new ResultScalar();
        rs.result =  ResultCodeEnum.success;
        rs.setMsg(msg);
        return rs;
    }
    public  static ResultScalar fail(String msg){
        ResultScalar rs = new ResultScalar();
        rs.result =  ResultCodeEnum.fail;
        rs.setMsg(msg);
        return rs;
    }
    
    public ResultCodeEnum getResult() {
        return result;
    }
    public void setResult(ResultCodeEnum result) {
        this.result = result;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}

5、编写业务方法 (以增加clxx数据这个接口为例,其他小接口参照即可。)

  • 5.1 定义clxx mapper 操作数据库
package com.aigov.graphql_java.mapper;

import com.aigov.graphql_java.entity.ClxxVoAdd;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author : aigoV
 * @date :2019/8/26
 * 车辆信息mapper
 **/
@Mapper
public interface ClxxMapper {

    @Insert("INSERT INTO aigov_core.clxx (cldm,cph,cpys,vin) " +
            "VALUES(#{cldm,jdbcType=VARCHAR},#{cph,jdbcType=VARCHAR},#{cpys,jdbcType=INTEGER},#{vin,jdbcType=VARCHAR})")
    int addClxx(ClxxVoAdd clxxVoAdd);  //新增车辆信息
}
  • 5.2 service层调用mapper方法
package com.aigov.graphql_java.service;

import com.aigov.graphql_java.dataload.DoResultError;
import com.aigov.graphql_java.entity.ClxxVoAdd;
import com.aigov.graphql_java.entity.ResultScalar;
import com.aigov.graphql_java.mapper.ClxxMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author : aigoV
 * @date :2019/8/26
 * clxx业务处理
 **/
@Service
public class clxxServer {

    @Autowired
    ClxxMapper clxxMapper;

    //@DoResultError("clxx数据插入失败啦!")
    @Transactional
    public ResultScalar addClxx(ClxxVoAdd clxxVoAdd){

        clxxMapper.addClxx(clxxVoAdd);
        return ResultScalar.success("车辆信息数据已插入成功!");
    }

}

6、编写解析器Resolver

解释一下,由于业务逻辑简单,这里的解析器代码逻辑也简单,但是实际开发中,我们的解析器可能需要更复杂的逻辑代码来实现复杂需求,比如下面那个def对象会被利用起来,这个有时间我再把复杂点的解析器需求加在这篇博文里。

package com.aigov.graphql_java.resolver;

import com.aigov.graphql_java.entity.ClxxVoAdd;
import com.aigov.graphql_java.entity.ResultScalar;
import com.aigov.graphql_java.service.ClxxServer;
import com.coxautodev.graphql.tools.GraphQLResolver;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author : aigoV
 * @date :2019/8/26
 * clxx解析器
 **/
public class ClxxResolver implements GraphQLResolver {

    @Autowired
    ClxxServer clxxServer;

    public ResultScalar add (ClxxVoAdd clxxVoAdd,DataFetchingEnvironment dfe){
        return clxxServer.addClxx(clxxVoAdd);
    }
}

7、最后浏览器端借助graphiql 测试

 

好了,一个Spring boot集成Graphql实现前后端分离的实际业务过程和项目构造大致就是这样,当然这是一个简单的业务举例,实际开发中还会遇到更多需求,更复杂逻辑,比如如何在前端申请介入graphql api前验证web 用户权限等等。。

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值