paramiko

paramiko模块,基于SSH用于连接远程服务器并执行相关操作。

基本用法

SSHClient

基于用户名密码连接:

基础用法:

import paramiko

# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', password='123') # 执行命令
stdin, stdout, stderr = ssh.exec_command('ls')
# 获取命令结果
result = stdout.read() # 关闭连接
ssh.close()

SSHClient 封装 Transport

import paramiko

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', password='123') ssh = paramiko.SSHClient()
ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df')
print stdout.read() transport.close()

由此我们可以看出来,ssh执行命令时,我们可以使用sshclient transport两种方式来实现

基于公钥密钥连接:

基础用法:

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key) # 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read() # 关闭连接
ssh.close()

封装transport:

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key) ssh = paramiko.SSHClient()
ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df') transport.close()

SFTPClient

用于连接远程服务器并执行上传下载

基于用户名密码上传下载:

import paramiko

transport = paramiko.Transport(('hostname',22))
transport.connect(username='wupeiqi',password='123') sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path') transport.close()

基于公钥密钥上传下载:

import paramiko

private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')

transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key ) sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('/tmp/location.py', '/tmp/test.py')
# 将remove_path 下载到本地 local_path
sftp.get('remove_path', 'local_path') transport.close()

有此看出,如果只做上传下载方式的话,我们只能使用transport,其实无论是ssh,还是sftp,都是调用了transport,基于socket实现的

生产需求:上传某文件并覆盖

