socket通讯相互发送读取xml实例_java socket 方式 调用 传输xml格式内容-程序员宅基地

技术标签: java学习笔记  socket  网络通信  

首先了解下socket通讯传输数据的特点:数据在网络传输时使用的都是字节流或字符流,Socket也不例外,所以我们发送数据的时候需要转换为字节发送,读取的时候也是以字节为单位读取。

那么问题就在于socket通讯时,接收方并不知道此次数据有多长,因此无法精确地创建一个缓冲区(字节数组)用来接收,在不定长通讯中,通常使用的方式时每次默认读取8*1024长度的字节,若输入流中仍有数据,则再次读取,一直到输入流没有数据为止。但是如果发送数据过大时,发送方会对数据进行分包发送,这种情况下或导致接收方判断错误,误以为数据传输完成,因而接收不全。
所以,大部分情况下,双方使用socket通讯时都会约定一个定长头放在传输数据的最前端,用以标识数据体的长度,通常定长头有整型int,短整型short,字符串Strinng三种形式。

下面小编介绍两个socket+xml传输的实例,案例一,是使用writeUTF()和readUTF()方法,发送和读取传输的数据。

案例2是组装好xml后,计算xml的字节长度,放在报文头,使用write()方法发送数据,read()方法读取数据。

这里再介绍在writeUTF()和write()方法的区别:

writeUTF(String str);   
write(int b) ;   

可以看出二者的参数不一样,writeUTF可以直接将组装的字符串发送过去(方法封装,改方法内部也是应该需要转成字节或字符传输的),但是接受方也必须使用readUTF方法读取接受,要保持一样。wirte方法则是属于相对第一级的封装,需要将组装的xml字符串转成字节数组传输。此外, ASCII码:一个英文字母等于一个字节; UTF-8编码:一个英文字母等于一个字节; Unicode编码:一个英文字母等于两个字节。因为不同的编码格式对字节的统计也有区别,所以在计算xml字节长度的时候,是要规定好传输的编码格式,这些在下面的代码中都要体现,请读者自行体会。

案例一 服务端:

