0


java处理,调用外系统的 WebAPI(https请求)时,相关知识整理

======

■整理内容

1.外系统连接时,注意点

与外系统连接时,需要考虑的问题_sun0322的博客-CSDN博客

2.https证书相关问题---java---证书产生的错误---不被信任的证书

HttpClient 使用时,出现「no trusted certificate found」的原因 (JDK没有安装相应的证明书)_sun0322的博客-CSDN博客_no trusted certificate found

3.https证书相关问题---CURL---通过参数-可以忽略-证书信任问题

使用JDK中的 keytool【创建证书】・【查看】・【使用】_sun0322的博客-CSDN博客_keytool查看证书信息

└使用CURL命令访问https的网站

curl https://10.10.10.193/hello

如何不是信任机构发布的证书,会出现下面错误

curl: (60) schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - 证书链是由不受信任的颁发机构颁发的。

More details here: https://curl.se/docs/sslcerts.html

虽然,CURL中,使用参数k可以解决这个问题,

// F:Form 模拟用户在浏览器上点击“submit”按钮提交表单的操作。 比如,要提交存储密码的文件到服务器上,命令为:curl -F password=@/etc/passwd

// k: 接受服务器的ssl证书而不管合不合法。参数“-k”等同于“--insecure”。

// v:verbose 显示一次 http 通信的整个过程,包括端口连接和 http request 头信息。

但是,java的HttpClient和RestTemplate中,会出现认证的问题。「no trusted certificate found」

4.证书添加---在调用方-添加被调用方(WebAPI https)的证书

使用JDK中的 keytool【创建证书】・【查看】・【使用】_sun0322的博客-CSDN博客_keytool查看证书信息

└■扩展02.JDK添加证书的信任机构

加入JDK证书信任,C:\Program Files\Java\jre1.8.0_191\lib\security>目录下运行命令:

keytool -import -alias yourCacertName -keystore cacerts -file 盘:目录/证书文件.crt

keystore的默认密码“changeit”

===

5.之前的一个作业,使用SFDC的WebAPI

外部系统连接SFDC,获取SFDC侧的数据_sun0322的博客-CSDN博客

6.HttpClient和RestTemplate的使用(详细对比)

HttpClient和RestTemplate的使用(详细对比)_霞之秋诗羽的博客-CSDN博客_httpclient resttemplate

7.SOAP通信

Simple Object Access Protocol

简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简单的、基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WEB上交换结构化的和固化的信息。

Soap与ResuFul之间的区别

SOAP(Simple Object Access Protocol)和RESTful(Representational State Transfer)是两种不同的Web服务架构风格。

===

SOAP是一种基于XML的协议,用于在Web服务之间进行通信。它使用XML格式来封装数据,并使用HTTP、SMTP、TCP等协议来传输数据。SOAP具有严格的消息格式和协议规范,需要使用一些繁琐的工具和协议来实现它。

===

RESTful是一种基于HTTP协议的Web服务架构风格,它使用HTTP协议中的GET、POST、PUT、DELETE等方法来实现对资源的操作。它不像SOAP那样使用XML格式或其他格式来封装数据,而是使用JSON或XML等格式来表示资源的状态和数据。RESTful具有简单的API设计和易于扩展的优点,使得它成为现代应用程序的首选架构风格。

===

总的来说,SOAP和RESTful之间的区别在于它们的协议规范、数据格式、方法和架构风格等方面。SOAP更加复杂和繁琐,适合用在企业级应用中,而RESTful则更加简单、灵活和易于扩展,适合用在移动应用和Web应用中。

===

发送请求

SOAP XML发送请求及解析返回的XML_普罗旺斯_S的博客-CSDN博客_soap xml

package com.common;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

import javax.xml.soap.*;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

/**
 * Soap工具类
 *
 * @author XianYao
 * @version V1.0.0
 * @date 2022/3/8 15:40
 */
public class SoapUtil {
    public static void main(String[] args) {
        String xmlStr = "<Service>" +
                "<RegionCode>991</RegionCode>" +
                "<Word>嘉华园</Word>" +
                "<AccType></AccType>" +
                "<PageSize>10</PageSize>" +
                "<PageIndex>1</PageIndex>" +
                "</Service>";
        //webService接口地址
        String postUrl = "http://123.456.789:1234/ResWebservice/services/NewAddrService";
        //"http://tempuri.org/execute";
        String soapAction = "";
        //访问接口
        String result = SoapUtil.SplicingMessage(xmlStr, postUrl, soapAction, "searchAddr", "ns1:searchAddrResponse", "searchAddrReturn");
        System.out.println("返回的数据为:" + result);
    }

    /**
     * 访问webservice接口
     *
     * @param postUrl    webService接口地址
     * @param soapAction soapAction地址
     * @param method     方法名
     * @param node       节点
     * @param childNode  子节点
     * @return 返回值
     */
    public static String SplicingMessage(String xmlBodyStr, String postUrl, String soapAction, String method, String node, String childNode) {
        //自定义soap报文模板
        String xmlStr = "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
                "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:addr=\"http://addr.webservice.ztesoft.com\">" +
                "   <soapenv:Header/>" +
                "   <soapenv:Body>" +
                "      <addr:" + method + " soapenv:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" +
                "         <xml xsi:type=\"xsd:string\">" +
                "          <![CDATA[" + xmlBodyStr + "]]>" +
                "         </xml>" +
                "      </addr:" + method + ">" +
                "   </soapenv:Body>" +
                "</soapenv:Envelope>";

        System.out.println("自定义soap报文模板 ===> " + xmlStr);
        return doPostSoap(postUrl, xmlStr, soapAction, node, childNode);
    }

    /**
     * 使用SOAP发送消息
     *
     * @param postUrl    webService接口地址
     * @param soapXml    请求体
     * @param soapAction soapAction
     */
    public static String doPostSoap(String postUrl, String soapXml, String soapAction, String node, String childNode) {
        String retStr = "";
        // 创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // HttpClient
        CloseableHttpClient closeableHttpClient = httpClientBuilder.build();
        HttpPost httpPost = new HttpPost(postUrl);
        // 设置请求和传输超时时间
        RequestConfig requestConfig = RequestConfig.custom().build();
        httpPost.setConfig(requestConfig);
        try {
            httpPost.setHeader("Content-Type", "text/xml;charset=UTF-8");
            httpPost.setHeader("SOAPAction", soapAction);
            StringEntity data = new StringEntity(soapXml, StandardCharsets.UTF_8);
            httpPost.setEntity(data);
            CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            if (httpEntity != null) {
                // 打印响应内容
                retStr = EntityUtils.toString(httpEntity);
                System.out.println("soap响应内容 ===> " + retStr);
            }
            // 释放资源
            closeableHttpClient.close();
        } catch (Exception e) {
            
        }
        return soapXmlToBean(retStr, node, childNode);
    }

