




免费预览已结束,剩余21页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
通过comm.jar等配置 如果用applet应用程序的话,下面这个函数是可以取到串口的,但是如果通过web应用程序(或者通过jsp调用)却取不到串口,而且也不会抛出异常,感觉很奇怪,特来请教! CommPortIdentifier.getPortIdentifiers();同时目标机器的java运行环境也需要把w32comm.dll, comm.jar per等放到相应的目录就是用ibm的包而不用sun的comm包: ibm-javacomm-win32-x86.zip 只需要把comm驱动包这个类的装载更新一下即/serialcomm.htm利用Java实现串口全双工通讯一个嵌入式系统通常需要通过串口与其主控系统进行全双工通讯,譬如一个流水线控制系统需要不断的接受从主控系统发送来的查询和控制信息,并将执行结果或查询结果发送回主控系统。本文介绍了一个简单的通过串口实现全双工通讯的Java类库,该类库大大的简化了对串口进行操作的过程。本类库主要包括:SerialBean.java (与其他应用程序的接口), SerialBuffer.java(用来保存从串口所接收数据的缓冲区), ReadSerial.java (从串口读取数据的程序)。另外本类库还提供了一个例程SerialExample.java 作为示范。在下面的内容中将逐一对这几个部分进行详细介绍。1. SerialBeanSerialBean是本类库与其他应用程序的接口。该类库中定义了SerialBean的构造方法以及初始化串口,从串口读取数据,往串口写入数据以及关闭串口的函数。具体介绍如下:public SerialBean(int PortID)本函数构造一个指向特定串口的SerialBean,该串口由参数PortID所指定。PortID = 1 表示COM1,PortID = 2 表示COM2,由此类推。public int Initialize()本函数初始化所指定的串口并返回初始化结果。如果初始化成功返回1,否则返回-1。初始化的结果是该串口被SerialBean独占性使用,其参数被设置为9600, N, 8, 1。如果串口被成功初始化,则打开一个进程读取从串口传入的数据并将其保存在缓冲区中。public String ReadPort(int Length)本函数从串口(缓冲区)中读取指定长度的一个字符串。参数Length指定所返回字符串的长度。public void WritePort(String Msg)本函数向串口发送一个字符串。参数Msg是需要发送的字符串。public void ClosePort()本函数停止串口检测进程并关闭串口。SerialBean的源代码如下:package serial;import java.io.*;import java.util.*;import m.*;/* This bean provides some basic functions to implement full dulplex* information exchange through the srial port.*/public class SerialBeanstatic String PortName;CommPortIdentifier portId;SerialPort serialPort;static OutputStream out;static InputStream in;SerialBuffer SB;ReadSerial RT;/* Constructor* param PortID the ID of the serial to be used. 1 for COM1,* 2 for COM2, etc.*/public SerialBean(int PortID)PortName = COM + PortID;/* This function initialize the serial port for communication. It starts a* thread which consistently monitors the serial port. Any signal captured* from the serial port is stored into a buffer area.*/public int Initialize()int InitSuccess = 1;int InitFail = -1;tryportId = CommPortIdentifier.getPortIdentifier(PortName);tryserialPort = (SerialPort)portId.open(Serial_Communication, 2000); catch (PortInUseException e)return InitFail;/Use InputStream in to read from the serial port, and OutputStream/out to write to the serial port.tryin = serialPort.getInputStream();out = serialPort.getOutputStream(); catch (IOException e)return InitFail;/Initialize the communication parameters to 9600, 8, 1, none.tryserialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); catch (UnsupportedCommOperationException e)return InitFail; catch (NoSuchPortException e)return InitFail;/ when successfully open the serial port, create a new serial buffer,/ then create a thread that consistently accepts incoming signals from/ the serial port. Incoming signals are stored in the serial buffer.SB = new SerialBuffer();RT = new ReadSerial(SB, in);RT.start();/ return success informationreturn InitSuccess;/* This function returns a string with a certain length from the incoming* messages.* param Length The length of the string to be returned.*/public String ReadPort(int Length)String Msg;Msg = SB.GetMsg(Length);return Msg;/* This function sends a message through the serial port.* param Msg The string to be sent.*/public void WritePort(String Msg)int c;tryfor (int i = 0; i Content.length()available = false;while (available = false)trywait(); catch (InterruptedException e) CurrentMsg = Content.substring(0, LengthNeeded);TempContent = Content.substring(LengthNeeded);Content = TempContent;LengthNeeded = 1;notifyAll();return CurrentMsg;/* This function stores a character captured from the serial port to the* buffer area.* param t The char value of the character to be stored.*/public synchronized void PutChar(int c)Character d = new Character(char) c);Content = Content.concat(d.toString();if (LengthNeeded Content.length()available = true;notifyAll();3. ReadSerialReadSerial是一个进程,它不断的从指定的串口读取数据并将其存放到缓冲区中。public ReadSerial(SerialBuffer SB, InputStream Port)本函数构造一个ReadSerial进程,参数SB指定存放传入数据的缓冲区,参数Port指定从串口所接收的数据流。public void run()ReadSerial进程的主函数,它不断的从指定的串口读取数据并将其存放到缓冲区中。ReadSerial的源代码如下:package serial;import java.io.*;/* This class reads message from the specific serial port and save* the message to the serial buffer.*/public class ReadSerial extends Threadprivate SerialBuffer ComBuffer;private InputStream ComPort;/* Constructor* param SB The buffer to save the incoming messages.* param Port The InputStream from the specific serial port.*/public ReadSerial(SerialBuffer SB, InputStream Port)ComBuffer = SB;ComPort = Port;public void run()int c;trywhile (true)c = ComPort.read();ComBuffer.PutChar(c); catch (IOException e) 4. SerialExampleSerialExample是本类库所提供的一个例程。它所实现的功能是打开串口COM1,对其进行初始化,从串口读取信息对其进行处理后将处理结果发送到串口。import serial.*;import java.io.*;/* This is an example of how to use the SerialBean. It opens COM1 and reads* six messages with different length form the serial port.*/class SerialExamplepublic static void main(String args)/TO DO: Add your JAVA codes hereSerialBean SB = new SerialBean(1);String Msg;SB.Initialize();for (int i = 5; i = 10; i+)Msg = SB.ReadPort(i);SB.WritePort(Reply: + Msg);SB.ClosePort();5. 编译与调试本类库中使用了Java Communication API (m)。这是一个Java扩展类库,并不包括在标准的Java SDK当中。如果你尚未安装这个扩展类库的话,你应该从Sun公司的Java站点下载这个类库并将其安装在你的系统上。在所下载的包里面包括一个安装说明,如果你没有正确安装这个类库及其运行环境的话,运行这个程序的时候你会找不到串口。正确安装Java Communication API并将上述程序编译通过以后,你可以按如下方法测试这个程序。如果你只有一台机器,你可以利用一条RS-232电缆将COM1和COM2连接起来,在COM1上运行SerialExample,在COM2上运行Windows提供的超级终端程序。如果你有两台机器的话,你可以利用一条RS-232电缆将两台机器的COM1(或者是COM2)连接起来,在一端运行例程,另外一端运行Windows提供的超级终端程序。如果有必要的话,可以对SerialExample中所声明的串口进行相应改动。本程序在Windows 2000 + Java SDK 1.3环境下编译通过并成功运行。Java Applet操纵本地扫描仪技术 基于JDK1.3 交管局项目的软件系统采用了基于Java的B/S结构,服务器端采用Unix操作系统、Oracle数据库,需要在客户端用扫描仪扫描图片后上传到服务器端的Oracle数据库中,考虑到B/S结构、基于Java等特点,操纵本地扫描仪最优的办法是采用Java Applet技术,具体技术实现如下: 一、 技术难点 Java Applet操纵本地扫描仪主要有以下的技术难点: 1 JDK Sandbox的限制:出于安全性考虑,普通的Java Applet的只能运行于JDK的Sandbox之中,不能访问本地文件系统,不能建立除它所在服务端之外的网络连接等等,要操纵本地扫描仪就需要突破这些限制。 2 Java语言本身的限制:Java是一种跨平台的语言,由于要考虑到跨多种操作系统的运行,所以它也就丧失了直接操纵本地硬件系统的特性,因而要在Java中操纵扫描仪只能通过JNI技术(即Java Native Interface),通过Java本地接口调用扫描仪驱动软件,完成扫描。 3 其它技术难点:主要是涉及到Java数字签名技术,包括密钥对的生成和保存,证书文件的到如何到出,本地策略文件的配置,Jar文件的签署,证书的认证,软件的发布等等;采用Swing控件的Applet的网页的编写;服务器端和客户端文件的部署。 二、 问题的解决思路: 以上存在的技术难点需要逐一解决: 1 突破JDK Sandbox的控制:首先需寻找方法,突破JDK Sandbox的控制,使Java Applet获得比较大以至全部的访问权限,可以访问本地文件系统,操纵本地硬件设备。 2 解决Java操纵硬件设备的限制:需要通过查找资料,寻求一个相对来说比较简单的操纵扫描仪的方法。 三、 实际解决方法和采用的技术 1 突破JDK Sandbox限制的解决方法: 通过查找资料和与其他人交流,找到突破JDK Sandbox限制的两个方法: 1)修改本地JRE(Java 2 Runtime Environment)策略文件java.policy,在其中加上一段代码: grant codeBaseURL permission java.security.AllPermission; ; 其中的URL是你要运行的Jar文件的地址,这样此Applet即可获得所有权限 2)采用数字签名Jar文件,使其获得相关的访问权限:具体实现如下: Ø 生成密钥及密钥库: keytool genkey keystore dragon.store alias jizd 这个命令用来产生一个密匙库,执行完毕后应该在当前目录中产生一个dragon.store的文件,其中存放着一对密钥,这里的jizd是密钥所有者的名字 Ø 导出公有密钥成为一个X.509格式的证书: keytool export keystore dragon.store alias jizd file dragon.cer 这个命令用来产生验证签名时所要用的证书。 Ø 用私有密钥签署Jar文件: jarsigner -keystore dragon.store MyApplet.jar jizd 这个命令用上面产生的私有密钥将我们的jar文件进行了签名。 Ø 将证书中的公有密钥导入到客户密钥库中: keytool import keystore guest.store alias jizd file dragon.cer Ø 用Policytool生成运行此Applet的策略文件: 应该生成一个applet.policy策略文件,策略文件中着名了验证此前名Jar的密钥库的URL和公有密钥,以及此Applet应获得的权限。 Ø 修改客户端的$java.home/jre/lib/security目录下的java.security文件: 在其中添加一行: policy.url.3=URL/applet.policy URL为存放Applet.policy的服务器路径。 具体配置时,最后一步可以通过编制一个小程序自动完成,前几步完成后将所有的文件在服务器端部署。 由于系统的网络自成体系,不会和Internet相连,所以不必要购买权威机构签发的软件开发许可证,用来签署Jar文件,采用以上的自签名的Jar即可,但是需要在客户端做一简单修改工作。 2 解决Java操纵硬件设备的限制:由于JNI编程的复杂性,所以经过从网上寻找找到了一个Twain for Java的包,此包完成了整个Java 操纵扫描仪所需的所有JNI接口,大大减轻了编程的复杂性工作量,同时通过对它的示例程序的研究,完成了一个操纵扫描仪的简单Applet,配合上一个技术难点的解决,已经可以从IE中操纵本地扫描仪。 3 其他技术难点的解决,关于内嵌Swing 的Applet的IE网页代码的编写比较复杂,采用AWT控件的Applet嵌入网页时采用标签即可,但是采用Swing控件的Applet嵌入网页时需采用标签,代码繁杂冗长,工作量比较大,解决办法是首先编写采用标签的网页,然后采用Sun的HTMLConverter工具(可从S上免费下载)批量转化即可。 四、 采用的关键技术及实现情况。 1 突破JDK Sandbox限制技术: i. 修改客户端策略文件已实现 ii. 数字签名已实现 2解决Java操纵扫描仪限制:采用现成的Twain for java包已实现 此包是试用版,正式版报价2000$,有待于寻找类似的免费开发包。 3 用Swing控件的Applet的网页的编写,采用Sun HTMLConverter已实现 五、 技术实现的代价: 主要技术点 时间代价 成本代价 修改客户端策略文件 半天 0 数字签名的相关技术 3天 0 解决Java操纵扫描仪限制(JNI) 3天 暂时无法计算 Swing控件的Applet的网页的编写 半天 0 服务器端和客户端文件的部署 1天 0 六、 不完善或有待于解决的问题: 当前不完善或有待于解决的问题主要是Java操纵扫描仪的包是试用版,购买正式版需花费2000$,还需要寻求一些免费的或者价格低廉的开发包。 七、 技术前景 八、 参考资料: /Doc_CodeSigning.shtml / /docs/books/tutorial/security1.2/toolsign/index.html Java串行端口通讯技术慨论 了解串行通讯串行通讯协议有很多种,像RS232,RS485,RS422,甚至现今流行的USB等都是串行通讯协议。而串行通讯技术的应用无处不在。可能大家见的最多就是电脑的串口与Modem的通讯。记得在PC机刚开始在中国流行起来时(大约是在90年代前五年),那时甚至有人用一条串行线进行两台电脑之间的数据共享。除了这些,手机,PDA,USB鼠标、键盘等等都是以串行通讯的方式与电脑连接。而笔者工作性质的关系,所接触到的就更多了,像多串口卡,各种种类的具有串口通讯接口的检测与测量仪器,串口通讯的网络设备等。 虽然串行通讯有很多种,但笔者所知的在整个电子通讯产品方面,以RS232的通讯方式最为多见。虽然USB接口的电子产品也是层出不穷,但了解一下Java在串行通讯方面的技术还有有必要的,说不定有哪位读者还想用此技术写一个PDA与电脑之间数据共享的程序呢。 本文主要以RS232为主来讲解Java的串行通讯技术。RS232通讯基础RS-232-C(又称 EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。RS232是一个全双工的通讯协议,它可以同时进行数据接收和发送的工作。RS232的端口通常有两种:9针(DB9)和25针(DB25)。DB9和DB25的常用针脚定义常见的边线方式常见的通讯方式是三线式,这种方式是将两个RS232设备的发送端(TXD)和接收端(RXD)及接地端(GND)互相连接,也是许多读者所知道的连接方式:这种方式分别将两端的RS232接口的2-3,3-2,5(7)-5(7)针脚连接起来。其中2是数据接收线(RXD),3是数据发送线(TXD),5(7)是接地(RND)。如果有一台式PC,和一部NoteBook电脑,就可以用这种方式连线了。用三线式可以将大多数的RS232设备连接起来。但如果你认死了2-3,3-2,5(7)-5(7)对接这个理,会发现在连某些RS232设备时并不奏效。这是因为有些设备在电路内部已将2和3线调换过来了,你只要2,3,5(7)针一一对应就行了。小技巧:如何辨别TXD和RXD端口?搞电子的人手边应该常备一个电表,用来测测电压,电阻什么的会很有用。你只要分别测一下RS232端口的2-5或3-5针脚之间的电压,通常TXD针脚与GND之间会有315V左右的负电压,表示它是TXD针脚。 安装Java Communications API Sun的J2SE中并没有直接提供以上提到的任何一种串行通讯协议的开发包,而是以独立的jar包形式发布在网站上(从这里下载)-即comm.jar,称之为Javatm Communications API,它是J2SE的标准扩展。comm.jar并不是最近才有,早在1998年时,sun就已经发布了这个开发包。comm.jar分别提供了对常用的RS232串行端口和IEEE1284并行端口通讯的支持。目前sun发布的comm.jar只有Windows和Solaris平台两个版本,如果你需要Linux平台下的,可以在/kevinh/linuxcomm.html找到。在使用comm.jar之前,必须知道如何安装它。这也是困扰许多初学java RS232通讯者的一个难题。如果我们电脑上安装了JDK, 它将同时为我们安装一份JRE(Java Runtime Entironment),通常我们运行程序时都是以JRE来运行的。所以以下的安装适用于JRE。如果你是用JDK来运行程序的,请将相应的改成。下载了comm.jar开发包后,与之一起的还有两个重要的文件,win32com.dll和perties。 comm.jar提供了通讯用的java API,而win32com.dll提供了供comm.jar调用的本地驱动接口。而perties是这个驱动的类配置文件。首先将comm.jar复制到libext目录。再将win21com.dll复制到你的RS232应用程序运行的目录,即user.dir。然后将perties复制到lib目录。通讯前的准备如果你手头上没有现成的提供了标准RS232串口的设备,你可以将自己的电脑模拟成两台不同的串口设备。通常电脑主机后面的面板提供了两个9针的串口,请将这两个串口的2,3,5脚按前面介绍的方法连接。电子市场都有现成的连接头卖,请不要买那种封装的严严实实的接头,而要买用螺丝封装可以拆开的连接头,这样可以方便自己根据需要连接各个针脚。Comm API基础我无意于在此详细描述Comm API每个类和接口的用法,但我会介绍Comm API的类结构和几个重要的API用法。所有的comm API位于m包下面。从Comm API的javadoc来看,它介绍给我们的只有区区以下13个类或接口:m.CommDriver m.CommPort m.ParallelPort m.SerialPort m.CommPortIdentifier m.CommPortOwnershipLm.ParallelPortEvent m.SerialPortEvent m.ParallelPortEventListener (extends java.util.EventListener) m.SerialPortEventListener (extends java.util.EventListener) m.NoSuchPortException m.PortInUseException m.UnsupportedCommOperationException 下面讲解一下几个主要类或接口。1.枚举出系统所有的RS232端口在开始使用RS232端口通讯之前,我们想知道系统有哪些端口是可用的,以下代码列出系统中所有可用的RS232端口:Enumeration en = CommPortIdentifier.getPortIdentifiers();CommPortIdentifier portId;while (en.hasMoreElements() portId = (CommPortIdentifier) en.nextElement();/*如果端口类型是串口,则打印出其端口信息*/if (portId.getPortType() = CommPortIdentifier.PORT_SERIAL) System.out.println(portId.getName();在我的电脑上以上程序输出以下结果:COM1COM2CommPortIdentifier类的getPortIdentifiers方法可以找到系统所有的串口,每个串口对应一个CommPortIdentifier类的实例。2.打开端口如果你使用端口,必须先打开它。tryCommPort serialPort = portId.open(My App, 60);/* 从端口中读取数据*/InputStream input = serialPort.getInputStream();input.read(.); /* 往端口中写数据*/OutputStream output = serialPort.getOutputStream();output.write(.).catch(PortInUseException ex) . 通过CommPortIdentifier的open方法可以返回一个CommPort对象。open方法有两个参数,第一个是String,通常设置为你的应用程序的名字。第二个参数是时间,即开启端口超时的毫秒数。当端口被另外的应用程序占用时,将抛出PortInUseException异常。在这里CommPortIdentifier类和CommPort类有什么区别呢?其实它们两者是一一对应的关系。CommPortIdentifier主要负责端口的初始化和开启,以及管理它们的占有权。而CommPort则是跟实际的输入和输出功能有关的。通过CommPort的getInputStream()可以取得端口的输入流,它是java.io.InputStream接口的一个实例。我们可以用标准的InputStream的操作接口来读取流中的数据,就像通过FileInputSteam读取文件的内容一样。相应的,CommPort的getOutputStream可以获得端口的输出流,这样就可以往串口输出数据了。3. 关闭端口使用完的端口,必须记得将其关闭,这样可以让其它的程序有机会使用它,不然其它程序使用该端口时可能会抛出端口正在使用中的错误。很奇怪的是,CommPortIdentifier类只提供了开启端口的方法,而要关闭端口,则要调用CommPort类的close()方法。通讯方式CommPort的输入流的读取方式与文件的输入流有些不一样,那就是你可能永远不知这个InputStream何时结束,除非对方的OutputStream向你发送了一个特定数据表示发送结束,你收到这个特定字符后,再行关闭你的InputStream。而comm.jar提供了两种灵活的方式让你读取数据。1. 轮询方式(Polling)举个例子,你同GF相约一起出门去看电影,但你的GF好打扮,这一打扮可能就是半小时甚至一小时以上。这时你就耐不住了,每两分钟就催问一次“好了没?”,如此这样,直到你的GF说OK了才算完。这个就叫轮询(Polling)。在程序中,轮询通常设计成一个封闭的循环,当满足某个条件时即结束循环。刚才那个例子中,你的GF说“OK了!”,这个就是结束你轮询的条件。在单线程的程序中,当循环一直执行某项任务而又无法预知它何时结束时,此时你的程序看起来可能就像死机一样。在VB程序中,这个问题可以用在循环结构中插入一个doEvent语句来解决。而Java中,最好的方式是使用线程,就像以下代码片断一样。public TestPort extend Thread.InputStream input = serialPort.getInputStream();StringBuffer buf = new StringBuffer();boolean stopped = false;.public void run()try while( !stopped )int ch = input.read();if ( ch=q | ch=Q )/* 结束读取,关闭端口.*/stopped = true;.elsebuf.append(char)ch);.catch (InterruptedException e) 2. 监听方式(listening)Comm API支持标准的Java Bean型的事件模型。也就是说,你可以使用类似AddXXXListener这样的方法为一个串口注册自己的监听器,以监听方式进行数据读取。 如要对端口监听,你必须先取得CommPortIdentifier类的一个实例,CommPort serialPort = portId.open(My App, 60); 从而取得SerialPort,再调用它的addEventListener方法为它添加监听器,serialPort.addEventListener(new MyPortListener(); SerialPort的监听器必须继承于SerialPortEventListener接口。当有任何SerialPort的事件发生时,将自动调用监听器中的serialEvent方法。Serial Event有以下几种类型: BI - 通讯中断.CD - 载波检测.CTS - 清除发送.DATA_AVAILABLE - 有数据到达.DSR - 数据设备准备好.FE - 帧错误.OE - 溢位错误.OUTPUT_BUFFER_EMPTY - 输出缓冲区已清空.PE - 奇偶校验错.RI - 振铃指示.下面是一个监听器的示例:public void MyPortListener implements SerialPortEventListener public void serialEvent(SerialPortEvent evt)switch (evt.getEventType()case SerialPortEvent.CTS :System.out.println(CTS event occured.);break;case SerialPortEvent.CD :System.out.println(CD event occured.);break;case SerialPortEvent.BI :System.out.println(BI event occured.);break;case SerialPortEvent.DSR :System.out.println(DSR event occured.);break;case SerialPortEvent.FE :System.out.println(FE event occured.);break;case SerialPortEvent.OE :System.out.println(OE event occured.);break;case SerialPortEvent.PE :System.out.println(PE event occured.);break;case SerialPortEvent.RI :System.out.println(RI event occured.);break;case SerialPortEvent.OUTPUT_BUFFER_EMPTY :System.out.println(OUTPUT_BUFFER_EMPTY event occured.);break;case SerialPortEvent.DATA_AVAILA
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 北京工具式马道施工方案
- 世界肾脏日活动策划方案
- 残疾人社区营销活动方案
- 广东文旅水景施工方案
- 药品安全培训会议药监局课件
- 景观方案阶段设计合同5篇
- 《2024 秋季学期开学第一天学生安全方案》
- 图书馆管理系统系统分析
- 建筑单位大门建设方案设计
- 中国农业现代化发展策略
- 2025年军休服务管理机构招聘面试中常见陷阱问题解析与应对方法
- 信息系统维护与升级管理模板
- 2025年南京市事业单位招聘考试卫生类临床医学专业知识试题
- 图解2025年9月10日第41个教师节全文
- 低空旅游项目基础设施建设与可行性研究报告
- 2025至2030年中国晶质石墨深加工行业市场调查研究及投资战略咨询报告
- 船舶电气小知识培训课件
- 普及鸽子的课件
- 浙江省G12名校协作体2025学年第一学期9月高三上学期开学联考地理试卷
- Unit 2 My friends (Period 1) 课件2025-2026学年人教版英语四年级上册
- 2025版酒店租赁经营合作协议模板:2025年度版
评论
0/150
提交评论