Web Services Software Factory

Web服务软件工厂(WSSF)演练之三:创建服务契约和实现方法

关键字:Web Services Software Factory, Service Contracts, Service Implementation

您应该已经完成了本演练的第1部分和第2部分,然后再开始这一部分的演练。

今天的教程将为我们的WCF服务创建服务契约和实际实现方法。 首先,在您的解决方案资源管理器中,右键点击MyCryptographyService.model后Add–>New Model。

具体的命名请参见下图所示。

如果您的开发环境没有出现属性窗口,右击空白设计区域,然后单击属性。跟我们创建数据契约一样, Project Mapping Table选择我们对应的项目 “Implementation Technology”下拉列表中选择 WCF Extension。设置“Serializer Type”为DataContractSerializer 。

通过第二部分的练习,你应该熟悉如何操作我们的设计区域 ,工具箱的内容将显示与创建服务契约相关的工具。

拖动一个Service并命名为CryptService,一个Service Contract并命名为CryptService,一个Operation并命名为EncryptString,和两个messages分别命名为 EncryptStringRequest和EncryptStringResponse。到我们的空白设计区域,如图所示排列他们。

使用“Connector”连接工具连接Service Contract Service对象(也可以在Service的属性窗口中设置Service Contract的属性)。下面将是设定Operation和Service Contract及messages之间关系的操作,但这部分使用。“Connector”连接工具有些繁琐,可以直接定义Operation的Service Contract的属性为CryptService,“Request”属性为EncryptStringRequest,“Response”的属性为EncryptStringResponse即可。设置好以后应该如下图所示。

按照上述步骤,从工具箱中在拖动2个Operations到您的设计区域,并分别命名为DecryptString和HashString 。工具箱中在拖动4个Messages到设计区域,并分别命名为DecryptStringRequest 、DecryptStringResponse 、 HashStringRequest 和HashStringResponse 。Operations连接各对象间的连接关系参照EncryptString 的各项属性设置,完成后如下图所示 。

继续努力,我们已经接近成功。下面需要给messages对象添加一些Data Contract Message Part。右键单击EncryptStringRequest选择Add–>Data Contract Message Part。将其命名为EncryptionObject 。单击我们刚刚建立的EncryptionObject,在属性窗口中设置Type。单击(...)按钮,将弹出如下图所示的此对话框。选择逐层展开后选择EncryptionObject单击确定。

继续为DecryptStringRequest对象添加一个Data Contract Message Part 命名为EncryptionObject,为HashStringRequest添加命名为HashObject。并对应设置好Type属性。继续分别为3个Response messages对象添加一个Primitive Message Parts,分别命名为“ReturnValue”。需要注意的是,每个名称输入时要精确,名称字符串结尾不能留有空格,在您采用Copy / Paste名称时尤其要注意这一点,否则检查起来很麻烦。

现在,在设计区域的某个白色地方点击右键,选择Validate All(全部验证)如果返回一些错误,请逐一认真检查。如果全部验证已经通过,右键单击,并选择Generate Code(生成代码)。随后,将会有更多的生成代码出现在MyCryptographyService.ServiceImplementation和MyCryptographyService.ServiceContracts 解决方案的类库项目中。

下一步,右键点击MyCryptographyService.BusinessLogic项目,并选择添加一个Class(类)。命名为CryptographyServiceBusinessLogic.cs 。为了节省时间,我已经准备好了如下的代码,请直接使用如下的代码。

using MyCryptographyService.BusinessEntities;

using MyCryptographyService.DataAccess;

namespace MyCryptographyService.BusinessLogic

{

public class CryptographyServiceBusinessLogic

{

private CryptManager manager = new CryptManager();

public string EncryptString(EncryptionObject encryptionObject)

{

return manager.EncryptString(encryptionObject);

}

public string DecryptString(EncryptionObject encryptionObject)

{

return manager.DecryptString(encryptionObject);

}

public string HashString(HashObject hashObject)

{

return manager.HashString(hashObject);

}

}

}

using MyCryptographyService.BusinessEntities;

using MyCryptographyService.DataAccess;

namespace MyCryptographyService.BusinessLogic

{

///

/// This class isn't going to do much in this tutorial.

/// However, in here, you could apply business logic to your service,

/// and maybe make some decisions about which methods in the Data Access Layer's

/// "manager" that you wanted to call. For this example, it is just an

/// "enterprisey" pass-through to show the concept.

///

public class CryptographyServiceBusinessLogic

{

private CryptManager manager = new CryptManager();

public string EncryptString(EncryptionObject encryptionObject)

{

return manager.EncryptString(encryptionObject);

}

public string DecryptString(EncryptionObject encryptionObject)

{

return manager.DecryptString(encryptionObject);

}

public string HashString(HashObject hashObject)

{

return manager.HashString(hashObject);

}

}

}