    /**
     * @param soapXml 请求结果string
     * @return 请求结果
     */
    public static String soapXmlToBean(String soapXml, String node, String childNode) {
        Iterator<SOAPElement> iterator = null;
        String res = "";
        try {
            //javax.xml.soap类MessageFactory
            MessageFactory msgFactory = MessageFactory.newInstance();
            //创建一个soapMessage对象
            SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
                    new ByteArrayInputStream(soapXml.getBytes(StandardCharsets.UTF_8)));
            reqMsg.saveChanges();
            //取出soapBody对象
            SOAPBody body = reqMsg.getSOAPBody();
            //遍历子节点
            iterator = body.getChildElements();
        } catch (Exception e) {
            e.printStackTrace();
        }
        while (iterator.hasNext()) {
            SOAPElement element = iterator.next();
            System.out.println("节点名称---:" + element.getNodeName());
            if (node.equals(element.getNodeName())) {
                Iterator<SOAPElement> it = element.getChildElements();
                SOAPElement el = null;
                while (it.hasNext()) {
                    el = it.next();
                    //取到content子节点的值
                    if (childNode.equals(el.getNodeName())) {
                        System.out.println("子节点值---:" + el.getValue());
                        res = el.getValue();
                        break;
                    }
                }
                break;
            }
        }
        return res;
    }
}

===

解析

Java 发送和解析Soap Xml数据_青冘的博客-CSDN博客_soap xml 解析

==

8.客户端证书与服务器证书

客户端证书与服务器证书有什么区别

客户端证书与服务器证书有什么区别?_CauchyBDS的博客-CSDN博客_客户端证书

加密在传输过程中保护数据

服务器或SSL证书与客户端证书的角色非常相似,但后者用于标识客户端/个人,前者用于验证站点的所有者。服务器证书通常发布到主机名,主机名可以是计算机名称(例如“XYZ-SERVER-01”)或域名(例如“www.csdn.com”)。到达服务器的Web浏览器,并验证SSL服务器证书是否可信。这告诉用户他们与网站的互动没有窃听者,并且网站正是它声称的那个人。这种安全性对于电子商务至关重要,这就是证书现在如此广泛使用的原因。

他们是怎么做到的?实际上,网站运营商通过向证书提供者申请证书签名请求来获得证书。这是一份包含所有基本信息的电子文档:网站名称,联系电子邮件地址和公司信息。证书提供者签署请求,生成公共证书,该证书被提供给连接到网站的任何Web浏览器,并且关键地向Web浏览器证明提供者向他认为是其所有者的人颁发证书。网站。但是,在颁发证书之前,证书提供商将从公共域名注册商处请求该网站的联系电子邮件地址,并根据证书申请中提供的电子邮件地址检查该已发布的地址,

此外,您可以配置网站,以便任何希望连接的用户都需要提供有效的客户端证书以及有效的用户名和密码。这通常被称为“双因素身份验证” - 在这种情况下,“你知道的东西”(密码)和“你拥有的东西”(证书)。

客户端证书

ssh-keygen(linux 命令) 创建 private key(私钥) , public key (公钥),实现ssh,scp,sftp命令无密码连接_sshkeygen生成公钥私钥_sun0322的博客-CSDN博客

└5.客户端证书 (和【 https 网站 的 CA证书】, 分别是 两个 证书。)

9.客户端和服务器端的双向认证---客户端证明书(安装,指定)

1.浏览器安装

2.curl命令中指定

curl --cert client.crt  --key client.key --insecure https://此处添加自己的网址及端口

3.HttpClients代码中指定

https://www.cnblogs.com/jiaoyiping/p/5469660.html

===

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/*
 * Created with Intellij IDEA
 * USER: 焦一平
 * Date: 2016/5/8
 * Time: 1:10
 * To change this template use File | Settings | File Template
 */
