2024年8月

本文介绍基于
Python
语言,读取
Excel
表格文件,基于我们给定的规则,对其中的数据加以
筛选
,将
不在指定数据范围内
的数据剔除,保留
符合我们需要
的数据的方法。

首先,我们来明确一下本文的具体需求。现有一个
Excel
表格文件(在本文中我们就以
.csv
格式的文件为例),如下图所示。

image

其中,
Excel
表格文件具有大量的数据,
每一列
表示某一种
属性

每一行
表示某一个
样本
;我们需要做的,就是对于其中的部分属性加以数据筛选——例如,我们希望对上图中第一列的数据进行筛选,将其中大于
2
或小于
-1
的部分选出来,并将
每一个所选出的单元格
对应的

直接删除;同时,我们还希望对其他的属性同样加以筛选,不同属性筛选的条件也各不相同,但都是需要将不符合条件的单元格所在的
整行
都删除。最终,我们保留下来的数据,就是符合我们需要的数据,此时我们需要将其保存为一个新的
Excel
表格文件。

明白了需求,我们即可开始代码的撰写;本文用到的具体代码如下所示。

# -*- coding: utf-8 -*-
"""
Created on Wed Jun  7 15:40:50 2023

@author: fkxxgis
"""

import pandas as pd

original_file = "E:/01_Reflectivity/99_Model_Training/00_Data/02_Extract_Data/23_Train_model_NoH/Train_Model_1_NoH.csv"
result_file = "E:/01_Reflectivity/99_Model_Training/00_Data/02_Extract_Data/23_Train_model_NoH/Train_Model_1_NoH_New.csv"

df = pd.read_csv(original_file)

df = df[(df["inf"] >= -0.2) & (df["inf"] <= 18)]
df = df[(df["NDVI"] >= -1) & (df["NDVI"] <= 1)]
df = df[(df["inf_dif"] >= -0.2) & (df["inf_dif"] <= 18)]
df = df[(df["NDVI_dif"] >= -2) & (df["NDVI_dif"] <= 2)]
df = df[(df["soil"] >= 0)]
df = df[(df["inf_h"] >= -0.2) & (df["inf_h"] <= 18)]
df = df[(df["ndvi_h"] >= -1) & (df["ndvi_h"] <= 1)]
df = df[(df["inf_h_dif"] >= -0.2) & (df["inf_h_dif"] <= 18)]
df = df[(df["ndvi_h_dif"] >= -1) & (df["ndvi_h_dif"] <= 1)]

df.to_csv(result_file, index = False)

下面是对上述代码每个步骤的解释:

  1. 导入必要的库:导入了
    pandas
    库,用于数据处理和操作。
  2. 定义文件路径:定义了原始文件路径
    original_file
    和结果文件路径
    result_file
  3. 读取原始数据:使用
    pd.read_csv()
    函数读取原始文件数据,并将其存储在
    DataFrame
    对象
    df
    中。
  4. 数据筛选:对
    DataFrame
    对象
    df
    进行多个条件的筛选操作,使用了逻辑运算符
    &
    和比较运算符进行条件组合。例如,其中的第一行
    df["inf"] >= -0.2

    df["inf"] <= 18
    就表示筛选出
    "inf"
    列的值在
    -0.2

    18
    之间的数据;第二行
    df["NDVI"] >= -1

    df["NDVI"] <= 1
    则表示筛选出
    "NDVI"
    列的值在
    -1

    1
    之间的数据,以此类推。
  5. 保存结果数据:使用
    to_csv()
    函数将筛选后的
    DataFrame
    对象
    df
    保存为新的
    .csv
    文件,保存路径为
    result_file
    ,并设置
    index=False
    以避免保存索引列。

当然,如果我们需要对
多个属性
(也就是
多个列
)的数据加以筛选,除了上述代码中的方法,我们还可以用如下所示的代码,较之前述代码会更方便一些。

result_df = result_df[(result_df["blue"] > 0) & (result_df["blue"] <= 1) &
                              (result_df["green"] > 0) & (result_df["green"] <= 1) &
                              (result_df["red"] > 0) & (result_df["red"] <= 1) &
                              (result_df["inf"] > 0) & (result_df["inf"] <= 1) &
                              (result_df["NDVI"] > -1) & (result_df["NDVI"] < 1) &
                              (result_df["inf_dif"] > -1) & (result_df["inf_dif"] < 1) &
                              (result_df["NDVI_dif"] > -2) & (result_df["NDVI_dif"] < 2) &
                              (result_df["soil"] >= 0) &
                              (result_df["NDVI_dif"] > -2) & (result_df["NDVI_dif"] < 2) &
                              (result_df["inf_h_dif"] > -1) & (result_df["inf_h_dif"] < 1) &
                              (result_df["ndvi_h_dif"] > -1) & (result_df["ndvi_h_dif"] < 1)]

上述代码可以直接对
DataFrame
对象加以一次性的筛选,不用
每筛选一次就保存一次
了。

运行本文提及的代码,我们即可在指定的结果文件夹下获得数据筛选后的文件了。

至此,大功告成。

1.方法一:使用
sqlparse
库的方法

为了提取SQL语句中
WHERE
子句的值,我们可以利用Python的
sqlparse
库,这是一个专门用于解析SQL语句的库。以下是一个示例代码,演示如何使用
sqlparse
来提取
WHERE
子句中的条件。

