Java 快速开发框架 magic-api

Java
291
0
0
2024-03-17
标签   Java框架

magic-api

一个基于 Java 的接口快速开发框架,通过 magic-api 提供的 UI 界面完成编写接口,无需定义 ControllerServiceDaoMapperXMLVO 等 Java 对象即可完成常见的 HTTP API 接口开发。

官网地址:https://www.ssssssss.org/magic-api

官方在线演示:https://magic-api.ssssssss.org

官方示例项目:https://gitee.com/ssssssss-team/magic-api-example

特性

  • • 支持 MySQL、MariaDB、Oracle、DB2、PostgreSQL、SQLServer 等支持jdbc规范的数据库
  • • 支持非关系型数据库Redis、Mongodb
  • • 支持集群部署、接口自动同步。
  • • 支持分页查询以及自定义分页查询
  • • 支持多数据源配置,支持在线配置数据源
  • • 支持SQL缓存,以及自定义SQL缓存
  • • 支持自定义JSON结果、自定义分页结果
  • • 支持对接口权限配置、拦截器等功能
  • • 支持运行时动态修改数据源
  • • 支持Swagger接口文档生成
  • • 基于magic-script脚本引擎,动态编译,无需重启,实时发布
  • • 支持Linq式查询,关联、转换更简单
  • • 支持数据库事务、SQL支持拼接,占位符,判断等语法
  • • 支持文件上传、下载、输出图片
  • • 支持脚本历史版本对比与恢复
  • • 支持脚本代码自动提示、参数提示、悬浮提示、错误提示
  • • 支持导入Spring中的Bean、Java中的类
  • • 支持在线调试
  • • 支持自定义工具类、自定义模块包、自定义类型扩展、自定义方言、自定义列名转换等自定义操作

使用示例

添加依赖

新建 SpringBoot 项目,添加相关依赖:

<properties>
    <java.version>1.8</java.version>
    <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-boot.version>2.7.15</spring-boot.version>

    <magic-api.version>2.1.1</magic-api.version>
    <druid-spring-boot.varsion>1.2.6</druid-spring-boot.varsion>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.ssssssss</groupId>
        <artifactId>magic-api-spring-boot-starter</artifactId>
        <version>${magic-api.version}</version>
    </dependency>

    <dependency>
        <groupId>org.ssssssss</groupId>
        <artifactId>magic-api-plugin-task</artifactId>
        <version>${magic-api.version}</version>
    </dependency>

    <dependency>
        <groupId>org.ssssssss</groupId>
        <artifactId>magic-api-plugin-component</artifactId>
        <version>${magic-api.version}</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>${druid-spring-boot.varsion}</version>
    </dependency>
</dependencies>

配置文件

server:
  port: 8080

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/demo?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true
    username: root
    password: 123456
    initialSize: 10
    minIdle: 10
    maxActive: 100
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 300000
    minEvictableIdleTimeMillis: 3600000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20

magic-api:
  web: /api/web
  show-sql: true #配置打印SQL
  sql-column-case: camel
  security:
    username: admin # 登录用的用户名
    password: admin@123 # 登录用的密码
  support-cross-domain: true # 跨域支持,默认开启
  resource:
    type: database  # 配置接口存储方式,这里选择存在数据库中
    table-name: magic_api_file  # 数据库中的表名
    prefix: /  # 前缀
#    location: data/magic-api
  page:
    page: current
    size: size
  cache:
    enable: true  #开启缓存,默认是不开启的
    ttl: 3600000 #有效期1小时,默认-1 即永不过期
  response-code:
    success: 200 #执行成功的code值
    invalid: 400 #参数验证未通过的code值
    exception: 500 #执行出现异常的code值

详细配置见文档:https://www.ssssssss.org/magic-api/pages/config/spring-boot/#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E7%A4%BA%E4%BE%8B

统一请求响应配置

package com.demo.config;

import com.demo.base.WrapMapper;
import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.context.RequestEntity;
import org.ssssssss.magicapi.core.interceptor.ResultProvider;
import org.ssssssss.magicapi.modules.db.model.Page;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName: MagicAPIJsonConfig.java
 * @Description: 统一请求响应配置
 * @Author: tanyp
 **/
@Component
public class MagicAPIJsonConfig implements ResultProvider {