Next, right click on the MyCryptographyService.DataAccess project and add a new class called CryptographyServiceManager. The code for it is below.

下一步,右键点击MyCryptographyService.DataAccess项目,并添加一个新类称为CryptographyServiceManager 。它的代码如下。

using System;

using System.IO;

using System.Security.Cryptography;

using System.Text;

using MyCryptographyService.BusinessEntities;

namespace MyCryptographyService.DataAccess

{

/// <SUMMARY>

///

/// </SUMMARY>

public class CryptManager

{

private const string KEY = "$0ftw@r3";

private const string IV = "@p3t30n&";

private DESCryptoServiceProvider des = new DESCryptoServiceProvider();

public CryptManager()

{

des.Key = ASCIIEncoding.ASCII.GetBytes(KEY);

des.IV = ASCIIEncoding.ASCII.GetBytes(IV);

}

public string HashString(HashObject hashObject)

{

switch (hashObject.HashType)

{

case HashType.MD5:

return getMd5Sum(hashObject.StringToHash);

case HashType.SHA256:

return getSha256Hash(hashObject.StringToHash);

default:

throw new NotImplementedException("That Hashing Algorithm is not supported");

}

}

public string EncryptString(EncryptionObject encryptionObject)

{

string cryptText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

cryptText = encryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

cryptText = encryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return cryptText;

}

public string DecryptString(EncryptionObject encryptionObject)

{

string plainText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

plainText = decryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

plainText = decryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return plainText;

}

private string encryptDes(string plainText)

{

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(), CryptoStreamMode.Write);

StreamWriter writer = new StreamWriter(cryptoStream);

writer.Write(plainText);

writer.Flush();

cryptoStream.FlushFinalBlock();

writer.Flush();

return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);

}

private string decryptDes(string cryptText)

{

MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cryptText));

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateDecryptor(), CryptoStreamMode.Read);

StreamReader reader = new StreamReader(cryptoStream);

return reader.ReadToEnd();

}

private string encryptRijndael(string plainText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//This class uses an extension of the PBKDF1 algorithm defined in the PKCS#5 v2.0

//standard to derive bytes suitable for use as key material from a password.

//The standard is documented in IETF RRC 2898.

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric encryptor object.

ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream();

//Defines a stream that links data streams to cryptographic transformations

CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

cryptoStream.Write(plainBytes, 0, plainBytes.Length);

//Writes the final state and clears the buffer

cryptoStream.FlushFinalBlock();

byte[] cipherBytes = memoryStream.ToArray();

memoryStream.Close();

cryptoStream.Close();

string encryptedData = Convert.ToBase64String(cipherBytes);

return encryptedData;

}

private string decryptRijndael(string cipherText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] encryptedData = Convert.FromBase64String(cipherText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//Making of the key for decryption

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric Rijndael decryptor object.

ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream(encryptedData);

//Defines the cryptographics stream for decryption.THe stream contains decrpted data

CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

byte[] plainText = new byte[encryptedData.Length];

int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);

memoryStream.Close();

cryptoStream.Close();

//Converting to string

string decryptedData = Encoding.Unicode.GetString(plainText, 0, decryptedCount);

return decryptedData;

}

private string getMd5Sum(string inputText)

{

// First we need to convert the string into bytes, which

// means using a text encoder.

Encoder encoder = System.Text.Encoding.Unicode.GetEncoder();

// Create a buffer large enough to hold the string

byte[] unicodeText = new byte[inputText.Length * 2];

encoder.GetBytes(inputText.ToCharArray(), 0, inputText.Length, unicodeText, 0, true);

// Now that we have a byte array we can ask the CSP to hash it

MD5 md5 = new MD5CryptoServiceProvider();

byte[] result = md5.ComputeHash(unicodeText);

// Build the final string by converting each byte

// into hex and appending it to a StringBuilder

StringBuilder sb = new StringBuilder();

for (int i = 0; i < result.Length; i++)

{

sb.Append(result[i].ToString("X2"));

}

// And return it

return sb.ToString();

}

private string getSha256Hash(string plainText)