首先,确保安装了
sqlparse
库。如果未安装,可以使用pip安装:

bash复制代码

pip install sqlparse

然后,我们可以编写以下Python代码来提取
WHERE
子句的值:

import sqlparse  
from sqlparse.sql import IdentifierList, Identifier  
from sqlparse.tokens import Keyword, DML  
  
def extract_where_values(sql):  
    # 使用sqlparse解析SQL语句  
    parsed = sqlparse.parse(sql)[0]  
      
    # 提取WHERE子句  
    where_seen = False  
    for item in parsed.tokens:  
        if where_seen:  
            if is_subselect(item):  
                where_seen = False  
            else:  
                # 这里的item可能是WHERE子句的一部分  
                print(item)  
        elif item.ttype is Keyword and item.value.upper() == 'WHERE':  
            where_seen = True  
  
def is_subselect(parsed):  
    if not parsed.is_group:  
        return False  
    for item in parsed.tokens:  
        if item.ttype is DML and item.value.upper() == 'SELECT':  
            return True  
    return False  
  
# 示例SQL语句  
sql = """  
SELECT * FROM users  
WHERE id = 10 AND status = 'active' OR name = 'John Doe';  
"""  
  
extract_where_values(sql)

在这个例子中,
extract_where_values
函数接收一个SQL语句作为输入,然后使用
sqlparse
解析它。它遍历解析后的语句的标记(tokens),寻找
WHERE
关键字。一旦找到,它将打印出
WHERE
子句中的所有内容,直到遇到另一个子查询或SQL语句的结尾。

这个代码展示了如何提取和识别SQL语句中的
WHERE
子句。在实际应用中,我们可能需要更复杂的逻辑来处理更复杂的SQL语句,包括嵌套查询、复杂的条件表达式等。

2.方法二:使用正则表达式

要从SQL语句中提取
WHERE
子句的值,我们可以使用Python的正则表达式(
re
模块)来匹配和提取这些值。但是,需要注意的是,SQL语句的结构可能非常复杂,包含嵌套查询、子查询、函数、操作符等,因此完全准确地提取
WHERE
子句中的所有值(特别是当它们包含复杂表达式或嵌套时)可能非常具有挑战性。

下面,我将提供一个简单的示例,该示例能够处理一些基本的SQL查询,并尝试提取
WHERE
子句中的条件。请注意,这个示例可能无法处理所有可能的SQL查询情况,特别是那些包含复杂逻辑或嵌套查询的查询。

import re  
  
def extract_where_clause(sql):  
    # 使用正则表达式匹配WHERE子句  
    # 这个正则表达式假设WHERE子句在SQL语句中直接跟在SELECT, UPDATE, DELETE等之后  
    # 并且可能包含空格、换行符等  
    # 注意:这个正则表达式非常基础,可能无法处理所有情况  
    pattern = r'(?<=WHERE\s+)(.*?)(?=\s*(?:ORDER BY|GROUP BY|LIMIT|;|$))'  
    match = re.search(pattern, sql, re.IGNORECASE | re.DOTALL)  
      
    if match:  
        return match.group(0).strip()  
    else:  
        return "No WHERE clause found."  
  
# 示例SQL语句  
sql_examples = [  
    "SELECT * FROM users WHERE id = 10 AND name = 'John';",  
    "UPDATE users SET status = 'active' WHERE age > 30 AND status = 'inactive';",  
    "DELETE FROM orders WHERE order_date < '2023-01-01';",  
    "SELECT * FROM products;",  # 没有WHERE子句  
    "SELECT * FROM products WHERE (price > 100 OR quantity < 10) AND category = 'Electronics';"  
]  
  
# 遍历示例并打印结果  
for sql in sql_examples:  
    print(f"Original SQL: {sql}")  
    print(f"Extracted WHERE Clause: {extract_where_clause(sql)}\n")

说明:

(1)
正则表达式
:这个正则表达式尝试匹配
WHERE
关键字后直到遇到
ORDER BY

GROUP BY

LIMIT
、语句结束符(
;
)或字符串末尾的任意字符序列。它使用了
re.IGNORECASE
来忽略大小写,
re.DOTALL
来允许
.
匹配包括换行符在内的任意字符。

(2)
限制
:这个正则表达式假设
WHERE
子句是直接跟在SQL语句的主要操作(如
SELECT
,
UPDATE
,
DELETE
)之后的,并且
WHERE
子句之后直接跟着的是其他SQL子句或语句结束符。这在一些复杂的SQL语句中可能不成立,特别是当
WHERE
子句被嵌套在子查询中时。

(3)
输出
:对于每个示例SQL语句,代码将打印出原始SQL语句和提取的
WHERE
子句(如果存在)。

这个示例提供了一个基本的起点,但根据具体需求,您可能需要调整正则表达式或采用更复杂的解析方法(如使用SQL解析库)来处理更复杂的SQL查询。

接下来,我将提供一个更具体的代码示例,并给出一个完整的Python脚本,该脚本使用正则表达式来提取SQL语句中的
WHERE
子句。这个示例将包括一个函数来执行提取操作,并在脚本的末尾调用这个函数来测试几个不同的SQL语句。

请注意,这个示例仍然基于正则表达式,并且可能无法处理所有复杂的SQL查询情况。对于更复杂的SQL解析,您可能需要考虑使用专门的SQL解析库,例如上文提到的
sqlparse
库的方法。

