polenum,可以获取哪些信息
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了polenum,可以获取哪些信息相关的知识,希望对你有一定的参考价值。
目前,帐号仍然是最主要的用户身份认证方式,但由于安全意识的淡漠,很多人仍在使用弱口令。而一旦泄漏,所有安全防范机制都将形同虚设。本课程《用户口令审计》是『Kali Linux工具大全』技术系列的第5部分。向大家详述Kali Linux中全部在线/离线弱口令审计工具的用法,以此来帮助大家提前发现自己系统中的弱口令问题。

用户口令审计工具介绍
1、crunch
在面对妥善保护的系统时,我们可能很难发现其漏洞和可渗透的突破口。作为渗透测试人员,此时应尝试对目标系统进行弱密码的检测。密码**成败的关键在于字典的质量,crunch是一个密码字典生成器,它可以灵活的按照规则生成定制的密码字典,为了方便使用,其内建了常用的字符集文件,并支持自定义密码构成元素。
2、wordlists / SecLists
在面对妥善保护的系统时,我们可能很难发现其漏洞和可渗透的突破口。作为渗透测试人员,此时应尝试对目标系统进行弱密码的检测,密码**成败的关键在于字典的质量。为了方便使用,Kali中已默认包含了大量通用密码字典,它们分别存放在wordlists、seclists两个目录之中。除密码字典之外,以上目录中还包含大量漏洞挖掘和Fuzz用途的字典文件。 hashid / hash-identifier
单向加密算法是将可变长度输入数据,加密生成固定长度的密文输出值,即所谓的HASH值。此加密算法通常被认为是不可逆的。但我们可以提前计算常见数据的HASH值,并利用其进行反查匹对应的明文,实现HASH**。由于HASH算法种类众多,因此需要hashid、hash-identifier来提前判断生成密文的HASH算法,以便查询对应明文。 findmyhash
单向加密算法是将可变长度数据,加密生成固定长度的密文输出值,即所谓的HASH值。此加密算法通常被认为是不可逆的。但有众多网站会提前计算常见数据的HASH值,并利用其进行反查匹对应的明文,以此实现HASH值**。findmyhash可在线查询多个站点的HASH值数据库,批量完成HASH值匹配的**,其新版本查询效果更佳。
3、 fcrackzip
存有机密数据的文件,经常会被其所有者加密压缩保存。而作为数据安全审计者,则应对加密文件进行弱口令检查,以确保数据安全性。fcrackzip是一款快速的ZIP压缩文件密码**工具,其支持基于字典和**的两种工作模式,同时其内建了字符集和密码规则指定功能,免去了使用者提前准备和保存密码字典文件的繁琐。
4、cupp3 / cewl / fab-cewl
由于人性与生俱来的弱点,使得弱口令成为很多系统都存在的安全问题,即使是那些安全防护较好的站点也不例外。作为渗透测试者,如果能够获得目标系统的密码,则无需繁琐的漏洞挖掘,即可直接接管目标系统。密码**的关键在于字典的命中率,cupp3可依据个人信息生成专属字典,cewl则通过收集企业信息生成专属字典。使用这些有针对性的字典,使得密码**的成功率更高。
5、 pwdump / samdump2
出于安全性的考虑,windows系统并不会保存用户账号的明文密码,而是以加密的形式存储于本机的SAM数据库中。不过密码虽为密文保存,但如果密码过于简单,仍然存在被**的可能性。在可以物理接触电脑的情况下,我们可以利用pwdump、samdump2来读取SAM数据库文件中的密文密码,然后再使用其他工具进行密码**。
6、chntpw
我有一个同事曾经受到电脑勒索,攻击者修改了他的系统账号密码,并要求他支付赎金。众所周知,出于安全性的考虑,windows系统并不会保存用户账号的明文密码,而是以加密的形式存储于本机的SAM数据库中。因此我们可以通过chntpw工具本地读取并修改SAM数据库,将账号密码清空,从而避免受到坏人的勒索。
7、 hydra
密码**可以分为在线**和离线**两种。所谓在线**,就是使用不同的密码向目标服务器发起重复的身份验证请求,然后根据服务器的反馈信息判断登陆是否成功。hydra是开源世界在线密码**工具中的王者,它不但支持常见的所有协议类型,同时也支持不同形式的WEB表单认证**。它功能强大,使用灵活简洁。
8、 pw-inspector
由于人性与生俱来的弱点,弱口令成为很多系统都存在的安全问题,即使是很多安全防护较好的站点也不例外。密码**的关键在于字典的命中率,如果你知道密码的字符构成规则,可以使用pw-inspector对已有密码字典进行过滤筛选,以便提高密码**的效率。pw-inspector不能凭空生成字典,它只是对现有字典的过滤筛选工具。
9、medusa
密码**分为在线**和离线**两种。所谓在线**,就是使用不同的账号密码重复向目标服务器提交身份验证请求,然后根据服务器的反馈信息判断登陆是否成功。medusa是开源世界在线密码**工具中的又一王者(与hydra齐名),它支持常见的所有协议类型,同时超高的稳定性是其最大的优势,是密码**领域的必备工具。
10、cmospwd
计算机开机后运行的第一个程序是POST,即加电自检程序。其检测到的硬件参数和使用者的设置参数都存储于cmos内存芯片中,这些配置参数中也包括cmos密码。在你不小心忘记了密码而无法修改硬件参数时,我们可以使用debug命令或comspwd工具清空或找回密cmos密码,其中cmospwd工具兼容众多Bios生产厂商的产品,同时对某些品牌机的BIOS还有自动解锁的功能,是一个优秀的跨平台解密工具。
11、 gpp-decrypt
从windows server 2008开始,微软为其活动目录域新增加了20多项组策略首选项(gpp)设置,其中包括通过GPO统一修改客户端账号密码的功能。出于安全的考略,微软使用了强**的AES算法来加密下发的密码,但乌龙事件使得微软在其开发者网站上直接公布了该**,因此使得安全目标完全破灭。gpp-decrypt既是一个基于泄漏**,对加密密码进行解密还原的工具。
12、dbpwaudit
dbpwaudit是一个由java语言编写的数据库在线密码**工具,它只支持MSSQL、mysql、DB2、Oracle等四种数据库类型。直到授课前我才发现,最新版的Kali Linux中已经不再包含此工具,因此现在我们必须手动下载才能使用这款工具。在审计不同数据库时,我们还需要单独下载相应数据库的JDBC驱动,才能使其正常工作。
13、 crowbar
crowbar是一个在线的密码**工具,与同为密码**工具的hydra、medusa相比,crowbar支持的协议类型十分有限(只有四种),但却个性十足。crowbar支持的认证**方式可以很好的弥补hydra、medusa的不足,它支持Openv*n以及基于**方式身份认证的SSH、VNC服务,可作为其他强大密码**工具的重要补充。
14、brutespray
渗透测试初期,我们总是会通过nmap进行主机发现、端口发现、服务发现等几个步骤,来确认可进行密码**的服务类型,然后再放出hydra、medusa等工具来实施**。过程中如果相关端口数量众多的话,我们就不得不笨拙的一个一个进行输入。brutespray可以自动读取和解析nmap的扫描报告,并从中识别出可进行密码**的服务类型,让后再自动调用medusa实施**,这将大大提高我们的工作效率。
15、polenum
为了保护信息安全,企业网络通常会制定密码策略,强制要求员工设置足够安全的系统账号密码。但人永远都是安全中最薄弱的环节,由于人性中与生俱来怕麻烦和懒惰等特性,大家总是趋向于给自己设置简单的弱口令。作为企业中的安全和审计人员,有责任发现并纠正密码策略失效的情况,polenum是一个正向的安全检查工具,它能够帮助我们高效快捷的进行操作系统的密码策略审计。
16、rsmangler
与通过挖掘漏洞来进行渗透相比,通过密码**来渗透目标的技术门槛相对较低,而且一旦成功其渗透行为也更加隐秘,因此密码**成为了渗透过程中不可缺少的重要步骤。密码**的成功关键在于密码字典的命中率,基于大多数人构造密码的习惯(姓名-生日-爱好等),rsmangler可以基于有限的个人信息,变形生成数量巨大的针对性专属密码字典,从而大大提高密码**的成功率。
17、 cachedump / lsadump
creddump工具集中包含了三个关于windows系统密码的**工具。cachedump针对域账号在本地计算机中的缓存身分验证信息,它可以还原这些缓存的认证信息,并结合其他离线**工具进行密码**。运气好的话,你可能会得到域管理员的密码!!lsadump则可以直接还原那些由操作系统记住的密码,比如登陆网络驱动器的密码、v*n密码、拨号密码、系统自动登陆密码等,由于可以还原出明文密码,因此lsadump被视为安全从业人员的必备工具。
18、pack
如果你认为自己学会了几个密码**软件,就可以自称专业人士的话,那只能说明你还是个小白。众所周知,根据目前计算机的运算能力,实现全键盘空间字符的密码**是不可能的。但如果能准确的分析密码构成规则,则完全可以在可接受的时间范围内,完成半数以上的密码**。Pack全称是密码分析**工具包,他通过分析已有字典的密码构成规则,使我们可以在最短的时间里最大限度的完成**密码。这是你成为密码**专业人士的必备一课。
19、ophcrack
众所周知,windows系统会将用户帐号的密码,经过单向加密之后保存在用户帐号数据库中。但由于加密算法公开通用,因此明文密码加密之后的密永远不变,这直接导致了密码碰撞**思路的产生,即攻击者先计算出全部明文对应的密文,再通过比对密文来**明文。ophcrack是一个基于彩虹表的windows密码**工具,同时其官网提供了大量现成的彩虹表下载,从而大大提高了密码的**效率。
20、 rainbowcrack
虽然单向加密算法通常被认为是不可能被**的,但黑客却找到了碰撞**的思路。即先计算出全部明文对应的密文,然后再通过比对密文来倒推明文的方式。在碰撞**的过程中计算明文对应密文的过程最耗时,因此有人提出了彩虹表的概念,将明文加密后对应的密文结果保存下来,以便日后重复使用,即彩虹表。rainbowcrack内含一套彩虹表的生成、优化、**工具,并支持众多加密算法,更可利用GPU提高运算速度。
21、 ncrack
ncrack是由nmap项目共同维护的在线密码**工具,因此其命令格式和参数的用法都与nmap命令非常相似,这无疑会大大降低新用户的学习成本,同时其模块化的架构使其可以满足更多应用场景的需求。虽然其名气并不很大,但从密码**能力方面来看,ncrack毫不逊色于同类的hydra、medusa等著名在线密码**工具,而且在速度和稳定性方面还有更加优异的表现。
22、maskprocessor
众所周知,根据目前计算机的运算能力,要实现全键盘空间字符的密码**是不可能实现的。因此更多情况下,我们都会采用基于字典的密码**方式,而此时字典的命中率则成为密码**成败的关键。为了构成命中率更高、更有针对性的密码字典,maskprocessor给我们提供了众多的规则选择,是我们自定义密码字典的首选利器。
23、sucrack
通常渗透测试者在通过应用程序漏洞获得系统shell之后,会发现自己拥有的只是普通用户帐号的权限,因此需要进一步的提权操作,将自己提升为root权限。su是所有linux系统都支持的用户切换命令,而切换过程中需要提供目标帐号的密码,因此我们可以利用此功能,使用不同的密码重复向系统进行身份验证,以此来实现密码的暴力**,sucrack即是自动实现这一过程的首选工具。
24、thc-pptp-bruter
为防止内部系统暴露在公网之上,很多公司会采用v*n的解决方式,而微软的MSChapV2则是v*n最广泛被采用的身份验证方法。不幸的是,微软系统的早期版本在实现身份验证的过程中存在漏洞,微软虽然为此发布了补丁,但并未彻底修复该漏洞,使得所有采用该身份验证方式的v*n都会遭受到密码的暴力**攻击。thc-pptp-bruter即是利用此漏洞,专门针对PPTP v*n进行密码**的工具之一。
24、patator
虽然hydra、medusa、ncrack等工具都是优秀的在线密码**工具,但仍然无法满足所有场景的**需求,因此在厌倦了以上所有工具之后,作者开发了patator。这是一款高度定制化的密码**工具,使用者可以按照当前实际场景,灵活定义**成功与否的判断依据,但也同时使其学习成本明显高于其他工具。同时patator还包涵部分在线枚举和离线密码**功能,使其成为一个综合型的密码**工具。
25、 hashcat
如果上天只允许我选择一个离线密码**工具的话,那么我的选择一定是hashcat。hashcat不但开源免费,而且它还是世界上速度最快的离线密码**工具。它提供多系统、多算法、多硬件平台、分布式等几乎全特性的功能支持,同时还支持OpenCL、CUDA等编程标准。目前hashcat已经实现了所有版本的合并统一,使得初学者无需再迷茫的寻找适合自己的软件版本,现在hashcat会自动检测你的CPU和GPU,从而最大限度的发挥你的计算能力。
26、sipcrack
利用廉价共享带宽的IP网络承载实时语音通话的技术称为VoIP,SIP则是目前使用最广且接受度最高的VoIP信令协议。SIP是一种基于文本的信号控制协议,主要负责在客户端与服务期(PBX)间进行身份认证、会话建立和会话管理等工作。如果攻击者可以嗅探身份认证的通信过程,则可以利用sipcrack基于字典**其中的加密摘要信息。
27、oclGaussCrack
2009年震网病毒的出现,标志着***背景的武器化攻击程序已经走入现实。随后出现的火焰病毒再次证明,网络空间的战争其实每天都在我们身边悄悄的进行。2011年出现的高斯病毒使用了与震网、火焰病毒相同的基础代码、软件建构以及与CC服务器的通信方式,种种迹象表明它们全部出自同一开发队伍。由于采用了高级加密方式,最初高斯病毒的payload无法解密,直到ocalgausscrack工具的出现。
28、mimikatz
最近安全社区的一篇文章评出了黑客最经常使用的5个工具,其中就包括本课的mimikatz,此工具堪称windows系统凭据收集领域的瑞士军刀,即在统一框架下集成了众多身材小巧且功能强大的工具集合。凭据包括账号密码、HASH、证书、令牌、cookie等众多类型的信息,一旦获取将可能完全控制目标系统。但由于该工具涉及过多的背景知识,因此几乎没有人能发挥其全部功能(一般只用两条命令),本课我竭尽所能向大家展示这个神一样的存在。
29、 PtH / WCE / xfreerdp
密码**是个耗时耗资源的事情,如果可以不必忍受这个煎熬的过程,相信每个渗透测试者都会兴奋不已。在密码**领域有一种称为Pass the Hash的攻击思路,即在已经获得密码密文的情况下,并不进行**,而是直接提交密文从而实现身份认证。其最典型的应用场景就是攻击Windows操作系统,windows早期版本的密码加密过程不加盐,因此很容易遭受PtH攻击。本课为大家介绍的PtH工具包共包含10个具体工具,分别适合在不同需求环境下使用。
30、Statsprocessor / hcstatgen
依靠现代计算机的运算能力,并不足以在可接受的时间范围内完成全键盘字符空间的密码**任务,这正是现代密码学仍然可以提供安全性的前提,因此纯暴力的密码**是不现实的,同样也使得基于密码字典的**方式成为普遍的选择。如何减小字典的体积,同时提高命中率是所有**者的共同目标。本课我重点向大家介绍“马尔科夫链”在密码**领域的实际应用,同时利用本课的两个工具,我们可以轻松生成接近真实的密码字典。
31、 John / Johnny / unshadow
John the Ripper是你必须掌握的一个离线密码**工具,它可以自动识别并解密200多种加密算法和应用。其功能之丰富强大,已经达到了令人震惊的程度,为了降低使用者的难度,John通过配置文件保存大部分常用参数,因此使用者并不会觉得太过复杂。它支持4种**模式,可以满足所有用户和场景的需要,强大的掩码和规则更可对现有密码字典进行丰富的变形,最大程度提高密码**成功率。Johnny是图形化界面的John。 参考技术A polenum 为了保护信息安全,企业网络通常会制定密码策略,强制要求员工设置足够安全的系统账号密码。
通过jdbc获取数据库中的表结构
通过jdbc获取数据库中的表结构 主键 各个表字段类型及应用生成实体类
1、JDBC中通过MetaData来获取具体的表的相关信息。可以查询数据库中的有哪些表,表有哪些字段,字段的属性等等。MetaData中通过一系列getXXX函数,将这些信息存放到ResultSet里面,然后返回给用户。关于MetaData的说明网上也有不少,这里我只是从我自身学习的角度来记录一下简单使用JDBC以及获取数据表相关信息的方法。
DatabaseMetaData dbmd = con.getMetaData(); rs = dbmd.getColumns(con.getCatalog(), schema, tableName, null); rs.getString(DATA_TYPE) // java.sql.Types 的 SQL 类型 rs.getString(COLUMN_SIZE) //列的大小。对于 char 或 date 类型,列的大小是最大字符数,对于 numeric 和 decimal 类型,列的大小就是精度。 rs.getString(DECIMAL_DIGITS) //小数部分的位数
2、下面就是我的JDBC下的获取表信息的代码了。我是以MySQL 5.0作为测试平台的。可以通过下面四个步骤来实现:
//1. JDBC连接MYSQL的代码很标准。 class.forName("com.mysql.jdbc.Driver").newInstance(); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=root&password=123456"); //2. 下面就是获取表的信息。 m_DBMetaData = m_Connection.getMetaData(); ResultSet tableRet = m_DBMetaData.getTables(null, "%",m_TableName,new String[]{"TABLE"}); /*其中"%"就是表示*的意思,也就是任意所有的意思。其中m_TableName就是要获取的数据表的名字,如果想获取所有的表的名字,就可以使用"%"来作为参数了。*/ //3. 提取表的名字。 while(tableRet.next) System.out.println(tableRet.getString("TABLE_NAME")); /*通过getString("TABLE_NAME"),就可以获取表的名字了。 从这里可以看出,前面通过getTables的接口的返回,JDBC是将其所有的结果,保存在一个类似table的内存结构中,而其中TABLE_NAME这个名字的字段就是每个表的名字。*/ //4. 提取表内的字段的名字和类型 String columnName; String columnType; ResultSet colRet = m_DBMetaData.getColumns(null,"%", m_TableName,"%"); while(colRet.next()) { columnName = colRet.getString("COLUMN_NAME"); columnType = colRet.getString("TYPE_NAME"); int datasize = colRet.getInt("COLUMN_SIZE"); int digits = colRet.getInt("DECIMAL_DIGITS"); int nullable = colRet.getInt("NULLABLE"); System.out.println(columnName+" "+columnType+" "+datasize+" "+digits+" "+ nullable); } /*JDBC里面通过getColumns的接口,实现对字段的查询。跟getTables一样,"%"表示所有任意的(字段),而m_TableName就是数据表的名字。 getColumns的返回也是将所有的字段放到一个类似的内存中的表,而COLUMN_NAME就是字段的名字,TYPE_NAME就是数据类型,比如"int","int unsigned"等等,COLUMN_SIZE返回整数,就是字段的长度,比如定义的int(8)的字段,返回就是8,最后NULLABLE,返回1就表示可以是Null,而0就表示Not Null。*/
每个列描述都有以下列: TABLE_CAT String => 表类别(可为 null) TABLE_SCHEM String => 表模式(可为 null) TABLE_NAME String => 表名称 COLUMN_NAME String => 列名称 DATA_TYPE int => 来自 java.sql.Types 的 SQL 类型 TYPE_NAME String => 数据源依赖的类型名称,对于 UDT,该类型名称是完全限定的 COLUMN_SIZE int => 列的大小。 BUFFER_LENGTH 未被使用。 DECIMAL_DIGITS int => 小数部分的位数。对于 DECIMAL_DIGITS 不适用的数据类型,则返回 Null。 NUM_PREC_RADIX int => 基数(通常为 10 或 2) NULLABLE int => 是否允许使用 NULL。 columnNoNulls - 可能不允许使用 NULL 值 columnNullable - 明确允许使用 NULL 值 columnNullableUnknown - 不知道是否可使用 null REMARKS String => 描述列的注释(可为 null) COLUMN_DEF String => 该列的默认值,当值在单引号内时应被解释为一个字符串(可为 null) SQL_DATA_TYPE int => 未使用 SQL_DATETIME_SUB int => 未使用 CHAR_OCTET_LENGTH int => 对于 char 类型,该长度是列中的最大字节数 ORDINAL_POSITION int => 表中的列的索引(从 1 开始) IS_NULLABLE String => ISO 规则用于确定列是否包括 null。 YES --- 如果参数可以包括 NULL NO --- 如果参数不可以包括 NULL 空字符串 --- 如果不知道参数是否可以包括 null SCOPE_CATLOG String => 表的类别,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) SCOPE_SCHEMA String => 表的模式,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) SCOPE_TABLE String => 表名称,它是引用属性的作用域(如果 DATA_TYPE 不是 REF,则为 null) SOURCE_DATA_TYPE short => 不同类型或用户生成 Ref 类型、来自 java.sql.Types 的 SQL 类型的源类型(如果 DATA_TYPE 不是 DISTINCT 或用户生成的 REF,则为 null) IS_AUTOINCREMENT String => 指示此列是否自动增加 YES --- 如果该列自动增加 NO --- 如果该列不自动增加 空字符串 --- 如果不能确定该列是否是自动增加参数 COLUMN_SIZE 列表示给定列的指定列大小。对于数值数据,这是最大精度。对于字符数据,这是字符长度。对于日期时间数据类型,这是 String 表示形式的字符长度(假定允许的最大小数秒组件的精度)。对于二进制数据,这是字节长度。对于 ROWID 数据类型,这是字节长度。对于列大小不适用的数据类型,则返回 Null。 参数: catalog - 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围 schemaPattern - 模式名称的模式;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围 tableNamePattern - 表名称模式;它必须与存储在数据库中的表名称匹配 columnNamePattern - 列名称模式;它必须与存储在数据库中的列名称匹配
3、获取所有表
String catalog = conn.getCatalog(); //catalog 其实也就是数据库名 ResultSet tablesResultSet = dbMetaData.getTables(catalog,null,null,new String[]{"TABLE"}); while(tablesResultSet.next()){ String tableName = tablesResultSet.getString("TABLE_NAME"); }
tablesResultSet 中有以下列:
TABLE_CAT String => 表类别(可为 null) TABLE_SCHEM String => 表模式(可为 null) TABLE_NAME String => 表名称 TABLE_TYPE String => 表类型。典型的类型是 "TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。 REMARKS String => 表的解释性注释 TYPE_CAT String => 类型的类别(可为 null) TYPE_SCHEM String => 类型模式(可为 null) TYPE_NAME String => 类型名称(可为 null) SELF_REFERENCING_COL_NAME String => 有类型表的指定 "identifier" 列的名称(可为 null) REF_GENERATION String => 指定在 SELF_REFERENCING_COL_NAME 中创建值的方式。这些值为 "SYSTEM"、"USER" 和 "DERIVED"。(可能为 null)
4、某个表的主键
String tableName = ...; ResultSet primaryKeyResultSet = dbMetaData.getPrimaryKeys(catalog,null,tableName); while(primaryKeyResultSet.next()){ String primaryKeyColumnName = primaryKeyResultSet.getString("COLUMN_NAME"); }
primayKeyResultSet 有以下几列: TABLE_CAT String => 表类别(可为 null) TABLE_SCHEM String => 表模式(可为 null) TABLE_NAME String => 表名称 COLUMN_NAME String => 列名称 KEY_SEQ short => 主键中的序列号(值 1 表示主键中的第一列,值 2 表示主键中的第二列)。 PK_NAME String => 主键的名称(可为 null)
5、某个表的外键
ResultSet foreignKeyResultSet = dbMetaData.getImportedKeys(catalog,null,tableName); while(foreignKeyResultSet.next()){ String fkColumnName = foreignKeyResultSet.getString("FKCOLUMN_NAM"); String pkTablenName = foreignKeyResultSet.getString("PKTABLE_NAME"); String pkColumnName = foreignKeyResultSet.getString("PKCOLUMN_NAME"); }
foreignKeyResultSet 有以下几列: PKTABLE_CAT String => 被导入的主键表类别(可为 null) PKTABLE_SCHEM String => 被导入的主键表模式(可为 null) PKTABLE_NAME String => 被导入的主键表名称 PKCOLUMN_NAME String => 被导入的主键列名称 FKTABLE_CAT String => 外键表类别(可为 null) FKTABLE_SCHEM String => 外键表模式(可为 null) FKTABLE_NAME String => 外键表名称 FKCOLUMN_NAME String => 外键列名称 KEY_SEQ short => 外键中的序列号(值 1 表示外键中的第一列,值 2 表示外键中的第二列) UPDATE_RULE short => 更新主键时外键发生的变化 DELETE_RULE short => 删除主键时外键发生的变化 PK_NAME String => 主键的名称(可为 null) FK_NAME String => 外键的名称(可为 null) DEFERRABILITY short => 是否可以将对外键约束的评估延迟到提交时间
6、应用:
大多数数据库有许多主键,但是在一个表中不允许两条记录的同一个主键具有相同的值。可以使用Java Database Connectivity(JDBC)来判断一个数据表的主键。 JDBC具有强大的元数据处理能力。java.sql.Connection类和java.sql.ResultSet类可以通过调用其getMetaData方法进行反射。可以通过下面两个方法:
//这两个方法都可以获取主外键信息,只是参照物不同 metaData.getExportedKeys("数据库名称", "schema", "表名"); metaData.getImportedKeys(catalog, null, tablename);
//Sql Server private static String url = "jdbc:sqlserver://192.168.1.220:1433;User=admin;Password=123456;DatabaseName=Person";
package cn.test; import java.io.File; import java.io.FileOutputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.ResultSet; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; public class TestAll { private static String path = "D:\\\\tool\\\\project\\\\DynamicTable\\\\src\\\\cn\\\\test\\\\entity"; private static String pkname = "com.mysql.jdbc.Driver"; private static String url = "jdbc:mysql://192.168.1.220:3306/Person"; private static String[] classNames = new String[] { "ShipStopping", "ArriveShip", "TBLUserType" }; private static Map<String, String> fkTableNamesAndPk = new HashMap<String, String>(); public static void main(String[] args) { test(); } public static void test() { Connection conn = null; DatabaseMetaData metaData = null; ResultSet rs = null; ResultSet crs = null; try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); conn = DriverManager.getConnection(url, "admin", "123"); String catalog = conn.getCatalog(); // catalog 其实也就是数据库名 metaData = conn.getMetaData(); File dirFile = new File(path); if (!dirFile.exists()) { dirFile.mkdirs(); } // 获取表 rs = metaData.getTables(null, "%", "%", new String[] { "TABLE" }); while (rs.next()) { String tablename = rs.getString("TABLE_NAME"); String classname = getClassNameByTableName(tablename); StringBuffer sb = new StringBuffer(); StringBuffer sbpackage = new StringBuffer(); sbpackage.append("package cn.test.entity;\\r\\n\\r\\n"); sbpackage.append("import javax.persistence.Column;\\r\\n"); sbpackage.append("import javax.persistence.Entity;\\r\\n"); sbpackage.append("import javax.persistence.GeneratedValue;\\r\\n"); sbpackage.append("import javax.persistence.Id;\\r\\n"); sbpackage.append("import javax.persistence.Table;\\r\\n\\r\\n"); sb.append("\\r\\n@Entity\\r\\n"); sb.append("@Table(name = \\"" + tablename + "\\")\\r\\n"); sb.append("public class " + classname + " implements java.io.Serializable {\\r\\n"); // 获取当前表的列 crs = metaData.getColumns(null, "%", tablename, "%"); // 获取被引用的表,它的主键就是当前表的外键 fkTableNamesAndPk.clear(); ResultSet foreignKeyResultSet = metaData.getImportedKeys(catalog, null, tablename); while (foreignKeyResultSet.next()) { String pkTablenName = foreignKeyResultSet.getString("PKTABLE_NAME"); // 外键表 String fkColumnName = foreignKeyResultSet.getString("FKCOLUMN_NAME"); // 外键 if (!fkTableNamesAndPk.containsKey(fkColumnName)) fkTableNamesAndPk.put(fkColumnName, pkTablenName); } // foreignKeyResultSet.close(); while (crs.next()) { String columnname = crs.getString("COLUMN_NAME"); String columntype = crs.getString("TYPE_NAME"); System.out.println("--------------------------"+ columntype); if (existFKColumn(columnname)) { String fkclassname = getClassNameByTableName(fkTableNamesAndPk.get(columnname)); sbpackage.append("import " + pkname + "." + fkclassname+ ";\\r\\n"); sb.append("\\t/** */\\r\\n"); sb.append("\\tprivate " + fkclassname + " " + columnname+ ";\\r\\n"); } else { sb.append("\\t/** */\\r\\n"); sb.append("\\tprivate "+ getFieldType(columntype, sbpackage) + " "+ columnname + ";\\r\\n"); } } sb.append("}"); File file = new File(dirFile, classname + ".java"); if (file.exists()) { file.delete(); } getTitle(sbpackage, classname); FileOutputStream outputStream = new FileOutputStream(file); outputStream.write(sbpackage.toString().getBytes()); outputStream.write(sb.toString().getBytes()); outputStream.close(); System.out.println(classname + " create success ... "); } } catch (Exception e) { e.printStackTrace(System.out); } finally { try { if (null != rs) { rs.close(); } if (null != conn) { conn.close(); } } catch (Exception e2) { } } } /** * 根据表名获取类名称 * * @param tablename * @return */ private static String getClassNameByTableName(String tablename) { String classname = getClassName(tablename); for (String name : classNames) { if (name.toLowerCase().equals(tablename.toLowerCase())) { classname = name; } } return classname; } private static boolean existFKColumn(String columnname) { if (fkTableNamesAndPk != null) { if (fkTableNamesAndPk.containsKey(columnname)) return true; } return false; } /** * 适合表名为单个单词, 例如:表名是TBLUSER 类名是TBLUser;当表名是USER 类名是User;当表面是USERTYPE(两个单词) * 时,类名是Usertype,如果要 UserType,将期望的类名添加到classNames字段中(与数据库表名一致 不区分大小写)。 * * @param tablename * @return */ public static String getClassName(String tablename) { String res = tablename.toLowerCase(); if (tablename.startsWith("TBL")) { return tablename.substring(0, 4) + res.substring(4); } return tablename.substring(0, 1).toUpperCase() + res.substring(1); } /** * 设置字段类型 MySql数据类型 * * @param columnType * 列类型字符串 * @param sbpackage * 封装包信息 * @return */ public static String getFieldType(String columnType, StringBuffer sbpackage) { /* * tinyblob tinyblob byte[] tinytext varchar java.lang.string blob blob byte[] text varchar java.lang.string mediumblob mediumblob byte[] mediumtext varchar java.lang.string longblob longblob byte[] longtext varchar java.lang.string enum(\'value1\',\'value2\',...) char java.lang.string set(\'value1\',\'value2\',...) char java.lang.string */ columnType = columnType.toLowerCase(); if (columnType.equals("varchar") || columnType.equals("nvarchar") || columnType.equals("char") // || columnType.equals("tinytext") // || columnType.equals("text") // || columnType.equals("mediumtext") // || columnType.equals("longtext") ) { return "String"; } else if (columnType.equals("tinyblob") ||columnType.equals("blob") ||columnType.equals("mediumblob") ||columnType.equals("longblob")) { return "byte[]1111"; } else if (columnType.equals("datetime") ||columnType.equals("date") ||columnType.equals("timestamp") ||columnType.equals("time") ||columnType.equals("year")) { sbpackage.append("import java.util.Date;\\r\\n"); return "Date"; } else if (columnType.equals("bit") ||columnType.equals("int") ||columnType.equals("tinyint") ||columnType.equals("smallint") // ||columnType.equals("bool") // ||columnType.equals("mediumint") // ||columnType.equals("bigint") ) { return "int"; } else if (columnType.equals("float")) { return "Float"; } else if (columnType.equals("double")) { return "Double"; } else if (columnType.equals("decimal")) { // sbpackage.append("import java.math.BigDecimal;\\r\\n"); // return "BigDecimal"; } return "ErrorType"; } /** * 设置类标题注释 * * @param sbpackage * @param className */ public static void getTitle(StringBuffer sbpackage, String className) { SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日"); sbpackage.append("\\r\\n/**\\r\\n"); sbpackage.append("*\\r\\n"); sbpackage.append("* 标题: " + className + "<br/>\\r\\n"); sbpackage.append("* 说明: <br/>\\r\\n"); sbpackage.append("*\\r\\n"); sbpackage.append("* 作成信息: DATE: " + format.format(new Date()) + " NAME: author\\r\\n"); sbpackage.append("*\\r\\n"); sbpackage.append("* 修改信息<br/>\\r\\n"); sbpackage.append("* 修改日期 修改者 修改ID 修改内容<br/>\\r\\n"); sbpackage.append("*\\r\\n"); sbpackage.append("*/\\r\\n"); } }
单表实现:
根据查询语句,获取表结构信息。
package cn.test; import java.io.File; import java.io.FileOutputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; public class Test { private static String path="D:\\\\tool\\\\project\\\\DynamicTable\\\\src\\\\cn\\\\test\\\\entity"; private static String url = "jdbc:sqlserver://192.168.1.220:1433;User=cjtc;Password=cjtc;DatabaseName=Person"; public static void main(String[] args) { test(); } public static void test() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; StringBuffer sb=new StringBuffer(); try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); conn = DriverManager.getConnection(url); String sql = "select * from TBLACCOUNT"; ps = conn.prepareStatement(sql); rs = ps.executeQuery(); sb.append("package cn.test.entity;\\r\\n"); sb.append("public class TBLACCOUNT {\\r\\n"); File dirFile = new File(path); if (!dirFile.exists()) { dirFile.mkdirs(); } // 获取列名及类型 int colunmCount = rs.getMetaData().getColumnCount(); String[] colNameArr = new String[colunmCount]; String[] colTypeArr = new String[colunmCount]; for (int i = 0; i < colunmCount; i++) { colNameArr[i] = rs.getMetaData().getColumnName(i + 1); colTypeArr[i] = rs.getMetaData().getColumnTypeName(i + 1); System.out.println(colNameArr[i] + "(" + colTypeArr[i] + ")"+ " | "); if (colTypeArr[i].equals("varchar")||colTypeArr[i].equals("nvarchar")) { sb.append("\\tprivate String "+colNameArr[i]+";\\r\\n"); }else if (colTypeArr[i].equals("datetime")) { } else if (colTypeArr[i].equals("int")) { } } sb.append("}"); File file = new File(dirFile,"TBLACCOUNT.java"); if(file.exists()){ file.delete(); } FileOutputStream outputStream = new FileOutputStream(file); outputStream.write(sb.toString().getBytes()); outputStream.close(); System.out.println(" success ... "); } catch (Exception e) { e.printStackTrace(System.out); } finally { try { if (null != rs) { rs.close(); } if (null != ps) { ps.close(); } if (null != conn) { conn.close(); } } catch (Exception e2) { } } } }
以上是关于polenum,可以获取哪些信息的主要内容,如果未能解决你的问题,请参考以下文章