`
longgangbai
  • 浏览: 7340117 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

前段时间的一个项目 本来用ae完成了种种的 查询,空间分析等等功能的代码,但是不幸的是 这是一个web项目,无奈 ae各种错误,显然ae放在server端是不好使的 无奈 一咬牙一跺脚 全部换 换成geotools  看文档 看api 从零 开始算是把 原来AE实现的东西 统统改了过来 用起来 反而觉得既稳定 效率还不错哈!

以下是部分功能总结:

1、连接数据库 这里使用的postgis 链接代码如下:

 

private static void conn(String dbtype, String host, String port,
			String database, String userName, String password) {
		Map<String, Object> params = new HashMap<String, Object>();
		// params.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis");    // 两种代码方式
		// params.put(PostgisNGDataStoreFactory.HOST.key, "localhost");
		// params.put(PostgisNGDataStoreFactory.PORT.key, new Integer(5432));
		// params.put(PostgisNGDataStoreFactory.DATABASE.key, "postgis");
		// params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
		// params.put(PostgisNGDataStoreFactory.USER.key, "postgres");
		// params.put(PostgisNGDataStoreFactory.PASSWD.key, "root");
		params.put(PostgisNGDataStoreFactory.DBTYPE.key, dbtype);
		params.put(PostgisNGDataStoreFactory.HOST.key, host);
		params.put(PostgisNGDataStoreFactory.PORT.key, new Integer(port));
		params.put(PostgisNGDataStoreFactory.DATABASE.key, database);
		params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
		params.put(PostgisNGDataStoreFactory.USER.key, userName);
		params.put(PostgisNGDataStoreFactory.PASSWD.key, password);
		try {
			pgDatastore = DataStoreFinder.getDataStore(params);
			if (pgDatastore != null) {
				System.out.println("系统连接到位于:" + host + "的空间数据库" + database
						+ "成功!");
			} else {
				System.out.println("系统连接到位于:" + host + "的空间数据库" + database
						+ "失败!请检查相关参数");
			}
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("系统连接到位于:" + host + "的空间数据库" + database
					+ "失败!请检查相关参数");
		}

	}
调用方法为:conn("postgis", "localhost", 5432, "postgis", "postgres", "root");

2、图层的操作

 

2.1 查询
public static ArrayList<SimpleFeature> queryMethod(String filterStr,
			String layerName) {
		//pgDatastore为上文连接数据库获取相当于AE中的workspace
		//SimpleFeatureSource相当于AE中的featureClass
		SimpleFeatureSource featureSource =pgDatastore.getFeatureSource(layerName); 
		ArrayList<SimpleFeature> featureList = new ArrayList<SimpleFeature>();
		if(featureSource==null)
			return featureList;
		try {
			Filter filter;
			filter = CQL.toFilter(filterStr); // filterStr形式 如  name='武汉大学' or code like 'tt123%'
			SimpleFeatureCollection result = featureSource.getFeatures(filter);

			FeatureIterator<SimpleFeature> itertor = result.features();
			while (itertor.hasNext()) {
				SimpleFeature feature = itertor.next();
				featureList.add(feature);
			}
			itertor.close();
			return featureList;
		} catch (CQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
2.2 要素操作  对上面4.1中的 SimpleFeature操作
//获取feature的geometry
Geometry geo=(Geometry) feature.getDefaultGeometry();
//获取geometry中的坐标 这里用string的方式保存
int geoUnm = geo.getNumGeometries();  // 一个geometry可能含有n个geometry
for (int i = 0; i < geoUnm; i++) {
	Geometry singleGeo = geo.getGeometryN(i); //获取其中每一个geometry
	int pointCount = singleGeo.getNumPoints();
	Coordinate[] coords = singleGeo.getCoordinates();
	for (int j = 0; j < pointCount; j++) {
		if (j == pointCount - 1)
			sBuilder.append(coords[j].x + "," + coords[j].y);
		else {
			sBuilder.append(coords[j].x + "," + coords[j].y
									+ ";");
		}
	}
	if (i != geoUnm - 1) {
		sBuilder.append("|");
	}
} 
//获取feature中的属性
feature.getAttribute(arg0);
2.3 拓扑查询
public static Filter getGeoFilter(FilterFactory2 ff,                //构建拓扑查询的filter
			String geometryAttributeName, Geometry refGeo,
			SpatialReltionType.TopoRelTypeEnum relType) {   //这个SpatialReltionType是我自己定义的。。。

		switch (relType) {
		case intersect:
			return ff.intersects(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case contains:
			return ff.contains(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case within:
			return ff.within(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case cross:
			return ff.crosses(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case overlaps:
			return ff.overlaps(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case touches:
			return ff.touches(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case equals:
			return ff.equals(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		case disjoint:
			return ff.disjoint(ff.property(geometryAttributeName), ff
					.literal(refGeo));
		default:
			return null;
		}
	}
// 普通的拓扑查询
public static ArrayList<Geometry> topoQueryMethod(Geometry refGeo,
			String layerName, SpatialReltionType.TopoRelTypeEnum relType) {
		ArrayList<SimpleFeature> featurelist=new ArrayList<SimpleFeature>();
		FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
		SimpleFeatureSource featureSource=pgDatastore.getFeatureSource(layerName); 
	
		SimpleFeatureType schema = featureSource.getSchema();
		String geometryAttributeName = schema.getGeometryDescriptor().getLocalName();
		Filter filter1= getGeoFilter(ff,geometryAttributeName, refGeo, relType);	//上面的方法
		SimpleFeatureCollection result=null;
		try {
			result = featureSource.getFeatures(filter1);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        if(result==null)
        	return null;
		FeatureIterator<SimpleFeature> itertor = result.features();
		while (itertor.hasNext()) {
			SimpleFeature feature = itertor.next();
			featurelist.add(feature);
		}
		//这个方法是将feature转为geometry 自己定义的
		return SpatialUtil.ConverToGeoList(featurelist);  
	}
//联合属性的拓扑查询
public static ArrayList<Geometry> topoQueryMethod(Geometry refGeo,
			String queryName, String layerName,
			SpatialReltionType.TopoRelTypeEnum relType) {
		FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
		ArrayList<SimpleFeature> featurelist=new ArrayList<SimpleFeature>();
		SimpleFeatureSource featureSource=pgDatastore.getFeatureSource(layerName); 
	
		SimpleFeatureType schema = featureSource.getSchema();
		String geometryAttributeName = schema.getGeometryDescriptor().getLocalName();
		Filter filter1= SpatialUtil.getGeoFilter(ff,geometryAttributeName, refGeo, relType);	
		Filter filter2=null;
		try {
		    filter2=CQL.toFilter("StandName = '"+queryName+"'");
		} catch (CQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		List<Filter> match = new ArrayList<Filter>();
		match.add(filter1);
		match.add(filter2);
		Filter filter = ff.and(match);

		SimpleFeatureCollection result=null;
		try {
			result = featureSource.getFeatures(filter);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        if(result==null)
        	return null;
		FeatureIterator<SimpleFeature> itertor = result.features();
		while (itertor.hasNext()) {
			SimpleFeature feature = itertor.next();
			featurelist.add(feature);
		}
		return SpatialUtil.ConverToGeoList(featurelist);
		
	}

3,编辑图层 

3.1 添加要素
    //添加一个feature到图层中 在添加前要确定构造featureType
	public static SimpleFeatureType createFeatureType(String typeName,Class type) {
		SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
		builder.setName(typeName);
		builder.setCRS(DefaultGeographicCRS.WGS84); // <- Coordinate reference
													// system
		builder.add("the_geom", type);  //这个为地理属性字段 postgis中为 the——geom

		builder.add("StandName", String.class); // 这是其他属性字段 自己定义的....							
		// build the type
		final SimpleFeatureType TYPE = builder.buildFeatureType();

		return TYPE;
	}
	
	//添加到图层的图层名,添加的要素空间属性和要素的某属性名
	public static boolean addFeature(String layerName,Geometry geo,String featureName){ 
		String type=geo.getGeometryType();
		Class TypeClass=null;
		if(type.toLowerCase().equals("point")){
			TypeClass=Point.class;
		}else if(type.toLowerCase().equals("polygon")){
			TypeClass=Polygon.class;
		}else if(type.toLowerCase().equals("polyline")){
			TypeClass=Polyline.class;
		}else if(type.toLowerCase().equals("multipolygon")){
		    TypeClass=MultiPolygon.class;
	    }
		SimpleFeatureType featureType=createFeatureType(layerName,TypeClass);
		 SimpleFeatureCollection collection = FeatureCollections.newCollection();

		SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
		 /* Longitude (= x coord) first ! */
		GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
     
        featureBuilder.add(geo);
        featureBuilder.add(featureName);
       
        SimpleFeature feature = featureBuilder.buildFeature(null);
        collection.add(feature);

        FeatureSource featureSource=pgDatastore.getFeatureSource(layerName); 
        if (featureSource instanceof SimpleFeatureStore) {
            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
            Transaction transaction = new DefaultTransaction("create");
            featureStore.setTransaction(transaction);
            try {
                featureStore.addFeatures(collection);
                transaction.commit();
                return true;

            } catch (Exception problem) {
                problem.printStackTrace();
                try {
					transaction.rollback();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

            } finally {
                try {
					transaction.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
            }
         
        } else {
            System.out.println(layerName + " does not support read/write access");      
        }
		return false;
	}
    3.2 修改要素
	// 修改feacode为XX的要素的名字为featureName 地理方位为geo  (feacode StandName为你的属性字段自定义)
	 public static boolean modifyFeature(String layerName,Geometry geo,String featureName,String FeaCode){
		  FeatureSource featureSource=pgDatastore.getFeatureSource(layerName); 
	        if (featureSource instanceof SimpleFeatureStore) {
	            SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
	            Transaction transaction = new DefaultTransaction("create");
	            featureStore.setTransaction(transaction);
	            try {
	            	String filterStr="FeaCode= '"+FeaCode+"'";
	            	String[] names=new String[2];
	            	names[0]="StandName";
	            	names[1]="the_geom";
	            	Object[] values=new Object[2];
	            	values[0]=featureName;
	            	values[1]=geo;
	            	featureStore.modifyFeatures(names, values, CQL.toFilter(filterStr));
	            
	               
	                transaction.commit();
                    return true;
	            } catch (Exception problem) {
	                problem.printStackTrace();
	                try {
						transaction.rollback();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

	            } finally {
	                try {
						transaction.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	            }
	         
	        } else {
	            System.out.println(layerName + " does not support read/write access");      
	        }
			return false;
	}

4 、Geometry 与 JTS

geotools 构建 geometry方法:这里转载一个别人写的比较好的 

4.1构建点
public Point createPoint(){  
        Coordinate coord = new Coordinate(109.013388, 32.715519);  
        Point point = geometryFactory.createPoint( coord );  
        return point;  
    } 
public Point createPointByWKT() throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        Point point = (Point) reader.read("POINT (109.013388 32.715519)");  
        return point;  
    } 
public MultiPoint createMulPointByWKT()throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        MultiPoint mpoint = (MultiPoint) reader.read("MULTIPOINT(109.013388 32.715519,119.32488 31.435678)");  
        return mpoint;  
    } 
4.2 构建线
public LineString createLine(){  
        Coordinate[] coords  = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};  
        LineString line = geometryFactory.createLineString(coords);  
        return line;  
    }  
 public LineString createLineByWKT() throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        LineString line = (LineString) reader.read("LINESTRING(0 0, 2 0)");  
        return line;  
    }  
public MultiLineString createMLine(){  
        Coordinate[] coords1  = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};  
        LineString line1 = geometryFactory.createLineString(coords1);  
        Coordinate[] coords2  = new Coordinate[] {new Coordinate(2, 2), new Coordinate(2, 2)};  
        LineString line2 = geometryFactory.createLineString(coords2);  
        LineString[] lineStrings = new LineString[2];  
        lineStrings[0]= line1;  
        lineStrings[1] = line2;  
        MultiLineString ms = geometryFactory.createMultiLineString(lineStrings);  
        return ms;  
    }  
public MultiLineString createMLineByWKT()throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        MultiLineString line = (MultiLineString) reader.read("MULTILINESTRING((0 0, 2 0),(1 1,2 2))");  
        return line;  
    } 
4.3 构建多边形
public Polygon createPolygonByWKT() throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        Polygon polygon = (Polygon) reader.read("POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))");  
        return polygon;  
    }  
public MultiPolygon createMulPolygonByWKT() throws ParseException{  
        WKTReader reader = new WKTReader( geometryFactory );  
        MultiPolygon mpolygon = (MultiPolygon) reader.read("MULTIPOLYGON(((40 10, 30 0, 40 10, 30 20, 40 10),(30 10, 30 0, 40 10, 30 20, 30 10)))");  
        return mpolygon;  
    }  
4.4 构建geo集合
public GeometryCollection createGeoCollect() throws ParseException{  
        LineString line = createLine();  
        Polygon poly =  createPolygonByWKT();  
        Geometry g1 = geometryFactory.createGeometry(line);  
        Geometry g2 = geometryFactory.createGeometry(poly);  
        Geometry[] garray = new Geometry[]{g1,g2};  
        GeometryCollection gc = geometryFactory.createGeometryCollection(garray);  
        return gc;  
    } 
4.5 构建圆
public Polygon createCircle(double x, double y, final double RADIUS){  
        final int SIDES = 32;//圆上面的点个数  
        Coordinate coords[] = new Coordinate[SIDES+1];  
        for( int i = 0; i < SIDES; i++){  
            double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;  
            double dx = Math.cos( angle ) * RADIUS;  
            double dy = Math.sin( angle ) * RADIUS;  
            coords[i] = new Coordinate( (double) x + dx, (double) y + dy );  
        }  
        coords[SIDES] = coords[0];  
        LinearRing ring = geometryFactory.createLinearRing( coords );  
        Polygon polygon = geometryFactory.createPolygon( ring, null );  
        return polygon;  
    }  

 

postgis 删除表  SELECT DropGeometryTable ('my_schema','my_spatial_table');

如: SELECT DropGeometryTable ('public','river');

 

分享到:
评论

相关推荐

    dnSpy-net-win32-222.zip

    dnSpy-net-win32-222.zip

    和美乡村城乡融合发展数字化解决方案.docx

    和美乡村城乡融合发展数字化解决方案.docx

    如何看待“适度宽松”的货币政策.pdf

    如何看待“适度宽松”的货币政策.pdf

    C#连接sap NCO组件 X64版

    NCO 3.0.18 64位

    法码滋.exe法码滋2.exe法码滋3.exe

    法码滋.exe法码滋2.exe法码滋3.exe

    基于MATLAB的导航科学计算库

    * GPS IMU经典15维ESKF松组合 * VRU/AHRS姿态融合算法 * 捷联惯导速度位置姿态解算例子 * UWB IMU紧组合融合 * 每个例子自带数据集

    毕业设计Jupyter Notebook基于深度网络的垃圾识别与分类算法研究项目源代码,用PyTorch框架中的transforms方法对数据进行预处理操作,后经过多次调参实验,对比不同模型分类效果

    在现代社会生活与生产活动下,不可避免的会产生巨量且多样的垃圾。我国的人口和经济总量均位居世界前列,因此,必然面临着庞大数量的垃圾处理的难题。如何通过人工智能来对垃圾进行有效分类,成为当前备受关注的研究热点。本文为展开基于深度网络的垃圾识别与分类算法研究,先使用PyTorch框架中的transforms方法对数据进行预处理操作,后经过多次调参实验,对比朴素贝叶斯模型、Keras卷积神经网络模型、ResNeXt101模型的垃圾分类效果。确定最佳分类模型是ResNeXt101,该模型在GPU环境下的分类准确率达到了94.7%。最后利用postman软件来测试API接口,完成图片的在线预测。在微信开发者工具的基础上,利用一些天行数据的垃圾分类的API接口再结合最佳模型的API接口,开发出了一个垃圾分类微信小程序。本文的研究内容丰富和完善了垃圾图像分类的相关研究,也为后续的研究提供了一定的参考价值。

    C#上位机开发与工控通讯实战课程

    一、上位机简介   在单片机项目开发中,上位机也是一个很重要的部分,主要用于数据显示(波形、温度等)、用户控制(LED,继电器等),下位机(单片机)与 上位机之间要进行数据通信的两种方式都是基于串口的: USB转串口 —— 上位机和下位机通过USB转串口连接线直接相连进行数据交互 串口转WIFI(ESP8266)—— 上位机和下位机基于TCP/IP协议通过以太网或者WIFI传输数据 串口转蓝牙(HC-06)—— 不多用,暂不介绍   Windows上位机(EXE可执行程序),最早用VB语言开发,后来由于C++的发展,采用MFC开发,近几年,微软发布了基于.NET框架的面向对象语言C#,更加稳定安全,再配合微软强大的VS进行开发,效率奇高。   本文使用Visual Studio 2022作为开发环境,上位机开发主要有WPF框架与Winform框架,他们都是基于.NET框架 WPF需要C/S基础,使用XAML来构建应用UI,界面比较美观,但是内存开销大 Winform可以使用窗口控件来构建应用,比较简单易学 二、开发环境设置 1. 安装Visual Studio 首先,确保你已经

    course_s4_ALINX_ZYNQ_MPSoC开发平台Linux驱动教程V1.04.pdf

    course_s4_ALINX_ZYNQ_MPSoC开发平台Linux驱动教程V1.04.pdf

    基于JavaWeb的毕业季旅游一站式定制服务平台_88z1j4jp_208-wx-(1).zip

    基于JavaWeb的毕业季旅游一站式定制服务平台_88z1j4jp_208-wx-(1).zip

    数据恢复软件 Apeaksoft Data Recovery for Mac v1.6.16

    Apeaksoft Data Recovery for Mac v1.6.16

    cms测试练习项目(linux系统部署)

    cms测试练习项目(linux系统部署),可以用来进行python的测试练手项目

    大学录取结果数据集,大学录取结果分析数据,大学录取因素分析

    数据集简介:大学录取结果分析 概述 大学录取结果数据集包含了有关大学录取过程的信息,包括关键变量,可用于分析不同学术因素与申请者是否被录取之间的关系。该数据集非常适合进行探索性数据分析、训练预测模型以及研究影响录取决策的因素。 数据集列描述 admit:指示申请者是否被录取(1=被录取,0=未录取)。 paes:申请者在高等教育能力测试(PAES)中获得的分数。 nem:中学教育成绩平均分,评分范围从1.0到7.0。 rank:申请者在其班级中的排名,数值越低表示排名越好。 数据集目的 本数据集旨在让用户探索学术指标(如PAES分数、GPA和排名)与大学录取成功率之间的关系。这可以用于: 开发预测模型:基于学术表现预测录取可能性。 识别趋势:找出影响录取的关键学术因素。 生成可视化图表:理解分数分布及录取结果的关系。 数据集规模 记录数:1813条。 列数:5列。

    STM32F427+rtthread下的bootload 网口(webclient)+串口(ymodem)传输,代码无质量,谨慎使用

    STM32F427+rtthread下的bootload 网口(webclient)+串口(ymodem)传输,代码无质量,谨慎使用

    电影院购票-JAVA-基于springBoot的电影院购票系统设计与实现(毕业论文)

    1. 用户管理功能 用户注册与登录:用户可以通过手机号、邮箱等方式注册账户,并且可以通过账号登录系统进行购票、查看历史订单等操作。 个人信息管理:用户可以查看和修改个人信息(如姓名、手机号、邮箱等),并进行密码重置等操作。 实名认证:部分电影院购票系统要求用户进行实名认证,确保用户身份的真实性。 2. 电影信息展示功能 电影排片查询:用户可以查看当前和未来一段时间内的电影排片表,包括电影名称、上映时间、影片时长、类型、导演、演员等详细信息。 电影详情页:点击具体电影后,用户可以查看电影的详细信息,如剧情介绍、影评、评分、预告片等内容。 电影评分与评论:用户可以查看其他观众的评分和评论,也可以对已观看的电影进行评分和评论。 3. 座位选择与预定功能 影厅座位图:系统展示每场次的影厅座位图,用户可以通过座位图查看当前座位的状态(如可选、已选、已售出、VIP座位等)。 座位选择:用户可以选择自己喜欢的座位,系统会实时更新座位的可用状态,避免重复选择。 座位偏好设置:用户可以设置自己的座位偏好,如选择前排、中排或后排,靠窗或靠过道等。 4. 电影票购买与支付功能 票价展示:系统会展示每个座位的

    Bukkit-BETA1.8.1服务端核心

    Bukkit-BETA1.8.1服务端核心

    快速排序在Go中的高效实现与应用

    内容概要:本文详细介绍了快速排序算法的原理和在Go语言中的高效实现方法。首先解释了快速排序的基本思想和实现步骤,接着提供了Go语言中实现快速排序的核心代码,并讨论了性能优化策略。最后,通过具体的应用场景实例,展示了快速排序在实际项目中的高效应用。 适合人群:具备一定编程基础,特别是对Go语言感兴趣的开发人员。 使用场景及目标:①理解快速排序算法的基本原理和分治策略;②学习如何在Go语言中高效实现快速排序;③掌握快速排序在实际项目中的应用实例。 阅读建议:本文不仅详细讲解了快速排序的原理,还提供了具体的实现代码和优化策略,建议读者在阅读过程中尝试实现和调试代码,以便更好地理解和掌握相关知识点。

    java毕设项目之学生社团管理系统+vue(完整前后端+说明文档+mysql+lw).zip

    项目包含完整前后端源码和数据库文件,均测试可正常运行 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 部署容器:tomcat7

    NSMethodNotImplementedException如何解决.md

    NSMethodNotImplementedException如何解决

    计算机接口实验报告.zip

    计算机接口实验报告,环境:PC 机一台,TD-PITE 实验装置一套。报告内容有,实验目的、实验设备、实验内容、实验步骤、实验程序(汇编)、实验结果、实验总结,一步到位!!!!!! 一步到位!!!!!!

Global site tag (gtag.js) - Google Analytics