import re  
  
def extract_where_clause(sql):  
    """  
    从SQL语句中提取WHERE子句的内容。  
      
    参数:  
    sql (str): SQL查询语句。  
      
    返回:  
    str: 提取的WHERE子句内容(如果存在),否则返回"No WHERE clause found."。  
    """  
    # 使用正则表达式匹配WHERE子句  
    # 这个正则表达式尝试匹配WHERE关键字后直到遇到SQL语句结束或特定SQL子句开始的位置  
    pattern = r'(?<=WHERE\s+)(.*?)(?=\s*(?:ORDER BY|GROUP BY|LIMIT|;|$))'  
    match = re.search(pattern, sql, re.IGNORECASE | re.DOTALL)  
      
    if match:  
        return match.group(0).strip()  
    else:  
        return "No WHERE clause found."  
  
# 完整的Python脚本  
if __name__ == "__main__":  
    # 示例SQL语句  
    sql_examples = [  
        "SELECT * FROM users WHERE id = 10 AND name = 'John';",  
        "UPDATE users SET status = 'active' WHERE age > 30 AND status = 'inactive';",  
        "DELETE FROM orders WHERE order_date < '2023-01-01';",  
        "SELECT * FROM products;",  # 没有WHERE子句  
        "SELECT * FROM products WHERE (price > 100 OR quantity < 10) AND category = 'Electronics';",  
        "SELECT * FROM (SELECT * FROM nested WHERE nested_id = 1) AS subquery WHERE subquery.id = 5;"  # 嵌套查询  
    ]  
      
    # 遍历示例并打印结果  
    for sql in sql_examples:  
        print(f"Original SQL: {sql}")  
        where_clause = extract_where_clause(sql)  
        print(f"Extracted WHERE Clause: {where_clause}\n")  
  
# 输出将显示每个SQL语句的原始形式和提取的WHERE子句(如果存在)

在这个示例中,
extract_where_clause
函数使用了一个正则表达式来查找
WHERE
关键字后的内容,直到遇到
ORDER BY

GROUP BY

LIMIT
、SQL语句的结束(
;
)或字符串的末尾。然后,它返回匹配到的内容(如果有的话),否则返回一个说明没有找到
WHERE
子句的消息。

请注意,对于包含嵌套查询的SQL语句(如示例中的最后一个),这个正则表达式可能无法正确提取嵌套查询内部的
WHERE
子句,因为它只查找最外层的
WHERE
子句。要处理这种情况,您可能需要编写更复杂的正则表达式或使用SQL解析库。

此外,这个示例中的正则表达式使用了
re.DOTALL
标志,允许
.
匹配包括换行符在内的任意字符,这对于处理跨越多行的SQL语句很有用。然而,这也可能导致在不应该匹配的地方进行匹配,特别是当SQL语句中包含注释或字符串字面量时。在实际应用中,您可能需要进一步调整正则表达式以处理这些情况。

前言

这篇文章主要两个内容。
一,把上一篇关于requires_grad的内容补充一下。
二,介绍一下线性回归。

关闭张量计算

关闭张量计算。这个相对简单,阅读下面代码即可。

print("============关闭require_grad==============")
x = torch.randn(3, requires_grad=True)
print(x)
x.requires_grad_(False)  # 关闭x的张量计算

print("关闭x的张量计算后的x:", x)  # 没有requires_grad属性了

x = torch.randn(3, requires_grad=True)
print("新的带张量计算的x:", x)
y = x.detach()  # 去出x的张量附加属性,返回普通张量
print("y没有张量属性:", y)
print("x还有张量属性:", x)
print("============区域内去除x的张量附加属性==============")
with torch.no_grad():
    y = x+2
    print("y没有张量属性:", y)
print("x还有张量属性:", x)

一个有趣的例子

代码1如下,代码可以正常运行。

x = torch.tensor(1.0)
y = torch.tensor(2.0)
w = torch.tensor(1.0, requires_grad=True)
y_hat = w*x
loss = (y_hat-y)**2
print(loss)
loss.backward()
print(w.grad)

代码2如下,下面代码不能运行。

x = torch.tensor([1.0,2.0])
y = torch.tensor([1.0,2.0])
w = torch.tensor([1.0,2.0],requires_grad=True)
y_hat = w*x
loss =(y_hat-y)**2
print(loss)
loss.backward()
print(w.grad)

这是因为代码1的loss是个值,是个标量,所以它可以执行backward。
而代码2的loss是个向量,他不能执行backward。

线性回归 linear regression

很多视频或文章都说,深度学习要先理解线性回归。然后,大家一翻线性回归的视频,又是一堆。
其实,完全不用看那些课程,不用耽误那些时间。而且,你耽误了那些时间,也未必能理解。
线性回归是要学,但不用刷视频学,其实简单几句话就能讲明白的。只是没人好好讲而已,似乎都等着我们花费非常多的时间自己研究,自己开悟。

线性回归快速理解