{

byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

byte[] saltBytes = Encoding.UTF8.GetBytes(IV);

byte[] plainTextWithSaltBytes =

new byte[plainTextBytes.Length + saltBytes.Length];

for (int i = 0; i < plainTextBytes.Length; i++)

plainTextWithSaltBytes[i] = plainTextBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

HashAlgorithm hash = new SHA256Managed();

byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

byte[] hashWithSaltBytes = new byte[hashBytes.Length +

saltBytes.Length];

for (int i = 0; i < hashBytes.Length; i++)

hashWithSaltBytes[i] = hashBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

return hashValue;

}

}

}

using System;

using System.IO;

using System.Security.Cryptography;

using System.Text;

using MyCryptographyService.BusinessEntities;

namespace MyCryptographyService.DataAccess

{

///

/// This is the class where all the action happens, and all gathering of external

/// resources (DB, XML files, registry, etc) should be done from here. Ideally, in this

/// scenerio, you would store your keys external to the application and the

/// transformations would be done here with those keys after they were received.

///

/// NOTE: These implementations are derivations (or outright copying) from samples

/// posted on the internet. Included are:

///

/// http://blog.stevex.net/index.php/c-code-snippet-creating-an-md5-hash-string/

/// http://www.codeproject.com/KB/cs/NET_Encrypt_Decrypt.aspx

/// http://www.obviex.com/samples/hash.aspx

///

public class CryptManager

{

// Note: This is not a tutorial on encryption. Key management

// is paramount in good encryption and of course storing your

// key in plain text in the code is not a good idea. This is

// merely sample code and should not be considered good

// cryptography practice.

private const string KEY = "$0ftw@r3";

private const string IV = "@p3t30n&";

private DESCryptoServiceProvider des = new DESCryptoServiceProvider();

public CryptManager()

{

des.Key = ASCIIEncoding.ASCII.GetBytes(KEY);

des.IV = ASCIIEncoding.ASCII.GetBytes(IV);

}

public string HashString(HashObject hashObject)

{

switch (hashObject.HashType)

{

case HashType.MD5:

return getMd5Sum(hashObject.StringToHash);

case HashType.SHA256:

return getSha256Hash(hashObject.StringToHash);

default:

throw new NotImplementedException("That Hashing Algorithm is not supported");

}

}

public string EncryptString(EncryptionObject encryptionObject)

{

string cryptText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

cryptText = encryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

cryptText = encryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return cryptText;

}

public string DecryptString(EncryptionObject encryptionObject)

{

string plainText = string.Empty;

switch (encryptionObject.EncryptionAlgorithm)

{

case EncryptionAlgorithm.DES:

plainText = decryptDes(encryptionObject.Text);

break;

case EncryptionAlgorithm.Rijndael:

plainText = decryptRijndael(encryptionObject.Text);

break;

default:

throw new NotImplementedException("You provided an algorithm that is not implemented.");

}

return plainText;

}

private string encryptDes(string plainText)

{

MemoryStream memoryStream = new MemoryStream();

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(), CryptoStreamMode.Write);

StreamWriter writer = new StreamWriter(cryptoStream);

writer.Write(plainText);

writer.Flush();

cryptoStream.FlushFinalBlock();

writer.Flush();

return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);

}

private string decryptDes(string cryptText)

{

MemoryStream memoryStream = new MemoryStream(Convert.FromBase64String(cryptText));

CryptoStream cryptoStream = new CryptoStream(memoryStream, des.CreateDecryptor(), CryptoStreamMode.Read);

StreamReader reader = new StreamReader(cryptoStream);

return reader.ReadToEnd();

}

private string encryptRijndael(string plainText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] plainBytes = Encoding.Unicode.GetBytes(plainText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//This class uses an extension of the PBKDF1 algorithm defined in the PKCS#5 v2.0

//standard to derive bytes suitable for use as key material from a password.

//The standard is documented in IETF RRC 2898.

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric encryptor object.

ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream();

//Defines a stream that links data streams to cryptographic transformations

CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);

cryptoStream.Write(plainBytes, 0, plainBytes.Length);

//Writes the final state and clears the buffer

cryptoStream.FlushFinalBlock();

byte[] cipherBytes = memoryStream.ToArray();

memoryStream.Close();

cryptoStream.Close();

string encryptedData = Convert.ToBase64String(cipherBytes);

return encryptedData;

}

private string decryptRijndael(string cipherText)

{

RijndaelManaged rijndaelCipher = new RijndaelManaged();

byte[] encryptedData = Convert.FromBase64String(cipherText);

byte[] salt = Encoding.ASCII.GetBytes(KEY.Length.ToString());

//Making of the key for decryption

PasswordDeriveBytes secretKey = new PasswordDeriveBytes(KEY, salt);

//Creates a symmetric Rijndael decryptor object.

ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));

MemoryStream memoryStream = new MemoryStream(encryptedData);

