返回顶部
首页 > 资讯 > 精选 >Scitter库的增强方法是什么
  • 822
分享到

Scitter库的增强方法是什么

2023-06-17 20:06:33 822人浏览 安东尼
摘要

本篇内容介绍了“Scitter库的增强方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!现在对于Scala而言,Twitter是一个很

本篇内容介绍了“Scitter库的增强方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

现在对于Scala而言,Twitter是一个很好的学习对象。在之前一篇文章中,Ted已经谈到了 Twitter,这个微博客站点目前正引起社会性网络的极大兴趣,我们还谈到它的基于 XML-/REST 的 api 如何使它成为开发人员进行研究和探索的一个有趣平台。为此,我们首先充实了“Scitter” 的基本结构,Scitter 是用于访问 Twitter 的一个 Scala 库。

我们对于 Scitter 有几个目标:

  1. 简化 Twitter 访问,比过去打开 Http 连接然后 “手动” 执行操作更容易。

  2. 可以从 Java 客户机轻松访问它。

  3. 轻松模拟以便进行测试

在这一期,我们不必完成整个 Twitter API,但是我们将完成一些核心部分,目的是让这个库达到公共源代码控制库的程度,便于其他人来完成这项工作。

到目前为止:Scitter 0.1

首先我们简单回顾一下到目前为止我们所处的阶段:

清单 1. Scitter v0.1

package com.tedneward.scitter{  import org.apache.commons.httpclient._, auth._, methods._, params._  import scala.xml._    abstract class Status  {        abstract class User    {      val id : Long      val name : String      val screenName : String      val description : String      val location : String      val profileImageUrl : String      val url : String      val protectedUpdates : Boolean      val followersCount : Int    }        object User    {                  def fromXml(node : Node) : User =      {        new User {          val id = (node \ "id").text.toLong          val name = (node \ "name").text          val screenName = (node \ "screen_name").text          val description = (node \ "description").text          val location = (node \ "location").text          val profileImageUrl = (node \ "profile_image_url").text          val url = (node \ "url").text          val protectedUpdates = (node \ "protected").text.toBoolean          val followersCount = (node \ "followers_count").text.toInt        }      }    }      val createdAt : String    val id : Long    val text : String    val source : String    val truncated : Boolean    val inReplyToStatusId : Option[Long]    val inReplyToUserId : Option[Long]    val favorited : Boolean    val user : User  }    object Status  {            def fromXml(node : Node) : Status =    {      new Status {        val createdAt = (node \ "created_at").text        val id = (node \ "id").text.toLong        val text = (node \ "text").text        val source = (node \ "source").text        val truncated = (node \ "truncated").text.toBoolean        val inReplyToStatusId =          if ((node \ "in_reply_to_status_id").text != "")            Some((node \"in_reply_to_status_id").text.toLong)          else            None        val inReplyToUserId =           if ((node \ "in_reply_to_user_id").text != "")            Some((node \"in_reply_to_user_id").text.toLong)          else            None        val favorited = (node \ "favorited").text.toBoolean        val user = User.fromXml((node \ "user")(0))      }    }  }    object Scitter  {        def test : Boolean =    {      val client = new HttpClient()      val method = new GetMethod("http://twitter.com/help/test.xml")      method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))      client.executeMethod(method)            val statusLine = method.getStatusLine()      statusLine.getStatusCode() == 200    }        def publicTimeline : List[Status] =    {      import scala.collection.mutable.ListBuffer          val client = new HttpClient()      val method = new GetMethod("http://twitter.com/statuses/public_timeline.xml")      method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))      client.executeMethod(method)            val statusLine = method.getStatusLine()      if (statusLine.getStatusCode() == 200)      {        val responseXML =          XML.loadString(method.getResponseBodyAsString())        val statusListBuffer = new ListBuffer[Status]        for (n <- (responseXML \\ "status").elements)          statusListBuffer += (Status.fromXml(n))                statusListBuffer.toList      }      else      {        Nil      }    }  }    class Scitter(username : String, passWord : String)  {        def verifyCredentials : Boolean =    {      val client = new HttpClient()      val method = new GetMethod("http://twitter.com/help/test.xml")      method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))              client.getParams().setAuthenticationPreemptive(true)      val creds = new UsernamePasswordCredentials(username, password)      client.getState().setCredentials(        new AuthScope("twitter.com", 80, AuthScope.ANY_REALM), creds)      client.executeMethod(method)            val statusLine = method.getStatusLine()      statusLine.getStatusCode() == 200    }  }}

