Java客戶端調用SOAP方式的WebService服務實現方式分析

簡介

在多系統交互中,有時候需要以Java作為客戶端來調用SOAP方式的WebService服務,本文通過分析不同的調用方式,以Demo的形式,幫助讀者在生產實踐中選擇合適的調用方式。

本文JDK環境為JDK17。

結論

推薦使用Axis2或者Jaxws,以無客戶端的形式來調用WebService。

有客戶端,推薦Maven插件。

有客戶端調用

主要時利用wsdl文檔,自動生成對應的Java代碼來實現

建議在pom文件中,配置對應的Maven插件來實現WebService客戶端代碼的自動生成。

JDK wsimport命令生成(不推薦)

簡介

主要是利用jdk的自帶工具wsimport工具實現,執行命令如下:

wsimport?-s C:\tmp\com?-p?com.example.demo5.wsdl?-encoding?utf-8?http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl

優點

通常裝有JDK的電腦或者服務器都可以直接運行,方便生成。

缺點

在實際的運用中wsimport命令會有很多問題,首先只有JDK1.8才支持這個命令,即使能使用,仍然存在一些問題。其次,在JDK17以上沒有自帶這個工具,可能要安裝插件才能使用,但是筆者安裝了一些插件仍然無法使用。

ApacheCXF自動生成(不推薦)

簡介

ApacheCXF通過安裝也可以自動生成對應的WebService客戶端代碼。具體操作可見鏈接。

缺點

需要額外安裝ApacheCXF插件。

Maven插件自動生成(推薦)

簡介

通過spring.io網址的Demo示例,可以配置pom的maven插件,自動生成代碼。

demo獲取鏈接如下:

Getting Started | Consuming a SOAP web service (spring.io)

pom配置示例如下:

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- tag::wsdl[] --><plugin><groupId>com.sun.xml.ws</groupId><artifactId>jaxws-maven-plugin</artifactId><version>3.0.0</version><executions><execution><goals><goal>wsimport</goal></goals></execution></executions><configuration><packageName>com.example.consumingwebservice.wsdl</packageName><wsdlUrls>
<!--						<wsdlUrl>http://localhost:8080/ws/countries.wsdl</wsdlUrl>--><wsdlUrl>http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl</wsdlUrl></wsdlUrls><sourceDestDir>${sourcesDir}</sourceDestDir><destDir>${classesDir}</destDir><extension>true</extension></configuration></plugin><!-- end::wsdl[] --></plugins></build>

生成代碼如下:

調用方式:

@RequestMapping(value = "/{ip}", method = RequestMethod.GET)public ArrayOfString searchIp(@PathVariable("ip") String ip) {IpAddressSearchWebServiceSoap ipAddressSearchWebServiceSoap = new IpAddressSearchWebService().getIpAddressSearchWebServiceSoap();ArrayOfString response = ipAddressSearchWebServiceSoap.getCountryCityByIp(ip);return response;}

優點

操作簡單,改動小。

缺點

唯一的缺點,也是有客戶端調用普遍存在的,自動生成代碼后,需要重新部署一次。

Springboot集成Git插件實現

通過Springboot集成git插件,可以通過接口的形式來修改maven的wsdlUrls配置,然后推送到git服務,最后觸發Jenkins自動部署。

以Git推送代碼的形式來實現代碼的自動生成,其缺點是,每次根據一份wsdl文件生成完代碼,需要重啟一次服務,但是筆者通過自動配置的形式可以做到一鍵部署。

其中觸發Jenkins自動部署,可以通過git的配置實現,通過訪問特定的url實現。配置好的git部署鏈接如下:

http://192.168.22.22:8080/job/demo_test/build?token=1987654567890hjkoijghfvgjjnmkjkmk

其中token的值可以自動定義,這樣在借助代碼的形式就可以做到一鍵部署。

其實現代碼如下:

