【RuoYi-SpringBoot3-Pro】:Magic API 低代码开发

2025博客之星年度评选已开启 10w+人浏览 3.3k人参与

【RuoYi-SpringBoot3-Pro】:Magic API 低代码开发

本文详细介绍 RuoYi-SpringBoot3-Pro 框架中集成的 Magic API 低代码开发平台,帮助开发者快速构建 REST API 接口。

GitHub:https://github.com/undsky/RuoYi-SpringBoot3-Pro

点击获取最新AI资讯、n8n工作流、开发经验分享

一、什么是 Magic API?

Magic API 是一个基于 Java 的接口快速开发框架,通过 Web 界面编写脚本即可完成接口开发,无需定义 Controller、Service、Mapper 等传统分层代码。

1.1 核心优势

特性说明
可视化开发通过 Web 界面编写接口,所见即所得
即时生效接口修改后无需重启,立即生效
脚本语言基于 Java 语法的脚本语言,学习成本低
数据库操作内置强大的数据库操作 API
多数据源支持动态切换多个数据源
参数校验内置参数校验功能
接口文档自动生成接口文档
版本控制支持接口历史记录和回滚

1.2 适用场景

  • 快速原型开发
  • 简单 CRUD 接口
  • 数据查询报表
  • 临时接口需求
  • 低代码平台集成

二、项目集成

2.1 Maven 依赖

RuoYi-SpringBoot3-Pro 已集成 Magic API 2.2.2 版本:

<!-- Magic API 核心依赖 -->
<dependency>
    <groupId>org.ssssssss</groupId>
    <artifactId>magic-api-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

<!-- Magic API Redis 插件 -->
<dependency>
    <groupId>org.ssssssss</groupId>
    <artifactId>magic-api-plugin-redis</artifactId>
    <version>2.2.2</version>
</dependency>

2.2 配置文件

application.yml 中配置 Magic API:

# Magic API 配置
# 官方文档:https://www.ssssssss.org/magic-api/pages/config/spring-boot/
magic-api:
  # Web 编辑器访问路径(生产环境建议设为 null 禁用)
  web: /magic/web
  
  # 编辑器配置文件
  editor-config: classpath:./magic-editor-config.js
  
  # 接口存储方式
  resource:
    type: database           # 存储类型:database(数据库)/ file(文件)
    tableName: magic_api_file  # 存储表名
  
  # 接口访问前缀
  prefix: /magic/api
  
  # 编辑器登录认证
  security:
    username: jyx            # 登录用户名
    password: jyx_692483     # 登录密码
  
  # 历史记录备份
  backup:
    enable: true             # 是否启用备份
    max-history: -1          # 最大历史记录数(-1 表示不限制)
    table-name: magic_backup_record  # 备份表名
  
  # 响应结果格式
  response: |- 
    {
      code: code,
      msg: message,
      data,
    }

2.3 编辑器主题配置

magic-editor-config.js 文件配置编辑器主题:

var MAGIC_EDITOR_CONFIG = {
    theme: 'dark',  // 主题:dark(暗色)/ light(亮色)
}

2.4 安全配置

Magic API 接口默认放行,在 SecurityConfig.java 中配置:

@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
        .authorizeHttpRequests(auth -> auth
            // Magic API 接口放行
            .requestMatchers("/magic/**").permitAll()
            .anyRequest().authenticated()
        );
    return httpSecurity.build();
}

三、访问编辑器

3.1 访问地址

启动项目后,访问 Magic API 编辑器:

http://localhost:8087/magic/web

3.2 登录认证

使用配置文件中设置的账号密码登录:

  • 用户名:jyx
  • 密码:jyx_692483

3.3 编辑器界面

┌─────────────────────────────────────────────────────────────┐
│  Magic API Editor                                    [用户] │
├─────────────┬───────────────────────────────────────────────┤
│             │                                               │
│  接口列表    │              脚本编辑区                        │
│             │                                               │
│  📁 分组1    │  // 编写接口脚本                              │
│    └─ 接口1  │  var list = db.select("""                    │
│    └─ 接口2  │      SELECT * FROM sys_user                  │
│  📁 分组2    │  """)                                        │
│    └─ 接口3  │  return list                                 │
│             │                                               │
├─────────────┼───────────────────────────────────────────────┤
│  接口配置    │              执行结果                          │
│  请求方式    │  [                                            │
│  请求路径    │    {"userId": 1, "userName": "admin"},       │
│  请求参数    │    {"userId": 2, "userName": "test"}         │
│             │  ]                                            │
└─────────────┴───────────────────────────────────────────────┘

