...
 
Commits (16)
    https://gitcode.net/ssssssss-team/magic-api/-/commit/ee4f361477b513e58b2de017139b66c34cc960ea add template 2022-04-26T14:27:43+08:00 wangyao biantaila@hotmail.com https://gitcode.net/ssssssss-team/magic-api/-/commit/2d4e5b067e36d0897d930fd956ffd45bcd0ca328 feat:swagger 添加认证配置 2022-05-25T16:57:39+08:00 taogang 1102014862@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/17b571c2dde03909d5e886ae06e947654784e20c update magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/NamedTa... 2022-06-01T07:39:59+00:00 cjn 1067473628@qq.com 此处拼接sql语句时,当order by和group by 一起使用时,应当先分组再排序,sql语句错误 https://gitcode.net/ssssssss-team/magic-api/-/commit/4d0a73475f78d03b85db43f79dca1a658afe94d9 “组件”插件 2022-06-08T21:03:56+08:00 zegezy 1098696801@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/a75c329767e10a075241975e7933c48e8f389a5d !45 add Issues&PR template 2022-06-08T13:07:51+00:00 小东 838425805@qq.com Merge pull request !45 from 奇健陀螺王/dev https://gitcode.net/ssssssss-team/magic-api/-/commit/3a902a8a21cfd6ca809fdff39ab6e5f48a27d613 !47 添加Swagger 全局认证配置,包括Basic,ApiToken,Oauth2认证方式,支持同时配置多种认证 2022-06-08T13:08:05+00:00 小东 838425805@qq.com Merge pull request !47 from success/master https://gitcode.net/ssssssss-team/magic-api/-/commit/4178f35377b678d966b534c9e406a9c57c140eb2 fix 2022-06-08T21:09:13+08:00 mxd 838425805@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/d40dcb2cb9032d646a11cb1c5b71657c99a78b14 修复可能出现的空指针异常 2022-06-08T21:09:31+08:00 mxd 838425805@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/a360bb896f5f66bc75f7eaccbb4e89472c0fb7a4 update 2022-06-08T21:09:55+08:00 mxd 838425805@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/7027d5376a1e4e19473f2f02fdeb69fc080562d8 update magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java. 2022-07-05T05:42:47+00:00 码上有钱 383366063@qq.com 修复字符串转字节数组的时候指定UTF-8编码 https://gitcode.net/ssssssss-team/magic-api/-/commit/d37368ec8dfa7528bb3fc8ecbb4894ac888d63c6 [*]zip脚本上传window中文乱码兼容 2022-07-14T14:45:24+08:00 Lianjy lian6316@qq.com https://gitcode.net/ssssssss-team/magic-api/-/commit/6103f1ea2300ac188f3fb997383432f5927aac57 !49 update magic-api/src/main/java/org/ssssssss/magicapi/utils/IoUtils.java. 2022-07-28T10:00:44+00:00 彭秦进 ashang.peng@aliyun.com Merge pull request !49 from 码上有钱/N/A https://gitcode.net/ssssssss-team/magic-api/-/commit/5a3791b530c565869ee76ffda06701eae4fe1c95 分页查询兼容注释情况 2022-08-01T17:15:08+08:00 wangyao biantaila@hotmail.com https://gitcode.net/ssssssss-team/magic-api/-/commit/26c594e7e9c5b634260c5b2e7da66c689212ffb3 !51 分页查询兼容语句注释 2022-08-01T22:45:51+00:00 小东 838425805@qq.com Merge pull request !51 from 奇健陀螺王/dev https://gitcode.net/ssssssss-team/magic-api/-/commit/7f0cf5b3705f9c615be6abbfa8eeb6bbd9e40333 !48 update magic-api/src/main/java/org/ssssssss/magicapi/modules/db/table/Nam... 2022-08-25T23:20:59+00:00 小东 838425805@qq.com Merge pull request !48 from cjn/N/A https://gitcode.net/ssssssss-team/magic-api/-/commit/4fa10ed139f8f9d3f598230f4e4c4a56a6e8ea20 Merge branch 'master' into dev 2022-08-26T07:28:59+08:00 mxd 838425805@qq.com