//Defines the cryptographics stream for decryption.THe stream contains decrpted data

CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);

byte[] plainText = new byte[encryptedData.Length];

int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);

memoryStream.Close();

cryptoStream.Close();

//Converting to string

string decryptedData = Encoding.Unicode.GetString(plainText, 0, decryptedCount);

return decryptedData;

}

private string getMd5Sum(string inputText)

{

// First we need to convert the string into bytes, which

// means using a text encoder.

Encoder encoder = System.Text.Encoding.Unicode.GetEncoder();

// Create a buffer large enough to hold the string

byte[] unicodeText = new byte[inputText.Length * 2];

encoder.GetBytes(inputText.ToCharArray(), 0, inputText.Length, unicodeText, 0, true);

// Now that we have a byte array we can ask the CSP to hash it

MD5 md5 = new MD5CryptoServiceProvider();

byte[] result = md5.ComputeHash(unicodeText);

// Build the final string by converting each byte

// into hex and appending it to a StringBuilder

StringBuilder sb = new StringBuilder();

for (int i = 0; i < result.Length; i++)

{

sb.Append(result[i].ToString("X2"));

}

// And return it

return sb.ToString();

}

private string getSha256Hash(string plainText)

{

byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

byte[] saltBytes = Encoding.UTF8.GetBytes(IV);

byte[] plainTextWithSaltBytes =

new byte[plainTextBytes.Length + saltBytes.Length];

for (int i = 0; i < plainTextBytes.Length; i++)

plainTextWithSaltBytes[i] = plainTextBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

HashAlgorithm hash = new SHA256Managed();

byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

byte[] hashWithSaltBytes = new byte[hashBytes.Length +

saltBytes.Length];

for (int i = 0; i < hashBytes.Length; i++)

hashWithSaltBytes[i] = hashBytes[i];

for (int i = 0; i < saltBytes.Length; i++)

hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

string hashValue = Convert.ToBase64String(hashWithSaltBytes);

return hashValue;

}

}

}

在最后完成本部分演练之前,我们还需要做一件事,我们需要将实现的方法联系起来,这将是我们的endpoints(节点)。当我们确定了我们的服务契约,我们定义了一些方法。我们必须实现这些方法,用我们的业务层配合他们,并最终实现我们的数据访问层。

然而,我们每次对服务契约的设计所做任何更改,由于生成的代码将因覆盖而改变,因此我们必须创建另一个partial class代码文件。根据我们自己的实现情况,重写其中的方法,根据提交的请求实现并返回结果。现在MyCryptographyService.ServiceImplementation项目下的CryptImplementation.cs 。文件中,你应该有以下的代码。

using MyCryptographyService.BusinessLogic;

using MyCryptographyService.MessageContracts;

namespace MyCryptographyService.ServiceImplementation

{

public partial class CryptService : CryptServiceBase

{

protected CryptographyServiceBusinessLogic businessLogic = new CryptographyServiceBusinessLogic();

public override EncryptStringResponse EncryptString(EncryptStringRequest request)

{

EncryptStringResponse response = new EncryptStringResponse();

response.ReturnValue = businessLogic.EncryptString(

EncryptionObjectTranslator.TranslateEncryptionObjectToEncryptionObject(request.EncryptionObject));

return response;

}

public override DecryptStringResponse DecryptString(DecryptStringRequest request)

{

DecryptStringResponse response = new DecryptStringResponse();

response.ReturnValue = businessLogic.DecryptString(

EncryptionObjectTranslator.TranslateEncryptionObjectToEncryptionObject(request.EncryptionObject));

return response;

}

public override HashStringResponse HashString(HashStringRequest request)

{

HashStringResponse response = new HashStringResponse();

response.ReturnValue = businessLogic.HashString(

HashObjectTranslator.TranslateHashObjectToHashObject(request.HashObject));

return response;

}

}

}

我们使用Translators的方法创建一些代码,他们对业务实体和数据契约进行了映射。代码应该是非常简单,但如果您有任何问题,请在此留下您的意见,我会尽快答复。

在演练的第4部分,我们会创建托管主机,部署和测试WSDL。敬请关注。

Web服务软件工厂(WSSF)演练之四:创建托管主机,部署和测试WSDL

转载于:https://www.cnblogs.com/LiYunQi/archive/2009/02/07/1385968.html