public class SSLDemo {
    public static void main(String[] args) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\ClientCert.p12")), "pwd123456".toCharArray());
        SSLContext sslcontext = SSLContexts.custom()
                //忽略掉对服务器端证书的校验
                .loadTrustMaterial(new TrustStrategy() {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return true;
                    }
                })
                
                //加载服务端提供的truststore(如果服务器提供truststore的话就不用忽略对服务器端证书的校验了)
                //.loadTrustMaterial(new File("D:\\truststore.jks"), "123456".toCharArray(),
                //        new TrustSelfSignedStrategy())
                .loadKeyMaterial(keyStore, "cmcc".toCharArray())
                .build();
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .build();

        try {

            HttpGet httpget = new HttpGet("https://10.2.5.116/PnsReceiver/ReceiveMessage");

            System.out.println("Executing request " + httpget.getRequestLine());

            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();
                System.out.println(response.getStatusLine());
                System.out.println(IOUtils.toString(entity.getContent()));
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

===

■代码 (原生代码)

・JSON(Bean)

@JsonProperty使用详解_不坠青云之志的博客-CSDN博客_@jsonproperty

package com.sxz.entity;

import org.codehaus.jackson.annotate.JsonProperty;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestRequest {
 
    // JackSon 默认是通过驼式命名
    
    @JsonProperty(value = "userName")
    private String userName;
 
    @JsonProperty(value = "userAge")
    private String userAge;
    
    // {"user_name":"sss", "user_age":"22"}
 
}

===

package com.sxz.entity;

import lombok.Data;

@Data
public class TestResponse {
     
    private String status;
 
    private String message;
 
    @Override
    public String toString() {
        return "TestResponse [status=" + status + ", message=" + message + "]";
    }
}

===

・请求(@path标注 的类、方法)

Jersey框架常用注解3:媒体类型注解@Consumes和@Produces_机器熊技术大杂烩的博客-CSDN博客_@consumes

package com.sxz.webapi.test;
 
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
import com.sxz.entity.TestRequest;
import com.sxz.entity.TestResponse;
 
@Path("/test")
public class UserRes {    
    //创建用户
    @Path("/createUser")
    @POST
    @Consumes(MediaType.APPLICATION_JSON+";charset=utf-8")
    @Produces(MediaType.APPLICATION_JSON+";charset=utf-8")
    public TestResponse add(final TestRequest test) {
        TestResponse response = new TestResponse();
        
        String userName = test.getUserName();
        String age = test.getUserAge();
        
        response.setMessage(userName + "---" + age);
        response.setStatus("1");
        
        return response ;
    }
}

====

・Maven

・POM---配置

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.sxz</groupId>
    <artifactId>webAPI</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <project.build.encoding>UTF-8</project.build.encoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <jersey.version>2.25</jersey.version>
    </properties>

    <dependencies>
        <dependency>
            <!--jersey服务端包,将 Jersey 当做 Servlet-->
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.25</version>
        </dependency>
        <dependency>
            <!--服务端核心包-->
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <!--客户端包,封装了一些客户端操作的类-->
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>${jersey.version}</version>
        </dependency>

        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.9.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <version>1.18.20</version>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <!--指定maven编译之后的war的文件名 -->
        <finalName>testWebAPI</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source><!-- 指定源代码使用的JDK版本 -->
                    <target>${java.version}</target><!-- 指定class文件的编译版本 -->
                    <encoding>${project.build.encoding}</encoding><!-- 指定字符集编码 -->
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>

                    <!--指定web.xml等文件所在位置 -->
                    <webXml>src/main/webapp/WEB-INF/web.xml</webXml>

                    <!--指定jsp等文件所在位置 -->
                    <!-- <warSourceDirectory>src\java\webapp</warSourceDirectory> -->

                </configuration>
            </plugin>

        </plugins>

    </build>
</project>

・Jar---POM---配置

=======================

=======================

・web.xml ( servlet 4.0 )

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    version="4.0" metadata-complete="true">

    <display-name>testWebAPI</display-name>

<!--注册jersey 框架 servlet-->
    <servlet>
        <!--Servlet配置-->
        <servlet-name>jerseyServlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

        <init-param>
            <!--包名-->
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.sxz.webapi.test</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>jerseyServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

===

■代码 (Spring boot)

===

・全部代码

・启动类

package com.sxz;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

・Bean(Entiry)

request

package com.sxz.entity;

import org.codehaus.jackson.annotate.JsonProperty;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestRequest {
 
    // JackSon 默认是通过驼式命名
    
    @JsonProperty("userName")
    private String userName;
 
    @JsonProperty("userAge")
    private String userAge;
    
    // {"user_name":"sss", "user_age":"22"}
 
}

response

package com.sxz.entity;

import lombok.Data;

@Data
public class TestResponse {
     
    private String status;
 
    private String message;
 
    @Override
    public String toString() {
        return "TestResponse [status=" + status + "message=" + message + "]";
    }
}

・Controler

package com.sxz.controler;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.sxz.entity.TestRequest;
import com.sxz.entity.TestResponse;

@RestController
public class TestController {

    @RequestMapping(value = "/createUser", consumes = "application/json;charset=utf-8", produces="application/json;;charset=utf-8")
    public TestResponse add(@RequestBody TestRequest test) {
        TestResponse response = new TestResponse();
        
        String userName = test.getUserName();
        String age = test.getUserAge();
        
        response.setMessage(userName + "---" + age);
        response.setStatus("1");
        
        return response ;
    }
}

・POM

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>sxz.com</groupId>
    <artifactId>restFul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>restFul</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.10.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.9.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <version>1.18.20</version>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

・YML

注意1:冒号后面要有一个半角空格(比如8081前面要有半角空格,不然无效)

注意2:不要混入全角空格(今天写代码的时候,不小心在servlet前面,写了一个全角空格,启动不报错,只是路径设定无效。)

server:
  port: 8081
  servlet:
    context-path: /testRest

注意3:区别yml和properties的写法,下面是properties的写法

server.port=8081
server.servlet.context-path=/testRest

===

・启动

Eclipse中启动

(右键工程,Run As -> java Application,选择Application类)

。。。
2023-03-04 19:57:59.656  INFO 17096 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2023-03-04 19:57:59.687  INFO 17096 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-03-04 19:57:59.688  INFO 17096 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.45]
2023-03-04 19:57:59.902  INFO 17096 --- [           main] o.a.c.c.C.[.[localhost].[/testRest]      : Initializing Spring embedded WebApplicationContext
2023-03-04 19:57:59.903  INFO 17096 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3322 ms
2023-03-04 19:58:00.379  INFO 17096 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2023-03-04 19:58:00.834  INFO 17096 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path '/testRest'
2023-03-04 19:58:00.856  INFO 17096 --- [           main] com.sxz.Application                      : Started Application in 6.017 seconds (JVM running for 7.866)
2023-03-04 19:58:21.844  INFO 17096 --- [nio-8081-exec-1] o.a.c.c.C.[.[localhost].[/testRest]      : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-03-04 19:58:21.846  INFO 17096 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-03-04 19:58:21.867  INFO 17096 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 20 ms

命令行启动

进入工程目录

cd C:\dev\workspace_202106\restFul

生成jar

mvn clean package -Dmaven.test.skip=true --settings C:\Name\Dev\Maven\repository\settings.xml

进入jar的目录

cd C:\dev\workspace_202106\restFul\target

运行jar

java -jar restFul-0.0.1-SNAPSHOT.jar

・Postman测试效果 (Spring boot)

http://localhost:8081/testRest/createUser

・测试效果 (使用 HttpClient)

结果

2023-03-21 22:03:23.917] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:28 ]
INFO:Begin--001

2023-03-21 22:03:23.957] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:64 ]
INFO:Begin--002

2023-03-21 22:03:26.319] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:75 ]
INFO:-----STATUS CODE :----

2023-03-21 22:03:26.320] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:76 ]
INFO:200

2023-03-21 22:03:26.323] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:81 ]
INFO:----Response Body-----

2023-03-21 22:03:26.324] [level: INFO] [Thread: main] [ Class:com.sxz.study.http.HttpClientTest >> Method: post:82 ]
INFO:{"status":"1","message":"张三---22---/C:/dev/workspace_202106/restFul/target/classes/"}

代码

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.6</version>
        </dependency>

--- HttpClient 【4.X】

package com.sxz.study.http;

import java.io.IOException;
import java.net.ConnectException;
import java.nio.charset.StandardCharsets;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HttpClientTest {

    public static void main(String[] args) {
        post();
    }

    public static void post() {
        log.info("Begin--001");

        // 创建httppost
        // HttpPost httpPost = new HttpPost("http://192.168.11.123:8081/testRest/createUser");
        HttpPost httpPost = new HttpPost("http://localhost:8081/testRest/createUser");

        // 解决httpclient超时设置不生效,附各版本设置方法
        // https://www.aqwdzy.com/content/99

        // Set Timeout Config
        RequestConfig requestConfig = RequestConfig.custom()
                // .setConnectionRequestTimeout(1033) // 指从连接池获取连接的timeout超出预设时间
                // 如果连接池里连接都被用了,且超过设定时间,
                // 就会报错 connectionrequesttimeout,会抛出超时异常
                // 如果是非连接池的话,该参数暂时没有发现有什么用处。
                //
                .setConnectTimeout(3000) // connectTimeOut就是指在进行三次握手行为时所设置的超时
                                            // 就是http请求的三个阶段,
                                            // 一:建立连接;
                                            // 二:数据传送;
                                            // 三,断开连接。
                                            //
                                            // "http://localhost:8081/testRest/createUser" 時無効
                                            //
                .setSocketTimeout(22000) // 指客户端从服务器读取数据的timeout超出预期设定时间,
                                            // 超出后会抛出SocketTimeOutException
                .build();
        httpPost.setConfig(requestConfig);

        // Set Header
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8");

        // Set Body
        String jsonStr = "{\"userName\":\"张三\", \"userAge\":\"22\"}";
        httpPost.setEntity(new StringEntity(jsonStr, StandardCharsets.UTF_8));

        log.info("Begin--002");

        try (
                // 创建默认的httpClient实例.
                CloseableHttpClient httpclient = HttpClients.createDefault();
                // Send Post
                CloseableHttpResponse response = httpclient.execute(httpPost);) {

            // 获取响应 Status
            Integer statusInt = response.getStatusLine().getStatusCode();

            log.info("-----STATUS CODE :----");
            log.info(statusInt.toString());
            // 获取响应 Body
            HttpEntity httpEntity = response.getEntity();
            String responseContent = EntityUtils.toString(httpEntity, "UTF-8");

            log.info("----Response Body-----");
            log.info(responseContent);

        } catch (ClientProtocolException e) {
            log.error("ClientProtocolException");
            e.printStackTrace();
        } catch (HttpHostConnectException e) {
            log.error("HttpHostConnectException");
            e.printStackTrace();
        } catch (java.net.UnknownHostException e) {
            log.error("UnknownHostException");
            e.printStackTrace();
        } catch (ConnectException e) {
            log.error("ConnectException");
            e.printStackTrace();
        } catch (java.net.SocketTimeoutException e) {
            log.error("SocketTimeOutException");
            e.printStackTrace();
        } catch (IOException e) {
            log.error("IOException");
            e.printStackTrace();
        }

    }

}

