当前位置: 首页 > 工具软件 > Dataway > 使用案例 >

DataWay集成Spring Boot

祁权
2023-12-01

公众号:踏歌的 Java Daily

Dataway集成Spring Boot

Dataway踩坑指南



前言

Java早已厌烦了controller、service、dao,尤其是一些很简单的管理系统对一些单表的增删改;我也是偶然在一个项目初期进行使用,参与DataWay集成Spring Boot的全过程。
参考链接:https://www.hasor.net/doc/


以下是本篇文章正文内容,下面案例可供参考

一、什么是Dataway

DataQL(Data Query Language)DataQL 是一种查询语言。旨在通过提供直观、灵活的语法来描述客户端应用程序的数据需求和交互。数据的存储根据其业务形式通常是较为简单的,并不适合直接在页面上进行展示。因此开发页面的前端工程师需要为此做大量的工作,这就是 DataQL 极力解决的问题。

二、DataWay集成Spring Boot

引入依赖

Dataway 是 Hasor 生态中的一员,使用 Dataway 第一步需要通过 hasor-spring 打通两个生态。
**注意:**这里要看Spring Boot的版本号,官方没有提供对照文档,一般用spring boot 版本2.4.1不会出什么问题。还要看一个版本冲突问题,我在做的过程中由于初始项目引入过多的依赖jar包,搞了两天才解决

<!-- 引入依赖 -->
<dependency>
    <groupId>net.hasor</groupId>
    <artifactId>hasor-spring</artifactId>
    <version>4.2.2</version>
    <!-- 查看最新版本:https://mvnrepository.com/artifact/net.hasor/hasor-spring -->
</dependency>
<dependency>
    <groupId>net.hasor</groupId>
    <artifactId>hasor-dataway</artifactId>
    <version>4.2.2</version>
    <!-- 查看最新版本:https://mvnrepository.com/artifact/net.hasor/hasor-dataway -->
</dependency>
<!-- 我做的过程中引发问题的jar包 -->
<dependency>
	<groupId>net.sourceforge.nekohtml</groupId>
	<artifactId>nekohtml</artifactId>
</dependency>

启用 Hasor

@EnableHasor()    // 在Spring 中启用 Hasor
@EnableHasorWeb() // 将 hasor-web 配置到 Spring 环境中,Dataway 的 UI 是通过 hasor-web 提供服务。

然后第二步,在应用的 application.properties 配置文件中启用 Dataway

# 启用 Dataway 功能(默认不启用)
HASOR_DATAQL_DATAWAY=true
# 开启 ui 管理功能(注意生产环境必须要设置为 false,否则会造成严重的生产安全事故)
HASOR_DATAQL_DATAWAY_ADMIN=true
# 数据库类型
HASOR_DATAQL_FX_PAGE_DIALECT=mysql
# (可选)API工作路径
HASOR_DATAQL_DATAWAY_API_URL=/api/
# (可选)ui 的工作路径,只有开启 ui 管理功能后才有效
HASOR_DATAQL_DATAWAY_UI_URL=/interface-ui/

初始化必要的表(例:MySQL)

CREATE TABLE interface_info (
  api_id          varchar(64)  NOT NULL COMMENT 'ID',
  api_method      varchar(12)  NOT NULL COMMENT 'HttpMethod:GET、PUT、POST',
  api_path        varchar(512) NOT NULL COMMENT '拦截路径',
  api_status      varchar(4)   NOT NULL COMMENT '状态:-1-删除, 0-草稿,1-发布,2-有变更,3-禁用',
  api_comment     varchar(255) NOT NULL COMMENT '注释',
  api_type        varchar(24)  NOT NULL COMMENT '脚本类型:SQL、DataQL',
  api_script      mediumtext   NOT NULL COMMENT '查询脚本:xxxxxxx',
  api_schema      mediumtext   NOT NULL COMMENT '接口的请求/响应数据结构',
  api_sample      mediumtext   NOT NULL COMMENT '请求/响应/请求头样本数据',
  api_option      mediumtext   NOT NULL COMMENT '扩展配置信息',
  api_create_time varchar(32)  NOT NULL COMMENT '创建时间',
  api_gmt_time    varchar(32)  NOT NULL COMMENT '修改时间',
  PRIMARY KEY (api_id),
  UNIQUE KEY uk_interface_info (api_path)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Dataway 中的API';
 
CREATE TABLE interface_release (
  pub_id           varchar(64)  NOT NULL COMMENT 'Publish ID',
  pub_api_id       varchar(64)  NOT NULL COMMENT '所属API ID',
  pub_method       varchar(12)  NOT NULL COMMENT 'HttpMethod:GET、PUT、POST',
  pub_path         varchar(512) NOT NULL COMMENT '拦截路径',
  pub_status       varchar(4)   NOT NULL COMMENT '状态:-1-删除, 0-草稿,1-发布,2-有变更,3-禁用',
  pub_comment      varchar(255) NOT NULL COMMENT '注释',
  pub_type         varchar(24)  NOT NULL COMMENT '脚本类型:SQL、DataQL',
  pub_script       mediumtext   NOT NULL COMMENT '查询脚本:xxxxxxx',
  pub_script_ori   mediumtext   NOT NULL COMMENT '原始查询脚本,仅当类型为SQL时不同',
  pub_schema       mediumtext   NOT NULL COMMENT '接口的请求/响应数据结构',
  pub_sample       mediumtext   NOT NULL COMMENT '请求/响应/请求头样本数据',
  pub_option       mediumtext   NOT NULL COMMENT '扩展配置信息',
  pub_release_time varchar(32)  NOT NULL COMMENT '发布时间(下线不更新)',
  PRIMARY KEY (pub_id),
  KEY idx_interface_release_api  (pub_api_id),
  KEY idx_interface_release_path (pub_path)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Dataway

初始化数据源

@DimModule
@Component
public class ExampleModule implements SpringModule {
    @Autowired
    private DataSource dataSource = null;
 
    public void loadModule(ApiBinder apiBinder) throws Throwable {
        apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));
    }
}