Web服务软件工厂(WSSF)演练之三:创建服务契约和实现方法相关推荐

  1. 【转】Web服务软件工厂

    patterns & practices开发中心 摘要 Web服务软件工厂(英文为Web Service Software Factory,也称作服务工厂)是一个集成的工具.模式.源代码和规范 ...

  2. Mac系统home目录无法创建文件最全解决方法

    问题 mac 10.15及以上,默认开启了SIP系统保护,开发中普通用户是无法创建文件. 我们开发中有时会把一些文件目录设置为/home,比如日志:/home/logs/ 此时启动服务会报错,无法创建 ...

  3. 蚂蚁海图切片工具linux版本,Web海图服务软件 - 海图在线

    WMS 海图服务软件 很多服务,例如,海洋气象预报.海上船舶移动目标的监控等,都需要显示电子海图作为背景.ChartServer产品就是为满足此类需求 - Web海图服务而开发设计的. ChartSe ...

  4. 关于系统架构和WEB服务软件的概述

    关于系统架构 系统架构的两种形式 C/S架构 B/S架构 C/S架构 : Client / Server 即客户端 / 服务器 C/S架构的软件或者说系统有哪些 QQ(先去腾讯官网下载一个QQ软件,几 ...

  5. 软件2.0时代之三:毛新生谈他眼中的Web2.0

    软件2.0时代之三:毛新生谈他眼中的Web2.0 2007.08.31  来自:CSDN      共有评论(7)条 发表评论   [收藏到我的网摘] Web是一个"活物",是一个 ...

  6. 《企业软件交付:敏捷与高效管理精要》——3.4 企业软件交付的软件工厂方法...

    3.4 企业软件交付的软件工厂方法 正如我们前面讨论的,今天的机构面对的商业环境正以前所未有的速度发生变化.与此同时,这些机构还要管理和降低整个机构的运营成本.这就直接意味着,他们不仅要最大限度地减少 ...

  7. Android 图形架构 之三—— 创建Layer、Surface、SurfaceControl

    前言 上一篇我们分析了,app与SurfaceFlinger建立连接的过程,现在我们就可以继续往下分析,看下创建Surface的过程. 我们可以将Surface理解为一个绘图表面,Android应用程 ...

  8. 工控用Web组态软件比组态软件更高效

    从事相关工作的对"组态软件"应该都不陌生,那Web组态软件又是什么呢?本文将对Web组态可视化软件(下称"Web组态软件")做简单介绍,可视化编辑器是Web组态 ...

  9. 主流七款WEB服务器软件点评

    如今互联网的WEB平台种类繁多,各种软硬件组合的WEB系统更是数不胜数,下面就来介绍一下几种常用的WEB服务器: 1.Microsoft IIS Microsoft的Web服务器产品为Internet ...

最新文章

  1. QQ音乐爬取(python实现)
  2. 15.Three Sum
  3. Spring 常用注入注解(annotation)和其对应xml标签
  4. 世界各国的教育差距有多大?这几部全世界都在热议的教育纪录片,揭开一切.........
  5. NOI-砝码称重v2 多重背包 生成函数
  6. 2022年后人工智能/深度学习八大应用方向
  7. python大神的成长之路_Python大神成长之路: 第三次学习记录 集合 函数 装饰 re...
  8. ROS入门笔记(三):二进制包与源代码包
  9. STM32 I2C通信(读写eeprom)
  10. acer台式电脑怎么重装系统_电脑怎么重装系统 手把手教你
  11. Kubernetes 小白学习笔记(11)--搭建一个kubernetes集群-为worker节点配置命令行交互环境
  12. 计算机office软件版本,office哪个版本最好用,你在用的office是哪个版本
  13. 安装SHARP MX-3618NC PCL6打印机驱动程序
  14. 操作系统——信号量机制(PV操作)
  15. JavasScript 第二天课 课后笔记 2022.3.26
  16. 24种游戏化设计工具
  17. 页面插件集成:博客详情页
  18. 二维码之zxing二维码解析图片资源
  19. 用计算机发传真,如何用电脑发网络传真?在电脑里怎么发传真?
  20. css icon设置,CSS之字体图标 icon 的多种实现

热门文章

  1. 红外技术如何应用在 3D 电视
  2. JDK1.8 IdentityHashMap
  3. (74)信号发生器DDS三角波设计(二)(第15天)
  4. (11)Verilog HDL变量:wire型
  5. (30)System Verilog设计SPI发送
  6. MicroBlaze软核介绍
  7. nc65 单据非向导开发 源代码_最受Java开发者喜爱的5款开发工具
  8. html 左边固定右边自动,七种实现左侧固定,右侧自适应两栏布局的方法
  9. matlab两个数组竖向叠加,matlab - 过滤器同时使用两个数组中的元素 - 堆栈内存溢出...
  10. 进程通信方法的特点以及使用场景