demo:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid class SSHConnection(object): def __init__(self, host='172.16.103.191', port=22, username='wupeiqi',pwd='123'):
self.host = host
self.port = port
self.username = username
self.pwd = pwd
self.__k = None def create_file(self):
file_name = str(uuid.uuid4())
with open(file_name,'w') as f:
f.write('sb')
return file_name def run(self):
self.connect()
self.upload('/home/wupeiqi/tttttttttttt.py')
self.rename('/home/wupeiqi/tttttttttttt.py', '/home/wupeiqi/ooooooooo.py)
self.close() def connect(self):
transport = paramiko.Transport((self.host,self.port))
transport.connect(username=self.username,password=self.pwd)
self.__transport = transport def close(self): self.__transport.close() def upload(self,target_path):
# 连接,上传
file_name = self.create_file() sftp = paramiko.SFTPClient.from_transport(self.__transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(file_name, target_path) def rename(self, old_path, new_path): ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
cmd = "mv %s %s" % (old_path, new_path,)
stdin, stdout, stderr = ssh.exec_command(cmd)
# 获取命令结果
result = stdout.read() def cmd(self, command):
ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
stdin, stdout, stderr = ssh.exec_command(command)
# 获取命令结果
result = stdout.read()
return result ha = SSHConnection()
ha.run()

对于更多限制命令,需要在系统中设置:

位置:/etc/sudoers,代码:

Defaults    requiretty
Defaults:cmdb !requiretty

堡垒机

执行流程:

  1. 管理员为用户在服务器上创建账号(将公钥放置服务器,或者使用用户名密码)
  2. 用户登陆堡垒机,输入堡垒机用户名密码,现实当前用户管理的服务器列表
  3. 用户选择服务器,并自动登陆
  4. 执行操作并同时将用户操作记录

需要注意的是,如果想实现用户登录后直接操作,需要配置下堡垒机用户家目录的.bashrc文件:

/usr/bin/env python $PATH/s7.py
logout

将这两行假如即可.

看下实现方式:

简单调用:

import paramiko
import sys
import os
import socket
import select
import getpass tran = paramiko.Transport(('192.168.4.193', 22,))
tran.start_client()
tran.auth_password('root', '7ujm8ik,') # 打开一个通道
chan = tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell() #########
# 利用sys.stdin,肆意妄为执行操作
# 用户在终端输入内容,并将内容发送至远程服务器
# 远程服务器执行命令,并将结果返回
# 用户终端显示内容
#########

交互操作(无tab)

import paramiko
import sys
import os
import socket
import select
import getpass
from paramiko.py3compat import u tran = paramiko.Transport(('10.211.55.4', 22,))
tran.start_client()
tran.auth_password('wupeiqi', '123') # 打开一个通道
chan = tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell() while True:
# 监视用户输入和服务器返回数据
# sys.stdin 处理用户输入
# chan 是之前创建的通道,用于接收服务器返回信息
readable, writeable, error = select.select([chan, sys.stdin, ],[],[],1)
if chan in readable:
try:
x = u(chan.recv(1024))
if len(x) == 0:
print('\r\n*** EOF\r\n')
break
sys.stdout.write(x)
sys.stdout.flush()
except socket.timeout:
pass
if sys.stdin in readable:
inp = sys.stdin.readline()
chan.sendall(inp) chan.close()
tran.close()

但此次我们会发现,没有tab补全,跟我们真是在shell里执行命令还是略有差距的,那么来第二个.

交互操作(有tab功能)

#!/usr/bin/env python
# -*-coding=utf-8-*-
# Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/
# GitHub:https://github.com/ccorzorz import paramiko
import sys
import os
import socket
import select
import getpass
import termios
import tty
from paramiko.py3compat import u tran = paramiko.Transport(('192.168.4.193', 22,))
tran.start_client()
tran.auth_password('root', '7ujm8ik,') # 打开一个通道
chan = tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell() # 获取原tty属性
oldtty = termios.tcgetattr(sys.stdin)
try:
# 为tty设置新属性
# 默认当前tty设备属性:
# 输入一行回车,执行
# CTRL+C 进程退出,遇到特殊字符,特殊处理。 # 这是为原始模式,不认识所有特殊符号
# 放置特殊字符应用在当前终端,如此设置,将所有的用户输入均发送到远程服务器
tty.setraw(sys.stdin.fileno())
chan.settimeout(0.0) while True:
# 监视 用户输入 和 远程服务器返回数据(socket)
# 阻塞,直到句柄可读
r, w, e = select.select([chan, sys.stdin], [], [], 1)
if chan in r:
try:
x = u(chan.recv(1024))
if len(x) == 0:
print('\r\n*** EOF\r\n')
break
sys.stdout.write(x)
sys.stdout.flush()
except socket.timeout:
pass
if sys.stdin in r:
x = sys.stdin.read(1)
if len(x) == 0:
break
chan.send(x) finally:
# 重新设置终端属性,必须设置,否则再次登录后无法使用
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) chan.close()
tran.close()

生产需求

在生产中,我们还需要更多的需求:

  1. 有日志记录,我们可以把管理员的每一条记录都记录到数据库中
  2. tab补全时,记录的中间会有空格之类的需要处理

我们来看下怎么实现:

import paramiko
import sys
import os
import socket
import getpass # from paramiko.py3compat import u # windows does not have termios...
try:
import termios
import tty
has_termios = True
except ImportError:
has_termios = False def interactive_shell(chan):
if has_termios:
posix_shell(chan)
else:
windows_shell(chan) def posix_shell(chan):
import select oldtty = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
chan.settimeout(0.0)
f = open('handle.log','a+')
tab_flag = False
temp_list = []
while True:
r, w, e = select.select([chan, sys.stdin], [], [])
if chan in r:
try:
x = chan.recv(1024)
if len(x) == 0:
sys.stdout.write('\r\n*** EOF\r\n')
break
if tab_flag:
if x.startswith('\r\n'):
pass
else:
f.write(x)
f.flush()
tab_flag = False
sys.stdout.write(x)
sys.stdout.flush()
except socket.timeout:
pass
if sys.stdin in r:
x = sys.stdin.read(1)
if len(x) == 0:
break
if x == '\t':
tab_flag = True
else:
f.write(x)
f.flush()
chan.send(x) finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) def windows_shell(chan):
import threading sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") def writeall(sock):
while True:
data = sock.recv(256)
if not data:
sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
sys.stdout.flush()
break
sys.stdout.write(data)
sys.stdout.flush() writer = threading.Thread(target=writeall, args=(chan,))
writer.start() try:
while True:
d = sys.stdin.read(1)
if not d:
break
chan.send(d)
except EOFError:
# user hit ^Z or F6
pass def run():
# 获取当前登录用户
""" host_list = [
{'host': "192.168.11.139", 'username': 'oldboy', 'pwd': "123"},
{'host': "192.168.11.138", 'username': 'oldboy', 'pwd': "123"},
{'host': "192.168.11.137", 'username': 'oldboy', 'pwd': "123"},
]
for item in enumerate(host_list, 1):
print(item['host']) num = raw_input('序号:')
sel_host = host_list[int(num) -1]
hostname = sel_host['host']
username = sel_host['username']
pwd = sel_host['pwd']
print(hostname,username,pwd)
""" tran = paramiko.Transport((hostname, 22,))
tran.start_client()
tran.auth_password(username, pwd)
# 打开一个通道
chan = tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell() interactive_shell(chan) chan.close()
tran.close() if __name__ == '__main__':
run()