首先理解线性是什么。
A=2,B=4,我们肉眼识别B是A的2倍,所以,我们就可以说A和B有关系,是什么关系呢?就是线性关系;线性就是这个意思,就说俩数有关系。
我们现在有了线性这个词了,今后遇到俩数有倍数关系,我们就直接说俩数有线性关系,这样就高大上了。
上篇文章提过,名词是我们学习阻碍,线性这个名词就是具体体现了。
回归就是我们找到B是A的2倍的过程。简单来说,线性回归就是找到一个数,这个数指明了A和B的关系。
找A和B关系,用函数表示,就是y=wx+b;A带入x,B带入y。肉眼推测结果w=2,b=0。
现在把A和B换成俩矩阵,然后w也就是一个矩阵,b还是一个常数。当我们求出w和b时,就是求出了A和B的线性关系。
到此,我们不用去看三四十个线性回归的视频,就已经对线性回归有概念了。

代码

我们直接看代码,x是特征值,y是目标值。
例如我们有一个青蛙A的图片,他的矩阵就是y,然后找一个青蛙B的图片,x就是青蛙B的矩阵。
然后通过线性回归算出,青蛙B与青蛙A的线性关系(w和b)。
这里输入特征x我们写死,不用读取青蛙B的矩阵;y也不用读取青蛙A,也写死。
然后定义w是一个跟x同型矩阵,然后定义b是一个0张量。
然后利用前面的知识使用backward求梯度,然后得到w.grad和b.grad。
w.grad和b.grad和w,b是同型张量,现在我们用w.grad和b.grad去修正w和b,修正时我们使用learning_rate学习率,确保一次只修改一点点。
然后反复迭代多次,就得到了我们的关系(w和b)。
代码如下:

# 输入特征和目标值
x = torch.tensor([1.0, 2.0])
y = torch.tensor([115.0, 21.0]) 

# 权重初始化(包括偏差项)
w = torch.tensor([1.0, 2.0], requires_grad=True)
b = torch.tensor(0.0, requires_grad=True)

# 学习率
learning_rate = 0.01

# 迭代多次进行优化
for epoch in range(100):
    # 预测
    y_hat = w * x + b
    
    # 损失函数
    loss = (y_hat - y).pow(2).mean()
    
    # 反向传播
    loss.backward()
    
    # 更新权重和偏差
    with torch.no_grad():
        w -= learning_rate * w.grad
        b -= learning_rate * b.grad
    
    # 清零梯度
    w.grad.zero_()
    b.grad.zero_()

    print(f'Epoch {epoch + 1}, Loss: {loss.item()}')

# 最终模型参数
print("Final weights:", w)
print("Final bias:", b)

运行如下图:
image

如图,我循环了100次,但loss的值还是比较大,loss的含义是,越接近0,这个w和b的值就越精确。
当然,如果青蛙A和B实在是不像,那可能循环了1000次,loss还是会很大。
这里我们循环100次后w=[51.8260,-9.4314] b=45.1103
现在我们使用y=wx+b带入x、w、b得到y_pred=51.8260 * 1 +45.1103= 96.9363。我们的y的第一项是115.0。
可以看到x通过wx+b得到的预测值,已经变的很接近y的真实值了。

现在修改运行2000次,运行如下图:
image

y=wx+b带入x、w、b得到y_pred=62.4444 * 1 +52.5554= 114.9998。
而我们的y的第一项是115.0。
可以看到,预测值已经非常接近真实值了。

传送门:
零基础学习人工智能—Python—Pytorch学习(一)
零基础学习人工智能—Python—Pytorch学习(二)
零基础学习人工智能—Python—Pytorch学习(三)
学习就先到这。


注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!



若您觉得这篇文章还不错,请点击下方的【推荐】,非常感谢!

https://www.cnblogs.com/kiba/p/18350389

什么是面向对象编程 (OOP)?

OOP
代表面向对象编程。

过程式编程是编写执行数据操作的过程或方法,而面向对象编程则是创建包含数据和方法的对象。

与过程式编程相比,面向对象编程具有以下几个优势:

  • OOP
    更快且更易于执行
  • OOP
    为程序提供了清晰的结构
  • OOP
    有助于保持
    Kotlin
    代码的
    DRY
    原则(“不要重复自己”),使代码更易于维护、修改和调试
  • OOP
    使得创建可重用的完整应用程序成为可能,使用更少的代码和更短的开发时间

提示:“不要重复自己” (
DRY - Don't repeat yourself
) 原则旨在减少代码的重复。您应该将应用程序中常见的代码提取出来,放在一个地方重复使用,而不是一遍又一遍地编写相同的代码。

Kotlin - 什么是类和对象?

类和对象是面向对象编程的两个主要方面。

看看下面的示意图,了解类和对象之间的区别:

  • 水果

对象

  • 苹果
  • 香蕉
  • 芒果

另一个例子:

  • 汽车

对象

  • 沃尔沃
  • 奥迪
  • 丰田

因此,


对象
的模板,而
对象


的实例。

当创建单个对象时,它们继承了类中的所有变量和方法。

Kotlin 类和对象


Kotlin
中,一切都与类和对象以及它们的属性和函数相关。例如:在现实生活中,汽车是一个对象。汽车有属性,例如品牌、重量和颜色;以及功能,例如驾驶和刹车。


就像是对象的构造器,或者说是创建对象的“蓝图”。

创建一个类

要创建一个类,请使用
class
关键字,并指定类的名称:

示例

创建一个包含一些属性(品牌、型号和年份)的
Car
类:

class Car {
  var brand = ""
  var model = ""
  var year = 0
}

属性基本上是属于类的变量。

重要提示:为了更好地组织代码,通常建议类的名称以大写字母开头。

