JDBC重新来过--解耦-封装-反射

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> hot3.png

一.前言(废话)

JDBC是java数据库连接的简称,也算是一种协议,一种规定.

JDBC的规范由java定义,常用的接口和类在jdk的java.sql包下.

各个厂商均实现了java.sql下定义的接口.因此在java中访问各种数据库如oracle,mysql,sqlserver,psql等都有了统一的规范:

    加载驱动......

    获取连接......

    使用statement进行操作.....

    结果集遍历......

    关闭连接......

java.sql:

152826_V7HS_2481244.png152833_cGXG_2481244.png

 

二.实现一个JDBCUtil,用以获取连接和关闭连接.

    特点:从外部加载配置文件,使用static{ }对属性进行初始化,然后使用单例模式实现线程安全(单线程非必要)

package com.rk.test1;

//省略import各种包


/*
 * JDBCUtil 实现了获取数据库连接,关闭数据库连接等操作.
 * 
 *
 * 
 * 这个类的特点:
 * 1.从外部配置文件读取数据库信息,与具体的数据库驱动解耦,可直接使用oracle的驱动,也可以直接使用mysql,sqlserver的驱动
 * 2.静态单例模式,该类只能提供一个全局的(static) Connection实例,防止过多的connection占用大量系统资源.
 * */

public class JDBCUtil {
	
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	
	private static Connection conn = null;
	
