Selaa lähdekoodia

Swagger 开发和 Jaxb

赵平西 5 vuotta sitten
vanhempi
commit
35d38f8463

+ 267 - 0
httpclient/RestApiUtils.java

@@ -0,0 +1,267 @@
+package com.yiidata.intergration.api.utils;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ *
+ * 封装 RestApi 调用
+ *
+ *
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2020/4/3
+ * Time: 17:38
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+public class RestApiUtils {
+
+
+	static Logger log = LoggerFactory.getLogger(RestApiUtils.class);
+	
+    /**
+     * http client
+     */
+    static final HttpClient httpClient;
+
+    static {
+        try {
+            //设置协议http和https对应的处理socket链接工厂的对象
+            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+                    .register("http", PlainConnectionSocketFactory.INSTANCE)
+                    .register("https", new SSLConnectionSocketFactory(createIgnoreVerifySSL()))
+                    .build();
+
+            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+            httpClient = HttpClients.custom()
+                    .setConnectionManager(cm)
+                    .setRetryHandler(new DefaultHttpRequestRetryHandler(3, false))
+                    .build();
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+
+    /**
+     * 绕过验证
+     *
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws KeyManagementException
+     */
+    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
+        SSLContext sc = SSLContext.getInstance("SSLv3");
+
+        // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
+        X509TrustManager trustManager = new X509TrustManager() {
+            @Override
+            public void checkClientTrusted(
+                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+                    String paramString) throws CertificateException {
+            }
+
+            @Override
+            public void checkServerTrusted(
+                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
+                    String paramString) throws CertificateException {
+            }
+
+            @Override
+            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+        };
+
+        sc.init(null, new TrustManager[] { trustManager }, null);
+        return sc;
+    }
+
+    /**
+     * 调用一次远程 api
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> post(String url) throws IOException {
+        return post(url, new HashMap<>(), false);
+    }
+
+
+    /**
+     * 调用一次远程 api
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> post(String url, boolean not200ThrowError) throws IOException {
+        return post(url, new HashMap<>(), not200ThrowError);
+    }
+
+
+    /**
+     * 通过 Post 请求调用Rest 接口
+     *
+     * @param url
+     * @param json
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> post(String url, Map<String, Object> json) throws IOException {
+        return post(url, json, false);
+    }
+
+    /**
+     * 通过 Post 请求调用Rest 接口
+     * @param url
+     * @param json
+     * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> post(String url, Map<String, Object> json, boolean not200ThrowError) throws IOException {
+        return post(url, JSON.toJSONString(json), not200ThrowError);
+    }
+
+
+    public static Map<String, Object> post(String url, String jsonStr, boolean not200ThrowError) throws IOException {
+        HttpPost post = new HttpPost(url);
+        StringEntity entity = new StringEntity(jsonStr, "UTF-8");
+        entity.setContentType("application/json");
+        post.setEntity(entity);
+        try {
+            HttpResponse resp = httpClient.execute(post);
+            log.info("execute url {} return code: {}", url, resp.getStatusLine().getStatusCode());
+            HttpEntity entity1 = resp.getEntity();
+            String result = EntityUtils.toString(entity1);
+            EntityUtils.consume(entity1);
+            if(not200ThrowError && resp.getStatusLine().getStatusCode() != 200) {
+                throw new IOException(result);
+            }
+            Object jsonResult = JSON.parse(result);
+            JSONObject jsonObject = new JSONObject(2);
+            if(jsonResult instanceof JSONArray) {
+                jsonObject.put("result", jsonResult);
+            } else {
+                jsonObject = (JSONObject) jsonResult;
+            }
+            jsonObject.put("status_code", resp.getStatusLine().getStatusCode());
+            return jsonObject;
+        } finally {
+            post.releaseConnection();
+        }
+    }
+
+
+    //---------
+    /**
+     * 调用一次远程 api
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> get(String url) throws IOException {
+        return get(url, new HashMap<>(), false);
+    }
+
+
+    /**
+     * 调用一次远程 api
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> get(String url, boolean not200ThrowError) throws IOException {
+        return get(url, new HashMap<>(), not200ThrowError);
+    }
+
+
+    /**
+     * 通过 Post 请求调用Rest 接口
+     *
+     * @param url
+     * @param json
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> get(String url, Map<String, Object> json) throws IOException {
+        return get(url, json, false);
+    }
+
+    /**
+     * 通过 Post 请求调用Rest 接口
+     * @param url
+     * @param json
+     * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> get(String url, Map<String, Object> json, boolean not200ThrowError) throws IOException {
+        HttpGet get = new HttpGet(url);
+        if(json != null && !json.isEmpty()) {
+            BasicHttpParams params = new BasicHttpParams();
+            for (Map.Entry<String, Object> entry : json.entrySet()) {
+                params.setParameter(entry.getKey(), entry.getValue());
+            }
+            get.setParams(params);
+        }
+        try {
+            HttpResponse resp = httpClient.execute(get);
+            log.info("execute url {} return code: {}", url, resp.getStatusLine().getStatusCode());
+            HttpEntity entity = resp.getEntity();
+            String result = EntityUtils.toString(entity);
+            EntityUtils.consume(entity);
+            if(not200ThrowError && resp.getStatusLine().getStatusCode() != 200) {
+                throw new IOException(result);
+            }
+            Object jsonResult = JSON.parse(result);
+            JSONObject jsonObject = new JSONObject(2);
+            if(jsonResult instanceof JSONArray) {
+                jsonObject.put("result", jsonResult);
+            } else {
+                jsonObject = (JSONObject) jsonResult;
+            }
+            jsonObject.put("status_code", resp.getStatusLine().getStatusCode());
+            return jsonObject;
+        } finally {
+            get.releaseConnection();
+        }
+    }
+}

+ 58 - 0
jaxb-serde/JaxbTest.java

@@ -0,0 +1,58 @@
+package com.primeton.dgs.workspace.extractor.jaxb;
+
+import org.junit.Test;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+
+/**
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2019/9/10
+ * Time: 14:10
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+public class JaxbTest {
+
+
+    @Test
+    public void saveXmlTest() {
+        User user = new User("陈本布衣", 2018, "超级管理员","瞎哔哔");
+        File file = new File("user.xml");
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
+            Marshaller marshaller = jaxbContext.createMarshaller();
+            //格式化输出,即按标签自动换行,否则就是一行输出
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            //设置编码(默认编码就是utf-8)
+            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+            //是否省略xml头信息,默认不省略(false)
+            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
+            marshaller.marshal(user, file);
+        } catch (JAXBException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Test
+    public void getUserTest() {
+        File file = new File("user.xml");
+        try {
+            JAXBContext jaxbContext = JAXBContext.newInstance(User.class);
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            User user = (User) unmarshaller.unmarshal(file);
+            System.out.println(user.toString());
+        } catch (JAXBException e) {
+            e.printStackTrace();
+        }
+    }
+}
+

+ 93 - 0
jaxb-serde/User.java

@@ -0,0 +1,93 @@
+package com.primeton.dgs.workspace.extractor.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessOrder;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorOrder;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import java.io.Serializable;
+
+/**
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2019/9/10
+ * Time: 14:14
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+
+@XmlType(propOrder = {})
+@XmlRootElement(name = "user")
+@XmlAccessorType(XmlAccessType.PROPERTY)
+@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
+public class User implements Serializable {
+
+    private String userName;
+    private int age;
+    private String role;
+    private String bibi;
+
+
+    public User() {
+    }
+
+    public User(String userName, int age, String role, String bibi) {
+        this.userName = userName;
+        this.age = age;
+        this.role = role;
+        this.bibi = bibi;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    @XmlAttribute
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    @XmlElement
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    @XmlTransient
+    public String getBibi() {
+        return bibi;
+    }
+
+    public void setBibi(String bibi) {
+        this.bibi = bibi;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" +
+                "userName='" + userName + '\'' +
+                ", age=" + age +
+                ", role='" + role + '\'' +
+                ", bibi='" + bibi + '\'' +
+                '}';
+    }
+}

+ 79 - 0
swagger-support/SwaggerConfig.java

@@ -0,0 +1,79 @@
+package com.primeton.dgs.kernel.core.configure;
+
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.Optional;
+
+
+/**
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2020/8/27
+ * Time: 15:27
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+@Configuration //必须存在
+@EnableSwagger2 //必须存在
+public class SwaggerConfig {
+
+    @Value("${swagger.group}")
+    private String groupName;
+
+    @Value("${swagger.title}")
+    private String title;
+
+    @Value("${swagger.description}")
+    private String description;
+
+
+    @Value("${swagger.creator}")
+    private String creator;
+
+
+    @Value("${swagger.version}")
+    private String version;
+
+
+    @Value("${swagger.basepackage}")
+    private String basepackage;
+
+
+    @Bean
+    public Docket docket() {
+        return new Docket(DocumentationType.SWAGGER_2).groupName(groupName).apiInfo(apiInfo()).select()
+                // 必须扫描实现类所在的包
+                .apis(RequestHandlerSelectors.basePackage(basepackage)).paths(PathSelectors.any()).build();
+
+    }
+
+    // 构建api文档的详细信息函数
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                // 页面标题
+                .title(title)
+                // 创建人
+                .contact(new Contact(creator, "http://www.primeton.com/" + groupName, "" ))
+                // 版本号
+                .version(version)
+                // 描述
+                .description(description).build();
+    }
+
+}

+ 238 - 0
swagger-support/SwaggerExtentionSupport.java

@@ -0,0 +1,238 @@
+package com.primeton.dgs.kernel.core.configure;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.net.MediaType;
+import com.primeton.dgs.kernel.core.web.AppBaseDispatchCommand;
+import io.swagger.models.Path;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpMethod;
+import springfox.documentation.builders.ResponseMessageBuilder;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.Operation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Repository;
+import springfox.documentation.service.ApiDescription;
+import springfox.documentation.service.ApiListing;
+import springfox.documentation.service.Documentation;
+import springfox.documentation.service.ResponseMessage;
+import springfox.documentation.service.Tag;
+import springfox.documentation.spring.web.DocumentationCache;
+import springfox.documentation.spring.web.json.JsonSerializer;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ *
+ *
+ * 元数据老结构,支持 Swagger 适配器
+ *
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2020/8/28
+ * Time: 14:34
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+@Repository
+public class SwaggerExtentionSupport implements ApplicationListener<ContextRefreshedEvent> {
+
+    /**
+     * 版本
+     */
+    public final static String API_VER = "7.1.0";
+
+    @Autowired
+    DocumentationCache documentationCache;
+
+
+    @Autowired
+    private ServiceModelToSwagger2Mapper mapper;
+
+    @Autowired
+    private JsonSerializer jsonSerializer;
+
+
+    @Value("${swagger.group}")
+    private String groupName;
+
+
+    private static Logger log = LoggerFactory.getLogger(SwaggerExtentionSupport.class);
+
+
+    /**
+     * 扫描 cotext 中 .do 的 bean,扫描 方法
+     * @param context
+     */
+    private void initSwagger(ApplicationContext context) {
+        Documentation documentation = documentationCache.documentationByGroup(groupName);
+        if(documentation == null) {
+            // 如果 groupName 指定的下没有,则挂载 default 上
+            documentation = documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
+        }
+        if (documentation != null) {
+            // 取得所有的 API 合集
+            Multimap<String, ApiListing> apiListings = documentation.getApiListings();
+            //Swagger swagger = mapper.mapDocumentation(documentation);
+            String[] beanDefinitionNames = context.getBeanDefinitionNames();
+            for (String name : beanDefinitionNames) {
+                if(name.endsWith(".do")) {
+                    Class<?> aClass = context.getBean(name).getClass();
+                    if(!AppBaseDispatchCommand.class.isAssignableFrom(aClass)) {
+                        // 必须是 AppBaseDispatchCommand 的子类,才继续
+                        continue;
+                    }
+
+                    log.info("add swagger bean {}", name);
+                    Method[] servletMethods = aClass.getDeclaredMethods();
+                    for (Method servletMethod : servletMethods) {
+                        String methodName = servletMethod.getName();
+                        if(!"init".equals(methodName) && Modifier.isPublic(servletMethod.getModifiers())) {
+                            // 返回 tags
+                            Set<Tag> tags = addApi(apiListings, documentation.getBasePath(), name, methodName);
+                            if(!tags.isEmpty()) {
+                                documentation.getTags().addAll(tags);
+                            }
+                        }
+                    }
+                }
+            }
+
+            log.info("swagger apis size: {}", apiListings.size());
+        }
+    }
+
+
+    private Set<Tag> addApi(Multimap<String, ApiListing> apiListings,
+                            String basePath,
+                            String beanName,
+                            String methodName) {
+        // 获取去除了 .do 的 名称
+        String optGroup = getName(beanName);
+        String optId = optGroup + "_" + methodName;
+
+        // 生成唯一ID
+        Collection<ApiListing> apis = apiListings.get(optId);
+        if(apis == null) {
+            // 后面只是用 apis 的 size 获取长度
+            apis = new HashSet<>();
+        }
+
+        ArrayList<ApiDescription> apis1 = new ArrayList<>();
+
+        ArrayList<Operation> operations = new ArrayList<>();
+
+        ResponseMessageBuilder v1 = new ResponseMessageBuilder();
+        v1.code(200).message("OK");
+
+        // tag
+        HashSet<Tag> tags = new HashSet<>();
+        tags.add(new Tag(optGroup, beanName+"." + methodName));
+
+        // 注意 position,必须是不重复的值
+        Operation operaGet = new Operation(
+                HttpMethod.GET,
+                "do exec " + optGroup + "." + methodName,
+                "",
+                new ModelRef("ResponseCode"),
+                optId+"UsingGET",
+                0,
+                Sets.newHashSet(optGroup),
+                Sets.newHashSet(MediaType.ANY_TYPE.toString()),
+                Sets.newHashSet(MediaType.create("application", "json").toString()),
+                new HashSet<>(),
+                new ArrayList<>(),
+                new ArrayList<>(),
+                Sets.newHashSet(v1.build()),
+                "",
+                false,
+                new ArrayList<>()
+        );
+
+        Operation operaPost = new Operation(
+                HttpMethod.POST,
+                "do exec " + optGroup + "." + methodName,
+                "",
+                new ModelRef("ResponseCode"),
+                optId+"UsingPOST",
+                1,
+                Sets.newHashSet(optGroup),
+                Sets.newHashSet(MediaType.ANY_TYPE.toString()),
+                Sets.newHashSet(MediaType.create("application", "json").toString()),
+                new HashSet<>(),
+                new ArrayList<>(),
+                new ArrayList<>(),
+                Sets.newHashSet(v1.build()),
+                "",
+                false,
+                new ArrayList<>()
+        );
+
+        operations.add(operaGet);
+        operations.add(operaPost);
+
+        String url = "/" + beanName + "?invoke=" + methodName;
+        apis1.add(new ApiDescription(groupName,
+                url,
+                beanName+"." + methodName,
+                operations, false));
+
+        // 注意 position,必须是不重复的值
+        ApiListing apiListing = new ApiListing(
+                API_VER,
+                basePath,
+                "/" + beanName,
+                new HashSet<>(),new HashSet<>(),"", new HashSet<>(), new ArrayList<>(),
+                apis1,
+                new HashMap<>(), beanName+"." + methodName, apis.size(), tags);
+
+        // 放到api列表中
+        apiListings.put(optId, apiListing);
+        return tags;
+    }
+
+
+    private String getName(String beanName) {
+        if(StringUtils.isBlank(beanName)) {
+            return beanName;
+        }
+
+        int i = beanName.indexOf(".");
+        if(i > 0) {
+            return beanName.substring(0, i);
+        }
+        return beanName;
+    }
+
+
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        // Spring 框架加载完全后,扫描 bean,获取 servlet
+        initSwagger(event.getApplicationContext());
+    }
+}