package tcpSocket;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
public class TCPServer2 {
	public static void main(String args[]) {
			int serverPort = 7896;
			ServerSocket listenSocket ;
			Socket clientSocket ;
			try {
//				******************接收读取客户端传来的内容******************************************
					listenSocket = new ServerSocket(serverPort);
				    clientSocket = listenSocket.accept();
				    DataInputStream in = new DataInputStream(clientSocket.getInputStream());
					String data = in.readUTF();
//					System.out.println("接收到的数据:" + data);
					DOM(data);
					
//					******************向客户端写xml文件******************************************
					DataOutputStream out=new DataOutputStream(clientSocket.getOutputStream());
					// 定义工厂 API,使应用程序能够从 XML 文档获取生成 DOM 对象树的解析器
					DocumentBuilderFactory factory = DocumentBuilderFactory
							.newInstance();
					// 定义 API, 使其从 XML 文档获取 DOM 文档实例。使用此类,应用程序员可以从 XML 获取一个 Document
					DocumentBuilder builder = factory.newDocumentBuilder();
					// Document 接口表示整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问
					Document document = builder.newDocument();
					//组织生产xml文件内容
					Element root = document.createElement("persons");
					document.appendChild(root);
					Element person = document.createElement("person");
					Element name = document.createElement("name");
					name.appendChild(document.createTextNode("java小强"));
					person.appendChild(name);
					Element sex = document.createElement("sex");
					sex.appendChild(document.createTextNode("man"));
					person.appendChild(sex);
					Element age = document.createElement("age");
					age.appendChild(document.createTextNode("99"));
					person.appendChild(age);
					root.appendChild(person);
	
					TransformerFactory tf = TransformerFactory.newInstance();
					// 此抽象类的实例能够将源树转换为结果树
					Transformer transformer;
					transformer = tf.newTransformer();
	
					DOMSource source = new DOMSource(document);
					ByteArrayOutputStream bos = new ByteArrayOutputStream();
					transformer.transform(source, new StreamResult(bos));
					String xmlStr = bos.toString();
					out.writeUTF(xmlStr);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	public static void DOM(String data) {
		try {
			//遍历xml获取内容
			byte[] b = data.getBytes();
			InputStream inp = new ByteArrayInputStream(b);
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(inp);
			NodeList nl = doc.getElementsByTagName("persons");
//			System.out.println(nl.getLength());
			for (int i = 0; i < nl.getLength(); i++) {
				System.out.println("person:  "
						+ doc.getElementsByTagName("person").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("name:  "
						+ doc.getElementsByTagName("name").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("sex:  "
						+ doc.getElementsByTagName("sex").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("age:  "
						+ doc.getElementsByTagName("age").item(i)
								.getFirstChild().getNodeValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

客户端:

package tcpSocket;
 
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
 
public class TCPClient {
 
	public static void main(String[] args) throws Exception {
		// 2017年12月29日 下午1:43:11
		Socket soc = null;
		String data = "";
		InetAddress addr = InetAddress.getByName("127.0.0.1");
		int serverPort = 7896;
		if (addr.isReachable(5000)) {
			try {
				soc = new Socket(addr, serverPort);
				
//************************向客户端写xml文件******************************************
				DataOutputStream out=new DataOutputStream(soc.getOutputStream());
				// 定义工厂 API,使应用程序能够从 XML 文档获取生成 DOM 对象树的解析器
				DocumentBuilderFactory factory = DocumentBuilderFactory
						.newInstance();
				// 定义 API, 使其从 XML 文档获取 DOM 文档实例。使用此类,应用程序员可以从 XML 获取一个 Document
				DocumentBuilder builder = factory.newDocumentBuilder();
				// Document 接口表示整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的基本访问
				Document document = builder.newDocument();
				//组织生产xml文件内容
				Element root = document.createElement("persons");
				document.appendChild(root);
				Element person = document.createElement("person");
				Element name = document.createElement("name");
				name.appendChild(document.createTextNode("java小强"));
				person.appendChild(name);
				Element sex = document.createElement("sex");
				sex.appendChild(document.createTextNode("man"));
				person.appendChild(sex);
				Element age = document.createElement("age");
				age.appendChild(document.createTextNode("99"));
				person.appendChild(age);
				root.appendChild(person);
 
				TransformerFactory tf = TransformerFactory.newInstance();
				// 此抽象类的实例能够将源树转换为结果树
				Transformer transformer;
				transformer = tf.newTransformer();
 
				DOMSource source = new DOMSource(document);
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				transformer.transform(source, new StreamResult(bos));
				String xmlStr = bos.toString();
				out.writeUTF(xmlStr);
				
//********************************接收读取客户端传来的内容******************************************
				//接收来自服务器的数据,并解析打印
				DataInputStream in = new DataInputStream(soc.getInputStream());
				data = in.readUTF();
//				System.out.println("接收到的数据:" + data);
				DOM(data);
			} catch (UnknownHostException e) {
				System.out.println("Socket Error:" + e.getMessage());
			} catch (EOFException e) {
				System.out.println("EOF:" + e.getMessage());
			} catch (IOException e) {
				System.out.println("IO:" + e.getMessage());
			} finally {
				if (soc != null)
					try {
						soc.close();
					} catch (IOException e) {/* close failed */
					}
			}
		} else {
			System.out.println("FAILURE - ping " + addr
					+ " with no interface specified");
		}
	}
 
	public static void DOM(String data) {
		try {
			byte[] b = data.getBytes();
			InputStream inp = new ByteArrayInputStream(b);
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document doc = builder.parse(inp);
			NodeList nl = doc.getElementsByTagName("persons");
//			System.out.println(nl.getLength());
			for (int i = 0; i < nl.getLength(); i++) {
				System.out.println("person:  "
						+ doc.getElementsByTagName("person").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("name:  "
						+ doc.getElementsByTagName("name").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("sex:  "
						+ doc.getElementsByTagName("sex").item(i)
								.getFirstChild().getNodeValue());
				System.out.println("age:  "
						+ doc.getElementsByTagName("age").item(i)
								.getFirstChild().getNodeValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

用到的jar包可见:http://download.csdn.net/download/csdnliuxin123524/10180445

案例二,

客户端,

package socket;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetAddress;
import java.net.Socket;
 
import org.apache.commons.lang.StringUtils;
public class CallExtPboc {
	@SuppressWarnings("resource")
	public static void main(String[] args) throws Exception {
		Socket soc = null;
		String data = "";
		InetAddress addr = InetAddress.getByName("127.0.0.1");
		int serverPort = 7896;
		soc = new Socket(addr, serverPort);
		DataOutputStream out=new DataOutputStream(soc.getOutputStream());
		String xmlReq = builderReqXml();
		byte[] b = xmlReq.getBytes("UTF-8");
		long len=b.length;
		String length=String.format("%06d",len);
		 xmlReq = length+xmlReq;
		byte[] bt = xmlReq.getBytes("utf-8");
		 out.write(bt);
//		out.writeUTF(builderReqXml());
		//接收来自服务器的字节类型数据,并解析打印
		//DataInputStream in = new DataInputStream(soc.getInputStream());
		//byte[] buf =new byte[1024];
		//int readb=in.read(buf);
		//System.out.println("**************************************");
		//if(readb != -1){
		//	System.out.println(new String(buf,0,readb));
		//}
		//in.close();
	}
	
	private static String builderReqXml(){
		StringBuffer xmlReq = new StringBuffer();
//		xmlReq.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		xmlReq.append("<SERVICE xmlns=\"http://www.sss.com/dataspec/\">");
		//构造SERVICE_HEADER节点里面的数据
		StringBuilder serviceHeader = new StringBuilder();
		serviceHeader.append(getNode("SERVICE_SN","198234712374-17412748"));
		serviceHeader.append(getNode("SERVICE_ID","12100"));//交易码
		serviceHeader.append(getNode("ORG","org1"));
		serviceHeader.append(getNode("CHANNEL_ID","01"));//服务渠道编号----请求渠道
		serviceHeader.append(getNode("OP_ID","tt"));
		serviceHeader.append(getNode("REQUST_TIME","20050621123000"));
		serviceHeader.append(getNode("VERSION_ID","01"));
		serviceHeader.append("<MAC/>");
		//将SERVICE_HEADER节点数据加入报文中
		xmlReq.append(getNode("SERVICE_HEADER", serviceHeader.toString()));
		
		//构造SERVICE_BODY节点里面的数据
		StringBuilder serviceBody = new StringBuilder();
		//构造extAttributes节点的数据
		StringBuffer extAttributes =new StringBuffer();
		//构造auth节点数据
		StringBuffer auth =new StringBuffer();
		auth.append(getNode("Q_PIN", "0123456789ABCDEF"));
		//将auth节点加入到EXT_ATTRIBUTES中
		extAttributes.append(getNode("AUTH", auth.toString()));
		//将extAttributes节点加入到SERVICE_BODY中
		serviceBody.append(getNode("EXT_ATTRIBUTES", extAttributes.toString()));
		//构造REQUEST节点里面的数据
		StringBuilder request = new StringBuilder();
		request.append(getNode("SYS_ID","aps"));
		request.append(getNode("OPERATOR_ID", "tt"));
		request.append(getNode("ID_NO", "123"));
		request.append(getNode("ID_TYPE", "I"));
		request.append(getNode("NAME", "czy"));
		//将REQUEST节点数据加入至SERVICE_BODY中
		serviceBody.append(getNode("REQUEST", request.toString()));
		//将SERVICE_BODY节点数据加入至报文中EXT_ATTRIBUTES
		xmlReq.append(getNode("SERVICE_BODY", serviceBody.toString()));
		xmlReq.append("</SERVICE>");
		System.out.println(xmlReq);
		return xmlReq.toString();
	}
	
	/**
	 * 根据节点名称以及节点内容,返回节点字符串
	 * @param nodeName 节点名称
	 * @param nodeValue 节点内容
	 * @return	构造出的节点字符串
	 */
	private static String getNode(String nodeName,String nodeValue){
		StringBuilder node = new StringBuilder();
		if(!StringUtils.isEmpty(nodeName)){
			node.append("<"+nodeName+">");
			if(!StringUtils.isEmpty(nodeValue)){
				node.append(nodeValue);
			}
			node.append("</"+nodeName+">");
		}
		return node.toString();
	}
}

这里的xml数据也可以不使用dom4j组装,直接使用字符串拼接如下:客户端

package test.s;
 
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
 
public class CallApsService {
	private Socket s;
	private DataOutputStream out;
 
	public CallApsService() throws IOException {
	}
 
	public static void main(String[] args) throws Exception {
		CallApsService c = new CallApsService();
		int i = 0;
		Map<String, String> infoMap = initInput();
		for(Entry<String, String> enty: infoMap.entrySet()){
			i++;
			c.talk(enty.getKey(),enty.getValue(),i);
			System.out.println("发送信息完毕!");
		}
	}
 
	// 发送对象
	// ObjectOutputStream oos;
	// TransferObj obj;
	public void sendMessage(Socket s,String idNo,String name,int i) {
		try {
 
			// socket传字符串
			out = new DataOutputStream(s.getOutputStream());
			//批次号申请
			String xmlReq = "<SERVICE xmlns=\"http://www.asss.com/dataspec/\"><SERVICE_HEADER><SERVICE_SN>198234712374-17412748</SERVICE_SN><SERVICE_ID>12100</SERVICE_ID><ORG>org1</ORG><CHANNEL_ID>01</CHANNEL_ID><OP_ID>tt</OP_ID><REQUST_TIME>20050621123000</REQUST_TIME><VERSION_ID>01</VERSION_ID><MAC/></SERVICE_HEADER><SERVICE_BODY><EXT_ATTRIBUTES><AUTH><Q_PIN>0123456789ABCDEF</Q_PIN></AUTH></EXT_ATTRIBUTES><REQUEST><SYS_ID>aps</SYS_ID><OPERATOR_ID>tt</OPERATOR_ID><ID_NO>123</ID_NO><ID_TYPE>I</ID_TYPE><NAME>czy</NAME></REQUEST></SERVICE_BODY></SERVICE>";
			
			
			String lenthEncode = "UTF-8";
			long len = xmlReq.getBytes(lenthEncode).length;
			String length=String.format("%06d",len);
			xmlReq = length+ xmlReq;
			byte[] bt = xmlReq.getBytes(lenthEncode);
			out.write(bt);
 
		} catch (IOException e) {
			e.printStackTrace();
		}
 
	}
 
	public void talk(String idNo,String name,int i) throws Exception {
		try {
			// 发送对象
			s = new Socket("127.0.0.1", 7896);
			System.out.println("客户端:发送信息");
			sendMessage(s,idNo,name, i);
			System.out.println("发送信息完毕!");
			// 发字符串
//			 receiveMessage(s);
			out.close();
			// in.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (s != null)
					s.close(); // 断开连接
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	public static Map<String, String> initInput(){
		
		Map<String, String> infoMap = new HashMap<String, String>();
		infoMap.put("140106198506020369","湘一百二");
		
		return infoMap;
	}
	
	
}

服务器

package socket;
 
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
 
public class CallExtPbocServer {
 
	public static void main(String[] args) {
		int serverPort = 7896;
		ServerSocket listenSocket ;
		Socket clientSocket ;
		try {
//			******************接收读取客户端传来的内容******************************************
				listenSocket = new ServerSocket(serverPort);
			    clientSocket = listenSocket.accept();
			    DataInputStream in = new DataInputStream(clientSocket.getInputStream());
			    byte[] buf=new byte[1024];
			    int tag=in.read(buf);
			    if(tag!=-1){
			    	System.out.println(new String(buf,0,tag));
			    }
			    in.close();
		}catch(Exception e){
			
		}
		
	}
 
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_42946963/article/details/109388058

智能推荐

Ubuntu下使用pjsip点对点通话_pjsua2 点对点sip电话 二次开发-程序员宅基地

文章浏览阅读2.5k次。Ubuntu AUbuntu Bubuntu A IP:192.168.43.49ubuntu B IP:192.168.43.11方法一:使用pjsua1. 进入目录pjsip-apps/binubuntu A: ./pjsua-x86_64-unknown-linux-gnuubuntu B发起呼叫: ./pjsua-x86_64-unkno_pjsua2 点对点sip电话 二次开发

嵌入式系统开发学习_嵌入式系统需要开发版配合,本课程将使用何种开发版?搜寻开发版图形标出重要名称?-程序员宅基地

文章浏览阅读2.4k次。嵌入式系统开发学习:(载自:http://blog.csdn.net/leoocn/archive/2008/02/26/2121703.aspx) 随着现代社会信息化进程的加快,嵌入式系统被广泛的地应用于军事、家用、工业、商业、办公、医疗等社会各个方面,表现出很强的投资价值。从国际范围来看,作为数字化电子信息产品核心的嵌入式系统目前其硬件和软件开发工具市场已经突破2000亿美元,嵌入式系统带来的全球工业年产值更是达到了一万亿美元,随着全_嵌入式系统需要开发版配合,本课程将使用何种开发版?搜寻开发版图形标出重要名称?

flask实战-用户登录注册系统+密码动态加密(5-实战篇)_登陆密码加密是动态的 如何做登录器-程序员宅基地

文章浏览阅读1.7k次。该篇主要介绍使用flask如何实现用户注册登录功能,使用SQLAlchemy操作数据库,密码进行动态加密解密验证,以及基本登录逻辑和表单提交,项目中用到的东西前几篇都有介绍,如有不足请留言指出谢谢1. 项目结构2. HTML页面登录页面 login.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>登录</title._登陆密码加密是动态的 如何做登录器

android:launchMode、Intent.FLAG_ACTIVITY_NEW_TASK、android:taskAffinity和近期任务列表关系-程序员宅基地

文章浏览阅读250次。本文总结了android:launchMode、Intent.FLAG_ACTIVITY_NEW_TASK、android:taskAffinity和近期任务列表RecentsActivity关系实验辅助工具:通过adb shell dumpsys activity 命令观察 activity所属task栈的id(在输出中搜索Running activities,带#号的就是该activit..._android taskaffinity最近任务

百度竞价排名关键字管理技巧-程序员宅基地

文章浏览阅读191次。【标题】百度竞价排名关键字管理技巧【内容】1、为大量关键字注册不同的网页url比只注册首页url效果更好虽然,您可以为一个网页注册不限数量的不同关键字,但是,据我们所知: 如果您为不同的关键字注册不同的网页,让网页url指向跟该关键字相关的产品或服务网页,那么效果比全部关键字 都指向网站首页效果更好。比如,您的网站有“域名注册”的服务,那么建议您把关键字“域名注册”相应的url设定为指向提...

java中弹出窗口的默认大小,java – 当浏览器窗口调整大小时,GWT调整大小和居中弹出窗口...-程序员宅基地

文章浏览阅读206次。我需要在浏览器窗口调整大小时调整大小.我在我的弹出构造函数中添加了ResizeHandler,但在几个浏览器调整大小center()函数后创建新的弹出窗口,而不是居中当前.这里有一些我已经尝试过的代码.请告诉我如何解决这个问题或建议一些解决方案.public BigPopup() {...final BigPopup self = this;Window.addResizeHandler(new ..._java实现调用默认浏览器打开网址并设置桌面大小

随便推点

Andriod实现推送的解决方案(转)-程序员宅基地

文章浏览阅读73次。Andriod上实现消息推送的一般解决策略第一种解决方案:C2DM云端推送功能在Android手机平台上,Google提供了C2DM(Cloudto Device Messaging)服务,该服务提供了一个简单的、轻量级的机制,允许服务器可以通知移动应用程序直接与服务器进行通信,以便于从服务器获取应用程序更新和用户数据。C2DM服务负责处理诸如消息排队等事务并向运行于目标设备上的应用程序分...

三、常见设计模式_09(笔记)_@sneakythrows是代理模式吗-程序员宅基地

文章浏览阅读65次。Java常见设计模式总结_@sneakythrows是代理模式吗

JAVA练习题--小明可买什么_java中用switch购买铅笔橡皮-程序员宅基地

文章浏览阅读415次。javaSwitch条件语句练习题_java中用switch购买铅笔橡皮

java计算机毕业设计网上书店的设计与实现源码+系统+数据库+lw文档_网上书店的设计与实现数据库-程序员宅基地

文章浏览阅读104次。java计算机毕业设计网上书店的设计与实现源码+系统+数据库+lw文档。前端技术:Layui、HTML、CSS、JS、JQuery等技术。ssm基于uniapp+Vue框架的《露营》App开发与实现。JSP物流中心仓储信息管理系统的设计与实现sqlserver。jsp基于JSP的天津城建大学计算机学院校友录管理系统。ssm基于Android平台的球鞋销售系统。ssm基于H的新冠防疫宣传网站的设计与实现。ssm基于Java的摄影网上预约管理系统。ssm基于SSM框架的学生协会管理系统。_网上书店的设计与实现数据库

YOLO目标检测:叉车检测数据集_叉车数据集-程序员宅基地

文章浏览阅读496次,点赞10次,收藏10次。叉车检测数据集,3000多张图像,标注完整,叉车一类,未应用数据增强。_叉车数据集

百套精选安卓(Android)毕业设计大全:含论文、大作业及原创作品(Android Studio专用),配套完整源码与详尽论文,助力学术成果卓越展现_android studio 毕业设计网站-程序员宅基地

文章浏览阅读521次,点赞8次,收藏9次。我们专注于软件开发工程领域,熟练掌握多种开发技术,Android APP和微信小程序的开发。添+My number is one--zero-three-two-three-seven-one-two-one。的咖啡销售管理系统的设计与实现 ( 原材料交易 )的流浪猫狗求助系统的设计与实现。小说阅读系统的设计与实现。酒店管理系统的设计与实现。宠物寄养系统的设计与实现。校园疫情防控的设计与实现。的医院人力资源管理系统。的大学生实习管理系统。的高校实验室管理系统。网上书店电子商务系统。_android studio 毕业设计网站

推荐文章

热门文章

相关标签