・控制Httpclient多余DebugLog不显示 --- logback

logback-spring.xml (无效,只是以Springboot工程时启动时,这个文件的配置才是有效的)

logback.xml (有效) (单独启动main方法)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <property name="CONSOLE_LOG_PATTERN" value="%n%d{yyyy-MM-dd HH:mm:ss.SSS}] [level: %p] [Thread: %t] [ Class:%c >> Method: %M:%L ]%n%p:%m%n"/>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <!--  
            <pattern><![CDATA[%n[%d{yyyy-MM-dd HH:mm:ss.SSS}] [level: %p] [Thread: %t] [ Class:%c >> Method: %M:%L ]%n%p:%m%n]]></pattern>
            -->
        </encoder>
    </appender>
    <appender name="LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern><![CDATA[%n[%d{yyyy-MM-dd HH:mm:ss.SSS}] [level: %p] [Thread: %t] [ Class:%c >> Method: %M:%L ]%n%p:%m%n]]></pattern>
        </encoder>
        <file>J:/logs/sxz-web.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>logs/sports-web.-%d{yyyyMMdd}.%i.log</fileNamePattern>
            <!-- 每天一个日志文件,当天的日志文件超过10MB时,生成新的日志文件,当天的日志文件数量超过totalSizeCap/maxFileSize,日志文件就会被回滚覆盖。 -->
            <maxFileSize>10MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy> 
    </appender>
    <logger name="com.sxz" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LOG_FILE"/>
        <!--<appender-ref ref="myAppender"/>-->
    </logger>
    
    <logger name="org.apache" level="WARN" />
    <logger name="httpclient" level="WARN" />
    
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="LOG_FILE"/>
        <!--<appender-ref ref="mqAppender"/>-->
    </root>
</configuration>

====

■测试时使用的工具

1.postman

・请求 header 设定

“KEY:VALUE"

“Content-type:application/json; charset=utf-8”
“Accept: application/json; charset=utf-8“

===

・请求 Body(JSON情报设定)

选择【body】⇒ 【raw】

然后把 JSON 字符串复制进去。

・Postman运行效果 (本文代码)


对应代码

====

・启动失败时,重新安装Postman的方法( 删除的目录)

C:\Users\<user>\AppData\Local\Postman
C:\Users\<user>\AppData\Roaming\Postman

===

・Postman获取cookie

Postman调接口时获取Chrome浏览器Cookie数据携带发送
(前提:Chrom浏览器下载安装插件Postman Interceptor)

Postman调接口时获取Chrome浏览器Cookie数据携带发送_postman获取浏览器cookie_WziH_CSDN的博客-CSDN博客

==

2.SoapUI(PT测试(压力测试时使用))

一些很好的工具软件~_capt_st-CSDN博客

===

■证明书(从xx.P12文件中证书提取,Postman导入证书)

・从xxxx.p12文件(客户端证明书的密码)中,生成「crt file」、「key file」

(旧版本无法使用 xxx.p12, 需要使用 crt 和key者两个文件)

(在Linux或者AIX Server中,都有openssl这个命令)

导出公钥(证书)(crt)

openssl pkcs12 -in YourCert.p12 -clcerts -nokeys -out cert.crt

输入YourCert.p12的密码

导出秘钥(key)

openssl pkcs12 -in YourCert.p12 -nodes -nocerts -out private_key.key

输入YourCert.p12的密码

(选项-nodes不是英文单词“nodes”,而是“no DES”。 当作为参数给出时,这意味着OpenSSL不会encryptionPKCS#12文件中的私钥)

・直接使用 PXF File ( xxx.p12 文件 )

(新版本可以直接使用 xxx.p12)
(如果有秘密,在Postman中,指定密码)

(HttpClient的代码,可以直接使用xxx.p12这个文件)

===

■その他

・Jersey

Jersey RESTful 框架是开源的RESTful框架, 实现了JAX-RS (JSR 311 & JSR 339) 规范。它扩展了JAX-RS 参考实现, 提供了更多的特性和工具, 可以进一步地简化 RESTful service 和 client 开发。尽管相对年轻,它已经是一个产品级的 RESTful service 和 client 框架。与Struts类似,它同样可以和hibernate,spring框架整合。

jersey1.X使用的是sun的com.sun.jersey

jersey2.X使用的是glassfish的org.glassfish.jersey

・Log4J

<appender name="xxxLogAppender" class="org.apache.log4j.FileAppender"> ... </appender>

===

private Logger xxxLog;

。。。

xxxLog = Logger.getLogger("xxxLog");

===

・SPI技术

02)java web项目 使用spi技术 去除web.xml_影子2401的博客-CSDN博客_spi web

===

・把Maven項目转换为web项目

转换

将普通Maven项目改成Web项目的步骤_Ringo爸爸的博客-CSDN博客_将项目改成web项目的方法

恢复时遇到的问题以及解决

问题

Dynamic Web Module 4.0 cannot be uninstalled.

解决

.settings/org.eclipse.wst.common.project.facet.core.xml 并通过删除以下行手动卸载

<installed facet="jst.web" version="4.0"/>

====

・指定JDK8启动Tomcat9

(使用JDK11启动tomcat9,本次的工程启动报错,指定jdk8就OK了)

set JAVA_HOME="C:\Progra~1\Java\jdk1.8.0_191"
C:
cd "C:\YourName\Program Files\apache-tomcat-9.0.0.M13\bin"
startup.bat

pause

===

・获取运行的类,所在的路径

获取运行的class文件,所在的目录_sun0322的博客-CSDN博客

・获取运行的类,所在的主机信息