四、接口开发

4.1 创建第一个接口

  1. 点击左侧「+」创建分组
  2. 在分组下创建接口
  3. 配置请求方式和路径
  4. 编写脚本代码
  5. 点击「执行」测试
  6. 点击「保存」发布

4.2 基础语法

Magic API 使用类 Java 语法的脚本语言:

// 变量定义
var name = "张三"
var age = 18

// 条件判断
if (age >= 18) {
    return "成年人"
} else {
    return "未成年人"
}

// 循环
var list = [1, 2, 3, 4, 5]
for (item in list) {
    print(item)
}

// 函数定义
var add = (a, b) => a + b
return add(1, 2)

4.3 获取请求参数

// 获取 Query 参数:/api/user?name=张三&age=18
var name = name        // 直接使用参数名
var age = age

// 获取 Path 参数:/api/user/{id}
var userId = path.id

// 获取 Body 参数(JSON)
var user = body
var userName = body.userName

// 获取 Header
var token = header.Authorization

// 获取完整请求对象
var request = request

4.4 数据库操作

Magic API 内置强大的数据库操作 API:

// 查询列表
var list = db.select("""
    SELECT * FROM sys_user WHERE status = '0'
""")

// 查询单条
var user = db.selectOne("""
    SELECT * FROM sys_user WHERE user_id = #{userId}
""")

// 带参数查询
var users = db.select("""
    SELECT * FROM sys_user 
    WHERE dept_id = #{deptId} 
    AND user_name LIKE CONCAT('%', #{keyword}, '%')
""")

// 分页查询
var page = db.page("""
    SELECT * FROM sys_user WHERE status = '0'
""")

// 插入数据
var result = db.insert("""
    INSERT INTO sys_user (user_name, nick_name, email) 
    VALUES (#{userName}, #{nickName}, #{email})
""")

// 更新数据
var result = db.update("""
    UPDATE sys_user SET nick_name = #{nickName} WHERE user_id = #{userId}
""")

// 删除数据
var result = db.delete("""
    DELETE FROM sys_user WHERE user_id = #{userId}
""")

4.5 链式查询

// 使用链式 API 构建查询
var list = db.table('sys_user')
    .where()
    .eq('status', '0')
    .like('user_name', keyword)
    .orderBy('create_time desc')
    .page(pageNum, pageSize)
    .select()

// 插入
db.table('sys_user').insert({
    userName: '张三',
    nickName: '小张',
    email: 'zhangsan@example.com'
})

// 更新
db.table('sys_user')
    .where()
    .eq('user_id', 1)
    .update({
        nickName: '新昵称'
    })

// 删除
db.table('sys_user')
    .where()
    .eq('user_id', 1)
    .delete()

4.6 多数据源

// 切换数据源
var list = db.slave.select("""
    SELECT * FROM other_table
""")

// 或使用 datasource 指定
var list = db.datasource('slave').select("""
    SELECT * FROM other_table
""")

五、接口鉴权

5.1 鉴权拦截器

RuoYi-SpringBoot3-Pro 实现了 Magic API 的请求拦截器,支持登录验证和权限校验:

@Component
public class MagicApiRequestInterceptor implements RequestInterceptor {
    
    @Override
    public Object preHandle(ApiInfo info, MagicScriptContext context, 
            MagicHttpServletRequest request, MagicHttpServletResponse response) {
        
        // 获取接口配置的选项
        boolean needLogin = StringUtils.equals("true", info.getOptionValue(Options.REQUIRE_LOGIN));
        String role = info.getOptionValue(Options.ROLE);
        String permission = info.getOptionValue(Options.PERMISSION);
        
        // 需要角色或权限时,自动要求登录
        if (StringUtils.isNotBlank(role) || StringUtils.isNotBlank(permission)) {
            needLogin = true;
        }
        
        // 登录校验
        if (needLogin) {
            try {
                SecurityUtils.getLoginUser();
            } catch (Exception e) {
                return new JsonBean<>(401, "用户未登录");
            }
        }
        
        // 角色校验
        if (StringUtils.isNotBlank(role)) {
            if (!SecurityUtils.hasRole(role)) {
                return new JsonBean<>(403, "用户权限不足");
            }
        }
        
        // 权限校验
        if (StringUtils.isNotBlank(permission)) {
            if (!SecurityUtils.hasPermi(permission)) {
                return new JsonBean<>(403, "用户权限不足");
            }
        }
        
        return null;  // 返回 null 表示放行
    }
}