创建一个对象

现在我们可以使用名为
Car
的类来创建对象。

在下面的示例中,我们创建了一个名为
c1

Car
对象,然后使用点语法(
.
)访问
c1
的属性,就像我们访问数组和字符串的属性一样:

示例

// 创建 Car 类的 c1 对象
val c1 = Car()

// 访问属性并为其赋值
c1.brand = "Ford"
c1.model = "Mustang"
c1.year = 1969

println(c1.brand)   // 输出 Ford
println(c1.model)   // 输出 Mustang
println(c1.year)    // 输出 1969

多个对象

您可以创建一个类的多个对象:

示例

val c1 = Car()
c1.brand = "Ford"
c1.model = "Mustang"
c1.year = 1969

val c2 = Car()
c2.brand = "BMW"
c2.model = "X5"
c2.year = 1999

println(c1.brand)  // Ford
println(c2.brand)  // BMW

Kotlin 构造函数

我们创建了一个类的对象,并在类内部指定了属性,如下所示:

示例

class Car {
  var brand = ""
  var model = ""
  var year = 0
}

fun main() {
  val c1 = Car()
  c1.brand = "Ford"
  c1.model = "Mustang"
  c1.year = 1969
}


Kotlin
中,可以通过使用构造函数更快地完成此操作。

构造函数 就像一个特殊的函数,它通过在类名后面使用两个括号
()
来定义。您可以在括号内指定属性(就像向普通函数传递参数一样)。

构造函数会在您创建类的对象时初始化属性。只需记住指定属性/变量的类型即可:

示例

class Car(var brand: String, var model: String, var year: Int)

fun main() {
  val c1 = Car("Ford", "Mustang", 1969)
}

现在指定一个类的多个对象更加简单了:

示例

class Car(var brand: String, var model: String, var year: Int)

fun main() {
  val c1 = Car("Ford", "Mustang", 1969)
  val c2 = Car("BMW", "X5", 1999)
  val c3 = Car("Tesla", "Model S", 2020)
}

Kotlin 类函数

您还可以在类内部使用函数来执行某些操作:

示例


Car
类中创建一个
drive()
函数并调用它:

class Car(var brand: String, var model: String, var year: Int) {
  // 类函数
  fun drive() {
    println("Wrooom!")
  }
}

fun main() {
  val c1 = Car("Ford", "Mustang", 1969)
  
  // 调用函数
  c1.drive()
}

提示:当一个函数在类内部声明时,它被称为类函数或成员函数。

注意:当类的对象被创建时,它可以访问所有的类函数。

类函数参数

与普通函数一样,您可以向类函数传递参数:

示例

创建两个函数:
drive()

speed()
,并向
speed()
函数传递参数:

class Car(var brand: String, var model: String, var year: Int) {
  // 类函数
  fun drive() {
    println("Wrooom!")
  }
  
  // 带参数的类函数
  fun speed(maxSpeed: Int) {
    println("最大速度是:" + maxSpeed)
  }
}

fun main() {
  val c1 = Car("Ford", "Mustang", 1969)
  
  // 调用函数
  c1.drive()
  c1.speed(200)
}

Kotlin 继承


Kotlin
中,可以从一个类继承类属性和函数到另一个类。我们将“继承概念”分为两类:

  • 子类 (child) - 继承自另一个类的类
  • 超类 (parent) - 被继承的类

在下面的示例中,
MyChildClass
(子类)继承了
MyParentClass
类(超类)的属性:

示例

// 超类
open class MyParentClass {
  val x = 5
}

// 子类
class MyChildClass: MyParentClass() {
  fun myFunction() {
    println(x) // x 现在从超类继承而来
  }
}

// 创建 MyChildClass 的对象并调用 myFunction
fun main() {
  val myObj = MyChildClass()
  myObj.myFunction()
}

示例解释

  • 使用
    open
    关键字修饰超类/父类,使该类可以被其他类继承属性和函数。
  • 要继承一个类,请指定子类的名称,后跟冒号
    :
    ,然后是超类的名称。

为什么以及何时使用“继承”?

  • 它对代码重用非常有用:在创建新类时,可以重用现有类的属性和函数。

最后

为了方便其他设备和平台的小伙伴观看往期文章:

微信公众号搜索:
Let us Coding
,关注后即可获取最新文章推送

看完如果觉得有帮助,欢迎 点赞、收藏、关注

1、该代码展示了使用Apache HttpClient库进行HTTP请求,并处理基于MD5的HTTP Digest认证的过程。 Digests类实现了MD5加密算法,HttpUtils类处理了GET、POST方法的请求,包括设置请求头、生成授权信息和处理响应。

2、请求流程

2.1.发送一个请求

2.2.服务器返回401响应头,要求输入用户凭据(建立通信,发起请求。如果返回401,继续下一次请求。重新设置响应,并获取随机数,通过md5加密返回)

2.3.输入凭据后再发送请求

2.4.服务端验证通过后返回数据

2.4代码示例:本案例使用xml请求并返回xml数据响应,json请求同理

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>