银角究极版

珍藏下吧:

import paramiko
import sys
import os
import socket
import getpass from paramiko.py3compat import u # windows does not have termios...
try:
import termios
import tty
has_termios = True
except ImportError:
has_termios = False def interactive_shell(chan):
if has_termios:
posix_shell(chan)
else:
windows_shell(chan) def posix_shell(chan):
import select oldtty = termios.tcgetattr(sys.stdin)
try:
tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno())
chan.settimeout(0.0)
log = open('handle.log', 'a+', encoding='utf-8')
flag = False
temp_list = []
while True:
r, w, e = select.select([chan, sys.stdin], [], [])
if chan in r:
try:
x = u(chan.recv(1024))
if len(x) == 0:
sys.stdout.write('\r\n*** EOF\r\n')
break
if flag:
if x.startswith('\r\n'):
pass
else:
temp_list.append(x)
flag = False
sys.stdout.write(x)
sys.stdout.flush()
except socket.timeout:
pass
if sys.stdin in r:
x = sys.stdin.read(1)
import json if len(x) == 0:
break if x == '\t':
flag = True
else:
temp_list.append(x)
if x == '\r':
log.write(''.join(temp_list))
log.flush()
temp_list.clear()
chan.send(x) finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) def windows_shell(chan):
import threading sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") def writeall(sock):
while True:
data = sock.recv(256)
if not data:
sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
sys.stdout.flush()
break
sys.stdout.write(data)
sys.stdout.flush() writer = threading.Thread(target=writeall, args=(chan,))
writer.start() try:
while True:
d = sys.stdin.read(1)
if not d:
break
chan.send(d)
except EOFError:
# user hit ^Z or F6
pass def run():
default_username = getpass.getuser()
username = input('Username [%s]: ' % default_username)
if len(username) == 0:
username = default_username hostname = input('Hostname: ')
if len(hostname) == 0:
print('*** Hostname required.')
sys.exit(1) tran = paramiko.Transport((hostname, 22,))
tran.start_client() default_auth = "p"
auth = input('Auth by (p)assword or (r)sa key[%s] ' % default_auth)
if len(auth) == 0:
auth = default_auth if auth == 'r':
default_path = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
path = input('RSA key [%s]: ' % default_path)
if len(path) == 0:
path = default_path
try:
key = paramiko.RSAKey.from_private_key_file(path)
except paramiko.PasswordRequiredException:
password = getpass.getpass('RSA key password: ')
key = paramiko.RSAKey.from_private_key_file(path, password)
tran.auth_publickey(username, key)
else:
pw = getpass.getpass('Password for %s@%s: ' % (username, hostname))
tran.auth_password(username, pw) # 打开一个通道
chan = tran.open_session()
# 获取一个终端
chan.get_pty()
# 激活器
chan.invoke_shell() interactive_shell(chan) chan.close()
tran.close() if __name__ == '__main__':
run()

数据库模型

其实堡垒机的难点是在数据库的设计上

