From fb6c1ba46b93f727cc4460c533776cbd5e7237a7 Mon Sep 17 00:00:00 2001 From: "shihua.lei" Date: Mon, 4 Nov 2024 16:27:37 +0800 Subject: [PATCH] init 2 --- data/xxx-demo.mv.db | Bin 159744 -> 262144 bytes pom.xml | 47 +++++- .../XMLGregorianCalendarTypeAdapter.java | 36 +++++ .../ui/controller/MainController.java | 68 ++++++-- .../lsh/webservice/ui/entity/FormField.java | 19 +++ .../ui/entity/MyParameterizedType.java | 30 ++++ .../webservice/ui/entity/dto/ServerInfo.java | 3 + .../webservice/ui/entity/vo/DynamicWebVO.java | 52 ++++++ .../lsh/webservice/ui/utils/ExplainField.java | 89 ++++++++-- .../ui/utils/ExplainWebservice.java | 153 +++++++++++++++--- src/main/resources/application.yml | 2 + src/main/resources/static/vue/addwsdl.js | 32 +++- src/main/resources/static/vue/operation.js | 138 ++++++++++++++-- src/main/resources/templates/index.html | 10 +- src/test/java/com/lsh/TestCalendar.java | 15 ++ src/test/java/com/lsh/TestDTO.java | 44 +++++ src/test/java/com/lsh/test.java | 23 +++ src/test/java/com/lsh/test2.java | 15 ++ src/test/java/com/lsh/test3.java | 54 +++++++ 19 files changed, 761 insertions(+), 69 deletions(-) create mode 100644 src/main/java/org/lsh/webservice/ui/config/XMLGregorianCalendarTypeAdapter.java create mode 100644 src/main/java/org/lsh/webservice/ui/entity/MyParameterizedType.java create mode 100644 src/main/java/org/lsh/webservice/ui/entity/vo/DynamicWebVO.java create mode 100644 src/test/java/com/lsh/TestCalendar.java create mode 100644 src/test/java/com/lsh/TestDTO.java create mode 100644 src/test/java/com/lsh/test.java create mode 100644 src/test/java/com/lsh/test2.java create mode 100644 src/test/java/com/lsh/test3.java diff --git a/data/xxx-demo.mv.db b/data/xxx-demo.mv.db index b981e53af9092ccc4dc2dd8ba4c4741f893f307e..097982e236d17869a3eafebab52cd45c127ddb22 100644 GIT binary patch literal 262144 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 j)C1H5)C1H5PqYVI{=dt=_xb + + + + + + + + - com.alibaba - fastjson - 2.0.35 + com.fasterxml.jackson.core + jackson-core + 2.18.0 + + + + com.fasterxml.jackson.core + jackson-databind + 2.18.0 + + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.18.0 + + + + + com.fasterxml.jackson.core + jackson-annotations + 2.18.0 + + + + + com.google.code.gson + gson + 2.8.8 + + cn.hutool hutool-poi @@ -70,6 +107,10 @@ org.springframework.boot spring-boot-starter-thymeleaf + + com.jayway.jsonpath + json-path + diff --git a/src/main/java/org/lsh/webservice/ui/config/XMLGregorianCalendarTypeAdapter.java b/src/main/java/org/lsh/webservice/ui/config/XMLGregorianCalendarTypeAdapter.java new file mode 100644 index 0000000..b1fba86 --- /dev/null +++ b/src/main/java/org/lsh/webservice/ui/config/XMLGregorianCalendarTypeAdapter.java @@ -0,0 +1,36 @@ +package org.lsh.webservice.ui.config; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Date; +import java.util.GregorianCalendar; + +public class XMLGregorianCalendarTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter jsonWriter, XMLGregorianCalendar value) throws IOException { + // 将XMLGregorianCalendar转换为字符串写入JSON + jsonWriter.value(value.toXMLFormat()); + } + + @Override + public XMLGregorianCalendar read(JsonReader in) throws IOException { + // 从JSON读取字符串并转换为XMLGregorianCalendar + try { + String dateString = in.nextString(); + GregorianCalendar calendar = new GregorianCalendar(); + Date date = DateFormat.getDateInstance().parse(dateString); + calendar.setTime(date); + return DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar); + } catch (ParseException | DatatypeConfigurationException e) { + throw new IOException("Failed to parse XMLGregorianCalendar", e); + } + } +} diff --git a/src/main/java/org/lsh/webservice/ui/controller/MainController.java b/src/main/java/org/lsh/webservice/ui/controller/MainController.java index ce93968..b16eadf 100644 --- a/src/main/java/org/lsh/webservice/ui/controller/MainController.java +++ b/src/main/java/org/lsh/webservice/ui/controller/MainController.java @@ -1,7 +1,8 @@ package org.lsh.webservice.ui.controller; import cn.hutool.core.collection.CollectionUtil; -import com.alibaba.fastjson.JSON; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.lsh.webservice.ui.common.Result; import org.lsh.webservice.ui.entity.FormField; import org.lsh.webservice.ui.entity.FormItemV2; @@ -10,6 +11,7 @@ import org.lsh.webservice.ui.entity.dto.ServerInfo; import org.lsh.webservice.ui.entity.tree.Operation; import org.lsh.webservice.ui.entity.tree.Project; import org.lsh.webservice.ui.entity.tree.Webservice; +import org.lsh.webservice.ui.entity.vo.DynamicWebVO; import org.lsh.webservice.ui.entity.vo.OperationQueryVO; import org.lsh.webservice.ui.entity.vo.Wsdl; import org.lsh.webservice.ui.mapper.OperationMapper; @@ -34,6 +36,8 @@ public class MainController { OperationMapper operationMapper; @Resource ServerInfoMapper serverInfoMapper; + @Resource + ObjectMapper objectMapper; @PostMapping("/add-webservice") @ResponseBody @@ -63,8 +67,12 @@ public class MainController { Operation operation = new Operation(); operation.setWebserviceId(webservice.getId()); operation.setName(formItemV2.getOperation()); - operation.setInput(JSON.toJSONString(formItemV2.getInput())); - operation.setOutput(JSON.toJSONString(formItemV2.getOutput())); + try { + operation.setInput(objectMapper.writeValueAsString(formItemV2.getInput())); + operation.setOutput(objectMapper.writeValueAsString(formItemV2.getOutput())); + } catch (JsonProcessingException e) { + return Result.failed(e.getMessage()); + } operationMapper.insert(operation); } } @@ -81,7 +89,12 @@ public class MainController { ServerInfo serverInfo = serverInfoMapper.findByWebserviceId(webservice.getId()); if(serverInfo != null){ String formJson = serverInfo.getFormJson(); - FormV2 formV2 = JSON.parseObject(formJson, FormV2.class); + FormV2 formV2 = null; + try { + formV2 = objectMapper.readValue(formJson, FormV2.class); + } catch (JsonProcessingException e) { + return Result.failed(e.getMessage()); + } return Result.ok(formV2); } return Result.ok(); @@ -90,17 +103,20 @@ public class MainController { @PostMapping("/query-projects") @ResponseBody public Result> queryProjects( - ){ + @RequestParam(value = "loadWebservice",defaultValue = "true")String loadWebservice, + @RequestParam(value = "loadOperation",defaultValue = "true")String loadOperation + ){ // List projects = projectMapper.findAll(); - - for (Project project : projects) { - List webserviceList = webserviceMapper.findByProjectId(project.getId()); - project.setChildren(webserviceList); - if(CollectionUtil.isNotEmpty(webserviceList)){ - for (Webservice webservice : webserviceList) { - List operationList = operationMapper.findByWebserviceId(webservice.getId()); - webservice.setChildren(operationList); + if(loadWebservice.equals("true")) { + for (Project project : projects) { + List webserviceList = webserviceMapper.findByProjectId(project.getId()); + project.setChildren(webserviceList); + if (CollectionUtil.isNotEmpty(webserviceList) && loadOperation.equals("true")) { + for (Webservice webservice : webserviceList) { + List operationList = operationMapper.findByWebserviceId(webservice.getId()); + webservice.setChildren(operationList); + } } } } @@ -120,8 +136,12 @@ public class MainController { Webservice webservice = webserviceMapper.findById(operation.getWebserviceId()); operationQueryVO.setOperation(operation.getName()); operationQueryVO.setId(operation.getId()); - operationQueryVO.setInput(JSON.parseObject(operation.getInput(), FormField.class)); - operationQueryVO.setOutput(JSON.parseObject(operation.getOutput(), FormField.class)); + try { + operationQueryVO.setInput(objectMapper.readValue(operation.getInput(), FormField.class)); + operationQueryVO.setOutput(objectMapper.readValue(operation.getOutput(), FormField.class)); + } catch (JsonProcessingException e) { + return Result.failed(e.getMessage()); + } if(webservice != null){ operationQueryVO.setWsdl(webservice.getWsdl()); operationQueryVO.setWebserviceName(webservice.getName()); @@ -130,6 +150,24 @@ public class MainController { return Result.ok(operationQueryVO); } + @PostMapping("/invoke") + @ResponseBody + public Result invoke( + @RequestBody DynamicWebVO webservice + ){ + try { + FormField formField = ExplainWebservice.dynamicInvoke(webservice.getWsdl() + , webservice.getMethod() + , webservice.getInput() + , webservice.getOutput() + , webservice.getJson()); + return Result.ok(formField); + } catch (Exception e) { + e.printStackTrace(); + return Result.failed("调用发生了异常~"+e.getMessage()); + } + } + @RequestMapping("/index") public String hello(){ return "index"; // index.html页面 diff --git a/src/main/java/org/lsh/webservice/ui/entity/FormField.java b/src/main/java/org/lsh/webservice/ui/entity/FormField.java index 5a5f2df..841eef7 100644 --- a/src/main/java/org/lsh/webservice/ui/entity/FormField.java +++ b/src/main/java/org/lsh/webservice/ui/entity/FormField.java @@ -7,7 +7,10 @@ public class FormField implements Serializable { protected String fieldName; protected String typeName; + protected String genericType; protected boolean require; + protected Object value; + private List fields; public String getFieldName() { @@ -41,4 +44,20 @@ public class FormField implements Serializable { public void setFields(List fields) { this.fields = fields; } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getGenericType() { + return genericType; + } + + public void setGenericType(String genericType) { + this.genericType = genericType; + } } diff --git a/src/main/java/org/lsh/webservice/ui/entity/MyParameterizedType.java b/src/main/java/org/lsh/webservice/ui/entity/MyParameterizedType.java new file mode 100644 index 0000000..2782f81 --- /dev/null +++ b/src/main/java/org/lsh/webservice/ui/entity/MyParameterizedType.java @@ -0,0 +1,30 @@ +package org.lsh.webservice.ui.entity; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +public class MyParameterizedType implements ParameterizedType { + private Type[] args; + + private Class rawType; + + public MyParameterizedType( Class rawType,Type[] args) { + this.args = args; + this.rawType = rawType; + } + + @Override + public Type[] getActualTypeArguments() { + return args; + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } +} diff --git a/src/main/java/org/lsh/webservice/ui/entity/dto/ServerInfo.java b/src/main/java/org/lsh/webservice/ui/entity/dto/ServerInfo.java index 0e03137..f274dea 100644 --- a/src/main/java/org/lsh/webservice/ui/entity/dto/ServerInfo.java +++ b/src/main/java/org/lsh/webservice/ui/entity/dto/ServerInfo.java @@ -6,6 +6,9 @@ public class ServerInfo { private int webserviceId; private String formJson; + public ServerInfo() { + } + public ServerInfo(int webserviceId, String formJson) { this.webserviceId = webserviceId; this.formJson = formJson; diff --git a/src/main/java/org/lsh/webservice/ui/entity/vo/DynamicWebVO.java b/src/main/java/org/lsh/webservice/ui/entity/vo/DynamicWebVO.java new file mode 100644 index 0000000..019dd6b --- /dev/null +++ b/src/main/java/org/lsh/webservice/ui/entity/vo/DynamicWebVO.java @@ -0,0 +1,52 @@ +package org.lsh.webservice.ui.entity.vo; + +import org.lsh.webservice.ui.entity.FormField; + +public class DynamicWebVO { + + private String wsdl; + private String method; + private FormField input; + private FormField output; + private String json; + + public String getWsdl() { + return wsdl; + } + + public void setWsdl(String wsdl) { + this.wsdl = wsdl; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public FormField getInput() { + return input; + } + + public void setInput(FormField input) { + this.input = input; + } + + public FormField getOutput() { + return output; + } + + public void setOutput(FormField output) { + this.output = output; + } + + public String getJson() { + return json; + } + + public void setJson(String json) { + this.json = json; + } +} diff --git a/src/main/java/org/lsh/webservice/ui/utils/ExplainField.java b/src/main/java/org/lsh/webservice/ui/utils/ExplainField.java index ccfced7..22124db 100644 --- a/src/main/java/org/lsh/webservice/ui/utils/ExplainField.java +++ b/src/main/java/org/lsh/webservice/ui/utils/ExplainField.java @@ -1,5 +1,6 @@ package org.lsh.webservice.ui.utils; +import cn.hutool.core.collection.CollectionUtil; import org.lsh.webservice.ui.entity.FormField; import java.lang.reflect.Array; @@ -13,7 +14,16 @@ import java.util.ArrayList; import java.util.List; public class ExplainField { - public static void explain(Field declaredField, List formFieldList) throws ClassNotFoundException { + + public static void explain(Object o,Field declaredField, List formFieldList) throws ClassNotFoundException, IllegalAccessException { + // 集合 + FormField complexType = new FormField(); + Object currentValue = null; + if(o != null){ + declaredField.setAccessible(true); + currentValue = declaredField.get(o); + complexType.setValue(currentValue); + } // 判断Field类型 if(declaredField.getType() == List.class || declaredField.getType() == Array.class){ // 获取List的泛型类型 @@ -22,9 +32,9 @@ public class ExplainField { ParameterizedType parameterizedType = (ParameterizedType)genericType; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); if(actualTypeArguments.length>0){ - FormField complexType = new FormField(); complexType.setFieldName(declaredField.getName()); complexType.setTypeName(declaredField.getType().getTypeName()); + List formFields = new ArrayList<>(); complexType.setFields(formFields); // 获取List的泛型类型 @@ -32,9 +42,53 @@ public class ExplainField { Class classes = (Class) actualTypeArgument; // 泛型类加载器 if(classes != null) { - Field[] declaredFields2 = classes.getDeclaredFields(); - for (Field declaredField2 : declaredFields2) { - explain(declaredField2, formFields); + complexType.setGenericType(classes.getTypeName()); + if(currentValue != null){ + List list = (List)currentValue; + if(CollectionUtil.isEmpty(list)){ + currentValue = null; + // 集合第一个对象 + FormField firstObj = new FormField(); + firstObj.setFieldName("0"); + firstObj.setTypeName(classes.getTypeName()); + formFields.add(firstObj); + + List firstObjFields = new ArrayList<>(); + firstObj.setFields(firstObjFields); + Field[] declaredFields2 = classes.getDeclaredFields(); + for (Field declaredField2 : declaredFields2) { + explain(currentValue,declaredField2, firstObjFields); + } + }else{ + for (int i = 0; i < list.size(); i++) { + Object o1 = list.get(i); + // 集合第一个对象 + FormField firstObj = new FormField(); + firstObj.setFieldName(i+""); + firstObj.setTypeName(classes.getTypeName()); + formFields.add(firstObj); + + List firstObjFields = new ArrayList<>(); + firstObj.setFields(firstObjFields); + Field[] declaredFields2 = classes.getDeclaredFields(); + for (Field declaredField2 : declaredFields2) { + explain(o1,declaredField2, firstObjFields); + } + } + } + }else{ + // 集合第一个对象 + FormField firstObj = new FormField(); + firstObj.setFieldName("0"); + firstObj.setTypeName(classes.getTypeName()); + formFields.add(firstObj); + + List firstObjFields = new ArrayList<>(); + firstObj.setFields(firstObjFields); + Field[] declaredFields2 = classes.getDeclaredFields(); + for (Field declaredField2 : declaredFields2) { + explain(currentValue,declaredField2, firstObjFields); + } } } formFieldList.add(complexType); @@ -52,26 +106,37 @@ public class ExplainField { || declaredField.getType() == LocalDate.class || declaredField.getType().getTypeName().equals("int") || declaredField.getType().getTypeName().equals("long")){ - FormField basic = new FormField(); - basic.setFieldName(declaredField.getName()); - basic.setTypeName(declaredField.getType().getTypeName()); - formFieldList.add(basic); - System.out.println(declaredField); + + complexType.setFieldName(declaredField.getName()); + complexType.setTypeName(declaredField.getType().getTypeName()); + formFieldList.add(complexType); + }else { // 自定义的数据类型 System.out.println("进入自定义数据类型:" + declaredField.getName() + "====" + declaredField.getType()); // 获取该字段的参数类型 Class class2 = (Class)declaredField.getGenericType(); Field[] declaredFields = class2.getDeclaredFields(); - FormField complexType = new FormField(); + complexType.setFieldName(declaredField.getName()); complexType.setTypeName(declaredField.getType().getTypeName()); List formFields = new ArrayList<>(); complexType.setFields(formFields); for (Field field : declaredFields) { - explain(field, formFields); + explain(currentValue,field, formFields); } formFieldList.add(complexType); } } + + public static boolean isList(String typeName){ + return "java.util.List".equals(typeName) || "java.lang.Arrays".equals(typeName); + } + + public static String switchToObject(String typeName1,String typeName2){ + if(isList(typeName1)){ + return typeName2; + } + return typeName1; + } } diff --git a/src/main/java/org/lsh/webservice/ui/utils/ExplainWebservice.java b/src/main/java/org/lsh/webservice/ui/utils/ExplainWebservice.java index feda5cf..a65c252 100644 --- a/src/main/java/org/lsh/webservice/ui/utils/ExplainWebservice.java +++ b/src/main/java/org/lsh/webservice/ui/utils/ExplainWebservice.java @@ -1,17 +1,26 @@ package org.lsh.webservice.ui.utils; import cn.hutool.core.collection.CollectionUtil; -import com.alibaba.fastjson.JSON; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import org.apache.cxf.service.model.*; +import org.lsh.webservice.ui.config.XMLGregorianCalendarTypeAdapter; import org.lsh.webservice.ui.entity.FormItemV2; import org.lsh.webservice.ui.entity.FormV2; import org.lsh.webservice.ui.entity.FormField; +import org.lsh.webservice.ui.entity.MyParameterizedType; +import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.*; public class ExplainWebservice { @@ -32,13 +41,6 @@ public class ExplainWebservice { formV2.setServerName(serviceInfo.getName().getLocalPart()); /**创建Service*/ Collection bindings = serviceInfo.getBindings(); - Map extensionAttributes = serviceInfo.getExtensionAttributes(); - if(extensionAttributes != null) { - extensionAttributes.forEach((key, val) -> { - System.out.println("key:" + key + " values:" + val); - }); - } - // portType // 对于某个访问入口点类型所支持的操作的抽象集合; ----》服务端SEI //   指出了这个WebService所有支持的操作,就是说有哪些方法可供调用。 @@ -71,11 +73,11 @@ public class ExplainWebservice { System.out.println("====>"+aClass); for (Field declaredField : declaredFields) { System.out.println("declaredField:" + declaredField); - org.lsh.webservice.ui.utils.ExplainField.explain(declaredField, formFields); + org.lsh.webservice.ui.utils.ExplainField.explain(null,declaredField, formFields); } - System.out.println("解析表单结果:" + JSON.toJSONString(complex)); + //System.out.println("解析表单结果:" + JSON.toJSONString(complex)); messageMap.put(aClass.getSimpleName(),complex); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException | IllegalAccessException e) { e.printStackTrace(); } } @@ -92,25 +94,140 @@ public class ExplainWebservice { String inputTypeName = ""; String outputTypeName = ""; + FormItemV2 itemV2 = new FormItemV2(); + itemV2.setOperation(function); + OperationInfo operationInfo = operation.getOperationInfo(); - List inputMessageParts = operationInfo.getInput().getMessageParts(); + if(operation.isUnwrapped()){ + operationInfo = operation.getUnwrappedOperation().getOperationInfo(); + } + BindingMessageInfo messageInfo = null; + if(operation.isUnwrapped()){ + messageInfo = operation.getUnwrappedOperation().getInput(); + }else{ + messageInfo = operation.getWrappedOperation().getInput(); + } + + List messageParts = messageInfo.getMessageInfo().getMessageParts(); + StringBuilder params = new StringBuilder(); + for (MessagePartInfo messagePart : messageParts) { + String typeName = messagePart.getTypeClass().getTypeName(); + String param = messagePart.getName().getLocalPart(); + if(params.length()>0){ + params.append(","); + } + params.append(typeName+" "+param); + } + System.out.println("function==================>:" + function + "(" + params.toString()+")"); + + List inputMessageParts = messageInfo.getMessageParts(); for (MessagePartInfo inputMessagePart : inputMessageParts) { inputTypeName = inputMessagePart.getTypeClass().getSimpleName(); + String name = inputMessagePart.getName().getLocalPart(); + // 如果是参数命名,那么再往下,获取实际传参 + FormField input = messageMap.get(inputTypeName); +// if("parameters".equals(name) && input.getFields().size()>0){ +// input = input.getFields().get(0); +// } + itemV2.setInput(input); } List outputMessageParts = operationInfo.getOutput().getMessageParts(); for (MessagePartInfo outputMessagePart : outputMessageParts) { outputTypeName = outputMessagePart.getTypeClass().getSimpleName(); + String name = outputMessagePart.getName().getLocalPart(); + // 如果是参数命名,那么再往下,获取实际传参 + FormField output = messageMap.get(outputTypeName); +// if("parameters".equals(name) && output.getFields().size()>0){ +// output = output.getFields().get(0); +// } + itemV2.setOutput(output); } - - - FormItemV2 itemV2 = new FormItemV2(); - itemV2.setOperation(function); - itemV2.setInput(messageMap.get(inputTypeName)); - itemV2.setOutput(messageMap.get(outputTypeName)); itemV2s.add(itemV2); } } } return formV2; } + + public static FormField dynamicInvoke(String wsdl + ,String method + ,FormField input + ,FormField output + ,String json) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + // 创建动态客户端 + JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance(); + Client client = factory.createClient(wsdl); + String inputClassName = ExplainField.switchToObject(input.getTypeName(),input.getGenericType()); + Class inputClass = Thread.currentThread().getContextClassLoader().loadClass(inputClassName); + // 如果输入值是集合,那么需要将集合转化为对应类型 + JavaType inputJavaType = objectMapper.getTypeFactory().constructCollectionType(List.class, inputClass); + MyParameterizedType type = new MyParameterizedType(List.class, new Type[]{inputClass}); + + String outputClassName = ExplainField.switchToObject(output.getTypeName(),output.getGenericType()); + Class outputClass = Thread.currentThread().getContextClassLoader().loadClass(outputClassName); + JavaType outputJavaType = objectMapper.getTypeFactory().constructCollectionType(List.class, outputClass); + + + Object request = null; + if(ExplainField.isList(input.getTypeName())){ + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + //objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES,false); +// request = objectMapper.readValue(json, inputJavaType); + Gson gson = new GsonBuilder() + .registerTypeAdapter(XMLGregorianCalendar.class, new XMLGregorianCalendarTypeAdapter()) + .create(); + request = gson.fromJson(json, type); + }else{ + request = objectMapper.readValue(json, inputClass); + } + Object[] invoke = client.invoke(method,request); + FormField complex = new FormField(); + + if(invoke != null && invoke.length>0){ + String responseJson = objectMapper.writeValueAsString(invoke[0]); + System.out.println("=====response======>"+responseJson); + Object response = null; + if(ExplainField.isList(output.getTypeName())){ + response = objectMapper.readValue(responseJson, outputJavaType); + System.out.println("=====response======>"+response); + List formFields = new ArrayList<>(); + complex.setFieldName(output.getFieldName()); + complex.setFields(formFields); + complex.setTypeName(output.getTypeName()); + complex.setGenericType(output.getGenericType()); + + // 如果本身就是集合,那么字段名称就是下标 + List list = (List) response; + for (int i = 0; i < list.size(); i++) { + Object o1 = list.get(i); + List indexFormFields = new ArrayList<>(); + FormField indexForm = new FormField(); + indexForm.setTypeName(o1.getClass().getTypeName()); + indexForm.setFields(indexFormFields); + indexForm.setFieldName(i+""); + Field[] declaredFields = o1.getClass().getDeclaredFields(); + for (Field declaredField : declaredFields) { + org.lsh.webservice.ui.utils.ExplainField.explain(o1,declaredField, indexFormFields); + } + formFields.add(indexForm); + } + }else{ + response = objectMapper.readValue(responseJson, outputClass); + System.out.println("=====response======>"+response); + List formFields = new ArrayList<>(); + complex.setFields(formFields); + complex.setTypeName(outputClassName); + complex.setFieldName(output.getFieldName()); + Field[] declaredFields = outputClass.getDeclaredFields(); + for (Field declaredField : declaredFields) { + org.lsh.webservice.ui.utils.ExplainField.explain(response,declaredField, formFields); + } + } + } + return complex; + } + + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b280051..ae78d88 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,6 +15,8 @@ spring: username: sa password: password platform: h2 + hikari: + pool-name: h2- h2: console: enabled: true diff --git a/src/main/resources/static/vue/addwsdl.js b/src/main/resources/static/vue/addwsdl.js index fda3bbe..63c61f4 100644 --- a/src/main/resources/static/vue/addwsdl.js +++ b/src/main/resources/static/vue/addwsdl.js @@ -4,8 +4,7 @@ Vue.component('add-wsdl', { - - + @@ -21,9 +20,10 @@ Vue.component('add-wsdl', { props: ['isshow'], // html接收字段名都是小写,单向传递 data() { return { + projectList: [], form: { wsdl: '', - projectId: '1' + projectId: 1 } } }, @@ -37,7 +37,32 @@ Vue.component('add-wsdl', { // } // }, }, + created(){ + this.queryProjects(); + }, methods: { // 组件内方法 + queryProjects(){ + var _this = this; + $.ajax({ + type: 'POST', + url: '/query-projects?loadWebservice=false&loadOperation=false', + contentType:'application/json', + timeout: 5000, + data: JSON.stringify({}), + dataType: "JSON", + success: function ({code,data}, textStatus, jqXHR) { + if(data && code === 0){ + _this.projectList = data; + if(_this.projectList && _this.projectList.length>0){ + _this.form.projectId = _this.projectList[0].id + } + } + }, + error: function (xhrJson,status,error) { + + } + }); + }, onSubmit(){ var _this = this; $.ajax({ @@ -54,6 +79,7 @@ Vue.component('add-wsdl', { console.log(data) if(code === 0){ _this.$message.success(msg); + _this.$emit('reload-projects'); }else{ _this.$message.error(msg); } diff --git a/src/main/resources/static/vue/operation.js b/src/main/resources/static/vue/operation.js index 818bb1e..c592e80 100644 --- a/src/main/resources/static/vue/operation.js +++ b/src/main/resources/static/vue/operation.js @@ -2,21 +2,29 @@ Vue.component('operation', { template: `
-
  • {{form.wsdl}}
  • + + + 提交 + + + + + +
    - 请求参数 + 请求参数
    认证设置  请求头设置
    - - - + + @@ -33,6 +41,9 @@ Vue.component('operation', {    {{ data.fieldName }} +
    @@ -49,13 +60,13 @@ Vue.component('operation', {
    - 返回参数 + 返回参数
    - - @@ -93,6 +104,7 @@ Vue.component('operation', { return { form: { wsdl: '', + operationName: '', input: {}, output: {} }, @@ -103,7 +115,7 @@ Vue.component('operation', { listTypes: ['java.util.List'], textInputTypes: ['java.lang.String'], numberInputTypes: ['java.math.BigDecimal','java.lang.Integer'], - dateInputTypes: ['javax.xml.datatype.XMLGregorianCalendar'], + dateInputTypes: ['javax.xml.datatype.XMLGregorianCalendar','java.util.GregorianCalendar'], booleanTypes: ['java.lang.Boolean'] } }, @@ -118,11 +130,19 @@ Vue.component('operation', { }, }, created(){ - this.onSubmit(); + this.queryOperationInfo(); }, methods: { // 组件内方法 handleNodeClick(){}, - onSubmit(){ + addListItem(node){ + console.log(node) + if(node && node.fields){ + var cp = JSON.parse(JSON.stringify(node.fields[0])); + cp.fieldName = node.fields.length; + node.fields.push(cp); + } + }, + queryOperationInfo(){ var _this = this; $.ajax({ type: 'GET', @@ -136,13 +156,101 @@ Vue.component('operation', { success: function ({code,data,msg}, textStatus, jqXHR) { console.log(data) _this.form.wsdl = data.wsdl; - _this.form.input = data.input; - _this.form.output = data.output; + _this.form.input = [data.input]; + _this.form.output = [data.output]; + _this.form.operationName = data.operation; }, error: function (xhrJson,status,error) { _this.$message.error(error); } }); + }, + onSubmit(){ + // 获取参数 + if(this.form.input){ + console.log("this.form.input===========",this.form.input) + var body = this.form.input[0].fields?this.form.input[0].fields:this.form.input[0]; + const request = (this.form.input[0] && this.form.input[0].genericType) ? [] : {}; + this.generateRequest(request,body); + console.log('====================================='); + console.log(request); + var _this = this; + $.ajax({ + type: 'POST', + url: '/invoke', + contentType:'application/json', + timeout: 5000, + data: JSON.stringify({ + wsdl: _this.form.wsdl, + method: _this.form.operationName, + input: this.form.input[0], + output: this.form.output[0], + json: JSON.stringify(request) + }), + dataType: "JSON", + success: function ({code,data,msg}, textStatus, jqXHR) { + console.log(data) + if(code === 0){ + _this.form.output = [data]; + _this.$message.success(msg); + }else{ + _this.$message.error(msg); + } + }, + error: function (xhrJson,status,error) { + _this.$message.error(error); + } + }); + } + }, + generateRequest(root,input){ + if(input instanceof Array){ + for (var index in input){ + this.generateRequest(root,input[index]); + } + }else{ + // 判断进入的类型 + if (this.checkType(input.typeName) === 'obj') { + var currentObj = {}; + var key = input.fieldName; + if(root instanceof Array){ + console.log('===========generateRequest===root:') + root.push(currentObj); + }else{ + root[key] = currentObj; + } + if(input.fields && input.fields.length>0){ + for (var index in input.fields){ + this.generateRequest(currentObj,input.fields[index]); + } + } + } else if (this.checkType(input.typeName) === 'list') { + var currentList = []; + var key = input.fieldName; + root[key] = currentList; + if(input.fields && input.fields.length>0){ + for (var index in input.fields){ + this.generateRequest(currentList,input.fields[index]); + } + } + } else if (this.checkType(input.typeName) === 'base') { + root[input.fieldName] = input.value || '11'; + } + } + }, + checkType(typeName){ + if(typeName === 'java.lang.String' + || typeName === 'java.math.BigDecimal' + || typeName === 'javax.xml.datatype.XMLGregorianCalendar' + || typeName === 'java.util.GregorianCalendar' + || typeName === 'java.lang.Integer' + ){ + return 'base'; + }else if(typeName === 'java.util.List'){ + return 'list'; + }else { + return 'obj'; + } } } }) \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 1f1a638..5786aa2 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -103,6 +103,7 @@ @@ -120,7 +121,7 @@ :name="item.name" size="small" > - + @@ -142,6 +143,7 @@ el: '#app', data: { loading: false, + projectsLoading: false, defaultProps: { children: 'children', label: 'name' @@ -179,6 +181,8 @@ }, queryProjects(){ var _this = this; + _this.projectsLoading = true; + _this.projectList = [] $.ajax({ type: 'POST', url: '/query-projects', @@ -187,13 +191,13 @@ data: JSON.stringify({}), dataType: "JSON", success: function ({code,data}, textStatus, jqXHR) { - console.log(data) if(data && code === 0){ _this.projectList = data; } + _this.projectsLoading = false; }, error: function (xhrJson,status,error) { - + _this.projectsLoading = false; } }); }, diff --git a/src/test/java/com/lsh/TestCalendar.java b/src/test/java/com/lsh/TestCalendar.java new file mode 100644 index 0000000..6e73f77 --- /dev/null +++ b/src/test/java/com/lsh/TestCalendar.java @@ -0,0 +1,15 @@ +package com.lsh; + +import javax.xml.datatype.XMLGregorianCalendar; + +public class TestCalendar { + private XMLGregorianCalendar calendar; + + public XMLGregorianCalendar getCalendar() { + return calendar; + } + + public void setCalendar(XMLGregorianCalendar calendar) { + this.calendar = calendar; + } +} diff --git a/src/test/java/com/lsh/TestDTO.java b/src/test/java/com/lsh/TestDTO.java new file mode 100644 index 0000000..47b3406 --- /dev/null +++ b/src/test/java/com/lsh/TestDTO.java @@ -0,0 +1,44 @@ +package com.lsh; + +import org.lsh.webservice.ui.entity.dto.ServerInfo; + +import java.util.List; + +public class TestDTO { + private String name; + private String value; + private String qOrE; + private List children; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public String getqOrE() { + return qOrE; + } + + public void setqOrE(String qOrE) { + this.qOrE = qOrE; + } +} diff --git a/src/test/java/com/lsh/test.java b/src/test/java/com/lsh/test.java new file mode 100644 index 0000000..66d0f72 --- /dev/null +++ b/src/test/java/com/lsh/test.java @@ -0,0 +1,23 @@ +package com.lsh; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.lsh.webservice.ui.entity.FormV2; +import org.lsh.webservice.ui.utils.ExplainWebservice; + +public class test { + public static void main(String[] args) throws JsonProcessingException { + String [] arr = { + "http://10.30.35.155:8088/services/containerQueryWebService?wsdl", + "http://ws.webxml.com.cn/WebServices/WeatherWebService.asmx?WSDL", + "http://10.30.35.116:35180/services/queryPersonPostInfoWebService?wsdl", + "http://10.30.35.116:35180/services/itemSyncWebService?wsdl", + "http://10.30.35.59/weixin.asmx?WSDL", + "http://10.30.35.116:35180/services/okWebService?wsdl" + }; + ObjectMapper objectMapper = new ObjectMapper(); + FormV2 formV2 = ExplainWebservice.explainWsdlV2(arr[4]); + System.out.println(objectMapper.writeValueAsString(formV2)); + System.out.println(formV2); + } +} diff --git a/src/test/java/com/lsh/test2.java b/src/test/java/com/lsh/test2.java new file mode 100644 index 0000000..7f93d9a --- /dev/null +++ b/src/test/java/com/lsh/test2.java @@ -0,0 +1,15 @@ +package com.lsh; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebServiceClient; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.net.URL; + +public class test2 { + public static void main(String[] args) throws Exception { + URL wsdlUrl = new URL("http://10.30.35.116:35180/services/queryPersonPostInfoWebService?wsdl"); + + } +} diff --git a/src/test/java/com/lsh/test3.java b/src/test/java/com/lsh/test3.java new file mode 100644 index 0000000..1dd1eca --- /dev/null +++ b/src/test/java/com/lsh/test3.java @@ -0,0 +1,54 @@ +package com.lsh; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.reflect.TypeToken; +import org.lsh.webservice.ui.entity.MyParameterizedType; +import org.lsh.webservice.ui.entity.dto.ServerInfo; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; + +public class test3 { + public static void main(String[] args) throws JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper(); + String json = "[{\"bomDTO\":[{\"backFlush\":\"11\",\"bmeng\":\"11\",\"componentGbo\":\"11\",\"ebort\":\"11\",\"erpStep\":\"11\",\"menge\":\"11\",\"operation\":\"11\",\"qOrE\":\"11\",\"qty\":\"11\",\"reservedLine\":\"11\",\"reservedNumber\":\"11\",\"salesOrder\":\"11\",\"sequence\":\"11\",\"shopOrder\":\"11\",\"soLine\":\"11\",\"sumQty\":\"11\",\"unit\":\"11\"}],\"routingDTO\":[{\"description\":\"11\",\"erpControlKey\":\"11\",\"erpStep\":\"11\",\"manSeconds\":\"11\",\"manUnit\":\"11\",\"operation\":\"11\",\"sequence\":\"11\",\"shopOrder\":\"11\",\"staffQty\":\"11\",\"workCenter\":\"11\"}],\"shopOrderDTO\":{\"agingRatio\":\"11\",\"agingTime\":\"11\",\"agingVoltage\":\"11\",\"agingWay\":\"11\",\"baseSealRule\":\"11\",\"crestClampNum\":\"11\",\"deliveryDate\":\"2024-10-30\",\"demandPlant\":\"11\",\"demandQty\":\"11\",\"demandUser\":\"11\",\"erpStatus\":\"11\",\"fatherSo\":\"11\",\"hopeFinishTime\":\"2024-10-30\",\"innerBoxSeal\":\"11\",\"kdkg2\":\"11\",\"oriQty\":\"11\",\"outerBoxSeal\":\"11\",\"phosphorFatherSo\":\"11\",\"planNote\":\"11\",\"plannedCompDate\":\"2024-10-30\",\"plannedItem\":\"11\",\"plannedStartDate\":\"2024-10-30\",\"plannedWorkCenter\":\"11\",\"priorityNum\":\"11\",\"qtyOrdered\":\"11\",\"salesNote\":\"11\",\"salesOrder\":\"11\",\"salesOrderQuantity\":\"11\",\"salesman\":\"11\",\"shopOrder\":\"11\",\"shopOrderType\":\"11\",\"site\":\"11\",\"soItem\":\"11\",\"soLine\":\"11\",\"status\":\"11\",\"steelSealNum\":\"11\",\"stencilNum\":\"11\",\"stickerSealRule\":\"11\",\"supplyQty\":\"11\",\"switchingTime\":\"11\",\"targetLine\":\"11\",\"targetStorage\":\"11\",\"wbs\":\"11\",\"zext4\":\"11\",\"zrqyz10\":\"11\",\"zrqyz11\":\"11\",\"zrqyz5\":\"11\",\"zrqyz6\":\"11\",\"zrqyz7\":\"11\",\"zrqyz8\":\"11\",\"zrqyz9\":\"11\",\"zyp\":\"11\"}}]"; + Gson gson = new Gson(); + + MyParameterizedType type = new MyParameterizedType(List.class, new Type[]{ShopOrderSyncDTO.class}); + +// Type type = new TypeToken(ShopOrderSyncDTO.class.getTypeParameters()){}.getType(); + List deserializedList = gson.fromJson(json, type); + System.out.println(deserializedList); + + JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, ShopOrderSyncDTO.class); + List list2 = objectMapper.readValue(json, javaType); + + System.out.println(list2); + System.out.println(ShopOrderSyncDTO.class.getGenericSuperclass()); + + } + + public static XMLGregorianCalendar dateToXmlDate(Date date) { + GregorianCalendar gregorianCalendar = new GregorianCalendar(); + gregorianCalendar.setTime(date); + try { + return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar); + } catch (DatatypeConfigurationException e) { + e.printStackTrace(); + return null; + } + } + +}