代码有点长,但是很容易分为几个基本部分:

  1. case 类 UserStatus,表示 Twitter 在对 API 调用的响应中发回给客户机的基本类型,包括用于构造或提取 XML 的一些方法。

  2. 一个 Scitter 独立对象,处理那些不需要对用户进行验证的操作。

  3. 一个 Scitter 实例(用 username 和 password 参数化),用于那些需要对用户执行验证的操作。

到目前为止,对于这两种 Scitter 类型,我们只谈到了测试、verifyCredentials 和 public_timeline API。虽然这些有助于确定 HTTP 访问的基础(使用 Apache HttpClient 库)可以工作,并且我们将 XML 响应转换成 Status 对象的基本方式也是可行的,但是现在我们甚至不能进行基本的 “我的朋友在说什么” 的公共时间线查询,也没有采取过基本的措施来防止代码库中出现 “重复” 问题,更不用说寻找一些方法来模拟用于测试的网络访问代码。

显然,在这一期我们有很多事情要做。

连接

对于代码,***件让我烦恼的事就是,我在 Scitter 对象和类的每个方法中都重复这样的操作序列:创建 HttpClient 实例,对它进行初始化,用必要的验证参数对它进行参数化,等等。当它们只有 3 个方法时,可以进行管理,但是显然不易于伸缩,而且以后还会增加很多方法。此外,以后重新在那些方法中引入模拟和/或本地/离线测试功能将十分困难。所以我们要解决这个问题。

