让人上瘾的新一代开发神器——Magic-API
Magic-API是一个基于 Java语言,依托于Spring Boot 生态的一个快速开发框架。用完真的会感叹:真香。
新一代低代码开发神器——Magic-API - 烤鸡计算机技术分享烤鸡计算机技术分享新一代低代码开发神器——Magic-APIhttps://roastchicken.cn/doc/magic-api.html
介绍
Magic-API 是什么?
Magic-API是一个基于 Java语言,依托于Spring Boot 生态的一个快速开发框架。以下为官方的介绍。
magic-api 是一个基于Java的接口快速开发框架,编写接口将通过magic-api提供的UI界面完成,自动映射为HTTP接口,无需定义Controller、Service、Dao、Mapper、XML、VO等Java对象即可完成常见的HTTP API接口开发
Magic-API能做什么?
Magic-API 可以开发HTTP接口、RESTful接口,能作为SpringBoot+Mybatis(包括SSH、SSM等)的替代方案。
使用 Magic-API 有什么优势?
Magic-API编写代码使用的脚本语言的Magic-Script
,它语法和Java很相似,也和Javascript很相似,是吸取了二者语法的优势创造的新语言。
友好的语法意味着学习这个脚本语言的学习成本非常低。这样就不用专门去学一些不熟悉、古怪的语法、特殊的设定了。
对于熟悉Javascript和Java的程序员来说,使用Magic-API可以说是得心应手了。
语法学习成本低是一方面,另一方面是Magic-Script
还支持一些比较前瞻、好用的福利语法。比如你可以放心地使用多行字符串(JDK13中的文本块""",新增的语法)、Javascript ES6中的模板字符串(形如`${变量取值}`),而不用担心你使用的JDK版本仅仅是8。
另一个能大大提高开发效率的,是因为每次改完Magic-API的代码不需要去重启项目。虽然使用IDEA配合一些jRebel之类的插件也可以做到,但是,使用这些热加载的方式写Java代码还是会有一些局限的(比如热加载的reload速度、新写方法的方法签名变化、重新注入Spring环境等问题)。
在效率方面,Magic-Script
的代码也会经过解析、编译为AST,再编译为(ASM)字节码
去执行(1.4.0以前的版本为解释执行)。效率相比纯Java硬编码而言肯定是比不过,不过比那种解析执行的语言会好得多。在普遍的场景下,执行性能也绝不会成为瓶颈。
关于调试:使用Magic-API
的开发过程中,还可以进行debug,调试比较方便,比一些基于Nashorn引擎的框架更有优势。
导入模块:Magic-API
可以导入Spring中的bean、Java中的类以及其他Magic-API接口、Magic-API中的模块、函数。内置了方便操作的一些模块:数据库操作、redis操作、mongo操作、http请求、log日志、request请求模块、response响应模块、env环境模块等。
Magic-API使用浏览器作为开发过程中的编辑器。你甚至可以在平板电脑、手机上、在家里(只要网络能连上)就可以访问到编辑器开发了。想想看,简直可以随时随地进行开发(oh no...)。
既然使用浏览器可以随意访问,那么如何保证安全性呢?开发环境可以对访问Magic-API界面设置用户名和密码,如果是线上环境,还可以根据需要关闭在线编辑功能,防止代码被修改。
使用Magic-API还可以依托Java、Spring生态上的优势。这样使得集成一些可以集成Spring的框架和组件更加方便。让代码写起来更简洁、更顺手,让Javaer的开发变得更高效、便捷。
那么我们来开始吧
需要先了解那些知识?
你需要懂一些基本的计算机知识,比如安装Java环境、使用Maven、了解一些Spring Boot的知识,这个是最基本的。如果你刚好是一名Java EE开发人员,那就最好不过了。
引用依赖
是的。需要在pom.xml中添加magic-api-spring-boot-starter
的依赖。version则需要填最新的版本号(话说这版本号更新的老快了)。
如果你使用的是gradle,也类似,需要用gradle的方式添加依赖
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-spring-boot-starter</artifactId>
<version>magic-api-lastest-version</version>
</dependency>
还有一个properties
文件中的配置。下面是官方文档的配置
server.port=9999
#配置web页面入口
magic-api.web=/magic/web
#配置文件存储位置。当以classpath开头时,为只读模式
magic-api.resource.location=/data/magic-api
启动项目
使用IDE中的方式启动Spring Boot项目。如果不出意外的话,就可以看到控制台打印出Magic-API的访问路径了。
我在使用中配置了哪些东西?
配置
下面是关于Magic-API的一些配置内容:
# 配置web页面入口
magic-api.web=/magic/web
# 下面这两个是逻辑删除的列名和标记为删除时的值
magic-api.crud-config.logic-delete-column=deleted
magic-api.crud-config.logic-delete-value=1
# 指定代码存储模式为数据库
magic-api.resource.type=database
# 代码存储所使用的数据源,在这我使用 'source' 数据源
magic-api.resource.datasource=source
# 执行 SQL 时是否显示 SQL 语句,我设置为了 false,是为了后续对输出sql格式进行自定义
magic-api.show-sql=false
# 代码备份的设置
magic-api.backup-config.max-history=7
magic-api.backup-config.resource-type=database
magic-api.backup-config.datasource=source
magic-api.backup-config.table-name=magic_api_backup
magic-api.debug-config.timeout=600
# 驼峰命名规则,将表名下划线风格转为驼峰规则
magic-api.sql-column-case=camel
# swagger 展示的文字信息
magic-api.swagger-config.description=\u63a5\u53e3\u4fe1\u606f
magic-api.swagger-config.title=\u63a5\u53e3\u6587\u6863
# editor 编辑器的配置文件
magic-api.editor-config=classpath:./magic-editor-config.js
默认是会把写的代码存到本地磁盘文件的。可以通过magic-api.resource.type
设置为数据库存储。
最后的magic-api.editor-config
配置项指定了前端编辑器的一些字体配置,内容如下,位置位于classpath(maven 的 resources
目录),文件名:magic-editor-config.js
var MAGIC_EDITOR_CONFIG = {
editorFontFamily: 'YaHei Consolas Hybrid',
}
数据源配置
再来说数据源的部分,数据源部分是把源代码的保存指定了单独的一个位置。数据源的配置内容如下:
spring.datasource.url=jdbc:mysql://x.x.x.x:3306/pbi?serverTimezone=GMT%2B8
spring.datasource.jdbc-url=${spring.datasource.url}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.name=defaultDataSource
spring.datasource.username=root
spring.datasource.password=xxxx
spring.datasource.source.url=jdbc:mysql://x.x.x.x:3306/pbi_source?serverTimezone=GMT%2B8
spring.datasource.source.jdbc-url=${spring.datasource.source.url}
spring.datasource.source.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.source.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.source.username=root
spring.datasource.source.password=xxxx
Spring Boot 的配置类文件:
@Configuration
public class MagicApiConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
@Primary
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.source")
public DataSource sourceDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public MagicDynamicDataSource magicDynamicDataSource() {
MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource();
dynamicDataSource.setDefault(dataSource());
dynamicDataSource.add("source", sourceDataSource());
return dynamicDataSource;
}
}
其中的指定的source
数据源最后就会被用来存储使用Magic-API编写的源码。
这样做的目的是把代码存储和业务数据进行隔离,防止存放代码的数据库被误操作删除。
除了把代码存到数据库,还可以选择存到文件中。
SQL 打印配置
刚才提到我关闭了默认的SQL打印日志,我有个自己写的实现。还是在MagicApiConfig
中添加一个自定义的SQL打印的Bean
:
@Configuration
public class MagicApiConfig {
...
private static final Pattern SQL_PATTERN = Pattern.compile("\\?");
@Bean
public SQLInterceptor sqlInterceptor() {
return (boundSql, requestEntity) -> {
Logger logger = LoggerFactory.getLogger(filterName(boundSql.getRuntimeContext().getScriptContext()));
String[] parameters = Arrays.stream(boundSql.getParameters()).map(it -> {
if (it == null) {
return "null";
}
if (it instanceof Number) {
return "{" + it + "}";
}
if (it instanceof String) {
return "{'" + it + "'}";
}
if (it instanceof Date) {
return "{'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(it) + "'}";
}
return "{" + it + "(" + it.getClass().getSimpleName() + ")}";
}).toArray(String[]::new);
String dataSourceName = boundSql.getSqlModule().getDataSourceName();
String sql = boundSql.getSql().trim();
Matcher matcher = SQL_PATTERN.matcher(sql);
int patternCount = 0;
while (matcher.find()) {
patternCount++;
}
if (patternCount == parameters.length) {
matcher.reset();
boolean result = matcher.find();
if (result) {
int i = 0;
StringBuffer sb = new StringBuffer();
do {
matcher.appendReplacement(sb, parameters[i++]);
result = matcher.find();
} while (result);
matcher.appendTail(sb);
print(logger, dataSourceName, sb);
} else {
print(logger, parameters, dataSourceName, sql);
}
} else {
print(logger, parameters, dataSourceName, sql);
}
};
}
private static void print(Logger logger, String dataSourceName, StringBuffer sb) {
if (dataSourceName == null) {
logger.info("sql: [{}]", toSql(sb));
} else {
logger.info("datasource: {}\tsql: [{}]", dataSourceName, toSql(sb));
}
}
private static void print(Logger logger, String[] parameters, String dataSourceName, String sql) {
if (dataSourceName == null) {
logger.info("sql: [{}]\tparams: [{}]", toSql(sql), parameters);
} else {
logger.info("datasource: {}\tsql: [{}]\tparams: [{}]", dataSourceName, toSql(sql), parameters);
}
}
private static final Pattern SQL_SPACE = Pattern.compile("\\s*(\\r\\n|\\r|\\n)*\\s+|\\s+(\\r\\n|\\r|\\n)*\\s*");
private static String toSql(String sb) {
return SQL_SPACE.matcher(sb).replaceAll(" ");
}
private static String toSql(StringBuffer sb) {
return toSql(sb.toString());
}
public static String filterName(MagicScriptContext magicScriptContext) {
return PATTERN.matcher(magicScriptContext.getScriptName()).replaceAll("magic-api.[$1]");
}
private static final Pattern PATTERN = Pattern.compile("^.*\\((.*?)\\).*$");
...
}
还需要写另一个Config类,这个主要是对log模块的打印处理。这个Config类跟刚刚的作用不太一样,执行的时机略有区别,所以添加了@AutoConfigureAfter
:
@AutoConfigureAfter(MagicAPIAutoConfiguration.class)
@Import({MagicAPIAutoConfiguration.class, MagicConfiguration.class})
@Configuration
public class MagicApiLoggerConfig {
@Resource
@SuppressWarnings("unused")
private MagicConfiguration magicConfiguration;
@PostConstruct
public void init() {
// MagicResourceLoader.addModule("log", (DynamicModuleImport) magicScriptContext -> LoggerFactory.getLogger(filterName(magicScriptContext))); // 这个是低版本Magic-API的兼容写法
MagicResourceLoader.addModule("log", new DynamicModuleImport(Logger.class, context -> LoggerFactory.getLogger(MagicApiConfig.filterName(context))));
}
}
自定义结果结构、错误提示
我还对错误提示进行覆写,根据自己的需要重写。在下面,还对列表查询的结果类型进行了改造,便于后续调用后修改结构:
@Component
public class ResultHandler implements ResultProvider {
@Override
public Object buildResult(RequestEntity requestEntity, int code, String message, Object data) {
return new JsonBean<>(code, message, data, (int) (System.currentTimeMillis() - requestEntity.getRequestTime()));
}
@Override
public Object buildException(RequestEntity requestEntity, Throwable throwable) {
return buildResult(requestEntity, RESPONSE_CODE_EXCEPTION, "系统繁忙,请稍后重试");
}
@Override
public Object buildPageResult(RequestEntity requestEntity, Page page, long total, List<Map<String, Object>> data) {
return new PageResult<>(total, data);
}
public static class PageResult<T> extends HashMap<String, Object> {
public PageResult(long total, List<T> list) {
super(2);
this.put("total", total);
if (total == 0) {
this.put("list", new ArrayList<>(0));
} else {
this.put("list", list);
}
}
}
}
开始使用
magic-script 的语法语句行位可以写分号,也可以不写分号,用换行表示,这一点和javascript很像。
界面
图片来自官方文档
整体说明
接口信息
RequestBody
ResponseBody
debug
导入
导入是指import指令。比Java中的import功能更多。
导入类
import 可以导入某个类,例如:
import 'java.lang.System'
这样导入之后,我们就可以正常使用System
这个类了,比如执行System.out.println()
。
导入还可以写别名,例如:
import 'java.lang.System' as Sys
这样就可以用别名Sys
来使用System
这个类了。比如Sys.out.println()
。但是这样好像看起来很奇怪,在特定场景下再去用吧
导入并 new 实例:
import 'java.util.Date'
框架默认已经导入了 java.util.* ,所以不需要写导入Date也可以直接书写。使用的时候直接写new Date()
就可以啦。
导入 Spring 中的 Bean
import 可以导入 Spring 中的 Bean,例如:
import 'javax.sql.DataSource' as ds
这样可以导入一个DataSource的bean,后续可以使用ds
作为变量来使用了。
导入模块
improt 还可以导入模块,例如导入日志模块并使用:
import log
log.info('xxxxxx: {}', 'yy')
退出语法
magic-api 中的退出语法是指exit
,作用是退出本次请求,并返回一些数据。类似于return
,但是能传递更多的信息。比如某个入参条件不满足,可以使用exit 400, '参数不正确'
,这样就可以返回给前端接口数据了。
好了,Magic-API的介绍先告一段落了,用起来才知道什么是'真香'!
更多推荐
所有评论(0)