5.2 配置接口权限

在 Magic API 编辑器中,为接口配置权限选项:

选项说明示例值
require_login是否需要登录true / false
role需要的角色admin
permission需要的权限system:user:list

配置方式:

  1. 在编辑器中选择接口
  2. 点击「选项」标签
  3. 添加对应的选项配置

5.3 获取当前用户

在脚本中获取当前登录用户信息:

import com.ruoyi.common.utils.SecurityUtils

// 获取当前用户 ID
var userId = SecurityUtils.getUserId()

// 获取当前用户名
var username = SecurityUtils.getUsername()

// 获取当前用户信息
var loginUser = SecurityUtils.getLoginUser()
var user = loginUser.getUser()

六、Redis 缓存

6.1 基础操作

Magic API 集成了 Redis 插件,可直接使用:

// 设置缓存
redis.set('key', 'value')

// 设置缓存(带过期时间,单位秒)
redis.set('key', 'value', 3600)

// 获取缓存
var value = redis.get('key')

// 删除缓存
redis.del('key')

// 判断是否存在
var exists = redis.exists('key')

// 设置过期时间
redis.expire('key', 3600)

6.2 接口缓存示例

// 先从缓存获取
var cacheKey = 'user:list:' + deptId
var list = redis.get(cacheKey)

if (list == null) {
    // 缓存不存在,查询数据库
    list = db.select("""
        SELECT * FROM sys_user WHERE dept_id = #{deptId}
    """)
    // 存入缓存,1小时过期
    redis.set(cacheKey, list, 3600)
}

return list

6.3 Hash 操作

// 设置 Hash 字段
redis.hset('user:1', 'name', '张三')
redis.hset('user:1', 'age', 18)

// 获取 Hash 字段
var name = redis.hget('user:1', 'name')

// 获取所有字段
var user = redis.hgetAll('user:1')

// 删除 Hash 字段
redis.hdel('user:1', 'name')

七、高级特性

7.1 事务支持

import db

// 开启事务
db.transaction(() => {
    db.update("""
        UPDATE account SET balance = balance - 100 WHERE user_id = 1
    """)
    db.update("""
        UPDATE account SET balance = balance + 100 WHERE user_id = 2
    """)
})

7.2 异步执行

import async

// 异步执行
async.run(() => {
    // 耗时操作
    db.insert("""
        INSERT INTO log (content) VALUES ('异步日志')
    """)
})

return "请求已接收"

7.3 HTTP 请求

import http

// GET 请求
var result = http.get('https://api.example.com/users')

// POST 请求
var result = http.post('https://api.example.com/users', {
    body: {
        name: '张三',
        age: 18
    }
})

// 带 Header 的请求
var result = http.get('https://api.example.com/users', {
    headers: {
        'Authorization': 'Bearer token'
    }
})

7.4 参数校验

import assert

// 非空校验
assert.notNull(userId, '用户ID不能为空')
assert.notBlank(userName, '用户名不能为空')

// 条件校验
assert.isTrue(age >= 18, '年龄必须大于等于18')

