`
Dikaros
  • 浏览: 3382 次
文章分类
社区版块
存档分类
最新评论

基于org.json的快速构建和解析json文本扩展工具

 
阅读更多

之前做过一个项目需要使用json来传输数据,我用的是org.json,但是其构造和解析方法过于繁琐,想到之前解析xml时用的simpleXml可以通过注解的方式构造和解析xml文本,

我就参考simpleXml,利用java的反射机制做了一个基于org.json的工具包,这个工具同样可以通过注解来构造json。


首先是一个接口,这个接口是个标记,表名一个类可以使用这个工具转换json

package dikaros.json.annotation;

/**
 * 动态转换标记<br>
 * 表示该实例类可以被动态转换成json信息<br>
 * @author Dikaros
 *
 */
public interface Jsonable {

}


接下来是声明的注解JsonParam


package dikaros.json.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * JsonParam 标准类型注解用在类的基本属性前<br>
 * 在生成json文本后为键值对的key<br>
 * @author Dikaros
 *
 */
//注解会在class字节码文件中存在,在运行时可以通过反射获取到  
@Retention(RetentionPolicy.RUNTIME) 
public @interface JsonParam {
	/**
	 * json文本 键
	 * @return
	 */
	public String name() default "";
	
}


注解JsonListParam

package dikaros.json.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * JsonParam 标准类型注解用在类的基本属性前<br>
 * 在生成json文本后为键值对的key<br>
 * className表示数组类型或集合的泛型如<code>String.class</code><br>
 * 枚举类型TYPE表示数组类型ARRAY表示数组,例如int[], LIST表示集合,例如java.util.List<br>
 * 
 * @author Dikaros
 * @see TYPE
 * 
 */
// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonListParam {
	public String name() default "";

	/**
	 * 数组类型或集合泛型
	 * @return
	 */
	public Class contentClassName();

	/**
	 * 设置是集合还是数组
	 * @return <code>TYPE.ARRAY</code>或<code>TYPE.LIST</code>
	 * @see TYPE
	 */
	public TYPE classType() default TYPE.LIST;

	/**
	 * 多数据类型<br>
	 * ARRAY表示数组,例如int[]<br>
	 * LIST表示集合,例如java.util.List<br>
	 * 默认为LIST
	 * 
	 * @author Dikaros
	 * 
	 */
	public enum TYPE {
		ARRAY, LIST
	};
}

然后就是主要的工具类了,由于这个类是基于org,json的,所以相关的org.json大家可以从其他地方下载,另外本文还附带了一个jar包,需要的可以下载

package dikaros.json;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import dikaros.json.annotation.JsonListParam;
import dikaros.json.annotation.JsonParam;
import dikaros.json.annotation.Jsonable;
import dikaros.json.annotation.JsonListParam.TYPE;
import dikaros.org.json.JSONArray;
import dikaros.org.json.JSONException;
import dikaros.org.json.JSONObject;
import dikaros.org.json.JSONStringer;

/**
 * org.json扩展<br>
 * 将类构造成简单的json文本<br>
 * 注意:构造的类需要实现Jsonable接口,并且是标准的JavaBean<br>
 * 原理:通过反射机制获取需要转换成json对象的注解,根据注解的内容生成key<br>
 * 由于注解是添加在变量上的,如果类拥有标准get和set方法,则通过反射获取<br>
 * 并执行这些方法即可当作value<br>
 * 建议:将一些类型改变为基本类型,如java.util.Date用long来表示
 * 
 * @author Dikaros
 * @see Jsonable
 * @see JsonParam
 * @see JsonListParam
 */
public class JsonExtendedUtil {

	/**
	 * 构造一个对象的json
	 * 
	 * @param object
	 *            需要转换成json的对象,需要实现Jsonable接口
	 * @return json文本
	 * @throws Exception
	 */
	public static String generateJson(Object object) throws Exception {
		JSONStringer stringer = new JSONStringer();
		stringer.array();
		generateObjectMessage(object, stringer);
		stringer.endArray();
		return stringer.toString();
	}

	/**
	 * 构造json<br>
	 * 原理:通过反射机制获取注解并将其作为key,再调用field的get方法即可得到value
	 * 
	 * @param object
	 *            需要转换成json的对象,需要实现Jsonable接口
	 * @param stringer
	 *            org.json的json构造器
	 * @throws Exception
	 */
	private static void generateObjectMessage(Object object,
			JSONStringer stringer) throws Exception {
		// 如果object没有实现Jsonable接口,则抛出异常
		if (!(object instanceof Jsonable)) {
			throw new Exception("不支持的类型格式,是否忘记了实现JsonAble接口");
		}
		// 开始构造json对象
		stringer.object();
		Class clazz = object.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(JsonParam.class)) {
				JsonParam jsonParam = field.getAnnotation(JsonParam.class);
				// json键
				stringer.key(jsonParam.name());
				Method method = getFieldMethod(clazz, field);
				Object value = method.invoke(object, new Object[] {});
				// json值
				stringer.value(value);
			} else if (field.isAnnotationPresent(JsonListParam.class)) {
				// System.out.println("list");
				JsonListParam jsonListParam = field
						.getAnnotation(JsonListParam.class);
				// 字段名称,根据字段名称获取其对应的get方法
				Method method = getFieldMethod(clazz, field);

				Object value = method.invoke(object, new Object[] {});
				if (value == null) {
					continue;
				}
				if (jsonListParam.classType() == TYPE.ARRAY) {

					Array.getLength(value);
					// 调用get方法
					stringer.key(jsonListParam.name());
					// 集合的键
					stringer.array();

					// 集合字段
					for (int i = 0; i < Array.getLength(value); i++) {
						Object listItem = Array.get(value, i);
						// 如果集合是JsonAble的实例则调用此函数
						if ((listItem instanceof Jsonable)) {
							generateObjectMessage(listItem, stringer);
						}
						// 如果集合不是JsonAble的实例
						else if (isBaseType(listItem)) {
							stringer.value(listItem);
						} else {
							throw new Exception("集合元素类型不支持,请将集合内元素实现JsonAble接口");
						}
					}
					// 集合结束
					stringer.endArray();
				} else if (jsonListParam.classType() == TYPE.LIST) {
					// 调用get方法
					stringer.key(jsonListParam.name());
					// 集合的键
					stringer.array();

					// 集合字段
					List list = (List) value;
					for (Object listItem : list) {
						// 如果集合是JsonAble的实例则调用此函数
						if ((listItem instanceof Jsonable)) {
							generateObjectMessage(listItem, stringer);
						}
						// 如果集合不是JsonAble的实例
						else if (isBaseType(listItem)) {
							stringer.value(listItem);
						} else {
							throw new Exception("集合元素类型不支持,请将集合内元素实现JsonAble接口");
						}
					}
					// 集合结束
					stringer.endArray();
				}

			}
		}
		// json对象结束
		stringer.endObject();
	}

	/**
	 * 判断对象是否是基本类型
	 * 
	 * @return true是,false 不是
	 */
	private static boolean isBaseType(Object obj) {
		boolean result = false;
		if ((obj instanceof Integer) || (obj instanceof Byte)
				|| (obj instanceof Double) || (obj instanceof Boolean)
				|| (obj instanceof String) || (obj instanceof Short)
				|| (obj instanceof Long) || (obj instanceof Character)
				|| (obj instanceof Float)) {
			result = true;
		}

		return result;
	}

	/**
	 * 获取JavaBean字段的get方法
	 */
	private static Method getFieldMethod(Class clazz, Field field)
			throws Exception {
		String fieldName = field.getName();
		fieldName = fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		Method method = null;
		try {
			if (field.getType() == Boolean.class) {
				method = clazz.getMethod("is" + fieldName, null);
			} else {
				method = clazz.getMethod("get" + fieldName, null);
			}
		} catch (NoSuchMethodException e) {
			throw new Exception("不是标准的JavaBean,注意JavaBean的格式");
		}
		return method;
	}

	/**
	 * 获取JavaBean字段的set方法
	 */
	@SuppressWarnings("unchecked")
	private static Method setFieldMethod(Class clazz, Field field)
			throws Exception {
		String fieldName = field.getName();
		fieldName = fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		Method method = null;
		try {
			// System.out.println("set---" + fieldName);
			method = clazz.getMethod("set" + fieldName,
					new Class[] { field.getType() });
		} catch (NoSuchMethodException e) {
			throw new Exception("不是标准的JavaBean,注意JavaBean的格式");
		}
		return method;
	}

	public static Object compileJson(Class clazz, String jsonFile)
			throws Exception {
		JSONArray array = new JSONArray(jsonFile);
		Object object = null;
		if (array.length() > 0) {
			JSONObject jsonObject = array.getJSONObject(0);
			object = clazz.newInstance();
			getObjectFromJsonFile(object, jsonObject.toString());
		}

		return object;
	}

	/**
	 * 解析Json<br>
	 * 原理:传入Object获取其类型,通过其类型的注解调用属性的set方法更改Object的值<br>
	 * 注意:该方法的传入json是一个JSONObject型的
	 * 
	 * @param jsonable
	 *            待转换的类
	 * @param jsonFile
	 *            需要解析的jsonFile
	 * @throws Exception
	 */
	private static void getObjectFromJsonFile(Object jsonable, String jsonFile)
			throws Exception {
		if (!(jsonable instanceof Jsonable)) {
			throw new Exception("不支持的类型格式,是否忘记了实现JsonAble接口");
		}
		// 获取class
		Class clazz = jsonable.getClass();
		JSONObject obj = new JSONObject(jsonFile);
		// 获取类所有的属性
		Field[] fields = clazz.getDeclaredFields();
		// 遍历所有的属性
		for (Field field : fields) {
			/*
			 * 如果属性中存在JsonParam的注解 从JsonFile中获取内容 通过反射机制调用set方法更新属性
			 */
			if (field.isAnnotationPresent(JsonParam.class)) {
				JsonParam jsonParam = field.getAnnotation(JsonParam.class);
				String keyName = jsonParam.name();
				Object value = obj.get(keyName);
				Method method = setFieldMethod(clazz, field);
				// 调用set方法更新属性
				method.invoke(jsonable, new Object[] { value });

			}
			/*
			 * 如果属性中存在JsonListParam的注解 从JsonFile中获取内容 判断多值类型是集合还是数组
			 * 根据类型采用不同的方法更新属性
			 */
			else if (field.isAnnotationPresent(JsonListParam.class)) {
				JsonListParam jsonListParam = field
						.getAnnotation(JsonListParam.class);
				// 获取键
				String keyName = jsonListParam.name();

				JSONArray jArray = null;
				/*
				 * 判断有没有这样的keyName 如果没有,跳过进行下一次循环
				 */
				try {
					jArray = obj.getJSONArray(keyName);
				} catch (Exception e) {
					continue;
				}
				if (!(field.getType().equals(List.class))
						&& !field.getType().isArray()) {
					throw new Exception("类型错误,类型不是List的实例");
				}
				Method method = setFieldMethod(clazz, field);
				TYPE classType = jsonListParam.classType();
				/*
				 * 如果是集合 构建集合 递归调用此方法进行设置
				 */
				if (classType == TYPE.LIST) {
					List list = new ArrayList<>();
					for (int i = 0; i < jArray.length(); i++) {
						JSONObject item = jArray.getJSONObject(i);
						Class itemClass = jsonListParam.contentClassName();
						Object itemObject = itemClass.newInstance();
						if (itemObject instanceof Jsonable) {
							getObjectFromJsonFile(itemObject, item.toString());
							list.add(itemObject);
						} else if (isBaseType(itemObject)) {
							list.add(jArray.get(i));
						}
					}
					method.invoke(jsonable, new Object[] { list });
				}
				/*
				 * 如果是数组 根据JSONArray大小构建数组 递归调用此方法进行设置
				 */
				else if (classType == TYPE.ARRAY) {

					// Object[] items = new Object[jArray.length()];
					Object items = Array.newInstance(
							jsonListParam.contentClassName(), jArray.length());
					for (int i = 0; i < jArray.length(); i++) {
						Class itemClass = jsonListParam.contentClassName();
						Object itemObject = itemClass.newInstance();
						if (itemObject instanceof Jsonable) {
							JSONObject item = jArray.getJSONObject(i);
							getObjectFromJsonFile(itemObject, item.toString());
							// items[i] = itemObject;
							Array.set(items, i, itemObject);
						} else if (isBaseType(itemObject)) {
							Array.set(items, i, jArray.get(i));

						}
					}
					System.out.println("method--->" + method.getName() + ":"
							+ method.getParameterTypes()[0]);
					method.invoke(jsonable, new Object[] { items });
				}

			}
		}

	}

	/**
	 * 获取long值
	 * 
	 * @param jsonFile
	 * @param param
	 * @return
	 */
	public static long getLongParam(String jsonFile, String param) {
		long result = 0;
		JSONObject obj;
		JSONArray array;

		try {
			array = new JSONArray(jsonFile);
			if (array.length() > 0) {
				obj = array.getJSONObject(0);
				result = obj.getLong(param);
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 获取boolean值
	 * 
	 * @param jsonFile
	 * @param param
	 * @return
	 */
	public static boolean getBooleanParam(String jsonFile, String param) {
		boolean result = false;
		JSONObject obj;
		JSONArray array;

		try {
			array = new JSONArray(jsonFile);
			if (array.length() > 0) {
				obj = array.getJSONObject(0);
				result = obj.getBoolean(param);
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 获取指定字段的内容
	 * 
	 * @param jsonFile
	 * @param param
	 * @return
	 */
	public static String getParam(String jsonFile, String param) {
		String result = null;
		JSONObject obj;
		JSONArray array;

		try {
			array = new JSONArray(jsonFile);
			if (array.length() > 0) {
				obj = array.getJSONObject(0);
				result = obj.getString(param);
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 从json文件中获取整型值
	 * 
	 * @param jsonFile
	 * @param param
	 * @return
	 */
	public static int getIntParam(String jsonFile, String param) {
		int result = -1;
		JSONObject obj;
		JSONArray array;

		try {
			array = new JSONArray(jsonFile);
			if (array.length() > 0) {
				obj = array.getJSONObject(0);
				result = obj.getInt(param);
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 构建 传输信息
	 * 
	 * @param map
	 * @return
	 */
	public static String constructMapJson(HashMap map) {
		Set set = map.keySet();
		JSONStringer jsonStringer = new JSONStringer();
		try {
			jsonStringer.array();
			jsonStringer.object();

			for (Iterator iterator = set.iterator(); iterator.hasNext();) {
				String key = (String) iterator.next();
				jsonStringer.key(key);
				jsonStringer.value(map.get(key));
			}
			jsonStringer.endObject();
			jsonStringer.endArray();
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return jsonStringer.toString();
	}


}

下面有一个实例,这个实例演示怎么使用这个工具

假定有一个类Person,注意,由于利用的是java的反射机制,所以这个类一定要是标准的JavaBean,被注解的属性必须有getter和setter方法。

package dikaros.example;

import java.util.Arrays;
import java.util.List;

import dikaros.json.annotation.JsonListParam;
import dikaros.json.annotation.JsonParam;
import dikaros.json.annotation.Jsonable;
import dikaros.json.annotation.JsonListParam.TYPE;

/**
 * 示例对象
 * @author Dikaros
 *
 */
public class Person implements Jsonable{
	public Person(String name, String gender, int age, String cityName) {
		this.name = name;
		this.gender = gender;
		this.age = age;
		this.cityName = cityName;
	}
	
	public Person() {
	}
	
	@JsonParam(name="name")
	String name;
	
	@JsonParam(name="gender")
	String gender;
	
	@JsonParam(name="age")
	int age;
	
	@JsonParam(name="cityName")
	String cityName;
	
	@JsonListParam(name="friends",contentClassName=Person.class,classType = TYPE.LIST)
	List<Person> friend;
	
	@JsonListParam(name="phones",contentClassName=String.class,classType = TYPE.ARRAY)
	String [] phones;
	
	
	/**
	 * @return name
	 */
	public String getName() {
		return name;
	}
	/**
	 * @param name 要设置的 name
	 */
	public void setName(String name) {
		this.name = name;
	}
	/**
	 * @return gender
	 */
	public String getGender() {
		return gender;
	}
	/**
	 * @param gender 要设置的 gender
	 */
	public void setGender(String gender) {
		this.gender = gender;
	}
	/**
	 * @return cityName
	 */
	public String getCityName() {
		return cityName;
	}
	/**
	 * @param cityName 要设置的 cityName
	 */
	public void setCityName(String cityName) {
		this.cityName = cityName;
	}
	/**
	 * @return age
	 */
	public int getAge() {
		return age;
	}
	/**
	 * @param age 要设置的 age
	 */
	public void setAge(int age) {
		this.age = age;
	}
	/**
	 * @return friend
	 */
	public List<Person> getFriend() {
		return friend;
	}
	/**
	 * @param friend 要设置的 friend
	 */
	public void setFriend(List<Person> friend) {
		this.friend = friend;
	}

	/* (非 Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Person [name=" + name + ", gender=" + gender + ", age=" + age
				+ ", cityName=" + cityName + ", friend=" + friend + ", phones="
				+ Arrays.toString(phones) + "]";
	}

	/**
	 * @return phones
	 */
	public String[] getPhones() {
		return phones;
	}

	/**
	 * @param phones 要设置的 phones
	 */
	public void setPhones(String[] phones) {
		this.phones = phones;
	}

	
	
}

下面是调用

package dikaros.example;

import java.util.ArrayList;

import dikaros.json.JsonExtendedUtil;

public class Example {
	public static void main(String[] args) throws Exception {
		Person person = new Person("老王", "男", 20, "长沙");
		String[] phones ={"13000000000","14000000000"};
		person.setPhones(phones);
		ArrayList<Person> friends = new ArrayList<>();
		friends.add(new Person("A妹子", "女", 19, "江西"));
		friends.add(new Person("B妹子", "女", 20, "湖北"));
		person.setFriend(friends);
		String jsonFile = JsonExtendedUtil.generateJson(person);
		System.out.println(jsonFile);
		
		Person person2 = (Person) JsonExtendedUtil.compileJson(Person.class, jsonFile);
		System.out.println(person2);
	}
}

输出结果

[{"name":"老王","gender":"男","age":20,"cityName":"长沙","friends":[{"name":"A妹纸","gender":"女","age":19,"cityName":"江西"},{"name":"B妹纸","gender":"女","age":20,"cityName":"湖北"}],"phones":["13000000000","14000000000"]}]
Person [name=老王, gender=男, age=20, cityName=长沙, friend=[Person [name=A妹纸, gender=女, age=19, cityName=江西, friend=null, phones=null], Person [name=B妹纸, gender=女, age=20, cityName=湖北, friend=null, phones=null]], phones=[13000000000,14000000000]]

我这里有整合了org.json的工具包,需要的可以下载,顺便换点积分下载工具



分享到:
评论

相关推荐

    pdf2json:一个PDF文件解析器,可将PDF二进制文件转换为基于文本的JSON,由PDF.JS的分支提供支持

    pdf2json是一个模块,可将PDF从二进制格式转换为json格式,它是使用构建的,并通过交互式表单元素和文本内容解析器在浏览器外部进行扩展。 目标是当包装在Web服务中时,使服务器端PDF可以使用交互式表单元素进行...

    基于python知识图谱医疗领域问答系统实现. 完整代码+数据可直接运行

    本项目为一个使用深度学习方法解析问题,知识图谱存储、查询知识点,基于医疗垂直领域的对话系统的后台程序 项目的搭建大致分为三个模块: 基础数据爬取 知识图谱构建 自动问答实现 项目运行环境: python : ...

    基于Apache Nutch和Htmlunit的扩展实现AJAX页面爬虫抓取解析插件.zip

    这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。...

    java开源包10

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包101

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包1

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包11

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包2

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包3

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包6

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包5

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包4

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包8

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    Beanbun 是用 PHP 编写的多进程网络爬虫框架,具有良好的开放性、高可扩展性,基于 Workerman。.zip

    这些工具帮助爬虫定位和提取目标数据,如文本、图片、链接等。 数据存储: 爬虫将提取的数据存储到数据库、文件或其他存储介质中,以备后续分析或展示。常用的存储形式包括关系型数据库、NoSQL数据库、JSON文件等。...

    java开源包7

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    java开源包9

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    Java资源包01

    GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以...

    JAVA上百实例源码以及开源项目源代码

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

    JAVA上百实例源码以及开源项目

     基于JAVA的UDP服务器模型源代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 ...

Global site tag (gtag.js) - Google Analytics