#!/usr/bin/env python
# -*-coding=utf-8-*-
# Auther:ccorz Mail:ccniubi@163.com Blog:http://www.cnblogs.com/ccorz/
# GitHub:https://github.com/ccorzorz from sqlalchemy import create_engine, and_, or_, func, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, DateTime
from sqlalchemy.orm import sessionmaker, relationship engine = create_engine("mysql+pymysql://root:7ujm8ik,@192.168.4.193:3306/test13", max_overflow=5)
Base = declarative_base() # 生成一个SqlORM 基类 class UserProfile2HostUser(Base):
__tablename__ = 'userprofile_2_hostuser'
id = Column(Integer, primary_key=True, autoincrement=True)
userprofile_id = Column(Integer, ForeignKey('user_profile.id'),primary_key=True)
hostuser_id = Column(Integer, ForeignKey('host_user.id'),primary_key=True)
# userprofile = relationship('UserProfile',secondary=lambda :) class Host(Base):
__tablename__ = 'host'
id = Column(Integer, primary_key=True, autoincrement=True)
hostname = Column(String(64), unique=True, nullable=False)
ip_addr = Column(String(128), unique=True, nullable=False)
port = Column(Integer, default=22) class HostUser(Base):
__tablename__ = 'host_user'
id = Column(Integer, primary_key=True, autoincrement=True)
AuthTypes = [
(u'ssh-passwd', u'SSH/Password'),
(u'ssh-key', u'SSH/KEY'),
]
auth_type = Column(String(64))
username = Column(String(64), nullable=False)
password = Column(String(255))
host_id = Column(Integer, ForeignKey('host.id'))
host = relationship('Host', backref='uu')
__table_args__ = (UniqueConstraint(u'host_id', u'username', name='_host_username_uc'),) class Group(Base):
__tablename__ = 'group'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(64), unique=True, nullable=False) #
# obj = session.query(HostUser.username,HostUser.password,Host.hostname,Host.port).join(Host).filter(HostUser.id == 1).first()
# (用户名,密码,主机名,端口) class UserProfile(Base):
__tablename__ = 'user_profile'
id = Column(Integer, primary_key=True)
username = Column(String(64), unique=True, nullable=False)
# 存密码感觉没什么卵用
# password = Column(String(255),nullable=False)
# 如果是一个人只能在一个组下
group_id = Column(Integer, ForeignKey('group.id'))
#需要这么加secondary,否则插入数据时会报错
host_list = relationship('HostUser', secondary=lambda :UserProfile2HostUser.__table__, backref='userprofiles') """
# 输入用户名和密码:
#
obj = session.query(UserProfile).filter(username=输入的用户名, password=输入的密码).first()
if not obj:
# 堡垒机登录用户对象
# 输入这个人的所有机器
obj.host_list # 当前堡垒机登录用户,所有的服务器用户名
#
for item in obj.host_list:
# item,是一个HostUser对象
item.password,item.username,
# item.host 对象,host对象
item.host.hostname,item.host.port
# item 目标机器HostUser对象
host_obj = input(:...)
session.add(AuditLog(userprofile_id=obj.id,hostuser_id = host_obj.id, "ifconfig"))
""" class Log(Base):
__tablename__ = 'log'
id = Column(Integer, primary_key=True)
userprofile_id = Column(Integer, ForeignKey('user_profile.id'))
hostuser_id = Column(Integer, ForeignKey('host_user.id'))
cmd = Column(String(255))
date = Column(DateTime) # class Session:
# session = None
# def __init__(self):
# self.engine = create_engine("mysql+pymysql://root:7ujm8ik,@192.168.4.193:3306/test13", max_overflow=5)
# self.ss = sessionmaker(bind=self.engine)
# self.obj = ss()
# self.Session.session = obj
#
# @classmethod
# def instance(cls):
# if not cls.session:
# cls()
# return cls.session # ss = Session()
# 定义初始化数据库函数
def init_db():
Base.metadata.create_all(engine) # init_db() # 删除数据库函数
def drop_db():
Base.metadata.drop_all(engine) # drop_db() # 实例化数据库操作对象为session
Session = sessionmaker(bind=engine)
ss = Session()
#
# ss.add_all([
# Group(id=1, name='DBA'),
# Group(id=2, name='SA')
# ])
#
# ss.add_all([
# UserProfile(id=1,username='chengc',group_id=2),
# UserProfile(id=2,username='root',group_id=2)
# ])
#
# ss.add_all([
# Host(id=1,hostname='test',ip_addr='192.168.4.193',port=22),
# Host(id=2,hostname='zhongrt1',ip_addr='223.202.101.164',port=43228)
# ])
#
# ss.add_all([
# HostUser(id=1,auth_type='pwd',username='root',password='7ujm8ik,',host_id=1),
# HostUser(id=2,auth_type='pwd',username='root',password='asdf',host_id=2)
# ])
#
# ss.add_all([
# UserProfile2HostUser(userprofile_id=1,hostuser_id=1),
# UserProfile2HostUser(userprofile_id=2,hostuser_id=1)
# ])
# #
# ss.add_all([Group(id=3,name='SB')])
ss.commit()

特别注意:如果使用relationship虚拟关系时,需要添加secondary=类名.table,否则插入数据时会报错!