package com.sxz.system.info;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class SystemInfo {

    public static void main(String[] args) {
        // 创建本地主机的InetAddress对象
        InetAddress inetAddr;
        try {
            inetAddr = InetAddress.getLocalHost();

            // 获得本地主机的IP地址
            String ip = inetAddr.getHostAddress();
            // 获得本机的名称
            String HostName = inetAddr.getHostName();
            // 获得本机的域名
            String canonicalHostName = inetAddr.getCanonicalHostName();
            System.out.println("本机的IP为:" + ip);
            System.out.println("本机的名称为:" + HostName);
            System.out.println("本机的域名为:" + canonicalHostName);

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

====

・获取运行的类,所在的主机信息

org.codehaus.jackson.map.ObjectMapper
。。。
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(Object obj);

・介绍一下 TLS、SSL、SSH 之间的联系与区别

TLS(Transport Layer Security),SSL(Secure Sockets Layer)和SSH(Secure Shell)是三种网络安全协议,用于保护网络通信的安全性。尽管它们的目标相似,但在协议的实现和使用方面存在一些区别。

  1. TLS(Transport Layer Security):TLS是一种加密协议,用于在通信双方之间建立加密连接,确保数据的机密性和完整性。它广泛应用于Web浏览器和服务器之间的安全通信,例如HTTPS(基于HTTP的安全通信)。TLS提供了多种加密和身份验证机制,是一种更高级的安全协议,取代了较旧的SSL协议。
  2. SSL(Secure Sockets Layer):SSL是TLS的前身,早期用于保护通信双方之间的数据传输安全。SSL在互联网上广泛使用,用于安全地传输敏感信息,例如信用卡号码、登录凭证等。然而,由于一系列的漏洞和安全问题,SSL已逐渐被TLS所取代。目前,SSLv3已被广泛弃用,推荐使用TLS版本 (如TLS 1.3)以确保安全性。
  3. SSH(Secure Shell):SSH是一种基于加密的网络协议,用于在网络上安全地执行远程命令和文件传输。SSH提供身份验证、数据加密和完整性保护,可以用于远程登录和文件传输等各种网络操作。SSH协议专为安全性而设计,可替代不安全的传统协议(如Telnet等)。

虽然TLS、SSL和SSH都提供安全性保护,但它们的工作方式和应用场景略有不同。TLS和SSL主要用于保护Web浏览器和服务器之间的通信安全,而SSH用于安全地执行远程命令和文件传输。此外,TLS是一种更高级的加密协议,而SSL是早期版本的TLS。

・用語

1.オンプレミス(英:on-premises) // クラウドじゃない方
2.Interceptor 英 [ˌɪntəˈsɛptə] 阻止的人,妨碍者,拦截战斗机

3.RESTful (REST式的)

REST(Representation State Transfer):资源表述性状态转移,是一种结构风格。

・Resource:
“资源”,网络上的一个实体,或者说网络上一个具体信息。它可以是一段文字、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URL(统一资源定位符)指向它,每种资源对应一个特定的URL。要获取这个资源,访问它的URL就可以,因此URL就成了每一个资源地址或独一无二的识别符。(一切皆资源,URL用于资源的唯一标识)。

・Representation:
“资源”是一种信息实体,它可以有多种外在表现形式。我们把资源具体呈现出来的形式,叫做它的“表现层”。比如:文本可以用txt格式、HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用jpg、png、gif格式表现。(1.资源以什么样的表现形式呈现出来2.资源的表现层一般都在请求头信息中体现出来)。

・State Transfer:
访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态变化。互联网通信协议HTTP协议,是一个无状态的协议。这意味着,所有状态都保存在服务端。因此,如果客户端要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(state Transfer)。

而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。(1.在客户端和服务器的交互过程中,涉及到状态的转化,我们通过某种手段(ajax、form)让它进行转换)。

4.盐(Salt),SaltValue

・説明
在密码学中,是指在散列之前将散列内容(例如:密码)的任意固定位置插入特定的字符串。
这个在散列中加入字符串的方式称为“加盐”。
其作用是让加盐后的散列结果和没有加盐的结果不相同,在不同的应用情景中,这个处理可以增加额外的安全性。

・経緯
由于用户密码位数不足,短密码的散列结果很容易被彩虹表破解,因此,在用户的密码末尾添加特定字符串

・その他
彩虹表是一个用于加密散列函数逆运算的预先计算好的表, 为破解密码的散列值(或称哈希值、微缩图、摘要、指纹、哈希密文)而准备。一般主流的彩虹表都在100G以上。

5.2023_0315

=======
1.カタログ catalogue;商品目录。营业指南。
2.コンサルティング 【英】consulting;(接受)咨询,指回答专门事项的商谈
3.パラドックス paradox n. 自相矛盾的人或事;悖论
// 杀虫剂悖论 对软件进行越多的测试,那么该软件对软件测试人员的测试就越具有免疫力
4.二次元コード // QRコード
5.アルゴリズム algorithm 算法 [ˈælɡəˌrɪðəm]
6.AES 高级加密标准(Advanced Encryption Standard,AES)
7.インシデント 偶发事件,意外事件; // 障害
8.digest 英 [ˈdaɪˌdʒɛst] n. 摘要 v. 消化;领悟,理解 // MessageDigest
MD5
SHA-1
SHA-256
SHA-512
=======

6.

・EJB,WebSphere

JPA、EJB、事物管理---相关内容整理_jpa和ejb_sun0322的博客-CSDN博客

===

・通信関連(SSL、TLS)

・SSL(Secure Socket Layer)是指安全套接字层
・TLS(Transport Layer Security)是更为安全的升级版 SSL
・HTTPS,也称作HTTP over TLS。TLS的前身是SSL
・IHS(IBM HTTP Server)
・junction 英 [ˈdʒʌŋkʃn] n. 交叉路口,汇合处;连接;接合点

・对于Java 8应该是TLS 1.2,对于Java 7应该是TLS 1.0

关于ssl:Java HttpsURLConnection和TLS 1.2 | 码农家园

1.8

 SSLContext sc = SSLContext.getInstance("TLSv1.2");
 // Init the SSLContext with a TrustManager[] and SecureRandom()
 sc.init(null, trustCerts, new java.security.SecureRandom());
 
 httpsCon.setSSLSocketFactory(sc.getSocketFactory());

1.7

 SSLContext sc = SSLContext.getInstance("TLSv1");
 // Init the SSLContext with a TrustManager[] and SecureRandom()
 sc.init(null, trustCerts, new java.security.SecureRandom());
 
 httpsCon.setSSLSocketFactory(sc.getSocketFactory());

==

・AES加密,信息摘要(MD5,SHA)獲取

高级加密标准(Advanced Encryption Standard,AES)

AES加密、MD5、SHA256等散列生成(java代码)_sun0322的博客-CSDN博客

===

・JSONUtil (【Json字符串】与【对象】 之间的互相转换)

package com.sxz.json;

import java.io.IOException;

import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;

public class JsonUtilTest {

    public static void main(String[] args) {
        TestBean bean = new TestBean();
        bean.setTestAge("22");
        bean.setTestName("Zhang San");
        String jsonStr = objTOStr(bean);
        System.out.println(jsonStr);
        // {"TEST_NAME":"Zhang San","testAge":"22","testName":"Zhang San"}
        
        // JSON ⇒ Object 【Test1】        // 【結果】 22
        String str1 = "{\"TEST_NAME\":\"Zhang San\",\"testAge\":\"22\",\"testName\":\"Zhang San\"}";
        TestBean bean1 = strToObj(str1,TestBean.class );
        System.out.println(bean1.getTestAge());   
        
        // JSON ⇒ Object 【Test2】        // 【結果】 null
        String str2 = "{}";
        TestBean bean2 = strToObj(str2,TestBean.class );
        System.out.println(bean2.getTestAge()); 
        
        // JSON ⇒ Object 【Test3】       // 【結果】 java.io.EOFException: No content to map to Object due to end of input
        String str3 = "";
        TestBean bean3 = strToObj(str3,TestBean.class );
        System.out.println(bean3.getTestAge());

    }
    
    static ObjectMapper objectMapper=new ObjectMapper();
 
    /**
     * 对象转字符串
     * @param obj
     * @return
     */
        public static String objTOStr(Object obj){
            try {
                String s = objectMapper.writeValueAsString(obj);
                return s;
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
        }
 
 /**
     * 字符串转对象
     * @param obj
     * @return
     */
        public static <T> T strToObj(String str,Class<T> clazz){
            try {
                T t = objectMapper.readValue(str, clazz);
                return t;
            }  catch (JsonProcessingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
 
        }

}

===

・JSON

└POM(坑)↓

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.8.6</version>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.8.6</version>
    </dependency>

{"TEST_NAME":"张三","testName":"张三","testAge":"99"}

坑的解决方式:

=============

1.更改标签的位置

 去掉,属性变量的【@JsonProperty("TEST_NAME")】标签

  在属性的get和set方法上,添加【@JsonProperty("TEST_NAME")】标签

2.使用新版本的jar包 ↓

=============

└POM (无坑)↓

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-core-asl</artifactId>
        <version>1.9.13</version>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>

{"testName":"张三","TEST_NAME":"张三",}

Bean

package com.sxz.json;

import org.codehaus.jackson.annotate.JsonProperty;

public class TestBean {
    
    @JsonProperty("TEST_NAME")
    private String testName;
    
    private String testAge;

    public String getTestName() {
        return testName;
    }

    public void setTestName(String testName) {
        this.testName = testName;
    }

    public String getTestAge() {
        return testAge;
    }

    public void setTestAge(String testAge) {
        this.testAge = testAge;
    }
    
    

}

Main

package com.sxz.json;

import java.io.IOException;

import org.codehaus.jackson.map.ObjectMapper;

public class TestJson {
    
    public static void main(String[] args) {
        
        TestBean bean = new TestBean();
        
        bean.setTestName("张三");
        bean.setTestAge("99");

        
        ObjectMapper mapper = new ObjectMapper();
        
        try {
            String jsonStr = mapper.writeValueAsString(bean);
            System.out.println(jsonStr);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }

}

■浏览器 CROS Pplicy相关

提供 webAPI 时,是否需要考虑 CORS

(当调用方,在页面使用 Ajax 等方式访问时,受到同源策略限制)

是的,当提供Web API时,需要考虑跨域资源共享(CORS)策略。

CORS是一种安全机制,用于限制跨域请求(来自不同源的请求)的访问权限。默认情况下,浏览器会阻止跨域请求,以防止恶意行为或安全问题。

如果你的Web API需要被跨域访问,你可以在服务器端进行CORS配置。以下是一些考虑的要点:

  1. Access-Control-Allow-Origin:在响应头中添加该字段,指定允许访问API的域名。可以配置为特定的域名或通配符"*"表示允许任何域名的访问。
  2. Access-Control-Allow-Methods:指定允许的HTTP方法(例如GET、POST、PUT等)。
  3. Access-Control-Allow-Headers:指定允许的请求头。
  4. Access-Control-Expose-Headers:指定允许客户端获取的响应头。
  5. Access-Control-Allow-Credentials:如果API需要使用身份验证或设置cookie等敏感信息,需要将此字段设置为true,表示允许发送跨域请求时携带凭据。
  6. 预检请求(Preflight Request):对于某些复杂请求(例如带有自定义头部或使用PUT或DELETE方法等),浏览器会先发送一个OPTIONS请求进行预检。服务器需要正确处理这个请求,并返回合适的CORS响应。

配置CORS时,需要根据具体的应用程序和安全需求进行设置。确保在允许跨域访问时仍保持适当的安全性,避免潜在的安全漏洞和攻击。

xxx

PostMan 访问 WebAPI时, 为什么没有设置 CORS,也能正常访问

Postman 是一个用于测试和开发 API 的工具,它是一个独立的应用程序并不受浏览器的限制。因此,它可以绕过浏览器的同源策略,并且不会受到缺少 CORS 设置的影响。

与浏览器不同,Postman 不会对跨域请求进行限制,因此即使 Web API 没有设置 CORS,Postman 也能正常访问该 API。这对于测试和调试 API 来说是非常方便的,因为你可以在开发阶段灵活地测试不同的请求,而无需关注跨域限制。

但是需要注意的是,当在真实的前端应用程序中使用该 API 时,如果跨域资源共享(CORS)未正确配置,浏览器会限制该 API 的访问。因此,在生产环境中仍然需要正确设置 CORS,以确保其他客户端能够正常访问你的 API。

xxx

HTTP页面访问 webAPI ,使用 get请求 代码如何写,

// 使用 XMLHttpRequest 对象发送 GET 请求
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/api_endpoint", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    var response = JSON.parse(xhr.responseText);
    console.log(response);
  }
};
xhr.send();

// 使用 Fetch API 发送 GET 请求
fetch("https://api.example.com/api_endpoint", {
  method: "GET"
}).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function(error) {
  console.error(error);
});

xxx

使用Java 的第三方 jar 包 httpclient 访问 Web API 时,是否需要考虑 CORS

当使用Java的第三方库HttpClient访问Web API时,通常不需要直接考虑CORS(跨域资源共享)问题。CORS是浏览器的安全机制,用于限制跨域请求,而HttpClient是在服务端运行的库,没有受到浏览器限制。

xxx

为什么 访问 被浏览器的 CORS 策略阻止之后, Status 还是200

当浏览器的CORS策略阻止跨域请求时,它实际上是阻止浏览器将响应返回给JavaScript代码,而不是阻止服务器对请求的响应。因此,无论响应的状态是什么,都会返回200(OK)状态码。

CORS策略是浏览器机制的一部分,用于提供额外的安全性,防止恶意网站获取到其他网站的数据,从而保护用户的信息安全。当浏览器接收到跨域请求时,会发送一个预检请求(OPTIONS请求),由服务器返回相应的CORS头部信息。如果服务器返回的CORS头部信息不符合浏览器指定的安全策略,浏览器会阻止JavaScript代码获取响应内容,并抛出CORS相关的错误。

因此,虽然在服务器端看到的请求的状态码可能是200,但对于通过浏览器发起的跨域请求,浏览器会阻止JavaScript代码对响应内容的访问。需要注意的是,这种情况下,服务器返回的数据仍然会被浏览器接收到,只是阻止了JavaScript代码访问,所以对于通过浏览器进行的跨域请求,需要在服务器端进行相应的处理,如配置适当的CORS头部信息以允许跨域请求。

比如,使用下面代码,创建一个HTML页面,对某个WebAPI发送请求时,

<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/api_endpoint", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    var response = JSON.parse(xhr.responseText);
    console.log(response);
  }
};
xhr.send();
</script>

服务器端是可以接收到请求的,

如果上面的第三行,

是一个 存在的GET请求的URL,则会返回 200,

是一个不存在的GET请求的URL,则会返回 404,

xxx

====

■JSON变换

JSON变换工具类

package com.sxz.json;

import java.io.IOException;

import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.map.ObjectMapper;

public class JsonUtil {
    
    public static <T> String objToJson(T obj) {
        
        ObjectMapper mapper = new ObjectMapper();

        // 目的、下記の②になる
        // ①:{"TEST_NAME":"张三","testName":"张三","testAge":"99"}
        // ②:{"TEST_NAME":"张三","testAge":"99"}
        mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
                .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
                .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
                .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));

        try {
            return mapper.writeValueAsString(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return null;

    }
    
    
    public static <T> T jsonToObj(String strJson, Class<T> clas) {
        
        ObjectMapper mapper = new ObjectMapper();

        try {
            return mapper.readValue(strJson, clas);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

====

调用--->变换工具类

package com.sxz.json;

import java.io.IOException;

import org.codehaus.jackson.map.ObjectMapper;

public class TestJson {
    
    public static void main(String[] args) {
        
        TestBean bean = new TestBean();
        
        bean.setTestName("张三");
        bean.setTestAge("99");

        
        ObjectMapper mapper = new ObjectMapper();
        
        try {
            String jsonStr = mapper.writeValueAsString(bean);
            System.out.println(jsonStr);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        System.out.println(JsonUtil.objToJson(bean));
        
    }

}

以上代码运行结果

{"TEST_NAME":"张三","testAge":"99","testName":"张三"}
{"TEST_NAME":"张三","testAge":"99"}

====

使用到的Bean

package com.sxz.json;

import org.codehaus.jackson.annotate.JsonProperty;

public class TestBean {
    
    @JsonProperty("TEST_NAME")
    private String testName;
    
    private String testAge;

    public String getTestName() {
        return testName;
    }

    public void setTestName(String testName) {
        this.testName = testName;
    }

    public String getTestAge() {
        return testAge;
    }

    public void setTestAge(String testAge) {
        this.testAge = testAge;
    }
    
    

}

===

■发送JSON数据

get请求发送

        HttpGet httpGet = new HttpGet("http://example.com/api?data=" + encodedJsonData);
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class Main {
    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            // 创建JSON数据
            String jsonData = "{\"name\": \"John\", \"age\": 30}";

            // 将JSON数据编码为URL安全的字符串
            String encodedJsonData = URLEncoder.encode(jsonData, StandardCharsets.UTF_8.toString());

            // 创建HttpGet对象,并将JSON数据作为URL的一部分
            HttpGet httpGet = new HttpGet("http://example.com/api?data=" + encodedJsonData);

            // 发送请求
            CloseableHttpResponse response = httpClient.execute(httpGet);

            // 获取响应体
            HttpEntity responseEntity = response.getEntity();
            String responseBody = EntityUtils.toString(responseEntity);
            System.out.println("Response: " + responseBody);

            // 关闭响应
            response.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭HttpClient
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

post请求发送

        StringEntity entity = new StringEntity(jsonData, ContentType.APPLICATION_JSON);
         httpPost.setEntity(entity);
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class Main {
    public static void main(String[] args) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            // 创建JSON数据
            String jsonData = "{\"name\": \"John\", \"age\": 30}";

            // 创建HttpPost对象
            HttpPost httpPost = new HttpPost("http://example.com/api");

            // 设置请求头为application/json
            httpPost.setHeader("Content-Type", "application/json");

            // 设置JSON数据
            StringEntity entity = new StringEntity(jsonData, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);

            // 发送请求
            CloseableHttpResponse response = httpClient.execute(httpPost);

            // 获取响应体
            HttpEntity responseEntity = response.getEntity();
            String responseBody = EntityUtils.toString(responseEntity);
            System.out.println("Response: " + responseBody);

            // 关闭响应
            response.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 关闭HttpClient
                httpClient.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

windows中使用curl发送json请求

【精选】常用 doc bat 命令总结_doc命令大全-CSDN博客

curl.exe -X POST -H "Content-Type: application/json" -d "{\"key1\": \"value1\", \"key2\": \"value2\"}" http://example.com/api/endpoint

-X POST:指定 HTTP 请求方法为 POST。

-H "Content-Type: application/json":设置请求头部的 Content-Type 为 application/json,指定请求体的数据格式为 JSON。

-d "{"key1": "value1", "key2": "value2"}":发送 JSON 数据作为请求体。将键值对包装在双引号中,并确保 JSON 格式是有效的。在 Windows 的 cmd 中,需要使用反斜杠 \ 对双引号进行转义。

http://example.com/api/endpoint:指定请求的目标 URL(替换为实际的目标 URL)。

===

■Socket套接字,创建服务,建立连接

前言:

有各种各样的服务,有的服务是WebAPI restFul实现,

还有的服务,使用Socket建立服务实现。

1.1. SVF Connect for Java API 的功能概述 (wingarc.com.cn)

1.1. SVF Connect for Java APIの機能概要 (wingarc.com)

==

2.4.2. Java 版 SVF 执行部用于连接的 runtime(Socket)的设置 (wingarc.com.cn)

===各种文档一览

SVF Ver. 10 (wingarc.com)

==

通信流程

====

服务器端代码,创建服务

package com.sxz.study.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
 
public class Server {
    public static void main(String[] args) {
        try {
            // 创建ServerSocket对象,指定监听的端口号
            ServerSocket serverSocket = new ServerSocket(51233);
 
            System.out.println("服务器端【开始】运行。。。。。。。。。。。。。。。。。。。。。。。");
            System.out.println("等待客户端连接...");
 
            // 监听客户端的连接请求
            Socket clientSocket = serverSocket.accept();
            System.out.println("客户端已连接");
 
            // 获取输入流和输出流 输入流和输出流是通过socket对象来进行数据传输的。
            BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
 
            String message;
 
            while (true) {
                // 读取客户端发送的信息
                message = in.readLine();
 
                if (message.equalsIgnoreCase("exit")) {
                    // 如果接收到终止标志,退出循环
                    System.out.println("服务器端【停止】运行。。。。。。。。。。。。。。。。。。。。。。。");
                    // 通知客户端,停止运行
                    out.println("服务器端已【停止】运行:");
                    break;
                }
 
                System.out.println("收到客户端消息:" + message);
 
                // 发送响应给客户端
                out.println("已收到你的消息:" + message);
            }
 
            // 关闭连接
            clientSocket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

====

客户端代码,建立连接

import java.net.Socket;

。。。

            // 创建Socket对象,指定服务端的IP地址和端口号
            Socket socket = new Socket(SERVER_IP, 51233);

===

package com.sxz.study.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
 
public class Client {
    
    
// 【Server】  【Client】
//    创建Socket:使用Socket API创建一个Socket对象,指定协议类型和通信模式。
//    绑定端口:将Socket绑定到本地的IP地址和端口号上。
//    监听连接请求(仅服务器端):对于服务器端,调用Socket API监听来自客户端的连接请求。
//    建立连接(仅客户端):对于客户端,调用Socket API与服务器端建立连接。
//    数据传输:通过Socket发送和接收数据。
//    关闭连接:在通信结束后,关闭Socket连接。

    public static String SERVER_IP = "127.0.0.1";
    
    public static void main(String[] args) {
        try {
            // 创建Socket对象,指定服务端的IP地址和端口号
            Socket socket = new Socket(SERVER_IP, 51233);
 
            // 获取输入流和输出流 输入流和输出流是通过socket对象来进行数据传输的。
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
 
            // 从控制台读取用户输入
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String message;
 
            while (true) {
                System.out.println("请输入要发送的信息(输入 'exit' 退出):");
                message = reader.readLine();
 
                if (message.equalsIgnoreCase("exit")) {
                    // 如果用户输入 'exit',发送终止标志给服务端并退出循环
                    out.println("exit");
                    
                    String response = in.readLine();
                    System.out.println("服务端响应:" + response);
                    break;
                }
 
                // 将用户输入的信息发送给服务端
                out.println(message);
 
                // 接收服务端的响应并打印
                String response = in.readLine();
                System.out.println("服务端响应:" + response);
            }
 
            // 关闭连接
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

====

运行效果

服务启端


--

Socket clientSocket = serverSocket.accept();

这行代码是在服务端程序中执行的,它的作用是让服务端程序等待并接受来自客户端的连接请求。

当客户端尝试连接到服务端时,**

serverSocket.accept()

方法会阻塞程序的执行**,直到有客户端成功连接到服务端,此时

serverSocket.accept()

会返回一个新的

Socket

对象

clientSocket

,用来代表和客户端的通信。因此,这行代码表示服务端已经成功接受了客户端的连接请求,并进行了socket通信的建立。

端口使用情况

上半部分为开启服务器端 后的 端口使用情况


客户端



服务器端代码,创建服务(多用户)

上面代码,支支持单用户访问,多用户时,使用如下代码

Java多线程实现多用户与服务端Socket通信_java 实现socket通信-CSDN博客

--

/*
 * TCPThreadServer.java
 * Copyright (c) 2020-11-02
 * author : Charzous
 * All right reserved.
 */
 
package chapter05;
 
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class TCPThreadServer {
    private int port =8008;//服务器监听窗口
    private ServerSocket serverSocket;//定义服务器套接字
    //创建动态线程池,适合小并发量,容易出现OutOfMemoryError
    private ExecutorService executorService=Executors.newCachedThreadPool();
 
    public TCPThreadServer() throws IOException{
        serverSocket =new ServerSocket(8008);
        System.out.println("服务器启动监听在"+port+"端口...");
 
    }
 
    private PrintWriter getWriter(Socket socket) throws IOException{
        //获得输出流缓冲区的地址
        OutputStream socketOut=socket.getOutputStream();
        //网络流写出需要使用flush,这里在printWriter构造方法直接设置为自动flush
        return new PrintWriter(new OutputStreamWriter(socketOut,"utf-8"),true);
    }
 
    private BufferedReader getReader(Socket socket) throws IOException{
        //获得输入流缓冲区的地址
        InputStream socketIn=socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn,"utf-8"));
    }
 
    //多客户版本,可以同时与多用户建立通信连接
    public void Service() throws IOException {
        while (true){
            Socket socket=null;
                socket=serverSocket.accept();
                //将服务器和客户端的通信交给线程池处理
                Handler handler=new Handler(socket);
                executorService.execute(handler);
            }
    }
 
 
    class Handler implements Runnable {
        private Socket socket;
 
        public Handler(Socket socket) {
            this.socket = socket;
        }
 
        public void run() {
            //本地服务器控制台显示客户端连接的用户信息
            System.out.println("New connection accept:" + socket.getInetAddress());
            try {
                BufferedReader br = getReader(socket);
                PrintWriter pw = getWriter(socket);
 
                pw.println("From 服务器:欢迎使用服务!");
 
                String msg = null;
                while ((msg = br.readLine()) != null) {
                    if (msg.trim().equalsIgnoreCase("bye")) {
                        pw.println("From 服务器:服务器已断开连接,结束服务!");
 
                        System.out.println("客户端离开。");
                        break;
                    }
 
                    pw.println("From 服务器:" + msg);
                    pw.println("来自服务器,重复消息:"+msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (socket != null)
                        socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws IOException{
        new TCPThreadServer().Service();
    }
 
}
 
 

===

■TODO【已完成】

================

业务:

①A系统 ⇒ B系统 ⇒ C系统 ⇒本系统(insert/update API)⇒ B系统 (API https)⇒ (insert/update)B系统中 【XXX 数据库】

②X系统 ⇒ B系统 ⇒ C系统 ⇒ 本系统

按照要件,C系统 不做任何修改

================

1.B系统、有(权威机构认证的)证书?

           没有的话,B系统的证明书,是否已经导入到(本系统的)JDK的cacerts 中?

2.saop,json混在?

        ⇒ 根据 B系统 API 的 I/F 不使用SOAP,使用JSON

3.暗号化 有无已有代码

4.①里面真的需要update吗?

         如果需要, 在那个系统里面,什么时点调用?

        ⇒ 需要

5.B系统   提供了 insert I/F 接口。

        但是,按照现在的要件,B系统 并没有 提供  update I/F 接口 !!!

6.如何确认是 ① 这条流来的数据

(!!!注意:按照要件,C系统 不做任何修改)

(重点确认,能否根据,传递到 **本系统(insert/update API)** 的某个字段,来确认是: ① 这条流来的数据。  )

7.HttpClient和RestTemplate使用哪一个。(看看POM是否有已经引用的jar)

8.【XXX 数据库】和 【 A系统 】 有什么关系,看起来并不是一个系统。

9.org.apache.openjpa.persistence.EntityNotFoundException // type oid

可能发生的方法【org.apache.openjpa.persistence.OpenJPAEntityManager.find()】

org.apache.openjpa.persistence.OpenJPAEntityManager.find()方法的使用及代码示例_其他_NULL123

@SuppressWarnings({"unchecked"})
private void reindexOid(OpenJPAId oid, OpenJPAEntityManager em, CompassSession session) {
  try {
    Object o = em.find(oid.getType(), oid.getIdObject());
    reindex(o, session);
  } catch (EntityNotFoundException e) {
    delete(oid, session);
  }
}

⇒ 已经解决

JPA、EJB、事务管理、WebSphere ---相关内容整理_ejb jpa_sun0322的博客-CSDN博客

========

标签: https 网络协议 http

本文转载自: https://blog.csdn.net/sxzlc/article/details/128878523
版权归原作者 sun0322 所有, 如有侵权,请联系我们删除。

“java处理,调用外系统的 WebAPI(https请求)时,相关知识整理”的评论:

还没有评论