实际上,我们这里介绍的并不是 Scala 本身,而是不要重复自己(Don't-Repeat-Yourself)的思想。因此,我将从基本的面向对象方法开始:创建一个 helper 方法,用于做实际工作:

清单 2. 对代码库执行 DRY 原则

package com.tedneward.scitter{  // ...  object Scitter  {    // ...    private[scitter] def exec ute(url : String) =    {      val client = new HttpClient()      val method = new GetMethod(url)            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))              client.executeMethod(method)            (method.getStatusLine().getStatusCode(), method.getResponseBodyAsString())    }  }}

注意两点:首先,我从 execute() 方法返回一个元组,其中包含状态码和响应主体。这正是让元组成为语言中固有的一部分的一个强大之处,因为实际上很容易从一个方法调用返回多个返回值。当然,在 Java 代码中,也可以通过创建包含元组元素的***或嵌套类来实现这一点,但是这需要一整套专用于这一个方法的代码。此外,本来也可以返回一个包含 String 键和 Object 值的 Map,但是那样就在很大程度上丧失了类型安全性。元组并不是一个非常具有变革性的特性,它只不过是又一个使 Scala 成为强大语言的优秀特性。

由于使用元组,我需要使用 Scala 的另一个特色语法将两个结果都捕捉到本地变量中,就像下面这个重写后的 Scitter.test 那样:

清单 3. 这符合 DRY 原则吗?

package com.tedneward.scitter{  // ...  object Scitter  {        def test : Boolean =    {      val (statusCode, statusBody) =        execute("http://twitter.com/statuses/public_timeline.xml")      statusCode == 200    }  }}

实际上,我可以轻松地将 statusBody 全部去掉,并用 _ 替代它,因为我没有用过第二个参数(test 没有返回 statusBody),但是对于其他调用将需要这个 statusBody,所以出于演示的目的,我保留了该参数。

注意,execute() 没有泄露任何与实际 HTTP 通信相关的细节 — 这是 Encapsulation 101。这样便于以后用其他实现替换 execute()(以后的确要这么做),或者便于通过重用 HttpClient 对象来优化代码,而不是每次重新实例化新的对象。

接下来,注意到 execute() 方法在 Scitter 对象上吗?这意味着我将可以从不同的 Scitter 实例中使用它(至少现在可以这样做,如果以后在 execute() 内部执行的操作不允许这样做,则另当别论)— 这就是我将 execute() 标记为 private[scitter] 的原因,这意味着 com.tedneward.scitter 包中的所有内容都可以看到它。

(顺便说一句,如果还没有运行测试的话,那么请运行测试,确保一切运行良好。我将假设我们在讨论代码时您会运行测试,所以如果我忘了提醒您,并不意味着您也忘记这么做。)

顺便说一句,对于经过验证的访问,为了支持 Scitter 类,需要一个用户名和密码,所以我将创建一个重载的 execute() 方法,该方法新增两个 String 参数:

清单 4. 更加 DRY 化的版本

package com.tedneward.scitter{  // ...  object Scitter  {    // ...    private[scitter] def execute(url : String, username : String, password : String) =    {      val client = new HttpClient()      val method = new GetMethod(url)            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))          client.getParams().setAuthenticationPreemptive(true)  client.getState().setCredentials(new AuthScope("twitter.com", 80, AuthScope.ANY_REALM),  new UsernamePasswordCredentials(username, password))            client.executeMethod(method)            (method.getStatusLine().getStatusCode(), method.getResponseBodyAsString())    }  }}

实际上,除了验证部分,这两个 execute() 基本上是做相同的事情,我们可以按照第二个版本完全重写***个 execute(),但是要注意,Scala 要求显式表明重载的 execute() 的返回类型:

清单 5. 放弃 DRY

package com.tedneward.scitter{  // ...  object Scitter  {    // ...    private[scitter] def execute(url : String) : (Int, String) =  execute(url, "", "")    private[scitter] def execute(url : String, username : String, password : String) =    {      val client = new HttpClient()      val method = new GetMethod(url)            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,         new DefaultHttpMethodRetryHandler(3, false))              if ((username != "") && (password != ""))      {        client.getParams().setAuthenticationPreemptive(true)        client.getState().setCredentials(          new AuthScope("twitter.com", 80, AuthScope.ANY_REALM),            new UsernamePasswordCredentials(username, password))      }            client.executeMethod(method)            (method.getStatusLine().getStatusCode(), method.getResponseBodyAsString())    }  }}

到目前为止,一切良好。我们对 Scitter 的通信部分进行了 DRY 化处理,接下来我们转移到下一件事情:获得朋友的 tweet 的列表。

连接(到朋友)

Twitter API 表明,friends_timeline API 调用 “返回认证用户和该用户的朋友发表的最近 20 条状态”。(它还指出,对于直接从 Twitter WEB 站点使用 Twitter 的用户,“这相当于 Web 上的 ‘/home’”。)对于任何 Twitter API 来说,这是非常基本的要求,所以让我们将它添加到 Scitter 类中。之所以将它添加到类而不是对象中,是因为正如文档中指出的那样,这是以验证用户的身份做的事情,而我已经决定归入 Scitter 类,而不是 Scitter 对象。

但是,这里我们碰到一块绊脚石:friends_timeline 调用接受一组 “可选参数”,包括 since_idmax_idcountpage,以控制返回的结果。这是一项比较复杂的操作,因为 Scala 不像其他语言(例如 Groovy、JRuby 或 javascript)那样原生地支持 “可选参数” 的思想,但是我们首先来处理简单的东西 — 我们来创建一个 friendsTimeline 方法,该方法只执行一般的、非参数化的调用:

清单 6.“告诉我你身边的朋友是怎样的...”

package com.tedneward.scitter{  class Scitter  {    def friendsTimeline : List[Status] =    {      val (statusCode, statusBody) =       Scitter.execute("http://twitter.com/statuses/friends_timeline.xml",                        username, password)      if (statusCode == 200)      {        val responseXML = XML.loadString(statusBody)        val statusListBuffer = new ListBuffer[Status]        for (n <- (responseXML \\ "status").elements)          statusListBuffer += (Status.fromXml(n))                statusListBuffer.toList      }      else      {        Nil      }    }  }}

到目前为止,一切良好。用于测试的相应方法看上去如下所示:

清单 7. “我能判断您是怎样的人 ”(Miguel de Cervantes)

package com.tedneward.scitter.test{  class ScitterTests  {    // ...    @Test def scitterFriendsTimeline =    {      val scitter = new Scitter(testUser, testPassword)      val result = scitter.friendsTimeline      assertTrue(result.length > 0)    }  }}

好极了。看上去就像 Scitter 对象中的 publicTimeline() 方法,并且行为也几乎完全相同。

对于我们来说,那些可选参数仍然有问题。因为 Scala 并没有可选参数这样的语言特性,乍一看来,惟一的选择就是完整地创建重载的 friendsTimeline() 方法,让该方法带有一定数量的参数。

幸运的是,还有一种更好的方式,即通过一种有趣的方式将 Scala 的两个语言特性(有一个特性我还没有提到过) — case 类和 “重复参数” 结合起来(见清单 8):

清单 8. “我有多爱你?……”

package com.tedneward.scitter{  // ...    abstract class OptionalParam  case class Id(id : String) extends OptionalParam  case class UserId(id : Long) extends OptionalParam  case class Since(since_id : Long) extends OptionalParam  case class Max(max_id : Long) extends OptionalParam  case class Count(count : Int) extends OptionalParam  case class Page(page : Int) extends OptionalParam    class Scitter(username : String, password : String)  {    // ...    def friendsTimeline(options : OptionalParam*) : List[Status] =    {      val optionsStr =        new StringBuffer("http://twitter.com/statuses/friends_timeline.xml?")      for (option <- options)      {        option match        {          case Since(since_id) =>            optionsStr.append("since_id=" + since_id.toString() + "&")          case Max(max_id) =>            optionsStr.append("max_id=" + max_id.toString() + "&")          case Count(count) =>            optionsStr.append("count=" + count.toString() + "&")          case Page(page) =>            optionsStr.append("page=" + page.toString() + "&")        }      }            val (statusCode, statusBody) =        Scitter.execute(optionsStr.toString(), username, password)      if (statusCode == 200)      {        val responseXML = XML.loadString(statusBody)        val statusListBuffer = new ListBuffer[Status]        for (n <- (responseXML \\ "status").elements)          statusListBuffer += (Status.fromXml(n))                statusListBuffer.toList      }      else      {        Nil      }    }  }}

看到标在选项参数后面的 * 吗?这表明该参数实际上是一个参数序列,这类似于 Java 5 中的 varargs 结构。和 varargs 一样,传递的参数数量可以像前面那样为 0(不过,我们将需要回到测试代码,向 friendsTimeline 调用增加一对括号,否则编译器无法作出判断:是调用不带参数的方法,还是出于部分应用之类的目的而调用该方法);我们还可以开始传递那些 case 类型,如下面的清单所示:

清单 9. “……听我细细说”(William Shakespeare)

package com.tedneward.scitter.test{  class ScitterTests  {    // ...    @Test def scitterFriendsTimelineWithCount =    {      val scitter = new Scitter(testUser, testPassword)      val result = scitter.friendsTimeline(Count(5))      assertTrue(result.length == 5)    }  }}

当然,总是存在这样的可能性:客户机传入古怪的参数序列,例如 friendsTimeline(Count(5), Count(6), Count(7)),但是在这里,我们只是将列表传递给 Twitter(希望它们的错误处理足够强大,能够只采用指定的***那个参数)。当然,如果真的担心这一点,也很容易在构造发送到 Twitter 的 URL 之前,从头至尾检查重复参数列表,并采用指定的每种参数的***一个参数。不过,后果自负

兼容性

但是,这又产生一个有趣的问题:从 Java 代码调用这个方法有多容易?毕竟,如果这个库的主要目标之一是维护与 Java 代码的兼容性,那么我们需要确保 Java 代码在使用它时不至于太麻烦。

我们首先通过我们的好朋友 javap 检验一下 Scitter 类:

清单 10. 哦,没错,Java 代码……我现在想起来了……

C:\>javap -classpath classes com.tedneward.scitter.ScitterCompiled from "scitter.scala"public class com.tedneward.scitter.Scitter extends java.lang.Object implements scala.ScalaObject{    public com.tedneward.scitter.Scitter(java.lang.String, java.lang.String);    public scala.List friendsTimeline(scala.Seq);    public boolean verifyCredentials();    public int $tag()       throws java.rmi.RemoteException;}

这时我心中有两点担心。首先,friendsTimeline() 带有一个 scala.Seq 参数(这是我们刚才用过的重复参数特性)。其次,friendsTimeline() 方法和 Scitter 对象中的 publicTimeline() 方法一样(如果不信,可以运行 javap 查证),返回一个元素列表 scala.List。这两种类型在 Java 代码中有多好用?

最简单的方法是用 Java 代码而不是 Scala 编写一组小型的 JUnit 测试,所以接下来我们就这样做。虽然可以测试 Scitter 实例的构造,并调用它的 verifyCredentials() 方法,但这些并不是特别有用 — 记住,我们不是要验证 Scitter 类的正确性,而是要看看从 Java 代码中使用它有多容易。为此,我们直接编写一个测试,该测试将获取 “friends timeline” — 换句话说,我们要实例化一个 Scitter 实例,并且不使用任何参数来调用它的 friendsTimeline() 方法。

这有点复杂,因为需要传入 scala.Seq 参数 — scala.Seq 是一个 Scala 特性,它将映射到底层 JVM 中的一个接口,所以不能直接实例化。我们可以尝试典型的 Java null 参数,但是这样做会在运行时抛出异常。我们需要的是一个 scala.Seq 类,以便从 Java 代码中轻松地实例化这个类。

最终,我们还是在 mutable.ListBuffer 类型中找到一个这样的类,这正是在 Scitter 实现本身中使用的类型:

清单 11. 现在我明白了自己为什么喜欢 Scala……

package com.tedneward.scitter.test;import org.junit.*;import com.tedneward.scitter.*;public class JavaScitterTests{  public static final String testUser = "TESTUSER";  public static final String testPassword = "TESTPASSWORD";    @Test public void getFriendsStatuses()  {    Scitter scitter = new Scitter(testUser, testPassword);    if (scitter.verifyCredentials())    {      scala.List statuses =        scitter.friendsTimeline(new scala.collection.mutable.ListBuffer());      Assert.assertTrue(statuses.length() > 0);    }    else      Assert.assertTrue(false);  }}

使用返回的 scala.List 不是问题,因为我们可以像对待其他 Collection 类一样对待它(不过我们的确怀念 Collection 的一些优点,因为 List 上基于 Scala 的方法都假设您将从 Scala 中与它们交互),所以,遍历结果并不难,只要用上一点 “旧式” Java 代码(大约 1995 年时候的风格):

清单 12. 重回 1995,又见 Vector……

package com.tedneward.scitter.test;import org.junit.*;import com.tedneward.scitter.*;public class JavaScitterTests{  public static final String testUser = "TESTUSER";  public static final String testPassword = "TESTPASSWORD";  @Test public void getFriendsStatuses()  {    Scitter scitter = new Scitter(testUser, testPassword);    if (scitter.verifyCredentials())    {      scala.List statuses =        scitter.friendsTimeline(new scala.collection.mutable.ListBuffer());      Assert.assertTrue(statuses.length() > 0);            for (int i=0; i<STATUSES.LENGTH(); PRE < } Assert.assertTrue(false); else stat.text()); + ? said System.out.println(stat.user().screenName() stat="(Status)statuses.apply(i);" Status { i++)>

这将我们引向另一个部分,即将参数传递到 friendsTimeline() 方法。不幸的是,ListBuffer 类型不是将一个集合作为构造函数参数,所以我们必须构造参数列表,然后将集合传递到方法调用。这样有些单调乏味,但还可以承受:

清单 13. 现在可以回到 Scala 吗?

package com.tedneward.scitter.test;import org.junit.*;import com.tedneward.scitter.*;public class JavaScitterTests{  public static final String testUser = "TESTUSER";  public static final String testPassword = "TESTPASSWORD";    // ...  @Test public void getFriendsStatusesWithCount()  {    Scitter scitter = new Scitter(testUser, testPassword);    if (scitter.verifyCredentials())    {      scala.collection.mutable.ListBuffer params =        new scala.collection.mutable.ListBuffer();      params.$plus$eq(new Count(5));            scala.List statuses = scitter.friendsTimeline(params);      Assert.assertTrue(statuses.length() > 0);      Assert.assertTrue(statuses.length() == 5);            for (int i=0; i<STATUSES.LENGTH(); PRE < } Assert.assertTrue(false); else stat.text()); + ? said System.out.println(stat.user().screenName() stat="(Status)statuses.apply(i);" Status { i++)>

所以,虽然 Java 版本比对应的 Scala 版本要冗长一点,但是到目前为止,从任何要使用 Scitter 库的 Java 客户机中调用该库仍然非常简单。好极了。

“Scitter库的增强方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Scitter库的增强方法是什么

本文链接: https://lsjlt.com/news/293136.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Scitter库的增强方法是什么
    本篇内容介绍了“Scitter库的增强方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!现在对于Scala而言,Twitter是一个很...
    99+
    2023-06-17
  • 增强WORKORDER_UPDATE方法是什么
    本篇内容主要讲解“增强WORKORDER_UPDATE方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“增强WORKORDER_UPDATE方法是什么”吧!题目这个增强的输入参数很恐怖,长...
    99+
    2023-06-04
  • SAP ABAP7.50隐式增强的方法是什么
    本篇内容介绍了“SAP ABAP7.50隐式增强的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!我们知道在SAP中除了可以使用EN...
    99+
    2023-06-04
  • virtualbox6安装centos增强功能的方法是什么
    这篇“virtualbox6安装centos增强功能的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“virtual...
    99+
    2023-06-26
  • java自定义切面增强的方法是什么
    本篇内容主要讲解“java自定义切面增强的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java自定义切面增强的方法是什么”吧!java自定义切面增强1. 自定义一个注解@Target...
    99+
    2023-07-05
  • Hybris做增强的两种方式是什么
    这篇文章主要讲解了“Hybris做增强的两种方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Hybris做增强的两种方式是什么”吧!传统的扩展方式,即In-App增强方式,Hybri...
    99+
    2023-06-04
  • 云服务器显示增强配置的方法是什么
    要显示云服务器的增强配置,可以通过以下方法:1. 登录云服务器控制台:打开云服务器提供商的控制台,使用您的账号和密码登录。2. 选择...
    99+
    2023-09-26
    云服务器
  • SAP订单编排和流程增强的方法是什么
    本篇内容主要讲解“SAP订单编排和流程增强的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SAP订单编排和流程增强的方法是什么”吧!SAP产品里的订单处理,无论是On-Premises...
    99+
    2023-06-04
  • Fiori标准应用的增强方式是什么
    这篇文章主要介绍“Fiori标准应用的增强方式是什么”,在日常操作中,相信很多人在Fiori标准应用的增强方式是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Fiori标准应用的增强方式是什么”的疑惑有所...
    99+
    2023-06-04
  • oracle强制关闭数据库的方法是什么
    Oracle数据库的强制关闭方法是使用SHUTDOWN命令进行关闭。可以使用以下两种方式进行强制关闭:1. 使用SQL*Plus关闭...
    99+
    2023-09-29
    oracle 数据库
  • Python基于域相关实现图像增强的方法是什么
    这篇文章主要讲解了“Python基于域相关实现图像增强的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python基于域相关实现图像增强的方法是什么”吧!介绍当在图像上训练深度神经...
    99+
    2023-06-26
  • django数据库增删改查的方法是什么
    Django是一个开发Web应用程序的框架,它提供了一种简单而强大的方式来进行数据库的增删改查操作。以下是Django中常用的数据库...
    99+
    2023-10-11
    django 数据库
  • SQLite数据库增删改查的方法是什么
    SQLite数据库的增删改查操作可以通过SQL语句来实现,常用的方法如下: 增加数据:使用INSERT INTO语句插入新的数据...
    99+
    2024-04-09
    sql
  • winform数据库增删改查的方法是什么
    在WinForm应用程序中,进行数据库的增删改查操作通常需要使用ADO.NET(ActiveX Data Objects.NET)来...
    99+
    2024-04-09
    winform
  • linux强制rpm的方法是什么
    在Linux中,可以使用以下方法强制安装RPM包:1. 使用“--force”选项:在命令行中使用“--force”选项可以强制安装...
    99+
    2023-09-16
    linux
  • Oracle和mysql数据库增、删、改的方法是什么
    这篇文章主要讲解了“Oracle和mysql数据库增、删、改的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Oracle和mysql数据库增、删、...
    99+
    2024-04-02
  • eclipse对数据库的增删改查方法是什么
    Eclipse本身并不提供直接操作数据库的方法,它是一个集成开发环境(IDE),用于开发和调试Java应用程序。但是,你可以使用Ja...
    99+
    2023-08-14
    eclipse 数据库
  • Python Opencv数据增强的方法
    本篇内容介绍了“Python Opencv数据增强的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!常见的数据增强操作有:按比例...
    99+
    2023-06-29
  • mysql增删改的方法是什么
    这篇文章主要介绍“mysql增删改的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“mysql增删改的方法是什么”文章能帮助大家解决问题。插入数据代码案例#...
    99+
    2022-11-30
    mysql
  • oracle增加列的方法是什么
    在Oracle中,要增加列可以通过使用ALTER TABLE语句来实现。具体步骤如下: 1、首先,使用ALTER TABLE语句来指...
    99+
    2024-04-09
    oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作