用paramiko写堡垒机的更多相关文章

  1. (转)用Python写堡垒机项目

    原文:https://blog.csdn.net/ywq935/article/details/78816860 前言 堡垒机是一种运维安全审计系统.主要的功能是对运维人员的运维操作进行审计和权限控制 ...

  2. Paramiko和堡垒机实现

    一.Paramiko paramiko模块,基于SSH用于连接远程服务器并执行相关操作. 1.安装:pip install paramiko 2.SSHClient:用于连接远程服务器并执行基本命令 ...

  3. Python paramiko模块 + 堡垒机

    paremiko SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: import paramiko    # 创建SSH对象 ssh = paramiko.SSHClient ...

  4. paramiko 堡垒机

    用paramiko写堡垒机 paramiko paramiko模块,基于SSH用于连接远程服务器并执行相关操作. 基本用法 SSHClient 基于用户名密码连接: 基础用法: import para ...

  5. 堡垒机前戏——paramiko

    提要:在写堡垒机之前,我们必须要了解paramiko这个第三方库.有关于python的第三方库的安装很简单,可以自行百度. 该模块基于SSH用于连接远程服务器并执行相关操作. SSHClient 用于 ...

  6. Python自动化运维之19、Paramiko模块和堡垒机实战

    paramiko模块 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实 ...

  7. Python----Paramiko模块和堡垒机实战

    paramiko模块 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的paramiko来现实 ...

  8. python2.0 s12 day8 _ 堡垒机前戏paramiko模块

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 paramiko模块是做主机管理的,他模拟了一个ssh. 有两种形式连接形式, ...

  9. 堡垒机(paramiko)

    实现思路 堡垒机执行流程: 管理员为用户在服务器上创建账号(将公钥放置服务器,或者使用用户名密码) 用户登陆堡垒机,输入堡垒机用户名密码,现实当前用户管理的服务器列表 用户选择服务器,并自动登陆 执行 ...

随机推荐

  1. vim下的ctags和taglist等的使用和配置

    1.ctags (1)到 http://prdownloads.sourceforge.net/ctags/ctags-5.6.tar.gz         下载ctags源码ctags-5.6.ta ...

  2. cordova屏幕尺寸

    <platform name="android"> <!-- ldpi : 36x36 px mdpi : 48x48 px hdpi : 72x72 px xh ...

  3. iOS 展示 gif

    gif 图 是多张依次有连续动作的图 顺时间展示的一种动态效果图 .   有的是均匀时间更换下一张  有的 则不是均匀时间变化 1. 那么 对于均匀 时间变化的gif图 比较适合 使用 iOS 系统自 ...

  4. 【leetcode刷题笔记】Best Time to Buy and Sell Stock II

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  5. new的越界访问

    今天敲代码的时候发现了一个BUG和大家分享一下,希望大家下次不要犯和我一样的错误. 如果犯了和我一样的错,也能知道自己错在哪里!   <(^-^)> 函数如下:(斐波那契数列的实现) lo ...

  6. 什么是gitlab CI ?CI代表什么?

    CI是Continuous Integration的简称,就是持续集成的意思. 就是说你代码改动了,测试了,提交了,持续集成系统会自动构建(编译等等).持续集成的理念是每个提交的版本都应该是可交付的, ...

  7. ansible普通用户su切换问题

    在现网应用中,安全加固后的主机是不允许直接以root用户登陆的,而很多命令又需要root用户来执行,在不改造现网的情况下.希望通过一个普通用户先登陆,再su切到root执行.而且每台主机的普通用户和r ...

  8. java深入探究05

    通讯录小程序 需求说明: 功能: 添加联系人 修改联系人 删除联系人 查询所有联系人 要求: console控制 数据保存在xml 1.创建联系人类 /** * 联系人实体对象 * @author A ...

  9. 针对PHP性能方面编程技巧的总结

    注:本文为作者多年工作经验总结,转贴请注明出处 Albert Wang 做PHP已经有4年多了吧,总是没写点什么总结一下,现在开始写博客了,也顺便总结下吧,留给那些新入行的朋友看看. 1. 不宜频繁使 ...

  10. java语法糖---枚举

    java语法糖---枚举   在JDK5.0中提供了大量的语法糖,例如:自动装箱拆箱.增强for循环.枚举.泛型等.所谓“语法糖”就是指提供更便利的语法供程序员使用,只是在编译器上做了手脚,却没有提供 ...