001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.apidoc;
017
018import com.alibaba.fastjson.JSONObject;
019import com.alibaba.fastjson.parser.Feature;
020import com.jfinal.kit.PathKit;
021import com.jfinal.kit.StrKit;
022import com.jfinal.plugin.activerecord.generator.ColumnMeta;
023import com.jfinal.plugin.activerecord.generator.MetaBuilder;
024import com.jfinal.plugin.activerecord.generator.TableMeta;
025import com.zaxxer.hikari.HikariConfig;
026import com.zaxxer.hikari.HikariDataSource;
027import io.jboot.Jboot;
028import io.jboot.codegen.CodeGenHelpler;
029import io.jboot.db.datasource.DataSourceConfig;
030import io.jboot.db.driver.DriverClassNames;
031import io.jboot.utils.DateUtil;
032import io.jboot.utils.FileUtil;
033import io.jboot.utils.StrUtil;
034
035import javax.sql.DataSource;
036import java.io.File;
037import java.math.BigDecimal;
038import java.math.BigInteger;
039import java.time.temporal.Temporal;
040import java.util.Date;
041import java.util.LinkedHashMap;
042import java.util.List;
043import java.util.Map;
044import java.util.function.Predicate;
045import java.util.stream.Collectors;
046
047public class ApiJsonGenerator {
048
049    /**
050     * 生成 Mock Json 数据
051     */
052    public static void genMockJson() {
053        genMockJson(new JsonGeneratorConfig("api-mock.json"));
054    }
055
056
057    /**
058     * 生成 Mock Json 数据
059     *
060     * @param config
061     */
062    public static void genMockJson(JsonGeneratorConfig config) {
063
064        Map<String, Map<String, Object>> root = new LinkedHashMap<>();
065
066        File file = new File(config.getJsonFilePathPathAbsolute());
067        //如果文件存在,则先读取其配置,然后再修改
068        if (file.exists()) {
069            String oldJson = FileUtil.readString(file);
070            JSONObject rootJsonObject = JSONObject.parseObject(oldJson, Feature.OrderedField);
071            if (rootJsonObject != null && !rootJsonObject.isEmpty()) {
072                for (String classOrSimpleName : rootJsonObject.keySet()) {
073                    root.put(classOrSimpleName, rootJsonObject.getJSONObject(classOrSimpleName));
074                }
075            }
076        }
077
078        MetaBuilder builder = CodeGenHelpler.createMetaBuilder(config.getDatasource(), config.getType(), false);
079        List<TableMeta> tableMetas = builder.build();
080
081        if (config.tableMetaFilter != null) {
082            tableMetas = tableMetas.stream()
083                    .filter(config.tableMetaFilter)
084                    .collect(Collectors.toList());
085        }
086
087
088        for (TableMeta tableMeta : tableMetas) {
089            Map<String, Object> classMockData = new LinkedHashMap<>();
090            for (ColumnMeta columnMeta : tableMeta.columnMetas) {
091                Object mockData = createMockData(columnMeta);
092                if (mockData != null && !"".equals(mockData)) {
093                    classMockData.put(columnMeta.attrName, mockData);
094                }
095            }
096            if (!classMockData.isEmpty()) {
097                root.put(StrKit.firstCharToLowerCase(tableMeta.modelName), classMockData);
098            }
099        }
100
101
102        String jsonContent = JSONObject.toJSONString(root, true);
103        FileUtil.writeString(file, jsonContent);
104
105        System.out.println("Gen Remarks Json File ----->" + FileUtil.getCanonicalPath(file));
106    }
107
108
109    private static Object createMockData(ColumnMeta columnMeta) {
110        if (String.class.getName().equals(columnMeta.javaType)) {
111            return columnMeta.remarks;
112        } else if (Date.class.getName().equals(columnMeta.javaType)) {
113            return DateUtil.toDateTimeString(new Date());
114        } else if (isTemporal(columnMeta.javaType)) {
115            return DateUtil.toDateTimeString(new Date());
116        } else if (int.class.getName().equals(columnMeta.javaType)) {
117            return 1;
118        } else if (Integer.class.getName().equals(columnMeta.javaType)) {
119            return 100;
120        } else if (long.class.getName().equals(columnMeta.javaType)) {
121            return 1;
122        } else if (Long.class.getName().equals(columnMeta.javaType)) {
123            return 100;
124        } else if (short.class.getName().equals(columnMeta.javaType)) {
125            return 1;
126        } else if (Short.class.getName().equals(columnMeta.javaType)) {
127            return 100;
128        } else if (BigDecimal.class.getName().equals(columnMeta.javaType)) {
129            return BigDecimal.ONE;
130        } else if (BigInteger.class.getName().equals(columnMeta.javaType)) {
131            return BigDecimal.ONE;
132        } else if (boolean.class.getName().equals(columnMeta.javaType)) {
133            return Boolean.TRUE;
134        } else if (Boolean.class.getName().equals(columnMeta.javaType)) {
135            return Boolean.TRUE;
136        } else if (float.class.getName().equals(columnMeta.javaType)) {
137            return 1.0f;
138        } else if (Float.class.getName().equals(columnMeta.javaType)) {
139            return 1.0f;
140        } else if (double.class.getName().equals(columnMeta.javaType)) {
141            return 1.0d;
142        } else if (Double.class.getName().equals(columnMeta.javaType)) {
143            return 1.0d;
144        } else {
145            return "";
146        }
147    }
148
149    private static boolean isTemporal(String javaType) {
150        try {
151            return Temporal.class.isAssignableFrom(Class.forName(javaType));
152        } catch (ClassNotFoundException e) {
153            e.printStackTrace();
154        }
155        return false;
156    }
157
158
159    /**
160     * 生成 Model 的字段备注数据
161     */
162    public static void genRemarksJson() {
163        genRemarksJson(new JsonGeneratorConfig("api-remarks.json"));
164    }
165
166    /**
167     * 生成 Model 的字段备注数据
168     */
169    public static void genRemarksJson(JsonGeneratorConfig config) {
170
171        Map<String, Map<String, String>> root = new LinkedHashMap<>();
172
173        File file = new File(config.getJsonFilePathPathAbsolute());
174        //如果文件存在,则先读取其配置,然后再修改
175        if (file.exists()) {
176            String oldJson = FileUtil.readString(file);
177            JSONObject rootJsonObject = JSONObject.parseObject(oldJson, Feature.OrderedField);
178            if (rootJsonObject != null && !rootJsonObject.isEmpty()) {
179                for (String classOrSimpleName : rootJsonObject.keySet()) {
180                    Map<String, String> remarks = new LinkedHashMap<>();
181                    JSONObject modelRemarks = rootJsonObject.getJSONObject(classOrSimpleName);
182                    modelRemarks.forEach((k, v) -> remarks.put(k, String.valueOf(v)));
183                    root.put(classOrSimpleName, remarks);
184                }
185            }
186        }
187
188
189        MetaBuilder builder = CodeGenHelpler.createMetaBuilder(config.getDatasource(), config.getType(), false);
190        List<TableMeta> tableMetas = builder.build();
191
192        if (config.tableMetaFilter != null) {
193            tableMetas = tableMetas.stream()
194                    .filter(config.tableMetaFilter)
195                    .collect(Collectors.toList());
196        }
197
198
199        for (TableMeta tableMeta : tableMetas) {
200            Map<String, String> modelRemarks = new LinkedHashMap<>();
201            for (ColumnMeta columnMeta : tableMeta.columnMetas) {
202                if (StrUtil.isNotBlank(columnMeta.remarks)) {
203                    modelRemarks.put(columnMeta.attrName, columnMeta.remarks);
204                }
205            }
206            if (!modelRemarks.isEmpty()) {
207                root.put(StrKit.firstCharToLowerCase(tableMeta.modelName), modelRemarks);
208            }
209        }
210
211
212        String jsonContent = JSONObject.toJSONString(root, true);
213        FileUtil.writeString(file, jsonContent);
214
215        System.out.println("Gen Remarks Json File ----->" + FileUtil.getCanonicalPath(file));
216    }
217
218
219    public static class JsonGeneratorConfig {
220
221        private boolean useJbootDatasource = true;
222
223        private String jdbcUrl;
224        private String userName;
225        private String password;
226        private String type = DataSourceConfig.TYPE_MYSQL;
227
228        private String jsonFilePath;
229        private Predicate<TableMeta> tableMetaFilter;
230
231        public JsonGeneratorConfig() {
232        }
233
234        public JsonGeneratorConfig(String jsonFilePath) {
235            this.jsonFilePath = jsonFilePath;
236        }
237
238        public boolean isUseJbootDatasource() {
239            return useJbootDatasource;
240        }
241
242        public void setUseJbootDatasource(boolean useJbootDatasource) {
243            this.useJbootDatasource = useJbootDatasource;
244        }
245
246        public String getJdbcUrl() {
247            return jdbcUrl;
248        }
249
250        public void setJdbcUrl(String jdbcUrl) {
251            this.jdbcUrl = jdbcUrl;
252        }
253
254        public String getUserName() {
255            return userName;
256        }
257
258        public void setUserName(String userName) {
259            this.userName = userName;
260        }
261
262        public String getPassword() {
263            return password;
264        }
265
266        public void setPassword(String password) {
267            this.password = password;
268        }
269
270        public String getType() {
271            return type;
272        }
273
274        public void setType(String type) {
275            this.type = type;
276        }
277
278        public String getJsonFilePath() {
279            return jsonFilePath;
280        }
281
282        public void setJsonFilePath(String jsonFilePath) {
283            this.jsonFilePath = jsonFilePath;
284        }
285
286        public String getJsonFilePathPathAbsolute() {
287            if (FileUtil.isAbsolutePath(jsonFilePath)) {
288                return jsonFilePath;
289            }
290            return FileUtil.getCanonicalPath(new File(PathKit.getRootClassPath(), "../../" + jsonFilePath));
291        }
292
293
294        public Predicate<TableMeta> getTableMetaFilter() {
295            return tableMetaFilter;
296        }
297
298        public void setTableMetaFilter(Predicate<TableMeta> tableMetaFilter) {
299            this.tableMetaFilter = tableMetaFilter;
300        }
301
302
303        public DataSource getDatasource() {
304            if (useJbootDatasource) {
305                DataSourceConfig datasourceConfig = Jboot.config(DataSourceConfig.class, "jboot.datasource");
306                HikariConfig config = new HikariConfig();
307                config.setJdbcUrl(datasourceConfig.getUrl());
308                config.setUsername(datasourceConfig.getUser());
309                config.setPassword(datasourceConfig.getPassword());
310                config.setDriverClassName(datasourceConfig.getDriverClassName());
311
312                return new HikariDataSource(config);
313            } else {
314                HikariConfig config = new HikariConfig();
315                config.setJdbcUrl(this.jdbcUrl);
316                config.setUsername(this.userName);
317                config.setPassword(this.password);
318                config.setDriverClassName(DriverClassNames.getDefaultDriverClass(this.type));
319
320                return new HikariDataSource(config);
321            }
322        }
323    }
324}