    /**
     * @MonthName: buildResult
     * @Description: 定义返回结果,默认返回JsonBean
     * @Author: tanyp
     * @Param: [requestEntity, i, s, o]
     * @return: java.lang.Object
     **/
    @Override
    public Object buildResult(RequestEntity requestEntity, int code, String message, Object data) {
        return WrapMapper.wrap(code, message, data);
    }

    /**
     * @MonthName: buildPageResult
     * @Description: 定义分页返回结果
     * @Author: tanyp
     * @Param: [requestEntity, page, total, data]
     * @return: java.lang.Object
     **/
    @Override
    public Object buildPageResult(RequestEntity requestEntity, Page page, long total, List<Map<String, Object>> data) {
        return new HashMap<String, Object>() {
            {
                put("total", total);
                put("pages", page.getOffset());
                put("size", page.getLimit());
                put("records", data);
            }
        };
    }
}

定义返回结果实体类

package com.demo.base;

import java.util.Objects;

/**
 * @ClassName: WrapMapper.java
 * @Description: 返回包装类
 * @Author: tanyp
 **/
public class WrapMapper {

    private WrapMapper() {
    }

    public static <E> Wrapper<E> wrap(int code, String message, E o) {
        return new Wrapper<E>(code, message, o);
    }

    public static <E> Wrapper<E> wrap(int code, String message) {
        return new Wrapper<E>(code, message);
    }

    public static <E> Wrapper<E> wrap(int code) {
        return wrap(code, null);
    }

    public static <E> Wrapper<E> wrap(Exception e) {
        return new Wrapper<E>(Wrapper.ERROR_CODE, e.getMessage());
    }

    public static <E> E unWrap(Wrapper<E> wrapper) {
        return wrapper.getResult();
    }

    public static <E> Wrapper<E> illegalArgument() {
        return wrap(Wrapper.ILLEGAL_ARGUMENT_CODE_, Wrapper.ILLEGAL_ARGUMENT_MESSAGE);
    }

    public static <E> Wrapper<E> error() {
        return wrap(Wrapper.ERROR_CODE, Wrapper.ERROR_MESSAGE);
    }

    public static <E> Wrapper<E> error(String message) {
        return wrap(Wrapper.ERROR_CODE, Objects.isNull(message) ? Wrapper.ERROR_MESSAGE : message);
    }

    public static <E> Wrapper<E> error(int code, String message) {
        return wrap(code, Objects.isNull(message) ? Wrapper.ERROR_MESSAGE : message);
    }

    public static <E> Wrapper<E> ok() {
        return new Wrapper<E>();
    }

    public static <E> Wrapper<E> wrap(E o) {
        return new Wrapper<>(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, o);
    }

    public static <E> Wrapper<E> ok(E o) {
        return new Wrapper<>(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE, o);
    }

    public static <E> Wrapper<E> success() {
        return new Wrapper<>(Wrapper.SUCCESS_CODE, Wrapper.SUCCESS_MESSAGE);
    }
}
package com.demo.base;

import java.io.Serializable;

/**
 * @ClassName: Wrapper.java
 * @Description: 包装类
 * @Author: tanyp
 **/
public class Wrapper<T> implements Serializable {

    /**
     * 成功码.
     */
    public static final int SUCCESS_CODE = 200;

    /**
     * 成功信息.
     */
    public static final String SUCCESS_MESSAGE = "操作成功";

    /**
     * 错误码.
     */
    public static final int ERROR_CODE = 500;

    /**
     * 错误信息.
     */
    public static final String ERROR_MESSAGE = "系统异常,请稍后重试!";

    /**
     * 错误码:参数非法
     */
    public static final int ILLEGAL_ARGUMENT_CODE_ = 400;

    /**
     * 错误信息:参数非法
     */
    public static final String ILLEGAL_ARGUMENT_MESSAGE = "请求参数非法,请核查!";

    /**
     * 错误码:参数非法
     */
    public static final int AUTHORIZATION_CODE = 402;

    /**
     * 错误信息:参数非法
     */
    public static final String AUTHORIZATION_MESSAGE = "Token has expired";

    /**
     * 编号.
     */
    private int code;

    /**
     * 信息.
     */
    private String message;