packagecom.ywb.common.utils.http;importcom.ywb.common.constant.Constants;importorg.junit.Test;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;import javax.net.ssl.*;import java.io.*;importjava.net.ConnectException;importjava.net.SocketTimeoutException;importjava.net.URL;importjava.net.URLConnection;importjava.security.cert.X509Certificate;importorg.apache.commons.codec.digest.DigestUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.http.Header;importorg.apache.http.HeaderElement;importorg.apache.http.HttpEntity;importorg.apache.http.HttpStatus;importorg.apache.http.client.config.RequestConfig;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.entity.StringEntity;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.impl.client.HttpClients;importorg.apache.http.util.EntityUtils;import java.io.*;importjava.nio.charset.StandardCharsets;importjava.util.HashMap;/*** 通用http发送方法
*
*
@authorywb*/
public classHttpUtils {private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);/*** 向指定 URL 发送GET方法的请求
*
*
@paramurl 发送请求的 URL
*
@paramparam 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
*
@return所代表远程资源的响应结果*/
public staticString sendGet(String url, String param) {returnsendGet(url, param, Constants.UTF8);
}
/*** 向指定 URL 发送GET方法的请求
*
*
@paramurl 发送请求的 URL
*
@paramparam 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
*
@paramcontentType 编码类型
*
@return所代表远程资源的响应结果*/
public staticString sendGet(String url, String param, String contentType) {
StringBuilder result
= newStringBuilder();
BufferedReader in
= null;try{
String urlNameString
= url + "?" +param;
log.info(
"sendGet - {}", urlNameString);
URL realUrl
= newURL(urlNameString);
URLConnection connection
=realUrl.openConnection();
connection.setRequestProperty(
"accept", "*/*");
connection.setRequestProperty(
"connection", "Keep-Alive");
connection.setRequestProperty(
"user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in
= new BufferedReader(newInputStreamReader(connection.getInputStream(), contentType));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info(
"recv - {}", result);
}
catch(ConnectException e) {
log.error(
"调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" +param, e);
}
catch(SocketTimeoutException e) {
log.error(
"调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" +param, e);
}
catch(IOException e) {
log.error(
"调用HttpUtils.sendGet IOException, url=" + url + ",param=" +param, e);
}
catch(Exception e) {
log.error(
"调用HttpsUtil.sendGet Exception, url=" + url + ",param=" +param, e);
}
finally{try{if (in != null) {
in.close();
}
}
catch(Exception ex) {
log.error(
"调用in.close Exception, url=" + url + ",param=" +param, ex);
}
}
returnresult.toString();
}
/*** 向指定 URL 发送POST方法的请求
*
*
@paramurl 发送请求的 URL
*
@paramparam 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
*
@return所代表远程资源的响应结果*/
public staticString sendPost(String url, String param) {
PrintWriter out
= null;
BufferedReader in
= null;
StringBuilder result
= newStringBuilder();try{
String urlNameString
=url;
log.info(
"sendPost - {}", urlNameString);
URL realUrl
= newURL(urlNameString);
URLConnection conn
=realUrl.openConnection();
conn.setRequestProperty(
"accept", "*/*");
conn.setRequestProperty(
"connection", "Keep-Alive");
conn.setRequestProperty(
"user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty(
"Accept-Charset", "utf-8");
conn.setRequestProperty(
"contentType", "utf-8");
conn.setDoOutput(
true);
conn.setDoInput(
true);
out
= newPrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in
= new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
log.info(
"recv - {}", result);
}
catch(ConnectException e) {
log.error(
"调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" +param, e);
}
catch(SocketTimeoutException e) {
log.error(
"调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" +param, e);
}
catch(IOException e) {
log.error(
"调用HttpUtils.sendPost IOException, url=" + url + ",param=" +param, e);
}
catch(Exception e) {
log.error(
"调用HttpsUtil.sendPost Exception, url=" + url + ",param=" +param, e);
}
finally{try{if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
}
catch(IOException ex) {
log.error(
"调用in.close Exception, url=" + url + ",param=" +param, ex);
}
}
returnresult.toString();
}
public staticString sendSSLPost(String url, String param) {
StringBuilder result
= newStringBuilder();
String urlNameString
= url + "?" +param;try{
log.info(
"sendSSLPost - {}", urlNameString);
SSLContext sc
= SSLContext.getInstance("SSL");
sc.init(
null, new TrustManager[]{new TrustAnyTrustManager()}, newjava.security.SecureRandom());
URL console
= newURL(urlNameString);
HttpsURLConnection conn
=(HttpsURLConnection) console.openConnection();
conn.setRequestProperty(
"accept", "*/*");
conn.setRequestProperty(
"connection", "Keep-Alive");
conn.setRequestProperty(
"user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty(
"Accept-Charset", "utf-8");
conn.setRequestProperty(
"contentType", "utf-8");
conn.setDoOutput(
true);
conn.setDoInput(
true);

conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(
newTrustAnyHostnameVerifier());
conn.connect();
InputStream is
=conn.getInputStream();
BufferedReader br
= new BufferedReader(newInputStreamReader(is));
String ret
= "";while ((ret = br.readLine()) != null) {if (ret != null && !"".equals(ret.trim())) {
result.append(
new String(ret.getBytes("ISO-8859-1"), "utf-8"));
}
}
log.info(
"recv - {}", result);
conn.disconnect();
br.close();
}
catch(ConnectException e) {
log.error(
"调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" +param, e);
}
catch(SocketTimeoutException e) {
log.error(
"调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" +param, e);
}
catch(IOException e) {
log.error(
"调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" +param, e);
}
catch(Exception e) {
log.error(
"调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" +param, e);
}
returnresult.toString();
}
/*** 摘要认证 两次请求
*
*
@paramurl
*
@return返回结果*/
public staticString doPostDigest(String url, String uri, String username, String password, String requestXml) {
CloseableHttpClient httpClient
= null;
CloseableHttpResponse response
= null;
HttpPost httpPost
= null;
String strResponse
= null;try{
httpClient
=HttpClients.createDefault();//httpClient = new SSLClient();
httpPost = newHttpPost(url);//构造请求头
httpPost.setHeader("Content-Type", "application/xml");
httpPost.setHeader(
"X-Requested-With", "XMLHttpRequest");
httpPost.addHeader(
"Cache-Control", "no-cache"); //设置缓存
httpPost.setHeader("Connection", "Close");

RequestConfig.Builder builder
=RequestConfig.custom();
builder.setSocketTimeout(
5000); //设置请求时间
builder.setConnectTimeout(8000); //设置超时时间
builder.setRedirectsEnabled(false);//设置是否跳转链接(反向代理)//设置 连接 属性
httpPost.setConfig(builder.build());
StringEntity entityss
= new StringEntity(requestXml, "utf-8");
httpPost.setEntity(entityss);
//执行请求
response =httpClient.execute(httpPost);
HttpEntity responseEntity
=response.getEntity();//检验返回码
int statusCode =response.getStatusLine().getStatusCode();
log.debug(
"第一次发送摘要认证 Post请求 返回码:{}" +statusCode);if (401 ==statusCode) {
strResponse
= EntityUtils.toString(responseEntity, "utf-8");
log.debug(
"Post请求401返回结果:{}" +strResponse);//组织参数,发起第二次请求
Header[] headers = response.getHeaders("WWW-Authenticate");
HeaderElement[] elements
= headers[0].getElements();
String realm
= null;
String qop
= null;
String nonce
= null;
String opaque
= null;
String method
= "POST";for(HeaderElement element : elements) {if (element.getName().equals("Digest realm")) {
realm
=element.getValue();
}
else if (element.getName().equals("qop")) {
qop
=element.getValue();
}
else if (element.getName().equals("nonce")) {
nonce
=element.getValue();
}
else if (element.getName().equals("opaque")) {
opaque
=element.getValue();
}
}
//以上为 获取第一次请求后返回的 数据
String nc = "00000001";
String cnonce
= "uniview";//后期变成可配置
String a1 = username + ":" + realm + ":" +password;
String a2
= method + ":" +uri;
String response1
= null;//获取 Digest 这个字符串
String backString = response.getFirstHeader("WWW-Authenticate").getValue();try{
response1
= DigestUtils.md5Hex((DigestUtils.md5Hex(a1.getBytes("UTF-8")) + ":" + nonce + ":" +nc+ ":" + "uniview" + ":" + qop + ":" + DigestUtils.md5Hex(a2.getBytes("UTF-8"))).getBytes("UTF-8"));
}
catch(UnsupportedEncodingException e) {
log.error(
"MD5异常:{}" +e.getLocalizedMessage(), e);
}
httpPost.addHeader(
"Authorization", backString + ",username=\"" + username + "\"" + ",realm=\"" + realm + "\""
+ ",nonce=\"" + nonce + "\"" + ",uri=\"" + uri + "\"" + ",qop=\"" + qop + "\"" + ",nc=\"" + nc + "\""
+ ",cnonce=\"" + cnonce + "\"" + ",response=\"" + response1 + "\"" + ",opaque=\"" +opaque);//发送第二次请求
response =httpClient.execute(httpPost);
HttpEntity entity
=response.getEntity();int statusCode1 =response.getStatusLine().getStatusCode();
log.debug(
"第二次发送摘要认证 Post请求 返回码:{}" +statusCode1);if (HttpStatus.SC_OK ==statusCode1) {
strResponse
=EntityUtils.toString(entity, StandardCharsets.UTF_8);
log.debug(
"第二次发送strResponse" +strResponse);returnstrResponse;
}
else{
strResponse
=EntityUtils.toString(entity, StandardCharsets.UTF_8);
log.debug(
"第二次鉴权认证请求非 200 返回结果:{}" +strResponse);returnstrResponse;
}
}
else{
strResponse
=EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
log.error(
"第一次鉴权认证请求非401 返回结果:{}" +strResponse);
}
}
catch(Exception e) {
log.error(
"摘要认证 发送请求失败" +e.getLocalizedMessage(), e);
}
finally{if (null !=httpPost) {
httpPost.releaseConnection();
}
if (null !=response) {try{
response.close();
}
catch(IOException e) {
log.error(
"httpResponse流关闭异常:", e);
}
}
if (null !=httpClient) {try{
httpClient.close();
}
catch(IOException e) {
log.error(
"httpClient 流关闭异常:", e);
}
}
}
returnstrResponse;
}
private static class TrustAnyTrustManager implementsX509TrustManager {
@Override
public voidcheckClientTrusted(X509Certificate[] chain, String authType) {
}

@Override
public voidcheckServerTrusted(X509Certificate[] chain, String authType) {
}

@Override
publicX509Certificate[] getAcceptedIssuers() {return newX509Certificate[]{};
}
}
private static class TrustAnyHostnameVerifier implementsHostnameVerifier {
@Override
public booleanverify(String hostname, SSLSession session) {return true;
}
}

@Test
public voidtestHttpPostRaw() {final String url = "http://18.18.167.120/ISAPI/Traffic/ContentMgmt/Statistic/operator";final String uri = "/ISAPI/Traffic/ContentMgmt/Statistic/operator";final String encode = "utf-8";
String requestXml
= "<?xml version='1.0' encoding='utf-8'?>" +
"<StatisticOperator>" +
"<operationType>search</operationType>" +
"<searchCond>" +
"<searchID>CAD8E0D6-1480-0001-C0B7-1E50E290140D</searchID>" +
"<timeSpanList><timeSpan>" +
"<startTime>2024-06-21T15:25:10Z</startTime>" +
"<endTime>2024-06-21T15:27:59Z</endTime>" +
"</timeSpan></timeSpanList>" +
"<maxResults>20</maxResults>" +
"<searchResultPosition>0</searchResultPosition>" +
"</searchCond>" +
"</StatisticOperator>";final HashMap<String, String> headers = new HashMap<String, String>();
headers.put(
"Content-Type", "application/x-www-form-urlencoded");
headers.put(
"X-Requested-With", "XMLHttpRequest");

System.out.println(doPostDigest(url, uri,
"admin", "123456", requestXml));
<?xml version="1.0" encoding="UTF-8"?>-<StatisticOperatorResultxmlns="http://www.isapi.org/ver20/XMLSchema"version="2.0">

<statusCode>1</statusCode>

<description>OK</description>

<searchID>CAD8E0D6-1480-0001-C0B7-1E50E290140D</searchID>

<numOfMatches>2</numOfMatches>

<totalMatches>2</totalMatches>-<StatisticList>-<Statistic>

<IDmax="65535"min="1">1</ID>

<direction>0</direction>

<laneNo>18</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:26:03</startTime>

<endTime>2024-06-21T15:27:03</endTime>

<timePoint>2024-06-21T15:26:03</timePoint>

<channel>1</channel>

<carFlux>2</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>1</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>26.2</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>50</averTimeOccupancy>

<averQueueLength>35</averQueueLength>

<averTimeHeadway>102</averTimeHeadway>

<nonmotorFlux>1</nonmotorFlux>

</Statistic>-<Statistic>

<IDmax="65535"min="1">2</ID>

<direction>0</direction>

<laneNo>19</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:26:03</startTime>

<endTime>2024-06-21T15:27:03</endTime>

<timePoint>2024-06-21T15:26:03</timePoint>

<channel>1</channel>

<carFlux>0</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>0</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>0.0</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>0</averTimeOccupancy>

<averQueueLength>0</averQueueLength>

<averTimeHeadway>0</averTimeHeadway>

<nonmotorFlux>0</nonmotorFlux>

</Statistic>-<Statistic>

<IDmax="65535"min="1">3</ID>

<direction>0</direction>

<laneNo>3</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:26:03</startTime>

<endTime>2024-06-21T15:27:03</endTime>

<timePoint>2024-06-21T15:26:03</timePoint>

<channel>1</channel>

<carFlux>0</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>0</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>0.0</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>0</averTimeOccupancy>

<averQueueLength>0</averQueueLength>

<averTimeHeadway>0</averTimeHeadway>

<nonmotorFlux>0</nonmotorFlux>

</Statistic>-<Statistic>

<IDmax="65535"min="1">4</ID>

<direction>0</direction>

<laneNo>18</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:27:03</startTime>

<endTime>2024-06-21T15:28:03</endTime>

<timePoint>2024-06-21T15:27:03</timePoint>

<channel>1</channel>

<carFlux>1</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>1</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>27.0</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>98</averTimeOccupancy>

<averQueueLength>35</averQueueLength>

<averTimeHeadway>54</averTimeHeadway>

<nonmotorFlux>0</nonmotorFlux>

</Statistic>-<Statistic>

<IDmax="65535"min="1">5</ID>

<direction>0</direction>

<laneNo>19</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:27:03</startTime>

<endTime>2024-06-21T15:28:03</endTime>

<timePoint>2024-06-21T15:27:03</timePoint>

<channel>1</channel>

<carFlux>0</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>0</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>0.0</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>0</averTimeOccupancy>

<averQueueLength>0</averQueueLength>

<averTimeHeadway>0</averTimeHeadway>

<nonmotorFlux>0</nonmotorFlux>

</Statistic>-<Statistic>

<IDmax="65535"min="1">6</ID>

<direction>0</direction>

<laneNo>3</laneNo>

<vehicleType>0</vehicleType>

<startTime>2024-06-21T15:27:03</startTime>

<endTime>2024-06-21T15:28:03</endTime>

<timePoint>2024-06-21T15:27:03</timePoint>

<channel>1</channel>

<carFlux>0</carFlux>

<smallCarFlux>0</smallCarFlux>

<bigCarFlux>0</bigCarFlux>

<passerbyFlux>0</passerbyFlux>

<averOccpancy>0.0</averOccpancy>

<averSpeed>0</averSpeed>

<averCarDis>0</averCarDis>

<midCarFlux>0</midCarFlux>

<averTimeOccupancy>0</averTimeOccupancy>

<averQueueLength>0</averQueueLength>

<averTimeHeadway>0</averTimeHeadway>

<nonmotorFlux>0</nonmotorFlux>

</Statistic>

</StatisticList>

</StatisticOperatorResult>