	//从配置文件初始化数据库连接信息
	static {
		InputStream inStream = 
             JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
		//初始化driver url name password
		Properties p = new Properties();
		try {
			p.load(inStream);
			//初始化参数
			driver = p.getProperty("driver");
			url = p.getProperty("url");
			user = p.getProperty("user");
			password = p.getProperty("password");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() {
		//1.加载驱动  利用Class.forName()类加载器进行加载driver,
		try {
			Class.forName(driver);
			//双重校验锁保证获取connection是线程安全的(单线程程序中非必要)
			if(conn == null) {
				synchronized(JDBCUtil.class){
					if(conn == null)
					conn = DriverManager.getConnection(url, user, password);
				}
			}
			return conn;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	//关闭方法
	public static void close() {
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		conn = null;
	}
}

 

这是一个通用的JDBCUtil,用以提供数据库连接和关闭数据库连接.

三.对JDBCUtil进行扩展,使用通用的增删改方法

    在实际使用过程中,普遍使用PreparedStatement进行参数化查询.而这过程中增删改这三个方法执行的过程如出一辙,我们可以使用这样的一个通用方法来定义增删改:

        public static int addDeleteUpdate(String sql,Object ...args) {
			//2.方法执行必须在数据库连接之后操作,若没有连接数据库则抛出异常
			if(conn == null) {
				try {
					throw new Exception("没有获取数据库连接!");
				} catch (Exception e) {
					e.printStackTrace();
				}
				return 0;
			}
			PreparedStatement pstmt = null;
			try {
				//准备pstmt
				pstmt = conn.prepareStatement(sql);
				//sql参数设置
				for (int i = 0; i < args.length; i++) {
					pstmt.setObject(i+1, args[i]);
				}
				//执行
				int rs = pstmt.executeUpdate();
				//返回
				return rs;
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				try {
					pstmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			return 0;
		}

这个方法可以定义在JDBCUtil这个类中,然后在这个类中在创建一个静态内部类用于提供这些方法.当然我们还是先看一下这三个方法:

        //通用删除方法 add delete update select
		public static int insert(String sql,Object ...args) {
			return addDeleteUpdate(sql,args);
		}
		
		public static int delete(String sql, Object ...args) {
			return addDeleteUpdate(sql,args);
		}
		
		public static int update(String sql, Object ...args) {
			return addDeleteUpdate(sql,args);
		}

有没有感受到,瞬间增删改变得简单明了!

那么select方法为什么要和增删改区分开来呢?

    因为select方法返回的是一个结果集,ResultSet,模型与增删改不一样,因此我们需要重新写一个通用的select方法.

四,通用的查找方法(查找一个和多个模型类似)

    如何定义一个通用的查找方法呢?

    首先我们明白,查找在得到ResultSet前的代码应该是一致的:

    //获取连接,使用pstmt执行excuteQuery()

    不同点在于获取结果集之后如何处理.如查找t_admin数据库表和t_user会得出不一样的列名和值.

    因此在处理结果集的时候需要使用不同的类型--泛型来处理:

    我们这样定义这个方法:

    

public static <T> T select(Class<T> clazz,String sql, Object ...args) {
    //.....
}

    public static 是可选的,视情况而定嘛.

    <T>表示该方法为泛型方法,方法持有泛型T,后面的返回值类型为T,传入T类型的类,用于制造T类型的实例.

    前面一部分代码用于得到ResultSet,应该为:

            if(conn == null) {
				try {
					throw new Exception("没有获取数据库连接!");
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}
			PreparedStatement pstmt = null;
			try {
				//准备pstmt
				pstmt = conn.prepareStatement(sql);
				//sql参数设置
				for (int i = 0; i < args.length; i++) {
					pstmt.setObject(i+1, args[i]);
				}
				//执行
				ResultSet rs = pstmt.executeQuery();

    这段代码并不完整,但其功能非常明显,获取连接,然后,查找得出结果集.

    得出结果集之后就是此方法的精髓部分了.

    得到结果集后,我们从结果集拿出从mysql中查找到的数据 记录,然后放在<String,Object>的一个Map中,然后接着利用反射的方法创建一个传入的类类型.

    紧接着在利用反射的方法为创建的这个类调用其setter为变量进行赋值.这里的要求是entity的变量要和数据库列一 一对应.

    代码如下:

                //对结果集进行获取元数据操作
				ResultSetMetaData rsmd= rs.getMetaData();
				Map<String,Object> data = new HashMap<String,Object>();
				if(rs.next()) {
					for (int i = 0; i < rsmd.getColumnCount(); i++) {
						data.put(rsmd.getColumnLabel(i+1), rs.getObject(i+1));
					}
				}
				//然后反射生成对象
				if(!data.isEmpty()) {
					T obj = clazz.newInstance();
					//利用反射进行对象赋值.
					for(Entry<String,Object> entry:data.entrySet()) {
						ReflectionForSet.setFileds(obj,entry.getKey(),entry.getValue());
					}
					return obj;
				}
				
			} catch (SQLException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}finally {
				try {
					pstmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			return null;

    其中,ReflectionForSet.setFileds(obj,entry.getKey(),entry.getValue())  为自定义方法:

package com.rk.test1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionForSet {
	
	public static  void setFileds(Object obj,String filedName,Object value) {
		Method[] method = obj.getClass().getDeclaredMethods();
		//获取方法
		for (Method md : method) {
			if(md.getName().contains("set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1))) {
				try {
					//System.out.println("即将被反射调用的方法:" + md.getName());
					md.invoke(obj, value);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}

	}
}

该自定义方法实现了通过查找传入的entity对象的setter方法为某个变量进行赋值操作.

五.总结

    1.将数据库配置文件从外部传入,解耦代码与具体相关数据库(也可以通过配置多个驱动加载不同数据库,从而避免配置文件).

    2.封装Connection的获取和close方法,提高安全和性能.

    3.封装CRUD操作的基本代码,最高程度降低相同代码的书写,使得在复杂业务逻辑中代码重复率大大降低.

    4.总归只是练手用,实际使用过程中也没人会这么用吧.大家都用数据连接池和DBUtils组件.不过作为学习和练手,这让我学到了好多知识.

 

六.最后奉献上完整的JDBCUtil代码:

JDBCUtil  /   ReflectionForSet    /   Test

-------------------------------------------------------------

JDBCUtil

package com.rk.test1;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;


/*
 * JDBCUtil 实现了获取数据库连接,关闭数据库连接等操作.
 * 
 * 同时提供通用的 增删改 方法(通过匿名内部类 + 类方法实现)
 * 
 * 这个类的特点:
 * 1.从外部配置文件读取数据库信息,与具体的数据库驱动解耦,可直接使用oracle的驱动,也可以直接使用mysql,sqlserver的驱动
 * 2.静态单例模式,该类只能提供一个全局的(static) Connection实例,防止过多的connection占用大量系统资源.
 * 3.提供通用的增删改查方法,通过静态内部类提供,体现了工具的特点.
 * 	 同时用户也可以不适用工具类提供的通用增删改查方法,自己定义方法也可,此时此类只提供获取connection和关闭connection方法
 * */

public class JDBCUtil {
	
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	
	private static Connection conn = null;
	
	//从配置文件初始化数据库连接信息
	static {
		InputStream inStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
		//初始化driver url name password
		Properties p = new Properties();
		try {
			p.load(inStream);
			//初始化参数
			driver = p.getProperty("driver");
			url = p.getProperty("url");
			user = p.getProperty("user");
			password = p.getProperty("password");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static Connection getConnection() {
		//1.加载驱动  利用Class.forName()类加载器进行加载driver,
		try {
			Class.forName(driver);
			//双重校验锁保证获取connection是线程安全的(单线程程序中非必要)
			if(conn == null) {
				synchronized(JDBCUtil.class){
					if(conn == null)
					conn = DriverManager.getConnection(url, user, password);
				}
			}
			return conn;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	//关闭方法
	public static void close() {
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		conn = null;
	}
	
	/*
	 * 静态内部类,工具类,提供通用的增删改查方法.
	 * 
	 * 
	 * */
	static class CRUDUtil{
		//1.定义一个通用插入方法
		public static int addDeleteUpdate(String sql,Object ...args) {
			//2.方法执行必须在数据库连接之后操作,若没有连接数据库则抛出异常
			if(conn == null) {
				try {
					throw new Exception("没有获取数据库连接!");
				} catch (Exception e) {
					e.printStackTrace();
				}
				return 0;
			}
			PreparedStatement pstmt = null;
			try {
				//准备pstmt
				pstmt = conn.prepareStatement(sql);
				//sql参数设置
				for (int i = 0; i < args.length; i++) {
					pstmt.setObject(i+1, args[i]);
				}
				//执行
				int rs = pstmt.executeUpdate();
				//返回
				return rs;
			} catch (SQLException e) {
				e.printStackTrace();
			}finally {
				try {
					pstmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			return 0;
		}
		
		//通用删除方法 add delete update select
		public static int insert(String sql,Object ...args) {
			return addDeleteUpdate(sql,args);
		}
		
		public static int delete(String sql, Object ...args) {
			return addDeleteUpdate(sql,args);
		}
		
		public static int update(String sql, Object ...args) {
			return addDeleteUpdate(sql,args);
		}
		
		//通用的select方法
		/**
		 * 	查询某一个
		 *	返回值类型:泛型T
		 *  参数:传入一个T类型的Class,利用此Class通过反射创建一个实例对象,然后对对象进行赋值(利用反射的方法),最后对象类型
		 * 
		 * */
		/**
		 * 首先第一步得到 ResultSet
		 * 然后通过ResultSet获得ResultSetMetaData
		 * 然后获取列的别名,把列的别名和列的值(object类型,因为不知道是int还是String)放入map
		 * 然后遍历map,利用反射把map中的kv装载到T类型的对象中.在返回T就可以了.
		 * 
		 * */
		public static <T> T select(Class<T> clazz,String sql, Object ...args) {
			if(conn == null) {
				try {
					throw new Exception("没有获取数据库连接!");
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}
			PreparedStatement pstmt = null;
			try {
				//准备pstmt
				pstmt = conn.prepareStatement(sql);
				//sql参数设置
				for (int i = 0; i < args.length; i++) {
					pstmt.setObject(i+1, args[i]);
				}
				//执行
				ResultSet rs = pstmt.executeQuery();
				//对结果集进行获取元数据操作
				ResultSetMetaData rsmd= rs.getMetaData();
				Map<String,Object> data = new HashMap<String,Object>();
				if(rs.next()) {
					for (int i = 0; i < rsmd.getColumnCount(); i++) {
						data.put(rsmd.getColumnLabel(i+1), rs.getObject(i+1));
					}
				}
				//然后反射生成对象
				if(!data.isEmpty()) {
					T obj = clazz.newInstance();
					//利用反射进行对象赋值.
					for(Entry<String,Object> entry:data.entrySet()) {
						ReflectionForSet.setFileds(obj,entry.getKey(),entry.getValue());
					}
					return obj;
				}
				
			} catch (SQLException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				try {
					pstmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			return null;
		}
	}
}

ReflectionForSet 

package com.rk.test1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionForSet {
	
	public static  void setFileds(Object obj,String filedName,Object value) {
		Method[] method = obj.getClass().getDeclaredMethods();
		//获取方法
		for (Method md : method) {
			if(md.getName().contains("set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1))) {
				try {
					//System.out.println("即将被反射调用的方法:" + md.getName());
					md.invoke(obj, value);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}
}

test

package com.rk.test1;

import java.sql.Connection;

public class Test {
	
	public static void main(String[] args) {
		
		Connection conn = JDBCUtil.getConnection();
		
		System.out.println(conn);
		
//		String sql  = "select * from t_user where ";
		
//		try {
//			Statement stmt  = conn.createStatement();
//			ResultSet rs = stmt.executeQuery(sql);
//			
//			while(rs.next()) {
//				System.out.println("id:" + rs.getInt(1) + " stuid:" + rs.getInt(2) + " name:" + rs.getString(3) + " password:" + rs.getString(4) + " oldpasword:" + rs.getString(5));
//			}
//		} catch (SQLException e) {
//			e.printStackTrace();
//		}
		
		//增加
//		String sql = "insert into t_user(stuid,account,password0,oldpassword)values(?,?,?,?)";
//		int stuid = 20140162;
//		String account = "kun";
//		String password0 = "kun";
//		String oldpassword = "dsd";
//		long startTime = System.currentTimeMillis();
//		for(int i = 0; i < 2; i++) {
//			JDBCUtil.CRUDUtil.insert(sql, 30140564+i+1+100001,account,password0,oldpassword);
//		}
//		long endTime = System.currentTimeMillis();
//		System.out.println("插入完成,耗时:" + (endTime - startTime) + "ms");
		
		//删除
//		startTime = System.currentTimeMillis();
//		String sql2 = "delete from t_user where password0=?";
//		String password = "ruan";
//		JDBCUtil.CRUDUtil.delete(sql2, password);
//		endTime = System.currentTimeMillis();
//		System.out.println("删除完成,耗时:" + (endTime - startTime) + "ms");

		
		//更新
//		long startTime = System.currentTimeMillis();
//		String sql3 = "update t_user set account = ? where id = ?";
//		String accounts = "mrruan";
//		int id = 1;
//		JDBCUtil.CRUDUtil.update(sql3, accounts, id);
//		long endTime = System.currentTimeMillis();
//		System.out.println("更新完成,耗时:" + (endTime - startTime)/1000d + "s");
//		
		
		//查找
		String sql4 = "select id,userid,state from t_admin where id = ?";
		Admin admin = JDBCUtil.CRUDUtil.select(Admin.class, sql4, 1);
		System.out.println(admin);
		
		
		
		JDBCUtil.close();
	}
	
	
}

 

阮少年、
关注 关注
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JDBC与数据库解耦
weixin_42682923的博客
12-22 487
在学习JDBC的过程中,简短的几段代码我学了很久,论到底还是学习方法不正确。所以学一门语言还是以写代码为主,先看视频再看书,否则会很浪费精力还没多少收获。 既然讲的是JDBC,需要用到的软件包括MySQL、Eclipse、JDK、数据库驱动器、SQLYog。当然你们也可以使用其他的软件。这几款软件的版本一定得统一,否则会出现出乎意料的情况。如果你们连接数据库出错时,百度一下原因,看会不会是版本不匹...
06-Java反射面试题(11题)-新增.pdf
11-17
- 框架如Hibernate、Spring等也大量使用反射来实现解耦和动态绑定。 5. **获取`Class`对象的方法**: - `Class.forName("类的全限定名")` - 类名.class - 对象名.getClass() - 基本类型包装类的Type属性,如`...
JDBC换个装——连接解耦
weixin_30307267的博客
07-31 93
原始JDBC连接 package jdbc; import org.junit.jupiter.api.Test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; pu...
代码优化四部曲:“拆套”、“解耦”、”封装“、“重构”
weixin_33743703的博客
12-13 206
拆套:尽量让代码的嵌套在三层以内(常用的方法是用“分支”替代“if...else”嵌套) 解耦:拆解各个类只见的耦合,提高各个类的内聚 封装:将独立的功能封装为独立的模块,逐渐形成component library 重构:对原代码流程进行优化...
JDBC使用Dao工厂模式读取properties配置文件实现解耦
我的编程世界
02-04 1146
daoconfig.properties配置文件内容: userDaoClass=com.ls.www.dao.impl.UserDaoImpl 测试类 package com.ls.www.dao; import com.ls.www.domain.User; public class UserDaoTest { public static void main(String[
精品资料(2021-2022收藏)JAVA+android-.pdf
11-11
- DAO(Data Access Object)设计模式用于封装数据库操作,提供解耦和复用。 - MVC(Model-View-Controller)模式是Web开发的常用架构,分离了业务逻辑、数据模型和用户界面。 - Tomcat是常用的Servlet容器,...
spring整合jdbc学习资料
05-10
Spring整合JDBC主要涉及到Spring框架中的JdbcTemplate模块,这是一个用于简化数据库访问的API,它将JDBC相关的繁琐工作进行了封装,比如管理数据库连接、处理事务、执行SQL语句等,从而使得开发人员能够更加专注于...
框架经典面试题.pdf
09-30
1. **封装JDBC**:它将繁琐的JDBC代码封装起来,简化了数据访问层的代码。 2. **ORM实现**:Hibernate作为ORM工具,简化了DAO层的工作,可以直接操作对象,而不是SQL语句。 3. **反射机制**:利用Java反射,实现对象...
框架总结及springboot入门1
08-08
1. **Mybatis**:Mybatis是一个持久层框架,它封装JDBC,使得开发者能够使用ORM(对象关系映射)的方式来处理数据库操作。Mybatis的发展过程中,从JDBC的繁琐操作,如手动建立和关闭连接,到引入连接池,再到ORM,...
JDBC 解耦——提取配置类与工具类
weixin_44646187的博客
03-24 184
在使用JDBC 时,有时需要多次使用相同的代码,造成代码冗余,产生强耦合,因此可以使用提取相同的代码,将其写成配置文件和工具类进行解耦。 书写配置类 1.右键文件夹,选择NEW–>FILE,然后命名 2.在配置文件书写信息 driver = com.mysql.jdbc.Driver url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&charcaterEncoding=utf8&useSSL=true usern
利用配置文件解耦工厂类型
weixin_33671935的博客
01-08 108
定义一个接口 public interface IFactory { IProduct Create(); // 返回默认的 concrete product IProduct Create(string name); // 按照配置的逻辑名称返回指定的concrete product } 获取...
程序的耦合和解耦
China_HaoZi的博客
03-09 319
什么是程序的耦合? 耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接 口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间 的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强, 同时表明其独立性越差(降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软 件设计中独有的,但是我们只讨论软件工程...
设计模式:如果通过封装、抽象、模块化、中间层等解耦代码
OceanStar的博客
12-31 494
解耦”为何如此重要 软件设计与开发最重要的工作之一就是应对复杂性。人处理复杂性的能力是有限的。过于复杂的代码往往在可读性、可维护性上都不友好。那如果来控制代码的复杂性呢? 手段有很多,但最关键的是解耦,保证代码松耦合、高内聚。如果说重构是保证代码质量不至于腐化到无可救药地步的有效手段,那么利用解耦的方法对代码重构,就是保证倒霉不至于复杂到无法控制的有效手段 实际上,“高内聚、松耦合”是一个比较通用的设计思想,不仅可以指导细粒度的类和类之间关系的设计,还能指导粗粒度的系统、架构、模块的设计。相对于编码规范,
封装解耦,组合与继承
weixin_34138255的博客
06-11 523
2019独角兽企业重金招聘Python工程师标准>>> ...
Add/Delete/Update
weixin_30588827的博客
11-17 138
首先是数据访问层的代码: 1usingSystem;2usingSystem.Data;3usingSystem.Data.SqlClient;4usingSystem.Configuration;56namespaceWebTest.Common7{8/**////<summary>9///COperator的摘要...
mimo输入输出-状态反馈解耦 matlab
最新发布
06-20
MIMO系统是指多输入多输出的控制系统,通常需要进行输入输出-状态反馈解耦来降低系统的复杂度和提高控制效果。这种解耦方法可以将MIMO系统分解成若干个SISO系统,从而可以分别对每个SISO系统进行设计和控制。 ...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • ArcGIS Pro安装和深度学习入门及入门者的一些注意事项 19310
  • 无线传感器网络 | 简答题 5924
  • SpringMVC报错No converter found for return value of type的一种解决方案 4868
  • 无线传感器网络复习题 | 摘抄自网络 3989
  • 8253/8255/8259相关知识 3341

分类专栏

  • 群晖 1篇
  • 数据分析学习 3篇
  • ArcGIS 1篇
  • 服务器运维 6篇
  • java刷题必会的基础技巧 1篇
  • JAVA 5篇

最新评论

  • 黑白群晖激活AME(Advanced Media Extention)

    我才是猫爸爸: 黑群7.2,无效,依然是MD5 mismatch

  • vue+springboot前后端分离项目中配置https

    CSDN-Ada助手: 恭喜你写了这么一篇有用的博客!在vue+springboot前后端分离项目中配置https确实是一个非常重要的步骤,你的经验分享让我受益匪浅。希望你能继续分享更多关于前后端分离项目配置的经验,比如如何优化前端页面加载速度或者如何提高后端接口的安全性等内容。期待你的下一篇博客!

  • ArcGIS Pro安装和深度学习入门及入门者的一些注意事项

    rx159: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb9 in position 3: invalid start byte 我的一到训练模型这里就出现这种是什么情况

  • ArcGIS Pro安装和深度学习入门及入门者的一些注意事项

    Mo jio: 博主 请问打标签文件夹中没有.emd文件 为什么呢?

  • ArcGIS Pro安装和深度学习入门及入门者的一些注意事项

    噜噜噜啦啦啦: 请问是一定要先配置环境是吗

大家在看

  • 国内RubyGems镜像
  • LeetCode刷题(739/496/503)/华为od转盘寿司-单调栈 615
  • 【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(9) 462
  • Ruby中任务构建工具rake的入门学习教程
  • python+flask计算机毕业设计“请君一笑”休闲论坛(程序+开题+论文) 439

最新文章

  • 黑白群晖激活AME(Advanced Media Extention)
  • ESXI服务器在内网中安装黑群晖后不知道IP地址如何处理
  • vue+springboot前后端分离项目中配置https
2024年2篇
2023年2篇
2022年3篇
2021年6篇
2020年4篇
2019年16篇
2018年4篇
2017年77篇
2016年59篇
2015年1篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司永湖设计网站布吉网页制作宝安优化沙井百度标王坑梓高端网站设计罗湖网站制作惠州seo网站优化福田高端网站设计塘坑网站推广方案横岗网络推广永湖建网站惠州网站改版盐田网站改版同乐外贸网站建设吉祥优秀网站设计木棉湾设计公司网站坪地网页制作观澜品牌网站设计沙井网络营销同乐百搜标王大运网站推广丹竹头百度爱采购东莞营销型网站建设坪地网站优化按天扣费石岩百搜标王松岗网站搜索优化沙井网站开发坑梓设计公司网站木棉湾企业网站设计光明至尊标王歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化