    /**
     * 结果数据
     */
    private T result;

    public Wrapper() {
        this(SUCCESS_CODE, SUCCESS_MESSAGE);
    }

    public Wrapper(int code, String message) {
        this.code(code).message(message);
    }

    public Wrapper(int code, String message, T result) {
        super();
        this.code(code).message(message).result(result);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    public Wrapper<T> code(int code) {
        this.setCode(code);
        return this;
    }

    public Wrapper<T> message(String message) {
        this.setMessage(message);
        return this;
    }

    public Wrapper<T> result(T result) {
        this.setResult(result);
        return this;
    }

    @Override
    public String toString() {
        return "Wrapper{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", result=" + result +
                '}';
    }

    public boolean isSuccess() {
        return this.getCode() == Wrapper.SUCCESS_CODE;
    }

    public boolean isFail() {
        return !isSuccess();
    }
}

全局异常拦截

package com.demo.extension;

import com.demo.base.WrapMapper;
import com.demo.base.Wrapper;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * @ClassName: GlobalException.java
 * @Description: 全局异常拦截
 * @Author: tanyp
 **/
@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(value = Exception.class)
    public Wrapper handleException(Exception e) {
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
            // 参数校验异常
            return WrapMapper.wrap(Wrapper.ILLEGAL_ARGUMENT_CODE_, "参数有误:" + ex.getBindingResult().getFieldError().getDefaultMessage(), null);
        } else {
            // 统一系统异常
            return WrapMapper.wrap(Wrapper.ERROR_CODE, e.getMessage(), null);
        }
    }
}

初始化数据库

CREATE TABLE `magic_api_file` (
  `file_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `file_content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,
  PRIMARY KEY (`file_path`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='API 表';

CREATE TABLE `magic_backup_record` (
  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '原对象ID',
  `create_date` bigint NOT NULL COMMENT '备份时间',
  `tag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '标签',
  `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '类型',
  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原名称',
  `content` blob COMMENT '备份内容',
  `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '操作人',
  PRIMARY KEY (`id`,`create_date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='api 备份';

启动项目

启动成功,日志如下:

2024-01-03 09:44:24.290  INFO 4324 --- [           main] o.s.m.s.b.s.MagicAPIAutoConfiguration    : 注册扩展:class org.ssssssss.magicapi.modules.servlet.ResponseModule -> class org.ssssssss.magicapi.servlet.javaee.MagicJavaEEResponseExtension
  __  __                _           _     ____  ___ 
 |  \/  |  __ _   __ _ (_)  ___    / \   |  _ \|_ _|
 | |\/| | / _` | / _` || | / __|  / _ \  | |_) || | 
 | |  | || (_| || (_| || || (__  / ___ \ |  __/ | | 
 |_|  |_| \__,_| \__, ||_| \___|/_/   \_\|_|   |___|
                  |___/                        2.1.1
集成插件:
- 组件
- 定时任务
2024-01-03 09:44:24.308 ERROR 4324 --- [           main] o.s.m.s.b.s.MagicAPIAutoConfiguration    : 当前备份设置未配置,强烈建议配置备份设置,以免代码丢失。
2024-01-03 09:44:24.338  INFO 4324 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path '/'
2024-01-03 09:44:24.343  INFO 4324 --- [           main] com.ufan.admin.UfanAdminApplication      : Started UfanAdminApplication in 2.158 seconds (JVM running for 2.62)
********************************************当前服务相关地址********************************************
服务启动成功,magic-api已内置启动! Access URLs:
    接口本地地址:   http://localhost:8080/
    接口外部地址:   http://172.16.80.253:8080/
    接口配置平台:   http://172.16.80.253:8080/api/web/index.html
    可通过配置关闭输出:  magic-api.show-url=false
********************************************当前服务相关地址********************************************
2024-01-03 09:44:26.206  INFO 4324 --- [nio-7001-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]  : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-01-03 09:44:26.206  INFO 4324 --- [nio-7001-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-01-03 09:44:26.206  INFO 4324 --- [nio-7001-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

访问:http://localhost:8080/api/web/index.html

如图所示:

magic-api 总体来说还是非常方便的,在做一些中小型项目的时候可以轻易的解决问题。

了解更多请看官方文档:https://www.ssssssss.org/magic-api