// 正则校验
assert.regx(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$', '邮箱格式不正确')

7.5 日志输出

import log

log.info('这是一条信息日志')
log.warn('这是一条警告日志')
log.error('这是一条错误日志')
log.debug('这是一条调试日志')

八、实战示例

8.1 用户列表接口

/**
 * 接口路径:GET /magic/api/user/list
 * 请求参数:pageNum, pageSize, userName, status
 */

// 参数处理
var pageNum = pageNum ?: 1
var pageSize = pageSize ?: 10

// 构建查询
var query = db.table('sys_user')
    .where()
    .eq('del_flag', '0')

// 动态条件
if (userName) {
    query.like('user_name', userName)
}
if (status) {
    query.eq('status', status)
}

// 分页查询
var page = query.orderBy('create_time desc')
    .page(pageNum, pageSize)
    .select()

return page

8.2 用户详情接口

/**
 * 接口路径:GET /magic/api/user/{id}
 * 路径参数:id
 */

import assert

// 参数校验
assert.notNull(path.id, '用户ID不能为空')

// 查询用户
var user = db.selectOne("""
    SELECT u.*, d.dept_name 
    FROM sys_user u
    LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
    WHERE u.user_id = #{path.id} AND u.del_flag = '0'
""")

if (user == null) {
    return {
        code: 404,
        msg: '用户不存在'
    }
}

return user

8.3 新增用户接口

/**
 * 接口路径:POST /magic/api/user
 * 请求体:userName, nickName, email, phonenumber, deptId
 */

import assert
import com.ruoyi.common.utils.SecurityUtils

// 参数校验
assert.notBlank(body.userName, '用户名不能为空')
assert.notBlank(body.nickName, '昵称不能为空')

// 检查用户名是否存在
var exists = db.selectOne("""
    SELECT 1 FROM sys_user WHERE user_name = #{body.userName} AND del_flag = '0'
""")
if (exists) {
    return {
        code: 500,
        msg: '用户名已存在'
    }
}

// 插入用户
var result = db.insert("""
    INSERT INTO sys_user (user_name, nick_name, email, phonenumber, dept_id, 
        password, create_by, create_time)
    VALUES (#{body.userName}, #{body.nickName}, #{body.email}, #{body.phonenumber}, 
        #{body.deptId}, #{SecurityUtils.encryptPassword('123456')}, 
        #{SecurityUtils.getUsername()}, NOW())
""")

return {
    code: 200,
    msg: '新增成功'
}

8.4 统计报表接口

/**
 * 接口路径:GET /magic/api/report/user-stats
 * 请求参数:startDate, endDate
 */

// 用户统计
var stats = db.selectOne("""
    SELECT 
        COUNT(*) as totalCount,
        SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END) as activeCount,
        SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) as disabledCount
    FROM sys_user 
    WHERE del_flag = '0'
""")

// 部门分布
var deptStats = db.select("""
    SELECT d.dept_name, COUNT(u.user_id) as userCount
    FROM sys_dept d
    LEFT JOIN sys_user u ON d.dept_id = u.dept_id AND u.del_flag = '0'
    WHERE d.del_flag = '0'
    GROUP BY d.dept_id, d.dept_name
    ORDER BY userCount DESC
    LIMIT 10
""")

// 注册趋势
var trend = db.select("""
    SELECT DATE(create_time) as date, COUNT(*) as count
    FROM sys_user
    WHERE del_flag = '0'
    AND create_time BETWEEN #{startDate} AND #{endDate}
    GROUP BY DATE(create_time)
    ORDER BY date
""")

return {
    stats: stats,
    deptStats: deptStats,
    trend: trend
}

九、生产环境配置

9.1 禁用编辑器

生产环境建议禁用 Web 编辑器:

magic-api:
  web: null  # 设为 null 禁用编辑器

9.2 修改默认密码

magic-api:
  security:
    username: your_username
    password: your_strong_password

9.3 接口访问控制

通过 Spring Security 控制 Magic API 接口访问:

.requestMatchers("/magic/api/**").authenticated()  // 需要登录
.requestMatchers("/magic/web/**").hasRole("ADMIN") // 仅管理员

十、常见问题

10.1 接口不生效

  • 检查是否点击「保存」按钮
  • 检查接口路径是否正确
  • 查看控制台是否有错误日志

10.2 数据库连接失败

  • 检查数据源配置是否正确
  • 确认数据库服务是否启动
  • 查看连接池配置

10.3 权限校验失败

  • 确认接口配置了正确的权限选项
  • 检查请求是否携带有效的 Token
  • 验证用户是否拥有对应权限

十一、总结

RuoYi-SpringBoot3-Pro 集成的 Magic API 具有以下特点:

  • 开箱即用:预配置完善,启动即可使用
  • 可视化开发:Web 界面编写接口,所见即所得
  • 即时生效:无需重启,修改立即生效
  • 数据库持久化:接口存储在数据库,支持版本控制
  • 权限集成:与 RuoYi 权限体系无缝集成
  • Redis 支持:内置 Redis 插件,轻松实现缓存

Magic API 适合快速开发简单接口,与传统 Controller 开发方式互补,可根据实际需求灵活选择。


<think> 我们参考提供的引用来构建Dockerfile。特别是引用[1]提到K8s部署,引用[2]提到ruoyi-auth的配置文件,引用[3]提到网关路由配置,引用[4]提到MyBatis配置。但是,用户的需求是根据k8s中的ruoyi-auth.yaml文件来编写Dockerfile。 由于我们没有直接看到ruoyi-auth.yaml文件的具体内容,但我们可以根据Kubernetes部署文件的一般结构和RuoYi-Cloud-Plus项目的特性来推断。 通常,在Kubernetes中部署一个应用,我们会有一个Deployment资源,其中会指定容器镜像、环境变量、配置文件挂载等。因此,Dockerfile需要构建出该Deployment中指定的镜像。 根据RuoYi-Cloud-Plus项目的特点,它是一个Spring Cloud微服务项目,因此ruoyi-auth是一个Spring Boot应用。构建Dockerfile的标准做法是使用多阶段构建:第一阶段用Maven构建jar包,第二阶段用基础镜像运行jar包。 但是,用户要求根据k8s的ruoyi-auth.yaml文件编写Dockerfile,所以我们假设ruoyi-auth.yaml中可能包含镜像名称、端口、环境变量等信息。如果没有具体文件,我们可以参考一般实践。 根据引用[2]和引用[4],ruoyi-auth需要配置文件,这些配置文件通常放在项目的src/main/resources目录下,在Dockerfile中我们需要将构建好的jar包和配置文件一起放入镜像,或者通过外部挂载(但在Dockerfile中我们只关心构建镜像,挂载在K8s中处理)。 步骤: 1. 使用基础镜像构建项目(maven镜像) 2. 复制项目文件并构建 3. 使用轻量级运行镜像(如openjdk) 4. 复制构建好的jar包和配置文件 5. 指定启动命令 由于没有具体的ruoyi-auth.yaml,我们假设: - 应用端口可能在配置文件中设置,但通常在application.yml中,我们可以在Dockerfile中通过环境变量设置(如不设置,使用默认端口)。 - 根据引用[3],ruoyi-auth服务在网关中配置的路径是/auth/**,但这不影响Dockerfile。 我们还需要注意,在K8s部署中,通常配置是通过ConfigMap或外部配置中心(如Nacos)注入,因此Dockerfile中可能不需要包含具体的配置文件,但需要包含默认配置。 因此,我们编写一个通用的Dockerfile,同时参考引用[4]中提到的配置文件内容(如mybatis-plus配置)可能存在于项目中,但构建时这些配置文件已经打包在jar内或需要外部挂载。 由于是Spring Boot项目,我们使用构建好的fat jar(包含所有依赖)。 下面是Dockerfile的一个示例: </think>根据Kubernetes部署需求和RuoYi-Cloud-Plus项目特性,以下是针对`ruoyi-auth`服务的Dockerfile实现: ```dockerfile # 基础镜像 - 推荐使用官方镜像 FROM eclipse-temurin:17-jdk-focal as builder # 设置工作目录 WORKDIR /app # 复制构建文件 COPY mvnw . COPY .mvn .mvn COPY pom.xml . COPY src src # 构建应用 (包含依赖下载) RUN ./mvnw clean package -DskipTests # 最终运行阶段 FROM eclipse-temurin:17-jre-focal # 设置时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 创建应用目录 WORKDIR /app # 从构建阶段复制JAR文件 COPY --from=builder /app/target/ruoyi-auth-*.jar app.jar # 暴露服务端口 (根据实际配置) EXPOSE 9200 # 健康检查 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:9200/auth/health || exit 1 # 启动命令 (支持K8s环境变量注入) ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar"] ``` ### 关键配置说明: 1. **多阶段构建**: - 第一阶段使用JDK镜像编译项目,生成可执行JAR - 第二阶段使用轻量级JRE镜像运行,减小镜像体积(约减少40%) 2. **配置管理**: ```dockerfile # 若需挂载外部配置,添加以下声明 VOLUME /app/config ``` 通过K8s ConfigMap挂载配置文件到`/app/config`目录[^2] 3. **安全增强**: - `-Djava.security.egd`参数加速熵池生成 - 非root用户运行(建议在K8s SecurityContext中配置) 4. **服务发现**: ```dockerfile # 启用Spring Cloud服务发现 ENTRYPOINT ["java","-Dspring.cloud.nacos.discovery.server-addr=${NACOS_HOST:nacos}:${NACOS_PORT:8848}","-jar","app.jar"] ``` 通过环境变量注入Nacos地址[^3] ### K8s部署配合要点: 1. **服务路由**: 确保K8s Ingress配置与网关路由一致: ```yaml # ruoyi-gateway-dev.yml 路由配置 - id: ruoyi-auth uri: lb://ruoyi-auth predicates: - Path=/auth/** ```[^3] 2. **配置注入**: 在Deployment中挂载MyBatis等配置: ```yaml volumes: - name: app-config configMap: name: ruoyi-auth-config volumeMounts: - mountPath: /app/config name: app-config ```[^4] 3. **数据库配置**: ```yaml env: - name: SPRING_DATASOURCE_URL value: jdbc:mysql://ruoyi-mysql:3306/ry-cloud ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

undsky_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值