package com.example.consumingwebservice;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Date;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.HttpConfig;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;public class GitUtil {//private static Log log = LogFactory.getLog(GitUtil.class);private GitUtil() {}public static Git getGit(String uri, CredentialsProvider credentialsProvider, String localDir) throws Exception {Git git = null;if (new File(localDir).exists() ) {git = Git.open(new File(localDir));} else {git = Git.cloneRepository().setCredentialsProvider(credentialsProvider).setURI(uri).setDirectory(new File(localDir)).call();}//設置一下post內存,否則可能會報錯Error writing request body to servergit.getRepository().getConfig().setInt(HttpConfig.HTTP, null, HttpConfig.POST_BUFFER_KEY, 512*1024*1024);return git;}public static CredentialsProvider getCredentialsProvider(String username, String password) {return new UsernamePasswordCredentialsProvider(username, password);}public static Repository getRepository(Git git) {return git.getRepository();}public static void pull(Git git, CredentialsProvider credentialsProvider) throws Exception {git.pull().setRemote("origin").setCredentialsProvider(credentialsProvider).call();}public static void push(Git git, CredentialsProvider credentialsProvider, String filepattern, String message)throws Exception {git.add().addFilepattern(filepattern).call();git.add().setUpdate(true);git.commit().setMessage(message).call();git.push().setCredentialsProvider(credentialsProvider).call();}public static void main(String[] args) throws Exception {String uri = "http://192.168.9.11/test/webservice.git";String username = "343535@qq.com";String password = "xdfetrfrr";CredentialsProvider credentialsProvider = getCredentialsProvider(username, password);String localDir = "C:/tmp/git_test";Git git = getGit(uri, credentialsProvider, localDir);pull(git, credentialsProvider);changeFile(localDir + "/pom.xml");//        push(git, credentialsProvider, ".", "提交文件");push(git, credentialsProvider, "pom.xml", "修改pom文件" + new Date());}private static final String newText = "    <wsdlUrl>http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx?wsdl</wsdlUrl>\r\n                    </wsdlUrls>";protected static void changeFile(String filePath) {try {// 讀取文本文件的內容Path path = Paths.get(filePath);String content = Files.readString(path);System.out.println(content);// 替換內容String modifiedContent = content.replace("</wsdlUrls>", newText);// 將修改后的內容寫回文本文件Files.write(path, modifiedContent.getBytes(), StandardOpenOption.WRITE);System.out.println("文本文件內容已成功修改!");} catch (IOException e) {System.out.println("修改文本文件內容時出現錯誤:" + e.getMessage());}}}

?如要實現流程圖的規劃,可以后臺通過http的get請求上文的git部署鏈接,實現接口的自動部署。

無客戶端調用

也就是不需要按wsdl的格式來生成對應的Java代碼,原理時通過構建xml的形式來訪問WebService。

這里推薦使用Axis2或者Jaxws的方式來調用,二者各有優劣。

Axis調用(不推薦)

簡介

通過pom引入axis依賴,實現無客戶端訪問,所需依賴如下:

<dependency>
<groupId>axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency>

代碼實現如下:

public static void main(String[] args){try {String nameSpac = "http://WebXml.com.cn/";URL url = new URL("http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl");QName sname = new QName(nameSpac, "MobileCodeWS");QName pname = new QName(nameSpac, "MobileCodeWSSoap");Service service = new Service( url, sname);Call call = (Call)service.createCall(pname);call.setSOAPActionURI(nameSpac + "getMobileCodeInfo");call.setOperationName(new QName(nameSpac, "getMobileCodeInfo")); // 需要請求的方法call.addParameter(new QName(nameSpac, "mobileCode"), XMLType.XSD_STRING, ParameterMode.IN);  // 入參call.addParameter(new QName(nameSpac, "userID"), XMLType.XSD_STRING, ParameterMode.IN);  // 入參
//            call.addParameter("param3", XMLType.SOAP_STRING, ParameterMode.IN);  // 入參String param1 = "15932582632";  // 參數String param2 = null;  // 參數call.setReturnClass(String.class);  // 設置返回值call.setUseSOAPAction(true);Object invoke = call.invoke(new Object[]{param1, param2});// 調用獲取返回值
//            Object invoke =  call.invoke(new Object[]{});// 調用獲取返回值System.out.println(invoke);}catch (Exception e){e.printStackTrace();}}

優點

較少的代碼量,依賴需要少,實現簡單

缺點

通過筆者的實驗,發現Axis的調用并不穩定,對于不同的接口,有的接口無參數調用可以調通,有參數調用會報錯,有的接口有參數調用可以調通(如例),無參數調用會報錯。

實際上,這個依賴在2006年便沒有維護了,它的功能轉移到了Axis2。

Axis2調用(推薦)

簡介

通過pom引入axis2依賴,實現無客戶端訪問,所需依賴如下:

<dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-jaxws</artifactId>
<version>1.7.0</version>
</dependency><dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-adb-codegen</artifactId>
<version>1.7.0</version>
</dependency><dependency>
<groupId>org.apache.axis2</groupId>
<artifactId>axis2-transport-local</artifactId>
<version>1.7.0</version>
</dependency><dependency>
<groupId>org.apache.axiom</groupId>
<artifactId>com.springsource.org.apache.axiom</artifactId>
<version>1.2.5</version>
</dependency>

代碼實現如下:

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.impl.httpclient3.HttpTransportPropertiesImpl;/**** @ClassName: MobileClientDoc* @Description: TODO* 方法二: 應用document方式調用 用ducument方式應用現對繁瑣而靈活。現在用的比較多。因為真正擺脫了我們不想要的耦合* 即使用org.apache.axis2.client.ServiceClient類進行遠程調用web服務,不生成客戶端** @date 2017年11月9日 下午1:27:17**/
public class SoapAxis2Client {private static String requestName = "getCountryCityByIp";public static void ipWS() {try {ServiceClient serviceClient = new ServiceClient();//創建服務地址WebService的URL,注意不是WSDL的URLString url = "http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx";EndpointReference targetEPR = new EndpointReference(url);Options options = serviceClient.getOptions();options.setTo(targetEPR);//確定調用方法(wsdl 命名空間地址 (wsdl文檔中的targetNamespace) 和 方法名稱 的組合)options.setAction("http://WebXml.com.cn/" + requestName);//設置密碼HttpTransportPropertiesImpl.Authenticator auth = new HttpTransportPropertiesImpl.Authenticator();
//            auth.setUsername(username);  //服務器訪問用戶名
//            auth.setPassword(password); //服務器訪問密碼
//            options.setProperty(HTTPConstants.AUTHENTICATE, auth);OMFactory fac = OMAbstractFactory.getOMFactory();/** 指定命名空間,參數:* uri--即為wsdl文檔的targetNamespace,命名空間* perfix--可不填*/OMNamespace omNs = fac.createOMNamespace("http://WebXml.com.cn/", "");// 指定方法OMElement method = fac.createOMElement(requestName, omNs);// 指定方法的參數OMElement theIpAddress = fac.createOMElement("theIpAddress", omNs);theIpAddress.setText("111.249.198.56");
//            OMElement userID = fac.createOMElement("userID", omNs);
//            userID.setText("");method.addChild(theIpAddress);
//            method.addChild(userID);method.build();//遠程調用web服務OMElement result = serviceClient.sendReceive(method);//值得注意的是,返回結果就是一段由OMElement對象封裝的xml字符串。String xml = result.cloneOMElement().toString();System.out.println(xml);} catch (AxisFault axisFault) {axisFault.printStackTrace();}}public static void main(String[] args) throws AxisFault {ipWS();}}

優點

代碼量較少,通過配置xml節點實現系統調用,可以設置靈活的調用方式。經過實驗,對各種WebService接口的有參無參調用,都能取得正確的返回結果。

測試結果如下:

<getCountryCityByIpResponse xmlns="http://WebXml.com.cn/"><getCountryCityByIpResult><string>111.249.198.56</string><string>臺灣省 ?</string></getCountryCityByIpResult></getCountryCityByIpResponse>

缺點

所需的pom配置文件較多,且引用不正確較難排查問題,且各個pom之間的版本沖突也需要解決。

Jaxws調用(推薦)

簡介

引入對于的pom配置文件

<dependency><groupId>org.apache.axis2</groupId><artifactId>axis2-jaxws</artifactId><version>1.7.0</version>
</dependency>

這里提前說下,下面代碼大部分來自于csdn作者——LengYouNuan的文章,但是實在找不到對于作者了,提前聲明。

還有它的原始代碼并不能正常運行,會有服務器未能識別 HTTP 頭 SOAPAction 的值的報錯,筆者通過實驗和研究,添加了如下配置,才能正常運行:

//這句話很重要,否則報錯服務器未能識別 HTTP 頭 SOAPAction 的值
dispatch.getRequestContext().put(SOAPACTION_URI_PROPERTY, nameSpace + elementName);
dispatch.getRequestContext().put(SOAPACTION_USE_PROPERTY, true);

由于使用的JDK17,對應的配置和以前不一樣了:

public interface BindingProvider {String USERNAME_PROPERTY = "jakarta.xml.ws.security.auth.username";String PASSWORD_PROPERTY = "jakarta.xml.ws.security.auth.password";String ENDPOINT_ADDRESS_PROPERTY = "jakarta.xml.ws.service.endpoint.address";String SESSION_MAINTAIN_PROPERTY = "jakarta.xml.ws.session.maintain";String SOAPACTION_USE_PROPERTY = "jakarta.xml.ws.soap.http.soapaction.use";String SOAPACTION_URI_PROPERTY = "jakarta.xml.ws.soap.http.soapaction.uri";
......

應該主要是javax和jakarta的區別。

完整可運行代碼如下:

package com.example.consumingwebservice;import com.sun.xml.ws.client.BindingProviderProperties;
import com.sun.xml.ws.developer.JAXWSProperties;
import jakarta.xml.soap.*;
import jakarta.xml.ws.Dispatch;
import jakarta.xml.ws.Service;
import org.w3c.dom.Document;import javax.xml.namespace.QName;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;import static jakarta.xml.ws.BindingProvider.SOAPACTION_URI_PROPERTY;
import static jakarta.xml.ws.BindingProvider.SOAPACTION_USE_PROPERTY;/*** soap方式調用webservice方式客戶端** @author LengYouNuan* @create 2021-05-31 下午2:35*/
public class SoapJaxwsClient {String nameSpace = ""; //wsdl的命名空間String wsdlUrl = ""; //wsdl文檔地址String serviceName = ""; //服務的名字String portName = "";String responseName = ""; //@WebResult:注解上的name值String elementName = ""; //默認是要訪問的方法名 如果@WebMethod屬性name有值 則是該值,實際還是以wsdl文檔為主int timeout = 20000;/*** @param nameSpace* @param wsdlUrl* @param serviceName* @param portName* @param element* @param responseName*/public SoapJaxwsClient(String nameSpace, String wsdlUrl,String serviceName, String portName, String element,String responseName) {this.nameSpace = nameSpace;this.wsdlUrl = wsdlUrl;this.serviceName = serviceName;this.portName = portName;this.elementName = element;this.responseName = responseName;}/*** @param nameSpace* @param wsdlUrl* @param serviceName* @param portName* @param element* @param responseName* @param timeOut      毫秒*/public SoapJaxwsClient(String nameSpace, String wsdlUrl,String serviceName, String portName, String element,String responseName, int timeOut) {this.nameSpace = nameSpace;this.wsdlUrl = wsdlUrl;this.serviceName = serviceName;this.portName = portName;this.elementName = element;this.responseName = responseName;this.timeout = timeOut;}public String sendMessage(HashMap<String, String> inMsg) throws Exception {// 創建URL對象URL url = null;try {url = new URL(wsdlUrl);} catch (Exception e) {e.printStackTrace();return "創建URL對象異常";}// 創建服務(Service)QName sname = new QName(nameSpace, serviceName);Service service = Service.create(url, sname);// 創建Dispatch對象Dispatch<SOAPMessage> dispatch = null;try {dispatch = service.createDispatch(new QName(nameSpace, portName), SOAPMessage.class, Service.Mode.MESSAGE);} catch (Exception e) {e.printStackTrace();return "創建Dispatch對象異常";}// 創建SOAPMessagetry {//這句話很重要,否則報錯服務器未能識別 HTTP 頭 SOAPAction 的值dispatch.getRequestContext().put(SOAPACTION_URI_PROPERTY, nameSpace + elementName);dispatch.getRequestContext().put(SOAPACTION_USE_PROPERTY, true);SOAPMessage msg = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createMessage();msg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();// 創建SOAPHeader(不是必需)// SOAPHeader header = envelope.getHeader();// if (header == null)// header = envelope.addHeader();// QName hname = new QName(nameSpace, "username", "nn");// header.addHeaderElement(hname).setValue("huoyangege");// 創建SOAPBodySOAPBody body = envelope.getBody();QName ename = new QName(nameSpace, elementName, "");SOAPBodyElement ele = body.addBodyElement(ename);// 增加Body元素和值for (Map.Entry<String, String> entry : inMsg.entrySet()) {ele.addChildElement(new QName(nameSpace, entry.getKey())).setValue(entry.getValue());}// 超時設置dispatch.getRequestContext().put(BindingProviderProperties.CONNECT_TIMEOUT, timeout);dispatch.getRequestContext().put(JAXWSProperties.REQUEST_TIMEOUT, timeout);// 通過Dispatch傳遞消息,會返回響應消息SOAPMessage response = dispatch.invoke(msg);// 響應消息處理,將響應的消息轉換為doc對象Document doc = response.getSOAPPart().getEnvelope().getBody().extractContentAsDocument();String ret = doc.getElementsByTagName(responseName).item(0).getTextContent();return ret;} catch (Exception e) {e.printStackTrace();throw e;}}public static void main(String[] args) throws Exception {
//        SoapClient soapClient=new SoapClient("http://spring.io/guides/gs-producing-web-service","http://localhost:8080/ws/countries.wsdl",
//                "CountriesPortService","CountriesPortSoap11","getCountry",
//                "getCountryResponse",
//                2000);SoapJaxwsClient soapClient = new SoapJaxwsClient("http://WebXml.com.cn/", "http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl","MobileCodeWS", "MobileCodeWSSoap", "getDatabaseInfo","getDatabaseInfoResponse",2000);
//        SoapClient soapClient=new SoapClient("http://WebXml.com.cn/","http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.wsdl",
//                "IpAddressSearchWebService","IpAddressSearchWebServiceSoap","getCountryCityByIp",
//                "getCountryCityByIpResult",
//                2000);//封裝請求參數HashMap<String, String> msg = new HashMap<>();
//        msg.put("theIpAddress","111.249.198.56");
//        msg.put("mobileCode","18702750020");
//        msg.put("userID","");String s = soapClient.sendMessage(msg);System.out.println(s);}
}

測試結果:

優點

pom配置簡單,無須解決各種版本依賴的問題。

缺點

可以看到Jaxws的調用和Axis2一樣,都具有較高的靈活性,都可以自定義xml的節點數據。

所不同的是,它的調用代碼稍顯繁瑣,但如果在生產中,有良好的封裝,這應該不是問題。

小結

對于SOAP方式WebService的調用,有客戶端的調用,推薦maven插件自動生成代碼的形式,唯一的缺點是需要重新部署一次。

對于無客戶端的調用,推薦Axis2或者Jaxws的形式,考慮到二者實現其實各有優劣,有需要的讀者可以自行甄別選用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42591.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42591.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42591.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

拆分pdf文件最簡單的方法,pdf怎么拆成一頁一張

在數字化的時代&#xff0c;pdf文件已經成為我們日常辦公、學習不可或缺的文檔格式。然而&#xff0c;有時候我們可能需要對一個大的pdf文件進行拆分&#xff0c;以方便管理和分享。那么&#xff0c;如何將一個pdf文件拆分成多個pdf呢&#xff1f;本文將為你推薦一種好用的拆分…

PLSQL Day4

--使用顯式游標更新行&#xff0c;對所有salesman增加500獎金&#xff1a; declare cursor s_cursor is select * from emp where job SALESMAN for update; begin for e_s in s_cursor loop update emp set comm nvl(comm,0)500 where current of s_cur…

AFT:Attention Free Transformer論文筆記

原文鏈接 2105.14103 (arxiv.org) 原文翻譯 Abstract 我們介紹了 Attention Free Transformer (AFT)&#xff0c;這是 Transformer [1] 的有效變體&#xff0c;它消除了點積自注意力的需要。在 AFT 層&#xff0c;鍵key和值value首先與一組學習的位置偏差position biases相結…

ubuntu22安裝Docker并配置

安裝Docker sudo apt install docker.io使用腳本自動安裝docker&#xff1a; curl -fsSL get.docker.com -o get-docker.sh sudo sh get-docker.sh --mirror Aliyun配置國內鏡像 /etc/docker/daemon.json 推薦配置&#xff1a; {"registry-mirrors": ["htt…

Lab1 論文 MapReduce

目錄 &#x1f339;前言 &#x1f985;2 Programming Model &#x1f33c;2.1 Example &#x1f33c;2.2 Types &#x1f33c;2.3 More Examples &#x1f985;3 Implementation(實現) &#x1f33c;3.1 ~ 3.3 &#x1f33c;3.4 ~ 3.6 &#x1f985;4 Refinemen…

代理IP有什么用途

代理IP主要有以下應用場景&#xff1a; 1、隱藏真實IP地址&#xff1a;通過使用代理IP&#xff0c;可以隱藏真實的網絡請求來源&#xff0c;保護用戶隱私。 2、繞過網絡限制&#xff1a;一些地區或網絡環境可能存在訪問限制&#xff0c;通過使用代理IP可以繞過這些限制&#xf…

Anaconda+Pycharm 項目運行保姆級教程(附帶視頻)

最近很多小白在問如何用anacondapycharm運行一個深度學習項目&#xff0c;進行代碼復現呢&#xff1f;于是寫下這篇文章希望能淺淺起到一個指導作用。 附視頻講解地址&#xff1a;AnacondaPycharm項目運行實例_嗶哩嗶哩_bilibili 一、項目運行前的準備&#xff08;軟件安裝&…

BN的 作用

1、背景&#xff1a; 卷積神經網絡的出現&#xff0c;網絡參數量大大減低&#xff0c;使得幾十層的深層網絡成為可能。然而&#xff0c;在殘差網絡出現之前&#xff0c;網絡的加深使得網絡訓練變得非常不穩定&#xff0c;甚至出現網絡長時間不更新或者不收斂的情形&#xff0c;…

ER模型理論和三范式

ER模型理論和三范式 各種關系多對一一對一一對多多對多 三范式理論函數依賴完全函數依賴部分函數依賴傳遞&#xff08;間接&#xff09;函數依賴 第一范式&#xff1a;屬性&#xff08;表字段&#xff09;不可切割第二范式&#xff1a;不能存在 部分函數依賴(都存在完全函數依賴…

2款一鍵word生成ppt的AI工具,讓職場辦公更為簡單!

在當下主打異步溝通的職場辦公環境中&#xff0c;我們與很多人的溝通&#xff0c;都是通過書面材料來達成的&#xff0c;這就讓 Word 或文檔編輯軟件變得更為重要&#xff0c;與此同時&#xff0c;有時為了凸現書面材料中的重點&#xff0c;我們還要將 word 文檔轉換為 ppt 來進…

2024年06月CCF-GESP編程能力等級認證Python編程五級真題解析

本文收錄于專欄《Python等級認證CCF-GESP真題解析》&#xff0c;專欄總目錄&#xff1a;點這里&#xff0c;訂閱后可閱讀專欄內所有文章。 一、單選題&#xff08;每題 2 分&#xff0c;共 30 分&#xff09; 第 1 題 在Python中&#xff0c;print((c for c in “GESP”))的輸…

MiniGPT-Med 通用醫學視覺大模型:生成醫學報告 + 視覺問答 + 醫學疾病識別

MiniGPT-Med 通用醫學視覺大模型&#xff1a;生成醫學報告 視覺問答 醫學疾病識別 提出背景解法拆解 論文&#xff1a;https://arxiv.org/pdf/2407.04106 代碼&#xff1a;https://github.com/Vision-CAIR/MiniGPT-Med 提出背景 近年來&#xff0c;人工智能&#xff08;AI…

如何讓自動化測試框架更自動化?

一、引言 ?對于大廠的同學來說&#xff0c;接口自動化是個老生常談的話題了&#xff0c;畢竟每年的MTSC大會議題都已經能佐證了&#xff0c;不是大數據測試&#xff0c;就是AI測試等等&#xff08;越來越高大上了&#xff09;。不可否認這些專項的方向是質量智能化發展的方向&…

刷題(day02)

1、leetcode136.刪除鏈表的結點 給定單向鏈表的頭指針和一個要刪除的節點的值&#xff0c;定義一個函數刪除該節點。 返回刪除后的鏈表的頭節點。 示例 1: 輸入: head [4,5,1,9], val 5 輸出: [4,1,9] 解釋: 給定你鏈表中值為 5 的第二個節點&#xff0c;那么在調用了你的函數…

Windows圖形界面(GUI)-SDK-C/C++ - 應用程序結構

公開視頻 -> 鏈接點擊跳轉公開課程博客首頁 -> 鏈接點擊跳轉博客主頁 目錄 入口函數 窗口注冊 窗口創建 窗口顯示 窗口更新 消息循環 窗口過程 窗口銷毀 調試信息 示例代碼 入口函數 在Windows應用程序中&#xff0c;WinMain是主函數&#xff0c;作為應用程序…

網格化監控:Eureka與分布式服務網格的協同監控

網格化監控&#xff1a;Eureka與分布式服務網格的協同監控 引言 在微服務架構中&#xff0c;服務網格技術提供了一種有效的方式來管理和監控服務間的通信。Eureka作為Netflix開源的服務發現框架&#xff0c;雖然本身不直接提供服務網格的監控功能&#xff0c;但可以與服務網格…

設計模式探索:適配器模式

1. 適配器模式介紹 1.1 適配器模式介紹 適配器模式&#xff08;adapter pattern&#xff09;的原始定義是&#xff1a;將一個類的接口轉換為客戶期望的另一個接口&#xff0c;適配器可以讓不兼容的兩個類一起協同工作。 適配器模式的主要作用是把原本不兼容的接口&#xff0c…

【Python_GUI】thinker布局管理——place方法

place方法可以設置組件的大小以及組件在容器中的精確位置&#xff0c;其參數及含義如下&#xff1a; 參數含義X設置組件距離窗口左側的水平距離y設置組件距離窗口頂部的垂直距離width設置組件的寬度height設置組件的高度relx設置組件距離窗口左側的相對距離&#xff0c;范圍為…

c++初階學習----入門(上)

大家好啊。最近學習了一點關于c的知識。這不就迫不及待的來與大家分享了嘛。但我這也是現學現賣所以咧。有很多遺落甚至不對的地方希望大家可以在評論區里面指出來。這樣也可以增加大家對知識的鞏固。 c語言與c的聯系 不知道大家看到c會不會不由自主的聯想到C語言啊。畢竟都是…

手機自帶錄屏在哪?6個軟件教你快速進行手機錄屏

手機自帶錄屏在哪&#xff1f;6個軟件教你快速進行手機錄屏 手機自帶的錄屏功能可以讓你輕松錄制屏幕上的內容&#xff0c;記錄游戲過程、制作教程或捕捉其他重要時刻。不同品牌的手機可能在不同位置提供錄屏功能。以下是一些常見的手機品牌及其錄屏功能位置&#xff0c;以及一…