### 当前使用版本(必填,否则不予处理)
### 该问题是怎么引起的?
### 重现步骤(如果有就写完整)
### 报错信息
### 该 Pull Request 关联的 Issue
### 描述信息
### 测试用例
### 更新效果的截屏
### 当前使用版本(必填,否则不予处理)
### 该问题是怎么引起的?
### 重现步骤(如果有就写完整)
### 报错信息
### 该 Pull Request 关联的 Issue
### 描述信息
### 测试用例
### 更新效果的截屏
<?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.ssssssss</groupId>
<artifactId>magic-api-plugins</artifactId>
<version>2.0.1</version>
</parent>
<artifactId>magic-api-plugin-component</artifactId>
<packaging>jar</packaging>
<name>magic-api-plugin-component</name>
<description>magic-api-plugin-component</description>
<build>
<plugins>
<!-- npm install && npm run build -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>exec-npm-install</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
<workingDirectory>${basedir}/src/console</workingDirectory>
</configuration>
</execution>
<execution>
<id>exec-npm-run-build</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
<workingDirectory>${basedir}/src/console</workingDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-resource</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/magic-editor/plugins</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/console/dist</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
{
"name": "magic-component",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "vite build"
},
"author": "",
"license": "ISC",
"devDependencies": {
"vue": "^3.2.31",
"@vitejs/plugin-vue": "^2.2.4",
"vite-plugin-svg-icons": "^1.1.0",
"vite": "^2.8.6"
}
}
<template>
<div class="magic-component-info">
<form>
<label>{{ $i('component.form.name') }}</label>
<magic-input v-model:value="info.name" :placeholder="$i('component.form.placeholder.name')" width="250px"/>
<label>{{ $i('component.form.path') }}</label>
<magic-input v-model:value="info.path" :placeholder="$i('component.form.placeholder.path')" width="auto" style="flex:1"/>
</form>
<div style="flex:1;padding-top:5px;">
<magic-textarea v-model:value="info.description" :placeholder="$i('component.form.placeholder.description')"/>
</div>
</div>
</template>
<script setup>
import { inject } from 'vue'
const $i = inject('i18n.format')
const info = inject('info')
</script>
<style scoped>
.magic-component-info{
display: flex;
flex-direction: column;
flex: 1;
padding: 5px;
}
.magic-component-info form{
display: flex;
}
.magic-component-info form label{
display: inline-block;
width: 75px;
height: 22px;
line-height: 22px;
font-weight: 400;
text-align: right;
padding: 0 5px;
}
.magic-component-info form :deep(.magic-textarea){
margin: 5px;
}
</style>
export default {
component: {
title: 'Component Info',
name: 'Component',
form: {
name: 'Component Name',
path: 'Component Path',
description: 'Component Description',
placeholder: {
name: 'Please Enter Component Name',
path: 'Please Enter Component Path',
description: 'Please Enter Component Description'
}
}
},
}
export default {
component: {
title: '组件信息',
name: '组件',
form: {
name: '组件名称',
path: '组件路径',
description: '组件描述',
placeholder: {
name: '请输入组件名称',
path: '请输入组件路径',
description: '请输入组件描述'
}
}
}
}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1647853515880" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1190" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M914.5 653.5c-5.5 0-11 1.1-16 3.3l-0.2 0.1h-0.2L510.2 822.2 122.2 657h-0.2l-0.2-0.1c-5-2.1-10.3-3.3-16-3.3-23.1 0-41.8 19.3-41.8 43.1 0 18 10.7 33.3 25.8 39.8l403.9 172.1 0.4 0.1c10.2 4.4 21.8 4.4 32 0l0.2-0.1c0.1 0 0.1-0.1 0.2-0.1l403.9-172.1c15.1-6.5 25.8-21.8 25.8-39.8 0.1-23.8-18.6-43.1-41.7-43.1z m0-186.5c-7.9-0.2-16 3.2-16 3.2L510.2 635.6 121.8 470.2s-10.3-3.2-16-3.2C82.7 467 64 486.2 64 510c0 17.9 10.7 33.3 25.8 39.7l403.9 172c0.1 0 0.1 0.1 0.2 0.1l0.1 0.1c5 2.1 10.3 3.3 16 3.3 5.7 0 11.1-1.2 16-3.3l0.2-0.1c0.1 0 0.1 0 0.2-0.1l403.9-172c15.1-6.4 25.8-21.8 25.9-39.7 0.1-23.8-18.6-43-41.7-43zM89.8 363.2l403.9 172.1c0.1 0 0.1 0 0.2 0.1l0.1 0.1c5 2.1 10.3 3.2 16 3.2 5.5 0 10.9-1.1 16-3.2l0.2-0.1 0.2-0.1 403.9-172c15.1-6.5 25.8-21.8 25.9-39.7 0-18-10.7-33.3-25.8-39.8L526.5 111.6c-0.1 0-0.1 0-0.2-0.1l-0.2-0.1c-10.2-4.4-21.8-4.4-32 0l-0.1 0.1L89.8 283.7C74.7 290.1 64 305.5 64 323.5c0 17.9 10.7 33.2 25.8 39.7z" p-id="1191" fill="#000000"></path></svg>
\ No newline at end of file
import MagicComponent from './service/magic-component.js'
import localZhCN from './i18n/zh-cn.js'
import localEn from './i18n/en.js'
import MagicComponentInfo from './components/magic-component-info.vue'
import 'vite-plugin-svg-icons/register'
export default (opt) => {
const i18n = opt.i18n
// 添加i18n 国际化信息
i18n.add('zh-cn', localZhCN)
i18n.add('en', localEn)
return {
// 左侧资源
resource: [{
// 资源类型,和后端存储结构一致
type: 'component',
// 展示图标
icon: '#magic-component-component', // #开头表示图标在插件中
// 展示名称
title: 'component.name',
// 运行服务
service: MagicComponent(opt.bus, opt.constants, i18n.format, opt.Message, opt.request),
}],
// 底部工具条
toolbars: [{
// 当打开的资源类型为 task 时显示
type: 'component',
// 工具条展示的标题
title: 'component.title',
// 展示图标
icon: 'parameter',
// 对应的组件
component: MagicComponentInfo,
}]
}
}
export default function (bus, constants, $i, Message, request) {
return {
// svg text
getIcon: item => ['Vue', '#41B883'],
// 任务名称
name: $i('component.name'),
// 脚本语言
language: 'html',
// 默认脚本
defaultScript: `<template>
</template>
<script setup>
</script>
<style scoped>
</style>`,
// 是否允许执行测试
runnable: false,
// 是否需要填写路径
requirePath: true,
// 合并
merge: item => item
}
}
import vue from '@vitejs/plugin-vue'
import viteSvgIcons from 'vite-plugin-svg-icons'
import path from 'path'
import pkg from './package.json'
export default {
base: './',
build: {
minify: false,
cssCodeSplit: true, // 将组件的 style 打包到 js 文件中
outDir: 'dist',
lib: {
target: 'esnext',
formats: ['iife'],
entry: path.resolve(__dirname, 'src/index.js'),
name: 'MagicComponent',
fileName: (format) => `magic-component.${pkg.version}.${format}.js`
},
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['vue'],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
vue: 'Vue'
}
}
}
},
plugins: [
vue(),
viteSvgIcons({
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
symbolId: 'magic-component-[name]'
}),
]
}
package org.ssssssss.magicapi.component.model;
import org.ssssssss.magicapi.core.model.MagicEntity;
import org.ssssssss.magicapi.core.model.PathMagicEntity;
import java.util.Objects;
public class ComponentInfo extends PathMagicEntity {
/**
* 组件描述
*/
private String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public ComponentInfo copy() {
ComponentInfo info = new ComponentInfo();
super.copyTo(info);
info.setDescription(this.description);
return info;
}
@Override
public MagicEntity simple() {
ComponentInfo info = new ComponentInfo();
super.simple(info);
return info;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ComponentInfo componentInfo = (ComponentInfo) o;
return Objects.equals(id, componentInfo.id) &&
Objects.equals(path, componentInfo.path) &&
Objects.equals(script, componentInfo.script) &&
Objects.equals(name, componentInfo.name) &&
Objects.equals(description, componentInfo.description);
}
@Override
public int hashCode() {
return Objects.hash(id, path, script, name, groupId, description);
}
}
package org.ssssssss.magicapi.component.service;
import org.ssssssss.magicapi.component.model.ComponentInfo;
import org.ssssssss.magicapi.core.exception.InvalidArgumentException;
import org.ssssssss.magicapi.core.model.JsonCode;
import org.ssssssss.magicapi.core.service.AbstractPathMagicResourceStorage;
import java.util.UUID;
public class ComponentInfoMagicResourceStorage extends AbstractPathMagicResourceStorage<ComponentInfo> {
@Override
public String folder() {
return "component";
}
@Override
public Class<ComponentInfo> magicClass() {
return ComponentInfo.class;
}
@Override
public void validate(ComponentInfo entity) {
}
@Override
public String buildMappingKey(ComponentInfo info) {
return buildMappingKey(info, magicResourceService.getGroupPath(info.getGroupId()));
}
@Override
public boolean requirePath() {
return false;
}
}
package org.ssssssss.magicapi.component.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.ssssssss.magicapi.component.model.ComponentInfo;
import org.ssssssss.magicapi.core.event.FileEvent;
import org.ssssssss.magicapi.core.event.GroupEvent;
import org.ssssssss.magicapi.core.service.AbstractMagicDynamicRegistry;
import org.ssssssss.magicapi.core.service.MagicResourceStorage;
public class ComponentMagicDynamicRegistry extends AbstractMagicDynamicRegistry<ComponentInfo> {
public ComponentMagicDynamicRegistry(MagicResourceStorage<ComponentInfo> magicResourceStorage) {
super(magicResourceStorage);
}
@EventListener(condition = "#event.type == 'component'")
public void onFileEvent(FileEvent event) {
processEvent(event);
}
@EventListener(condition = "#event.type == 'component'")
public void onGroupEvent(GroupEvent event) {
processEvent(event);
}
}
package org.ssssssss.magicapi.component.starter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.ssssssss.magicapi.component.service.ComponentInfoMagicResourceStorage;
import org.ssssssss.magicapi.component.service.ComponentMagicDynamicRegistry;
import org.ssssssss.magicapi.core.config.MagicPluginConfiguration;
import org.ssssssss.magicapi.core.model.Plugin;
@Configuration
public class MagicAPIComponentConfiguration implements MagicPluginConfiguration {
@Bean
@ConditionalOnMissingBean
public ComponentInfoMagicResourceStorage componentInfoMagicResourceStorage() {
return new ComponentInfoMagicResourceStorage();
}
@Bean
@ConditionalOnMissingBean
public ComponentMagicDynamicRegistry componentMagicDynamicRegistry(ComponentInfoMagicResourceStorage componentInfoMagicResourceStorage) {
return new ComponentMagicDynamicRegistry(componentInfoMagicResourceStorage);
}
@Override
public Plugin plugin() {
return new Plugin("组件", "MagicComponent", "magic-component.1.0.0.iife.js");
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ssssssss.magicapi.component.starter.MagicAPIComponentConfiguration
package org.ssssssss.magicapi.swagger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
......@@ -23,9 +22,7 @@ import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
@Configuration
@EnableConfigurationProperties(SwaggerConfig.class)
......@@ -58,8 +55,37 @@ public class MagicSwaggerConfiguration implements MagicPluginConfiguration {
RequestMappingInfo requestMappingInfo = mapping.paths(swaggerConfig.getLocation()).build();
SwaggerEntity.License license = new SwaggerEntity.License("MIT", "https://gitee.com/ssssssss-team/magic-api/blob/master/LICENSE");
SwaggerEntity.Info info = new SwaggerEntity.Info(swaggerConfig.getDescription(), swaggerConfig.getVersion(), swaggerConfig.getTitle(), license, swaggerConfig.getConcat());
//具体参考:https://swagger.io/docs/specification/2-0/authentication/
Map<String, Object> securityDefinitionMap = new HashMap<>();
Map<String, Object> securityMap = new HashMap<>();
if (swaggerConfig.getBasicAuth() != null) {
securityDefinitionMap.put(SwaggerEntity.BasicAuth.KEY_NAME, swaggerConfig.getBasicAuth());
//the Basic and API key security items use an empty array instead.
securityMap.put(SwaggerEntity.BasicAuth.KEY_NAME, new String[]{});
}
if (swaggerConfig.getApiKeyAuth() != null) {
securityDefinitionMap.put(SwaggerEntity.ApiKeyAuth.KEY_NAME, swaggerConfig.getApiKeyAuth());
//the Basic and API key security items use an empty array instead.
securityMap.put(SwaggerEntity.ApiKeyAuth.KEY_NAME, new String[]{});
}
if (swaggerConfig.getOauth2() != null) {
SwaggerEntity.OAuth2 oAuth2 = swaggerConfig.getOauth2();
securityDefinitionMap.put(SwaggerEntity.OAuth2.KEY_NAME, oAuth2);
Map<String, String> scopes = oAuth2.getScopes();
if (scopes != null) {
Set<String> strings = scopes.keySet();
securityMap.put(SwaggerEntity.OAuth2.KEY_NAME, strings);
}
}
// 构建文档信息
SwaggerProvider swaggerProvider = new SwaggerProvider(requestMagicDynamicRegistry, magicResourceService, servletContext.getContextPath(), info, properties.isPersistenceResponseBody(), properties.getPrefix());
SwaggerProvider swaggerProvider = new SwaggerProvider(requestMagicDynamicRegistry, magicResourceService, servletContext.getContextPath(),
info, properties.isPersistenceResponseBody(), properties.getPrefix(), securityDefinitionMap, securityMap);
// 注册swagger.json
......
package org.ssssssss.magicapi.swagger;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.ssssssss.magicapi.swagger.entity.SwaggerEntity;
......@@ -36,6 +35,24 @@ public class SwaggerConfig {
@NestedConfigurationProperty
private SwaggerEntity.Concat concat = new SwaggerEntity.Concat();
/**
* 基本认证
*/
@NestedConfigurationProperty
private SwaggerEntity.BasicAuth basicAuth;
/**
* api密钥认证
*/
@NestedConfigurationProperty
private SwaggerEntity.ApiKeyAuth apiKeyAuth;
/**
* oauth2认证
*/
@NestedConfigurationProperty
private SwaggerEntity.OAuth2 oauth2;
/**
* 文档版本
*/
......@@ -88,4 +105,28 @@ public class SwaggerConfig {
public void setConcat(SwaggerEntity.Concat concat) {
this.concat = concat;
}
public SwaggerEntity.ApiKeyAuth getApiKeyAuth() {
return apiKeyAuth;
}
public void setApiKeyAuth(SwaggerEntity.ApiKeyAuth apiKeyAuth) {
this.apiKeyAuth = apiKeyAuth;
}
public SwaggerEntity.BasicAuth getBasicAuth() {
return basicAuth;
}
public void setBasicAuth(SwaggerEntity.BasicAuth basicAuth) {
this.basicAuth = basicAuth;
}
public SwaggerEntity.OAuth2 getOauth2() {
return oauth2;
}
public void setOauth2(SwaggerEntity.OAuth2 oauth2) {
this.oauth2 = oauth2;
}
}
......@@ -17,6 +17,10 @@ public class SwaggerEntity {
private Info info;
private final Map<String, Object> securityDefinitions = new HashMap<>();
private final List<Map<String, Object>> security = new ArrayList<>();
private final Set<Tag> tags = new TreeSet<>(Comparator.comparing(Tag::getName));
private final Map<String, Object> definitions = new HashMap<>();
......@@ -142,6 +146,22 @@ public class SwaggerEntity {
return paths;
}
public Map<String, Object> getSecurityDefinitions() {
return securityDefinitions;
}
public List<Map<String, Object>> getSecurity() {
return security;
}
public void addSecurityDefinitions(Map<String, Object> map) {
securityDefinitions.putAll(map);
}
public void addSecurity(Map<String, Object> map) {
security.add(map);
}
public static class Concat {
private String name;
......@@ -479,7 +499,6 @@ public class SwaggerEntity {
}
}
public static class License {
private String name;
......@@ -507,4 +526,112 @@ public class SwaggerEntity {
this.url = url;
}
}
public static class BasicAuth {
public final static String KEY_NAME = "BasicAuth";
/**
* 类型,默认值
*/
private String type = "basic";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
public static class ApiKeyAuth {
public final static String KEY_NAME = "ApiKeyAuth";
private String type = "apiKey";
private String name = "header";
private String in = "X-API-Key";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIn() {
return in;
}
public void setIn(String in) {
this.in = in;
}
}
public static class OAuth2 {
public final static String KEY_NAME = "OAuth2";
private String type = "oauth2";
private String flow;
private String authorizationUrl;
private String tokenUrl;
private Map<String, String> scopes;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFlow() {
return flow;
}
public void setFlow(String flow) {
this.flow = flow;
}
public String getAuthorizationUrl() {
return authorizationUrl;
}
public void setAuthorizationUrl(String authorizationUrl) {
this.authorizationUrl = authorizationUrl;
}
public String getTokenUrl() {
return tokenUrl;
}
public void setTokenUrl(String tokenUrl) {
this.tokenUrl = tokenUrl;
}
public Map<String, String> getScopes() {
return scopes;
}
public void setScopes(Map<String, String> scopes) {
this.scopes = scopes;
}
}
}
......@@ -47,14 +47,19 @@ public class SwaggerProvider {
private final SwaggerEntity.Info info;
private final boolean persistenceResponseBody;
private final String prefix;
private final Map<String, Object> securityDefinitionMap;
private final Map<String, Object> securityMap;
public SwaggerProvider(RequestMagicDynamicRegistry requestMagicDynamicRegistry, MagicResourceService magicResourceService, String basePath, SwaggerEntity.Info info, boolean persistenceResponseBody, String prefix) {
public SwaggerProvider(RequestMagicDynamicRegistry requestMagicDynamicRegistry, MagicResourceService magicResourceService,
String basePath, SwaggerEntity.Info info, boolean persistenceResponseBody, String prefix, Map<String, Object> securityDefinitionMap, Map<String, Object> securityMap) {
this.requestMagicDynamicRegistry = requestMagicDynamicRegistry;
this.magicResourceService = magicResourceService;
this.basePath = basePath;
this.info = info;
this.persistenceResponseBody = persistenceResponseBody;
this.prefix = StringUtils.defaultIfBlank(prefix, "") + "/";
this.securityDefinitionMap = securityDefinitionMap;
this.securityMap = securityMap;
}
@ResponseBody
......@@ -64,6 +69,9 @@ public class SwaggerProvider {
SwaggerEntity swaggerEntity = new SwaggerEntity();
swaggerEntity.setInfo(info);
swaggerEntity.setBasePath(this.basePath);
swaggerEntity.addSecurityDefinitions(securityDefinitionMap);
swaggerEntity.addSecurity(securityMap);
for (ApiInfo info : infos) {
String groupName = magicResourceService.getGroupName(info.getGroupId()).replace("/", "-");
String requestPath = PathUtils.replaceSlash(this.prefix + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath());
......
......@@ -15,6 +15,7 @@
<description>auto generate http api</description>
<modules>
<module>magic-api-plugin-task</module>
<module>magic-api-plugin-component</module>
<module>magic-api-plugin-swagger</module>
<module>magic-api-plugin-redis</module>
<module>magic-api-plugin-mongo</module>
......
......@@ -97,7 +97,7 @@ public class ApiInfo extends PathMagicEntity {
public Map<String, String> options() {
Map<String, String> map = this.options.stream()
.collect(Collectors.toMap(BaseDefinition::getName, it -> String.valueOf(it.getValue()), (o, n) -> n));
MagicConfiguration.getMagicResourceService().getGroupsByFileId(this.groupId)
MagicConfiguration.getMagicResourceService().getGroupsByFileId(this.id)
.stream()
.flatMap(it -> it.getOptions().stream())
.forEach(option -> {
......
package org.ssssssss.magicapi.core.resource;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
......@@ -36,7 +38,8 @@ public class ZipResource implements Resource {
while ((len = zis.read(buf, 0, buf.length)) != -1) {
os.write(buf, 0, len);
}
cachedContent.put(entry.getName(), os.toByteArray());
String charset = ((ZipArchiveEntry) entry).getGeneralPurposeBit().usesUTF8ForNames() ? StandardCharsets.UTF_8.name() : "GBK";
cachedContent.put(new String(((ZipArchiveEntry) entry).getRawName(), charset), os.toByteArray());
}
}
}
......
......@@ -36,6 +36,7 @@ import org.ssssssss.magicapi.utils.SignUtils;
import org.ssssssss.script.MagicScriptContext;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
......@@ -80,7 +81,7 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
String scriptName = PathUtils.replaceSlash(String.format("/%s/%s(/%s/%s)", fullGroupName, info.getName(), fullGroupPath, info.getPath()));
scriptContext.setScriptName(scriptName);
scriptContext.putMapIntoContext(context);
if(requestEntity != null){
if (requestEntity != null) {
requestEntity.setMagicScriptContext(scriptContext);
}
return (T) ScriptManager.executeScript(info.getScript(), scriptContext);
......@@ -91,12 +92,15 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
return execute(null, method, path, context);
}
private <T> T execute(RequestEntity requestEntity, String method, String path, Map<String, Object> context){
private <T> T execute(RequestEntity requestEntity, String method, String path, Map<String, Object> context) {
String mappingKey = Objects.toString(method, "GET").toUpperCase() + ":" + PathUtils.replaceSlash(this.prefix + "/" + Objects.toString(path, ""));
ApiInfo info = requestMagicDynamicRegistry.getMapping(mappingKey);
if (info == null) {
throw new MagicAPIException(String.format("找不到对应接口 [%s:%s]", method, path));
}
if (context == null) {
context = new HashMap<>();
}
context.put("apiInfo", info);
return execute(requestEntity, info, context);
}
......@@ -201,6 +205,7 @@ public class DefaultMagicAPIService implements MagicAPIService, JsonCodeConstant
MagicWebSocketDispatcher.processMessageReceived(clientId, content);
return true;
}
private boolean processWebSocketEventMessage(String content) {
MagicWebSocketDispatcher.processWebSocketEventMessage(content);
return true;
......
......@@ -18,7 +18,7 @@ public class DB2Dialect implements Dialect {
public String getPageSql(String sql, BoundSql boundSql, long offset, long limit) {
boundSql.addParameter(offset + 1);
boundSql.addParameter(offset + limit);
return "SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS ROW_ID FROM ( " + sql +
" ) AS TMP_PAGE) TMP_PAGE WHERE ROW_ID BETWEEN ? AND ?";
return "SELECT * FROM (SELECT TMP_PAGE.*,ROWNUMBER() OVER() AS ROW_ID FROM ( \n" + sql +
"\n ) AS TMP_PAGE) TMP_PAGE WHERE ROW_ID BETWEEN ? AND ?";
}
}
......@@ -44,7 +44,7 @@ public interface Dialect {
* @return 分页 count SQL
*/
default String getCountSql(String sql) {
return "select count(1) from (" + REPLACE_ORDER_BY.matcher(sql).replaceAll("") + ") count_";
return "select count(1) from ( \n" + REPLACE_ORDER_BY.matcher(sql).replaceAll("") + "\n ) count_";
}
/**
......
......@@ -19,8 +19,8 @@ public class DmDialect implements Dialect {
limit = (offset >= 1) ? (offset + limit) : limit;
boundSql.addParameter(limit);
boundSql.addParameter(offset);
return "SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( " +
sql + " ) TMP WHERE ROWNUM <= ? ) WHERE ROW_ID > ?";
return "SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( \n" +
sql + "\n ) TMP WHERE ROWNUM <= ? ) WHERE ROW_ID > ?";
}
}
......@@ -19,6 +19,6 @@ public class KingbaseSQLDialect implements Dialect {
public String getPageSql(String sql, BoundSql boundSql, long offset, long limit) {
boundSql.addParameter(limit);
boundSql.addParameter(offset);
return sql + " limit ? offset ?";
return sql + "\n limit ? offset ?";
}
}
......@@ -19,6 +19,6 @@ public class MySQLDialect implements Dialect {
public String getPageSql(String sql, BoundSql boundSql, long offset, long limit) {
boundSql.addParameter(offset);
boundSql.addParameter(limit);
return sql + " limit ?,?";
return sql + "\n limit ?,?";
}
}
......@@ -20,7 +20,7 @@ public class OracleDialect implements Dialect {
limit = (offset >= 1) ? (offset + limit) : limit;
boundSql.addParameter(limit);
boundSql.addParameter(offset);
return "SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( " +
sql + " ) TMP WHERE ROWNUM <= ? ) WHERE ROW_ID > ?";
return "SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( \n" +
sql + "\n ) TMP WHERE ROWNUM <= ? ) WHERE ROW_ID > ?";
}
}
......@@ -18,6 +18,6 @@ public class PostgreSQLDialect implements Dialect {
public String getPageSql(String sql, BoundSql boundSql, long offset, long limit) {
boundSql.addParameter(limit);
boundSql.addParameter(offset);
return sql + " limit ? offset ?";
return sql + "\n limit ? offset ?";
}
}
......@@ -18,6 +18,6 @@ public class SQLServerDialect implements Dialect {
public String getPageSql(String sql, BoundSql boundSql, long offset, long limit) {
boundSql.addParameter(offset);
boundSql.addParameter(limit);
return sql + " OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
return sql + "\n OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
}
}
......@@ -484,14 +484,14 @@ public class NamedTable extends Attributes<Object> {
}
builder.append(" from ").append(tableName);
List<Object> params = buildWhere(builder);
if (!groups.isEmpty()) {
builder.append(" group by ");
builder.append(String.join(",", groups));
}
if (!orders.isEmpty()) {
builder.append(" order by ");
builder.append(String.join(",", orders));
}
if (!groups.isEmpty()) {
builder.append(" group by ");
builder.append(String.join(",", groups));
}
BoundSql boundSql = new BoundSql(runtimeContext, builder.toString(), params, sqlModule);
boundSql.setExcludeColumns(excludeColumns);
return boundSql;
......
......@@ -10,6 +10,7 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.nio.charset.StandardCharsets;
/**
* IO工具包
......@@ -122,7 +123,7 @@ public class IoUtils {
if (content == null) {
return false;
}
return write(file, content.getBytes());
return write(file, content.getBytes(StandardCharsets.UTF_8));
}
public static boolean delete(File file) {
......