基于hibernate的泛型Dao框架
来源:互联网 发布:nginx 配置路径 编辑:程序博客网 时间:2024/05/23 14:28
这个东西是一年前弄的,不过一直没用到,里面有些东西已经记不太清了,还好注释应该可以看懂。
目的是希望设计一个基于hibernate的泛型Dao框架
推荐一个J2EE的群:46176507
首先创建一个java项目GenericDao
我们创建一个包com.hb.generic.dao
该包用来作为我们的基础dao包
首先我们创建一个针对单个实体操作的泛型EntityDao<T>接口。
用于定义针对单个实体的CRUD操作。
接着我们在定义一个接口类HibernateCallback,定义一个回调接口。
接下来我们定义一个com.hb.generic.dao.utils包,
该包的目的是用于防治一些常用方法的抽取,该包中的一些类是我平时的收集和积累。
我们这里只对关键类进行说明
BeanUtils :工具类,通过反射机制对对象进行存取值
GenericUtils:工具类,取得类中的泛型类型
里面基本上都有都有注释
我们在com.hb.generic.dao.support包下创建一个分页类(不做具体介绍,基本上分页都差不多)
我们需要在com.hb.generic.dao包下创建HibernateDaoHandler接口
在用户使用的时候需要实现该接口获取session
接下来我们会创建HibernateDaoSupport类
Dao的基类: 提供分页函数和若干便捷查询方法,并对返回值作了泛型类型转换.
HibernateGenericDao:最终面向用户使用的类。
现在我们的dao泛型框架已经完成,我们进行测试一下
我现在数据库中创建表Person
我们创建person.test包
我们创建实体bean
我们设置Person.hbm.xml映射文件
接下来我们配置hibernate.cfg.xml
接下来我们创建SessionFactory
这个会话工厂是由工具生成的这里不做详细介绍。
接下来我们创造PersonManager所有的Person操作都由他完成,神奇吧只需继承我们之前的HibernateGenericDao并实现getSession就可以。
下面我们写一个main方法进行测试。
目的是希望设计一个基于hibernate的泛型Dao框架
推荐一个J2EE的群:46176507
首先创建一个java项目GenericDao
我们创建一个包com.hb.generic.dao
该包用来作为我们的基础dao包
首先我们创建一个针对单个实体操作的泛型EntityDao<T>接口。
- /**
- * @author llying
- * @company qm
- */
- public interface EntityDao<T> {
- T get(Serializable id);
- List<T> getAll();
- void save(T newInstance);
- void remove(T transientObject);
- void removeById(Serializable id);
- String getIdName(Class clazz);
- }
用于定义针对单个实体的CRUD操作。
接着我们在定义一个接口类HibernateCallback,定义一个回调接口。
- import org.hibernate.Session;
- /**
- * @author llying
- * @company qm
- */
- public interface HibernateCallback {
- Object doInHibernate(Session session);
- }
接下来我们定义一个com.hb.generic.dao.utils包,
该包的目的是用于防治一些常用方法的抽取,该包中的一些类是我平时的收集和积累。
我们这里只对关键类进行说明
BeanUtils :工具类,通过反射机制对对象进行存取值
GenericUtils:工具类,取得类中的泛型类型
里面基本上都有都有注释
我们在com.hb.generic.dao.support包下创建一个分页类(不做具体介绍,基本上分页都差不多)
我们需要在com.hb.generic.dao包下创建HibernateDaoHandler接口
- import org.hibernate.Session;
- /**
- * @author llying
- * @company qm
- */
- public interface HibernateDaoHandler {
- Session getSession();
- }
在用户使用的时候需要实现该接口获取session
接下来我们会创建HibernateDaoSupport类
Dao的基类: 提供分页函数和若干便捷查询方法,并对返回值作了泛型类型转换.
- package com.hb.generic.dao;
- import java.io.Serializable;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.hibernate.Criteria;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.Transaction;
- import org.hibernate.criterion.CriteriaSpecification;
- import org.hibernate.criterion.Criterion;
- import org.hibernate.criterion.Order;
- import org.hibernate.criterion.Projection;
- import org.hibernate.criterion.Projections;
- import org.hibernate.criterion.Restrictions;
- import org.hibernate.impl.CriteriaImpl;
- import org.hibernate.impl.CriteriaImpl.OrderEntry;
- import com.hb.generic.dao.support.Page;
- import com.hb.generic.dao.utils.Assert;
- import com.hb.generic.dao.utils.BeanUtils;
- /**
- * Dao的基类.
- *
- * 提供分页函数和若干便捷查询方法,并对返回值作了泛型类型转换.
- * @author llying
- * @company qm
- */
- public abstract class HibernateDaoSupport<T> implements HibernateDaoHandler {
- private static final Log log = LogFactory.getLog(HibernateDaoSupport.class);
- public Object execute(HibernateCallback action){
- Assert.notNull(action, "Callback object 对象不能为 Null ");
- Session session = getSession();
- Transaction tr = session.beginTransaction();
- Object result = action.doInHibernate(session);
- tr.commit();
- session.close();
- return result;
- }
- /**
- * 获取全部的对象
- * @param <T>
- * @param entityClass 对象类型
- * @return
- */
- @SuppressWarnings("unchecked")
- public <T>List<T> getAll(final Class<T> entityClass) {
- return (List<T>)execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- Criteria criteria = session.createCriteria(entityClass);
- return criteria.list();
- }
- });
- }
- /**
- * 获取全部对象,带排序功能
- * @param <T>
- * @param entityClass 实体对象
- * @param orderBy 排序字段
- * @param isAsc 升序或降序
- * @return
- */
- @SuppressWarnings({ "hiding", "hiding", "unchecked" })
- public <T> List <T> getAll(final Class<T> entityClass,final String orderBy,final boolean isAsc){
- Assert.hasText(orderBy);
- return (List<T>) execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- if (isAsc)
- return session.createCriteria(entityClass).addOrder(Order.asc(orderBy)).list();
- return session.createCriteria(entityClass).addOrder(Order.desc(orderBy)).list();
- }
- });
- }
- /**
- * 保存对象
- * @param newInstance
- */
- @SuppressWarnings("unused")
- public void saveOrUpdate(final T newInstance){
- execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- session.saveOrUpdate(newInstance);
- return null;
- }
- });
- }
- /**
- * 删除对象
- * @param transientObject
- */
- public void remove(final T transientObject) {
- execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- session.delete(transientObject);
- return null;
- }
- });
- }
- /**
- *
- * @param entityClass
- * @param id
- */
- public void removeById(Class<T> entityClass, Serializable id) {
- remove( get(entityClass, id));
- }
- /**
- * 根据Id获取对象。
- * @param <T>
- * @param entityClass
- * @param id 实体Id
- * @return 实体对象
- */
- @SuppressWarnings({ "hiding", "unchecked" })
- public <T> T get(final Class<T> entityClass,final Serializable id) {
- return (T) execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- return session.get(entityClass, id);
- }
- });
- }
- /**
- * 创建一个Query对象。
- * @param hql
- * @param values
- * @return
- */
- public Query createQuery(String hql,Object...values){
- Assert.hasText(hql);
- Query query = getSession().createQuery(hql);
- for(int i = 0;i<values.length;i++){
- query.setParameter(i, values[i]);
- }
- return query;
- }
- /**
- * 创建Criteria对象。
- * @param <T>
- * @param entityClass
- * @param criterions
- * @return
- */
- public <T>Criteria createCriteria(Class<T> entityClass,Criterion...criterions){
- Criteria criteria = getSession().createCriteria(entityClass);
- for(Criterion c:criterions){
- criteria.add(c);
- }
- return criteria;
- }
- /**
- * 创建Criteria对象,有排序功能。
- * @param <T>
- * @param entityClass
- * @param orderBy
- * @param isAsc
- * @param criterions
- * @return
- */
- public <T>Criteria createCriteria(Class<T> entityClass,String orderBy,boolean isAsc,Criterion...criterions){
- Assert.hasText(orderBy);
- Criteria criteria = createCriteria(entityClass,criterions);
- if(isAsc){
- criteria.addOrder(Order.asc(orderBy));
- }else{
- criteria.addOrder(Order.desc(orderBy));
- }
- return criteria;
- }
- /**
- * 根据hql查询
- * @param hql
- * @param values
- * @return
- */
- public List find(final String hql,final Object...values){
- Assert.hasText(hql);
- return createQuery(hql, values).list();
- /* return (List) execute(new HibernateCallback(){
- public Object doInHibernate(Session session) {
- Query query = session.createQuery(hql);
- for(int i = 0;i<values.length;i++){
- query.setParameter(i, values[i]);
- }
- return query.list();
- }
- });*/
- }
- /**
- * 根据属性名和属性值查询.
- *
- * @return
- */
- public <T>List<T> findBy(Class<T> entityClass,String propertyName,Object value){
- Assert.hasText(propertyName);
- return createCriteria(entityClass, Restrictions.eq(propertyName, value)).list();
- }
- /**
- * 根据属性名和属性值查询. 有排序
- * @param <T>
- * @param entityClass
- * @param propertyName
- * @param value
- * @param orderBy
- * @param isAsc
- * @return
- */
- public <T>List<T> findBy(Class<T> entityClass,String propertyName,Object value,String orderBy,boolean isAsc){
- Assert.hasText(propertyName);
- Assert.hasText(orderBy);
- return createCriteria(entityClass, orderBy, isAsc, Restrictions.eq(propertyName, value)).list();
- }
- /**
- * 根据属性名和属性值 查询 且要求对象唯一.
- *
- * @return 符合条件的唯一对象.
- */
- public <T>T findUniqueBy(Class<T> entityClass,String propertyName,Object value){
- Assert.hasText(propertyName);
- return (T)createCriteria(entityClass, Restrictions.eq(propertyName, value)).uniqueResult();
- }
- /**
- * 分页 通过hql进行
- * @param hql
- * @param pageNo
- * @param pageSize
- * @param values
- * @return
- */
- public Page pagedQuery(String hql,int pageNo,int pageSize,Object...values){
- Assert.hasText(hql);
- Assert.isTrue(pageNo>=1);
- String countQueryString = "select count(*)" + removeSelect(removeOrders(hql));
- System.out.println(countQueryString);
- List countList = find(countQueryString, values);
- long totalCount = (Long) countList.get(0);
- System.out.println(totalCount);
- if(totalCount<1){
- return new Page();
- }
- int startIndex = Page.getStartOfPage(pageNo, pageSize);
- Query query = createQuery(hql,values);
- List list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
- return new Page(startIndex,totalCount,pageSize,list);
- }
- /**
- * 分页 通过criteria
- * @param criteria
- * @param pageNo
- * @param pageSize
- * @return
- */
- public Page pagedQuery(Criteria criteria,int pageNo,int pageSize){
- Assert.notNull(criteria);
- Assert.isTrue(pageNo>=1);
- CriteriaImpl criteriaImpl = (CriteriaImpl) criteria;
- //先把Projection和OrderBy条件取出来,清空两者来执行Count操作
- Projection projection = criteriaImpl.getProjection();
- List<CriteriaImpl.OrderEntry> orderEntitys = null;
- try {
- orderEntitys=(List<OrderEntry>) BeanUtils.forceGetProperty(criteriaImpl, "orderEntries");
- BeanUtils.forceSetProperty(criteriaImpl, "orderEntries", new ArrayList());
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- //取得总的数据数
- long totalCount = (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
- //将之前的Projection和OrderBy条件重新设回去
- criteria.setProjection(projection);
- if (projection == null) {
- criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
- }
- try {
- BeanUtils.forceSetProperty(criteriaImpl, "orderEntries", orderEntitys);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- if(totalCount<1)
- return new Page();
- int startIndex = Page.getStartOfPage(pageNo, pageSize);
- List data = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
- return new Page( startIndex, totalCount, pageSize, data);
- }
- /**
- * 分页查询函数
- * @param entityClass
- * @param pageNo
- * @param pageSize
- * @param criterions
- * @return
- */
- public Page pagedQuery(Class<T> entityClass,int pageNo,int pageSize,Criterion...criterions){
- Criteria criteria = createCriteria(entityClass, criterions);
- return pagedQuery(criteria, pageNo, pageSize);
- }
- /**
- * 分页查询带排序
- * @param entityClass
- * @param pageNo
- * @param pageSize
- * @param orderBy
- * @param isAsc
- * @param criterions
- * @return
- */
- public Page pagedQuery(Class<T> entityClass,int pageNo,int pageSize,String orderBy,boolean isAsc,Criterion...criterions){
- Criteria criteria = createCriteria(entityClass, orderBy, isAsc, criterions);
- return pagedQuery(criteria, pageNo, pageSize);
- }
- /**
- * 去除hql的select子句。
- * @param hql
- * @return
- * @see #pagedQuery(String,int,int,Object[])
- */
- private static String removeSelect(String hql){
- Assert.hasText(hql);
- int beginPos = hql.toLowerCase().indexOf("from");
- Assert.isTrue(beginPos!=-1,hql);
- return hql.substring(beginPos);
- }
- /**
- * 去除hql的orderBy子句。
- * @param hql
- * @return
- * @see #pagedQuery(String,int,int,Object[])
- */
- private static String removeOrders(String hql) {
- Assert.hasText(hql);
- Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
- Matcher m = p.matcher(hql);
- StringBuffer sb = new StringBuffer();
- while (m.find()) {
- m.appendReplacement(sb, "");
- }
- m.appendTail(sb);
- return sb.toString();
- }
- }
HibernateGenericDao:最终面向用户使用的类。
- /**
- *
- * @author llying
- * @company qm
- */
- @SuppressWarnings("unchecked")
- public abstract class HibernateGenericDao<T> extends HibernateDaoSupport<T> implements EntityDao<T>{
- protected Class<T> entityClass;
- public HibernateGenericDao(){
- /**
- * this.getClass()的目的是返回当前对象运行时的类
- * 通过工具类GenericUtils返回泛型T的实际类对象
- */
- entityClass = GenericUtils.getSuperClassGenericType(getClass());
- }
- public T get(Serializable id) {
- return get(entityClass,id);
- }
- public List<T> getAll() {
- return getAll(entityClass);
- }
- public String getIdName(Class clazz) {
- return null;
- }
- public void removeById(Serializable id) {
- removeById(entityClass,id);
- }
- public void save(T newInstance) {
- saveOrUpdate(newInstance);
- }
- /**
- * 查询全部,带排序
- * @param orderBy
- * @param isAsc
- * @return
- */
- public List<T> getAllByOrder(String orderBy,boolean isAsc){
- return getAll(entityClass,orderBy,isAsc);
- }
- /**
- * 根据属性名和属性值查询对象
- * @param propertyName
- * @param value
- * @return
- */
- public List<T> findBy(String propertyName,Object value){
- return findBy(entityClass, propertyName, value);
- }
- /**
- * 根据属性名和属性值进行查询对象,带排序
- * @param propertyName
- * @param value
- * @param isAsc
- * @param orderBy
- * @return
- */
- public List<T> findBy(String propertyName,Object value,boolean isAsc,String orderBy){
- return findBy(entityClass, propertyName, value, orderBy, isAsc);
- }
- /**
- * 根据属性名和属性值进行查询对象,返回符合条件的唯一对象。
- * 如果对象不唯一将抛出异常
- * @param <T>
- * @param propertyName
- * @param value
- * @return
- */
- public <T> T findUniqueBy(String propertyName,Object value){
- return (T) findUniqueBy(entityClass, propertyName, value);
- }
- }
现在我们的dao泛型框架已经完成,我们进行测试一下
我现在数据库中创建表Person
- CREATE TABLE `person` (
- `p_id` int(11) NOT NULL auto_increment,
- `p_name` varchar(255) NOT NULL,
- `p_age` int(11) NOT NULL,
- PRIMARY KEY (`p_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我们创建person.test包
我们创建实体bean
- package person.test;
- import java.io.Serializable;
- public class Person implements Serializable{
- private Integer id;
- private String name;
- private Integer age;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public Integer getAge() {
- return age;
- }
- public void setAge(Integer age) {
- this.age = age;
- }
- }
我们设置Person.hbm.xml映射文件
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="person.test.Person" table="person">
- <id name="id" type="java.lang.Integer">
- <column name="p_id"></column>
- <generator class="native"></generator>
- </id>
- <property name="name" type="java.lang.String">
- <column name="p_name" length="255" not-null="true"></column>
- </property>
- <property name="age" type="java.lang.Integer">
- <column name="p_age" not-null="true"></column>
- </property>
- </class>
- </hibernate-mapping>
接下来我们配置hibernate.cfg.xml
- <?xml version='1.0' encoding='UTF-8'?>
- <!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <property name="connection.username">root</property>
- <property name="connection.url">
- jdbc:mysql://localhost:3306/genericdao
- </property>
- <property name="dialect">
- org.hibernate.dialect.MySQLDialect
- </property>
- <property name="myeclipse.connection.profile">mysql</property>
- <property name="connection.driver_class">
- com.mysql.jdbc.Driver
- </property>
- <mapping resource="person/test/Person.hbm.xml" />
- </session-factory>
- </hibernate-configuration>
接下来我们创建SessionFactory
这个会话工厂是由工具生成的这里不做详细介绍。
接下来我们创造PersonManager所有的Person操作都由他完成,神奇吧只需继承我们之前的HibernateGenericDao并实现getSession就可以。
- package person.test;
- import org.hibernate.Session;
- import com.hb.generic.dao.HibernateGenericDao;
- public class PersonManager extends HibernateGenericDao<Person> {
- @Override
- public Session getSession() {
- // TODO Auto-generated method stub
- return HibernateSessionFactory.getSession();
- }
- }
下面我们写一个main方法进行测试。
- /**
- * 1.测试save方法
- */
- public void testSave(){
- for(int i=1;i<100;i++){
- Person p = new Person();
- p.setName("pname"+i);
- p.setAge(i);
- pm.save(p);
- }
- }
- /**
- * 2.测试getAll方法
- */
- public void testGetAll(){
- List<Person> list = pm.getAll();
- System.out.println(list.size());
- for(Person p: list){
- System.out.println("------------------------");
- System.out.println("id :" + p.getId());
- System.out.println("name :" + p.getName());
- System.out.println("age :" + p.getAge());
- }
- }
- /**
- * 3.测试get方法
- */
- public void testGet(){
- Person p = pm.get(new Integer(20));
- System.out.println("id :" + p.getId());
- System.out.println("name :" + p.getName());
- System.out.println("age :" + p.getAge());
- }
- /**
- * 4.测试排序方法 getAllByOrder
- */
- public void testGetAllByOrder(){
- List<Person> list = pm.getAllByOrder("age", true);
- System.out.println("-- Asc --");
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- System.out.println("-- Desc --");
- list = pm.getAllByOrder("age", false);
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- }
- /**
- * 5.测试find方法 即hql查询
- */
- public void testFind(){
- List<Person>list = pm.find("from Person p where p.age = ?", 50);
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- list = pm.find("from Person p where p.age > ? and p.age < ?",30,50);
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- }
- /**
- * 6.测试findBy方法 即简单查询
- */
- public void testFindBy(){
- List<Person>list = pm.findBy("age", 11);
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- //如果多个按name字段排序
- list = pm.findBy("age", 15, false, "name");
- for(Person p: list){
- System.out.println(p.getId());
- System.out.println(p.getName());
- System.out.println(p.getAge());
- }
- }
- /**
- * 7.findUniqueBy查询 仅返回单个对象
- */
- public void testFindUniqueBy(){
- Person p = pm.findUniqueBy("age", 16);
- System.out.println("id :" + p.getId());
- System.out.println("name :" + p.getName());
- System.out.println("age :" + p.getAge());
- }
- /**
- * 8.分页查询测试 pageQuery
- */
- public void testPagedQuery(){
- Page page = pm.pagedQuery("from Person p where p.age > ?", 1, 20, 11);
- System.out.println("currentPageNo " + page.getCurrentPageNo());
- System.out.println("totalCount " + page.getTotalCount());
- List<Person> list = (List<Person>) page.getResult();
- for(Person p: list){
- System.out.println("id :" + p.getId());
- System.out.println("name :" + p.getName());
- System.out.println("age :" + p.getAge());
- }
- }
- /**
- * 9.更新方法 测试saveOrUpdate
- */
- public void testUpdate(){
- Person p = pm.findUniqueBy("age", 16);
- p.setName("16per");
- pm.saveOrUpdate(p);
- p = pm.findUniqueBy("age", 16);
- System.out.println(p.getName());
- }
- /**
- * 10.测试通过id删除方法 removeById
- */
- public void testRemoveById(){
- pm.removeById(23);
- Person p = pm.get(new Integer(23));
- System.out.println(p==null);
- }
- /**
- * 11.测试通过对象删除 remove
- */
- public void testRemove(){
- Person p = pm.get(new Integer(24));
- pm.remove(p);
- p = pm.get(new Integer(24));
- System.out.println(p==null);
- }
0 0
- 基于hibernate的泛型Dao框架
- 基于Hibernate框架的泛型DAO层---SwiftDAO
- Hibernate基于持久层框架的DAO模式应用
- 基于泛型DAO的Facade设计模式. - Hibernate - Java
- 基于泛型的通用Dao接口hibernate实现
- 基于hibernate的泛型Dao层设计
- 基于泛型的通用Dao接口和hibernate的实现
- 基于泛型的通用Dao接口和hibernate的实现
- Hibernate基于Spring模板的DAO基类
- hibernate不是泛型的通用DAo
- 基于Hibernate编写DAO
- 基于泛型DAO的设计模式
- 基于Spring+Hibernate+DAO的hibernate的lazy的实现.
- hibernate通用泛型dao
- hibernate 通用泛型DAO
- Spring+Hibernate整合框架下DAO的数据库访问方法
- 通过Hibernate框架搭建简单的dao层
- 不要重复DAO!使用Hibernate 和Spring AOP 构建泛型类型安全的DAO
- Cocos2d-JS中使用CocosStudio资源——登录界面
- hdu 1422 重温世界杯
- easyui和thinkphp整合的分页功能
- 十期讨论反思
- EL表达式与jQuery
- 基于hibernate的泛型Dao框架
- [BZOJ1821]JSOI2010部落划分|贪心|Kruskal
- jedis 切片(分布式) 非切片的实例
- javascript快速入门之BOM模型—浏览器对象模型(Browser Object Model)
- 我学java的笔记
- C++类模板笔记
- 跟着我学python (3)---- 一个32岁销售python自学之路
- IOS6内存警告处理
- SDN/OpenFlow之Ryu控制器的安装与使用