可以启动了

参考链接:https://www.hasor.net/doc/pages/viewpage.action?pageId=1573294

加强版!!!

因为我们数据库里定义的字段大都为xx_xx,而我们返回给前端的都是大驼峰形式所以我们要在返回给前端之前进行一次拦截,这事Dataway就不是一个单独的服务需要在controller层进行拦截。

@RestController
// 自定义访问路径区分与非Dataway的接口
@RequestMapping("/dataapi")
public class DataController {
    @Resource
    private AppContext appContext;

    /**
     * @throws
     * @title 拦截get请求对响应体进行修改
     * @description
     * @updateTime 2021/12/31
     */
    @GetMapping("sqlapi/{menu}/{modular}/{interface}/{info}")
    @ApiOperation("datawayAPI")
    public Map<String, Object> getQuery(HttpServletRequest requestHeader, @RequestParam Map<String, Object> paramData) {
        try {
            DatawayService dataWay = appContext.getInstance(DatawayService.class);
            // 获取到动态的请求路径
            String servletPath = getReturn(requestHeader);
            if (servletPath.isEmpty()) {
                return null;
            }
            // 获取到dataway返回的所有数据类型
            Map<String, Object> get = (Map<String, Object>) dataWay.invokeApi("get", servletPath, paramData);
            // 删除掉多余的以及不需要的字段
            get.remove("lifeCycleTime");
            get.remove("executionTime");
            // 获取到返回的数据信息
            Object data = get.get("value");
            List<Map<String, Object>> list = new ArrayList<>();
            // 判断data是否为数组类型是则直接返回
            if (data instanceof ArrayList<?>) {
                for (Object o : (List<?>) data) {
                    list.add(Map.class.cast(o));
                }
                list = (List<Map<String, Object>>) data;
                // 进行大驼峰转换
                List list1 = toListCamelCase(list);
                get.put("data", list1);
            } else {
                try {
                    // 不是则将data强转为Map类型
                    Map<String, Object> data2 = (Map<String, Object>) data;
                    // 获取其中data2中为list的数据
                    list = (List<Map<String, Object>>) data2.get("list");
                    // 将list进行驼峰转换
                    List list1 = toListCamelCase(list);
                    // 返回给前端一个map
                    Map<String, Object> map = new HashMap<>();
                    // 将数据信息
                    map.put("list",list1);
                    // 总条数(分页需要总条数这个需要自己查询)
                    map.put("total",data2.get("total"));
                    get.put("data", map);
                } catch (Exception e) {
                    e.printStackTrace();
                    get.put("data", data);
                }
            }
            get.remove("value");
            return get;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getReturn(HttpServletRequest requestHeader) {
        String servletPath = requestHeader.getServletPath();
        String[] datawayapis = servletPath.split("dataapi");
        if (datawayapis != null && datawayapis.length > 1) {
            String datawayapi = datawayapis[1];
            return datawayapi;
        } else {
            return null;
        }
    }

    public static List toListCamelCase(List<Map<String, Object>> list) {
        if (list != null) {
            for (int i = 0; i < list.size(); ++i) {
                Map<String, Object> map = list.get(i);
                Map<String, Object> newMap = new HashMap();
                Iterator var5 = map.keySet().iterator();
                while (var5.hasNext()) {
                    // 获取到key的值
                    String columnName = (String) var5.next();
                    // 获取到key对应的值
                    Object obj = map.get(columnName);
                    // 将key转换为大驼峰
                    columnName = toCamelCase(columnName);
                    newMap.put(columnName, obj);
                }
                list.set(i, newMap);
            }
        }
        return list;
    }


    public static String toCamelCase(String s) {
        if (s == null) {
            return null;
        } else {
            // 把字符串都转换为小写
            s = s.toLowerCase();
            // 新建一个和s一样长的StringBuilder
            StringBuilder sb = new StringBuilder(s.length());
            // 默认为false
            boolean upperCase = false;
            for (int i = 0; i < s.length(); ++i) {
                char c = s.charAt(i);
                // 当中间有_时修改状态为true进入下一次循环
                if (c == '_') {
                    upperCase = true;
                } else if (upperCase) {
                    // 转换为大写并重置状态
                    sb.append(Character.toUpperCase(c));
                    upperCase = false;
                } else {
                    sb.append(c);
                }
            }
            return sb.toString();
        }
    }
}```

 类似资料: