Browse Source

[*]requestBody校验优化

Lianjy 4 years ago
parent
commit
9e0a6666c4

+ 44 - 12
magic-api/src/main/java/org/ssssssss/magicapi/controller/RequestHandler.java

@@ -112,22 +112,43 @@ public class RequestHandler extends MagicController {
 		}
 		MagicScriptContext context = createMagicScriptContext(requestEntity);
 		Object bodyValue = context.get(VAR_NAME_REQUEST_BODY);
-		if (bodyValue != null && StringUtils.isNotBlank(requestEntity.getApiInfo().getRequestBody()) && JsonUtils.readValue(requestEntity.getApiInfo().getRequestBody(), BaseDefinition.class).getChildren().size() > 0) {
-			// 验证 body
-			BaseDefinition body = JsonUtils.readValue(requestEntity.getApiInfo().getRequestBody(), BaseDefinition.class);
+		BaseDefinition body = JsonUtils.readValue(requestEntity.getApiInfo().getRequestBody(), BaseDefinition.class);
+		// 验证 body
+		if (body.getChildren() != null && body.getChildren().size() > 0) {
+
 			// 请求体首层是数组的时候单独处理
 			if (bodyValue instanceof List) {
-				if (!VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY.equalsIgnoreCase(body.getDataType().getJavascriptType())) {
-					Object result = resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, String.format("body参数错误,应为[%s]", body.getDataType().getJavascriptType()));
-					return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, result) : result;
+
+				if (body.isRequired()) {
+					Object result = null;
+					if (!VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY.equalsIgnoreCase(body.getDataType().getJavascriptType())) {
+						result = resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, String.format("body参数错误,应为[%s]", body.getDataType().getJavascriptType()));
+					} else if (((List)bodyValue).size() == 0) {
+						result = resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, String.format("%s[%s]为必填项", VAR_NAME_REQUEST_BODY, body.getName()));
+					}
+
+					if (result != null) {
+						return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, result) : result;
+					}
 				}
+
 				for (Map valueMap : (List<Map>) bodyValue) {
+
+					if (body.getChildren().get(0).isRequired() && ((Map)valueMap).size() == 0) {
+						Object result = resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, String.format("%s[%s]为必填项", VAR_NAME_REQUEST_BODY, body.getChildren().get(0).getName()));
+						return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, result) : result;
+					}
+
 					value = doValidate(requestEntity, VAR_NAME_REQUEST_BODY, body.getChildren().get(0).getChildren(), valueMap);
 					if (value != null) {
 						return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, value) : value;
 					}
 				}
 			} else {
+				if (body.isRequired() && ((Map)bodyValue).size() == 0) {
+					Object result = resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, String.format("%s[%s]为必填项", VAR_NAME_REQUEST_BODY, body.getName()));
+					return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, result) : result;
+				}
 				value = doValidate(requestEntity, VAR_NAME_REQUEST_BODY, body.getChildren(), (Map) bodyValue);
 				if (value != null) {
 					return requestEntity.isRequestedFromTest() ? new JsonBean<>(BODY_INVALID, value) : value;
@@ -161,16 +182,29 @@ public class RequestHandler extends MagicController {
 
 			// 针对requestBody多层级的情况
 			if (VAR_NAME_REQUEST_BODY_VALUE_TYPE_OBJECT.equalsIgnoreCase(parameter.getDataType().getJavascriptType())) {
-				Map map = (Map) parameters.get(parameter.getName());
-				Object result = doValidate(requestEntity, VAR_NAME_REQUEST_BODY, parameter.getChildren(), map);
+				if (!parameter.isRequired() && parameters.size() == 0) {
+					continue;
+				}
+				if (parameter.isRequired() && parameters.get(parameter.getName()) == null) {
+					return resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]为必填项", comment, parameter.getName())));
+				}
+				if (parameter.isRequired() && (parameters.get(parameter.getName()) instanceof List)) {
+					return resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]数据类型错误", comment, parameter.getName())));
+				}
+
+				Object result = doValidate(requestEntity, VAR_NAME_REQUEST_BODY, parameter.getChildren(), (Map) parameters.get(parameter.getName()));
 				if (result != null) {
 					return result;
 				}
 			} else if (VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY.equalsIgnoreCase(parameter.getDataType().getJavascriptType())) {
-				if (parameters.get(parameter.getName()) == null) {
+				if (!parameter.isRequired() && parameters.size() == 0) {
+					continue;
+				}
+
+				if (parameter.isRequired() && parameters.get(parameter.getName()) == null) {
 					return resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]为必填项", comment, parameter.getName())));
 				}
-				if (!(parameters.get(parameter.getName()) instanceof List)) {
+				if (parameter.isRequired() && !(parameters.get(parameter.getName()) instanceof List)) {
 					return resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]数据类型错误", comment, parameter.getName())));
 				}
 				for (Map valueMap : (List<Map>) parameters.get(parameter.getName())) {
@@ -482,8 +516,6 @@ public class RequestHandler extends MagicController {
 					}
 				}
 			} catch (HttpMessageNotReadableException ignored) {
-				System.out.println(ignored.getHttpInputMessage().getBody().toString());
-				ignored.printStackTrace();
 				return null;
 			}
 		}

+ 1 - 1
magic-api/src/main/java/org/ssssssss/magicapi/swagger/SwaggerProvider.java

@@ -124,7 +124,7 @@ public class SwaggerProvider {
 			if (StringUtils.isNotBlank(info.getRequestBody()) && !BODY_EMPTY.equals(info.getRequestBody().replaceAll("\\s", ""))) {
 				BaseDefinition baseDefinition = JsonUtils.readValue(info.getRequestBody(), BaseDefinition.class);
 				if (BooleanLiteral.isTrue(baseDefinition)) {
-					SwaggerEntity.Parameter parameter = new SwaggerEntity.Parameter(true, StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() : VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, baseDefinition.getDataType().getJavascriptType(), baseDefinition.getDescription(), baseDefinition);
+					SwaggerEntity.Parameter parameter = new SwaggerEntity.Parameter(baseDefinition.isRequired(), StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() : VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, baseDefinition.getDataType().getJavascriptType(), baseDefinition.getDescription(), baseDefinition);
 
 					Map<String, Object> schema = new HashMap<>(2);
 					String groupName = groupServiceProvider.getFullName(info.getGroupId()).replace("/", "-");

+ 0 - 1
magic-editor/src/console/src/components/common/magic-json-tree.vue

@@ -93,7 +93,6 @@
 
   .ma-tree .tree-item {
     cursor: pointer;
-    height: 20px;
   }
 
   .ma-tree .item-selected {

+ 21 - 6
magic-editor/src/console/src/components/common/magic-json.vue

@@ -1,12 +1,12 @@
 <template>
   <div class="ma-json-container">
-    <div class="json-view f_c">
+    <div class="json-view f_c" :style="'height:'+ height">
       <!-- 解决子组件不强制刷新 -->
       <div v-show="forceUpdate"></div>
       <div class="header">视图</div>
       <magic-json-tree :jsonData="jsonData" :forceUpdate="forceUpdate" class="view-box" v-on:jsonClick="handleJsonClick"></magic-json-tree>
     </div>
-    <div class="json-panel f_c">
+    <div class="json-panel f_c" :style="'height:'+ height">
       <div class="header">属性</div>
       <div class="panel-box f_c" v-if="fieldObj.dataType && fieldObj.dataType !== 'Object' && fieldObj.dataType !== 'Array'">
         <div class="box-item">
@@ -72,6 +72,12 @@
             <magic-input :value.sync="fieldObj.description" style="width: 100%"/>
           </div>
         </div>
+        <div class="box-item">
+          <div class="item-title">是否必填</div>
+          <div class="item-content">
+            <div style="width: 25px; height: 25px;"><magic-checkbox :value.sync="fieldObj.required"/></div>
+          </div>
+        </div>
       </div>
     </div>
   </div>
@@ -92,7 +98,8 @@
         required: true
       },
       // 解决子组件不强制刷新
-      forceUpdate: Boolean
+      forceUpdate: Boolean,
+      height: String
     },
     data() {
       return {
@@ -111,7 +118,8 @@
           {value: 'Byte', text: 'Byte'},
           {value: 'Boolean', text: 'Boolean'},
         ],
-        fieldObj: {dataType: "Object"}
+        fieldObj: {dataType: "Object"},
+        activeNodeFlag: false
       }
     },
     components: {
@@ -124,7 +132,11 @@
       jsonData: {
         handler(newVal, oldVal) {
           if (newVal && newVal.length > 0) {
+            this.activeNodeFlag = false;
             this.getActiveNode(newVal)
+            if (!this.activeNodeFlag) {
+              this.fieldObj = newVal[0];
+            }
           } else {
             this.fieldObj = {dataType: "Object"}
           }
@@ -137,6 +149,7 @@
         node.forEach(item => {
           if (item.selected) {
             this.fieldObj = item;
+            this.activeNodeFlag = true;
             return;
           } else {
             this.getActiveNode(item.children)
@@ -173,7 +186,8 @@
   }
 
   .json-view {
-    width: 55%;
+    width: 35vw;
+    overflow: scroll;
     margin: 0px 10px;
     border: 1px solid var(--border-color);
     border-top: none;
@@ -197,7 +211,7 @@
   }
 
   .json-panel .panel-box .box-item {
-    height: 35px;
+    min-height: 35px;
     display: flex;
     flex-direction: row;
     align-items: center;
@@ -208,6 +222,7 @@
   }
   .json-panel .panel-box .box-item .item-content {
     flex: 1;
+    word-break: break-all;
   }
   .header {
     height: 30px;

+ 0 - 1
magic-editor/src/console/src/components/editor/magic-script-editor.vue

@@ -494,7 +494,6 @@ export default {
           requestConfig.headers['Content-Type'] = 'application/json'
           requestConfig.transformRequest = []
         } catch (e) {
-          console.log('magic-script-editor', e);
           this.$magicAlert({
             content: 'RequestBody 参数有误,请检查!'
           })

+ 26 - 25
magic-editor/src/console/src/components/layout/magic-request.vue

@@ -154,11 +154,11 @@
 
           <div style="display: flex; flex-direction: row; height: calc(100% - 24px);">
             <div style="width: 40%">
-              <div class="header">编辑器(停止编辑2s后同步更新视图属性)</div>
+              <div class="header">编辑器</div>
               <div ref="bodyEditor" class="ma-body-editor"></div>
             </div>
             <div style="flex: 1;">
-              <magic-json :jsonData="requestBody" :forceUpdate="forceUpdate"></magic-json>
+              <magic-json :jsonData="requestBody" :forceUpdate="forceUpdate" :height="layoutHeight"></magic-json>
             </div>
           </div>
 
@@ -245,16 +245,13 @@
         requestBody: [],
         forceUpdate: false,
         editorJson: '{\n\t\n}',
-        bodyEditorFlag: false
+        bodyEditorFlag: false,
+        layoutHeight: '255px'
       }
-    },
-    created() {
-
     },
     watch: {
       requestBody: {
         handler(newVal, oldVal) {
-          // console.log('watch -handler', newVal);
           if (this.bodyEditorFlag) {
             this.info.requestBody = JSON.stringify(newVal[0])
           }
@@ -265,8 +262,8 @@
     mounted() {
       let that = this;
       bus.$on('update-request-body', (newVal) => {
-        // console.log('update-request-body', newVal);
-        this.initRequestBodyDom()
+       // console.log('update-request-body');
+        that.initRequestBodyDom()
         if (!newVal || newVal == null) {
           that.bodyEditorFlag = false
           that.requestBody = []
@@ -282,8 +279,8 @@
             /**
              * 旧的json结构,不能直接用,需通过editor转换
              */
-            this.editorJson = formatJson(newVal)
-            this.bodyEditor && this.bodyEditor.setValue(this.editorJson)
+            that.editorJson = formatJson(newVal)
+            that.bodyEditor && that.bodyEditor.setValue(that.editorJson)
           }
 
         } catch (e) {
@@ -334,6 +331,9 @@
         this.$nextTick(() => {
           if (this.bodyEditor && isVisible(this.$refs.bodyEditor)) {
             this.bodyEditor.layout()
+            if (this.$refs.bodyEditor && this.$refs.bodyEditor.firstChild) {
+              this.layoutHeight = this.$refs.bodyEditor.firstChild.style.height
+            }
           }
         })
       },
@@ -390,13 +390,6 @@
         }
         this.$forceUpdate()
       },
-      debounce(func, wait = 2000) {
-        // 清除定时器
-        if (timeout !== null) clearTimeout(timeout);
-        timeout = setTimeout(function () {
-          typeof func === 'function' && func();
-        }, wait);
-      },
       initRequestBodyDom() {
         if (this.bodyEditor == null && this.showIndex === 3) {
           this.bodyEditor = monaco.editor.create(this.$refs.bodyEditor, {
@@ -413,12 +406,8 @@
           })
           this.layout()
           this.bodyEditor.onDidChangeModelContent(() => {
-            // 延时更新,防止还没改完立即更新导致之前填写的属性信息丢失
-            this.debounce(() => {
-              this.bodyEditorFlag = true
-              this.updateRequestBody(this.bodyEditor.getValue())
-            })
-
+            this.bodyEditorFlag = true
+            this.updateRequestBody(this.bodyEditor.getValue())
           })
           bus.$on('update-window-size', () => this.layout())
         }
@@ -476,7 +465,19 @@
       },
       getType(object) {
         if (Object.prototype.toString.call(object) === '[object Number]') {
-          return "Integer";
+          if(parseInt(object) !== parseFloat(object)) {
+            return "Float";
+          }
+          // if (object >= -128 && object <= 127) {
+          //   return "Byte";
+          // }
+          // if (object >= -32768 && object <= 32767) {
+          //   return "Short";
+          // }
+          if (object >= -2147483648 && object <= 2147483647) {
+            return "Integer";
+          }
+          return "Long";
         }
         if (Object.prototype.toString.call(object) === '[object String]') {
           return "String";