更改 mac 多版本 php 启动方式
1 | brew services list |
1 | brew services restart php |
1 | brew services restart php@5.6 |
生活心情
1 | #方式一: |
virtualenvwrapper是用来管理virtualenv的扩展包,用着很方便。
1 | #安装virtualenv |
修改~/.bash_profile或其它环境变量相关文件(如 .bashrc(我的Ubuntu15.10 下的是这个) 或用 ZSH 之后的 .zshrc),添加以下语句:
1 | #WORKON_HOME,PROJECT_HOME 可以替换成你自己的目录 |
1 | #创建运行环境blog |
1 | #导入 Flask 模块包 |
1 | #使用装饰器来诸恶路由,启动的参数为 URL 的路径,对应的会调用 index() 函数 |
如果直接使用/index
那么不能兼容浏览器不能访问/index/和/index,
解决办法,路径定义改成/index/
1 | @app.route('/index/') |
重定向:当你访问url1的时候,服务器返回状态码302让用户访问url2
访问http://localhost:5000/index
,观察浏览器网络请求情况,可以看到发生了重定向,重定向到了http://localhost:5000/index/
这是因为,如果不做重定向,不带/ 的(index)和带/的(index/)都可以访问到视图函数。
那么就是说同一个视图函数对应着两个不同的路由,没有保证唯一url的原则
如果有两个url,那么在搜索引擎中会被索引两次,
这样会浪费性能,影响搜索引擎的优化,没有这个必要。
1 | #通过调用app的add_url_rule函数 |
1 | def route(self, rule, **options): |
1 | #载入配置文件 |
必须全部是大写
![必须大写!]必须名字一模一样
。if __name__ == "__name__"
加入这个判断以后,只有在启动入口文件以后,才会执行。而在被其他模块导入的时候不会执行
在生产环境中,我们一般是采用 Nginx + uwsgi 来部署我们的 Python 项目,我们使用 uwsgi 来启动项目的 flask 服务的时候,这个时候项目的启动文件(我们这项目文件名为:run.py),只是作为一个模块被调用,这时加上入口判断,在生产环境就就不会执行 app.run()方法,否则就会启动两个 Flask 服务。
1 | # run.py 文件代码 |
在上节我们通过db.create_all(app=app)
的方式解决了working outside application context
的错误,下面我们来深究,这个错误出现的具体原因是什么。
1 | from flask import Flask, current_app |
我们通过current_app
获取配置,看似没有问题的代码,却抛出了同样的异常。
通过断点调试发现current_app
并不是Flask对象,而是一个unbound
的LocalProxy
。
回想我们之前的request
对象,其实也是个LocalProxy
。
1 | # context locals |
那么这里为什么会抛出这个异常呢,想要回答这个问题,就需要深入理解这个LocalProxy
。我们在下一小节进行介绍
Flask
有两个上下文,应用上下文-AppContext
和请求上下文-RequestContext
。他们本质都是对象,是一种封装。应用上下文是对Flask
的封装,请求上下文是对Request
的封装
下面我们来通过源码,了解一下这两个上下文。Flask
源码的全貌,是在External Libraries/site-pacages/flask
下
Flask
是一个非常好的微框架,里面的源码并不多,大部分都是注释,这给我们可以很方便的阅读源码.
我们要看的两个上下文在ctx.py
(context的缩写)中,其中的AppContext
就是应用上下文,RequestContext
就是请求上下文
阅读AppContext
和RequestContext
的构造函数,发现他们都将核心对象app
作为了他们的一个属性
1 | def __init__(self, app): |
并且他们都有相同的四个方法
1 | def push(self): |
为什么需要上下文,我们之间操作Flask
的核心对象app
不可以吗?
这是一个设计思想。有时候呢,我们不光需要这个核心对象app
,还需要他外部的一些东西,这个时候,我们可以把他们统一结合封装到一起,组装成一个新的上下文对象,并且在这个对象之上,可以提供一些新的方法,如我们上面所提到的push
、pop
等
Flask:核心对象,核心对象里承载了各种各样的功能,比如保存配置信息,再比如注册路由试图函数等
AppContext:对Flask的封装,并且增加了一些额外的参数
Request:保存了请求信息,比如url的参数,url的全路径等信息
RequestContext:对Request的封装
我们在实际编码过程中,可能是需要Flask
或者Request
的信息的,但是这并不代表我们应该直接导入这两个对象获取相关信息,
正确的做法是从AppContext
,RequestContext
中间接的获得我们需要的信息
即使这样,我们也没有必要导入Context
去使用上下文,这就回到了current_app
和request
这些LocalProxy
,他们提供了间接操作上下文对象的能力,使用了代理模式
当一个请求进入Flask
框架,首先会实例化一个Request Context
,这个上下文封装了请求的信息在Request
中,并将这个上下文推入到一个栈(_request_ctx_stack/_app_ctx_strack)
的结构中,即之前将的push
方法
RequestContext
在入_request_ctx_stack
之前,首先会检查_app_ctx_strack
是否为空,如果为空,则会把一个AppContext
的对象入栈,然后再将这个请求入栈到_request_ctx_stack
中
我们的current_app
和request
对象都是永远指向_app_ctx_strack/_request_ctx_stack
的栈顶元素,也就是分别指向了两个上下文,如果这两个值是空的,那么LocalProxy
就会出现unbound
的状态
当请求结束的时候,这个请求会出栈-pop
回到我们之前的测试代码,如果要想让我们的测试代码正常运行,就需要手动将一个AppContext入栈。
1 | from flask import Flask, current_app |
注意
虽然current_app
和request
指向的是两个上下文,但是他们返回的却是Flask核心独享和Request
对象。下面来看下这部分的源码
globals.py
1 | # globals.py中实例化LocalProxy获取current_app的代码中,传入了一个_find_app方法 |
从源码中可以看到,他获取的是app核心对象。
我们上一小节通过手动将app推入栈,弹出栈的方式,解决了working outside application context
的问题。实际上更经典的做法是使用with语句来完成。
首先使用with语句替换之前的代码
1 | app = Flask(__name__) |
什么时候可以使用with语句:
1.实现了上下文协议的对象,可以使用with语句
2.对于实现了上下文协议的对象,我们通常称为上下文管理员
3.通过实现enter和exit来实现上下文协议
4.上下文表达式必须返回一个上下文管理器
对于上面一段代码来说,AppContext
就是上下文管理器;app.app_context()
就是上下文表达式。enter中做了push操作,__exit__
中做了pop操作。
所以只要进入with语句,current_app
就是有值的,一旦离开了with语句,current_app
就会弹出,然后就又没有值了(又变成了unbound)。
1 | def __enter__(self): |
通过数据库的链接和释放来理解with语句的具体含义
连接数据库的操作步骤:
如果上面的第二部分出错,那么第三部分的释放资源就不会被执行,资源就会一直被占用。
解决这个问题的通常做法是使用try-except-finally
但是在finally
中更优雅的方式就是使用with
语句中。
我们可以把连接数据库的操作写在上下文管理器的__enter__
方法里面,把业务代码写在with语句的代码块里面,把释放资源的语句写在__exit__
里面。
读写文件的具体例子
一般的写法
1 | try: |
使用with语句的写法:
1 | with open(r'/Users/test.txt') as f: |
注意上面的with语句后面的as 返回的并不是上下文管理器,他实际上是enter方法返回的一个值,
上面一段代码我们在enter中返回了一个a,所以下面as 后的obj_A就是1
exit方法详解
注意我们编写的测试代码,运行时会报错的,错误原因是exit
方法接受的参数数量不够。exit
方法的作用不只是释放资源,还有处理异常,所以exit方法还要多接受exc_type
,exc_value
,tb
三个参数。这三个参数在没有异常发生的时候回传控制,如果有异常的话,这三个参数分别是异常类型,异常消息,和详细的异常堆栈信息
exit
方法还需要返回一个boolean
类型的值,如果返回True
,那么外部就不会抛出异常,如果返回False
,那么还会在外部抛出异常,如果什么都不返回,按照False
处理。Flask
提供了一种非常灵活的方式,可以让我们选择在with语句内部还是外部处理异常
4.6 阅读源码解决db.create_all的问题
对于Flask来说,文档更适合中高级的开发者,而对于新手不是特别友好。所以以不变应万变。我们可以遇到问题的时候,可以通过阅读源码的时候来解决。
下面我们来看下在第三章的时候,为什么我们的flask_sqlalchemy
已经注册了app对象,但是create_all
方法还是需要传入app参数,不传就会报错
首先看一下init_app方法的源码
1 | def init_app(self, app): |
create_app 方法的源码
1 | def _execute_for_all_tables(self, app, bind, operation, skip_tables=False): |
可以看到create_all
方法调用了_execute_for_all_tables
私有方法,_execute_for_all_tables
里面第一行的get_app
方法用来获取一个app
核心对象
1 | def get_app(self, reference_app=None): |
所以通过三个判断,我们可以总结出三个不同的方法来解决我们遇到的问题。
1.在create_all
中传入关键字参数app
。也就是我们之前用过的。
2.向堆栈中推入一条app_context
,使得current_app
不为空。
1 | with app.app_context(): |
3.在初始化flask_sqlalchemy
对象的时候,传入app
参数。
具体选取哪种方式,是根据情况而定的,比如我们当前的情况,就不合适使用第三种方法,因为我们的flask_sqlalchemy
对象是在models
中的book.py
中的,如果用第三种方式,还需要在这里导入app
对象。
图书数据库的基地址
1 | # 基地址 |
截止2018你那9月11日,以上地址已经无法访问,此地址仅为项目演示地址
1 | @app.route("/search/q/<page>") |
isdigit()
in
关键字可以判断一个字符串是否包含在另外一个字符串中1 | @app.route("/search/<q>/<page>") |
1 | def is_isbn_or_key(word): |
helper.py
文件,可以重复利用。其他地方的代码多一点还可以接受,视图函数中不可以,因为视图函数是一个web项目的入口。所有人阅读都是从这里入手,应该把细节屏蔽掉,给阅读者一个选择。
看源码的技巧:先通读整体,了解整体过程,再回过头来了解细节,不要从一开始就深究每一个细节
过多的注释会让代码变的臃肿,尽量使用易懂的函数名来代替注释,保持代码的简洁性
1 | class HTTP: |
if-else
语句的几种方式 if+return
;if-else
里的代码提取成函数if+return
的理解:return
前的if+return
全都理解为正常流程之外的一种特例情况的处理;if-return
,提前结束一些逻辑分支,可以提高代码思维的清晰性 requests
的一些说明:get()
发送get
请求;r.status_code
获取返回状态吗;r.json()
将返回结果序列化成json
;r.text
将返回结果不做处理直接返回 HTTP
请求,获取结果的业务代码封装到`YuShuBook中1 | class YuShuBook: |
json.dumps
序列表返回结果,在视图函数中进行返回,并声明状态码和返回类型(一个元组)1 | @app.route("/book/search/<q>/<page>") |
可以使用
flask
提供的jsonify
替换麻烦的json.dumps
和元组
代码太长,不利于维护
从业务模型抽象的角度,不应该把他们都放在一个文件中。关于书籍相关的API就应该放在书籍模型的视图函数文件中,跟用户相关的API就应该放在用户模型相关的文件中
入口文件的意义比较独特,会启动web服务器以及做很多初始化的操作,就算要放在一个文件也不应该业务的操作放在入口文件中来
将试图函数抽离到单独的包中,然后在新的试图文件中引入flask.py来导入app核心对象。
为了新的试图文件中的路由可以成功注册,再在flask.py中引入刚刚抽离出的试图模块
1 | from flask import Flask |
1 | from flask import jsonify |
但是这样做并不是正确的做法,结果表明,这样修改以后,访问
search api
会404为了知道为什么这样做不行,我们需要先刨铣一下
Flask路由机制
的原理
flask的基本思想是内部会维护一个字典。
每一个
url
都会对应一个视图函数,但是不仅仅是这样。每一个
url
还会对应一个endpoint
端点。用于反向构建URL(后面会讲解)
flask的路由注册
app_url_rule(url=,view_func=,endpoint=)
会接受三个参数,前两个我们都知道了,第三个就是上面说的
endpoint
。他的默认值是view_func
的名称。当然,
app.route('url',endpoint=)
也可以传入
1 | def route(self, rule, **options): |
通过端点调试可以发现,Flask内部由
url_map
维护一个url->endpoint
的指向。由
view_functions
记录endpoint
所指向视图函数的函数,这样请求进入到Flask内部,才能通过
Url
找到对应的视图函数
从上面的断点调试中发现,我们的
url_map
和view_functions
中都已经维护了相关的信息。但是为什么还是会出现404的情况,这是因为
fisher.py
和book.py
出现了循环引入的情况。
下面看下fisher.py
和book.py
的具体流程图
图中有两种颜色的线:红色的线是
fisher
主执行文件被执行之后的执行路径;蓝色的线是book模块被导入之后循环导入的执行路径。
导入book
的语句。然后进入book
模块中执行导入fisher
的语句(循环导入),这个时候主流程暂时结束,重新执行fisher中的代码整个流程中,出现了两次核心app对象的初始化,注册路由是在蓝色流程中初始化的app注册的。
但是启动服务是红色流程中的app启动的
book中注册路由所使用的app对象,是他自己所导入fisher模块的app对象(蓝色流程中),
而不是红色主流程中所实例化的app对象
我们在app实例化,启动,注册路由是哪个地方加入日志信息,来观察一下
1 | print("id为"+str(id(app))+"的app注册路由") |
1 | app = Flask(__name__) |
1 | pydev debugger: process 63816 is connecting |
可以看到注册路由的app,和启动服务的app不是同一个app。
并且最后启动的app是最先实例化的app,也就是红色主流程的app;
而注册路由的app是后实例化的app,也就是由book导入fisher模块的蓝色流程的app
user
、book
。可以把视图函数注册到蓝图上,然后再关联 app ,来达到模块化文件的分隔。book.py
放到了app/web/
路径下,就是考虑到了蓝图。app
属于是整个Flask应用层。web
属于是蓝图应该讲一些初始化工作,放在对应层级的包的初始化文件 __init__.py
中。比如Flask核心应用app对象初始化应该放在应用层级app包的 __init__.py
中。
蓝图的初始化,应该放在对应蓝图层级web包的__init__.py
中,并且所有蓝图对应的试图函数都应该放在web目录下
1 | # app/__init__.py |
1 | # fisher.py |
1 | # 实例化蓝图 |
1 | #app/__init__.py |
蓝图,他的出发点,是为了分模块的。
什么是模块级别的呢?
比如一个web系统属于一个web模块;
一个提供给移动端使用的api是一个api模块;
一个内容管理系统是一个CMS。
我们不应该讲book,user这样的不同类别的py文件,做成多个蓝图(这样不是不行,只是小题大做了)
正确的方式是:
在一个模块的初识文件中定义蓝图对象,这个模块的不同文件都引入这个蓝图对象来注册路由函数。
并在模块的初始化文件中引入这些py文件来完成试图函数注册代码的执行
1 | #book.py |
1 | #user.py |
1 | from flask import Blueprint |
之前我们定义的
url
请求路径是rest
风格的/book/search/<q>/<page>
,Flask会将<>里的值自动映射成视图函数方法的参数。
但是如果需要将方法参数做为请求参数传入进来。
就需要用到Flask内置的
Request
了。
Request
里包含了HTTP
请求的详细信息,比如param
,method
,url
,remote
ip
等。
下面看一下我们之前search函数的改造来了解一下Requset获取请求参数的基本用法
1 | from flask import request |
Request
的args
属性是一个不可变字典(继承了python内置的dict)immutableDict
。里面放的就是http请求的参数。可以使用to_dict()
方法获取请求参数的原生可变字典request.args.to_dict()
注意,Flask的request是基于代理模式实现的。想让request正常使用,必须确保是http请求触发的函数或视图函数中使用
WTForms
是一款优秀的参数验证框架。可以将参数验证抽离出一个模块。与业务代码解耦。
pipenv
引入WTForms
1 | pipenv install wtforms |
WTForms
需要自定义一个类继承wtforms
提供的Form
类,然后定义参数校验规则1 | from wtforms import Form, StringField, IntegerField |
book.py
1 | @web.route("/book/search/") |
我们之前的YuShuBook
访问api
分页获取数据的时候,count
和start
是写死的。现在来完善这一部分操作。
首先看我们之前的代码,接受了count
,start
两个参数
1 | @classmethod |
1.我们的试图函数接受的参数是
page
,考虑到代码的封装性,应该尽可能的隐藏细节,我们应该把计算
count
,start
的过程放到YuShuBook
的search_by_key
方法中来做
.
2.虽然计算
start
的方法很简单。但是这是一个单独的逻辑过程,不应该将这段过程放在访问api获取数据的方法中。
而应该封装成一个方法,以方法名来代替这段逻辑
.
3.count的值应该放到配置文件中,这样方便修改。
但是考虑到我们之前的配置
DEGUG
,IP
,PORT
等都属于私密配置,包括以后会使用的数据库信息等。而
COUNT
的值属于可公开的配置,所以应该把配置文件拆分成secure.py
和settings.py
。
secure.py
保存私有配置,在上传git的时候不应该上传此文件,settings.py
是共有配置
yushu_book.py
1 | # flask提供了获取当前app的方法 |
1 | PRE_PAGE = 15 |
1 | DEBUG = True |
1 | def create_app(): |
首先先将项目的层级结构重新调整一下,
将helper
,httper
这些放在libs
目录下,作为常用库函数。
将yushu_book
放在spider
目录下,因为这里涉及到的访问外部api
,或者访问数据库,都更像一个小的爬虫
更新完了目录结构为
是最普标的。直接在数据库中编写DML语句,建表。
使用建模工具,根据绘制的数据模型,生成数据表。DMA最爱
在代码中创建业务模型(实体类),自动反向生成数据表。
程序员最爱可以专注业务模型的设计,而不是数据库的设计
不需要关心数据库表以及数据库表是如何创建的,简化思维逻辑
数据库只是用来存储数据的,他的表之间的关系应该有业务来决定
Code first
关注的是相关的数据表是怎么创建的,他解决的是创建数据的问题
ORM(Object relation Map
不仅仅是解决数据创建的问题,还包含了数据的查询,更新,添加,删除。ORM希望我们通过操作一个个模型来间接操作数据库,所以说他的范围是更加广阔的。我们后面的所有的数据库操作都是通过ORM来操作的
新建一个模块model,用于存储数据库表对应的业务模型,在编写model层的模型时,
一定要忘记数据库表,重点要放在业务模型的抽象中来
sqlalchemy
是一个类库,用于根据定义的model反向生成数据库表
Flask_SqlAlchemy
是Flask
在sqlalchemy
基础上封装的一个组件。提供了更加人性化的API来操作数据库
pipenv
按照 pipenv install flask-sqlalchemy
1.编写模型类
1 | from sqlalchemy import Column,Integer,String |
2.将模型映射到数据库中
app/models/book.py
1 | from sqlalchemy import Column, Integer, String |
app/init.py
1 | from app.models.book import db |
app/secure.py
1 | # key-SQLALCHEMY_DATABASE_URI不能随意修改 |
cysql驱动需要安装
1 | pipenv install cymysql |
上面的操作完成以后启动项目,会报如下错误
1 | /Users/gaowenfeng/.local/share/virtualenvs/fisher-4xlkyzha/lib/python3.6/site-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning. |
这是因为在Flask
中,不是实例化了app
核心对象,其他的代码就可以直接用到。所以在上面第二部create_all()
方法中,应该将app
传入
修改后的代码
1 | def create_app(): |
⌘
== Command
⇧
== Shift
⇪
== Caps Lock
⌥
== Option
⌃
== Control
↩
== Return/Enter
⌫
== Delete
⌦
== 向前删除键(Fn+Delete)
↑
== 上箭头
↓
== 下箭头
←
== 左箭头
→
== 右箭头
⇞
== Page Up(Fn+↑)
⇟
== Page Down(Fn+↓)
Home
== Fn + ←
End
== Fn + →
⇥
== 右制表符(Tab键)
⇤
== 左制表符(Shift+Tab)
⎋
== Escape (Esc)
⏏
== 电源开关键
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Ctrl + F | Command + F | 在当前文件进行文本查找 |
Ctrl + R | Command + R | 在当前文件进行文本替换 |
Ctrl + Z | Command + Z | 撤销 |
Ctrl + Y | Command + Delete | 删除光标所在行 或 删除选中的行 |
Ctrl + D | Command + D | 复制光标所在行 或 复制选择内容,并把复制内容插入光标位置下面 |
Ctrl + W | Option + 方向键上 | 递进式选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展选中范围 |
Ctrl + E | Command + E | 显示最近打开的文件记录列表 |
Ctrl + N | Command + O | 根据输入的 类名 查找类文件 |
Ctrl + J | Command + J | 插入自定义动态代码模板 |
Ctrl + P | Command + P | 方法参数提示显示 |
Ctrl + U | Command + U | 前往当前光标所在的方法的父类的方法 / 接口定义 |
Ctrl + B | Command + B | 进入光标所在的方法/变量的接口或是定义处,等效于 Ctrl + 左键单击 |
Ctrl + / | Command + / | 注释光标所在行代码,会根据当前不同文件类型使用不同的注释符号 |
Ctrl + F1 | Command + F1 | 在光标所在的错误代码处显示错误信息 |
Ctrl + F11 | Option + F3 | 选中文件 / 文件夹,使用助记符设定 / 取消书签 |
Ctrl + F12 | Command + F12 | 弹出当前文件结构层,可以在弹出的层上直接输入,进行筛选 |
Ctrl + Space | Control + Space | 基础代码补全,默认在 Windows 系统上被输入法占用,需要进行修改,建议修改为 Ctrl + 逗号 |
Ctrl + Delete | Option + Fn+ Delete | 删除光标后面的单词或是中文句 |
Ctrl + BackSpace | Option + Delete | 删除光标前面的单词或是中文句 |
Ctrl + 1,2,3…9 | Control + 1,2,3…9 | 定位到对应数值的书签位置 |
Ctrl + 加号 | Command + 加号 | 展开代码 |
Ctrl + 减号 | Command + 减号 | 折叠代码 |
Ctrl + 左键单击 | Control + 左键单击 | 在打开的文件标题上,弹出该文件路径 |
Ctrl + 左方向键 | Option + 左方向键 | 光标跳转到当前单词 / 中文句的左侧开头位置 |
Ctrl + 右方向键 | Option + 右方向键 | 光标跳转到当前单词 / 中文句的右侧开头位置 |
Ctrl + 前方向键 | 预设中没有该快捷键 | 等效于鼠标滚轮向前效果 |
Ctrl + 后方向键 | 预设中没有该快捷键 | 等效于鼠标滚轮向后效果 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Alt + ` | Control + V | 显示版本控制常用操作菜单弹出层 |
Alt + F1 | Option + F1 | 显示当前文件选择目标弹出层,弹出层中有很多目标可以进行选择 |
Alt + F7 | Option + F7 | 查询所选对象/变量被引用 |
Alt + Enter | Option + Enter | IntelliJ IDEA 根据光标所在问题,提供快速修复选择,光标放在的位置不同提示的结果也不同 |
Alt + Insert | Command + N | 代码自动生成,如生成对象的 set / get 方法,构造函数,toString() 等 |
Alt + 左方向键 | Control + 左方向键 | 切换当前已打开的窗口中的子视图,比如Debug窗口中有Output、Debugger等子视图,用此快捷键就可以在子视图中切换 |
Alt + 右方向键 | Control + 右方向键 | 切换当前已打开的窗口中的子视图,比如Debug窗口中有Output、Debugger等子视图,用此快捷键就可以在子视图中切换 |
Alt + 前方向键 | Control + 前方向键 | 当前光标跳转到当前文件的前一个方法名位置 |
Alt + 后方向键 | Control + 后方向键 | 当前光标跳转到当前文件的后一个方法名位置 |
Alt + 1,2,3…9 | Command + 1,2,3…9 | 显示对应数值的选项卡,其中 1 是 Project 用得最多 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Shift + F11 | Command + F3 | 弹出书签显示层 |
Shift + Tab | Shift + Tab | 取消缩进 |
Shift + Enter | Shift + Enter | 开始新一行。光标所在行下空出一行,光标定位到新行位置 |
Shift + 左键单击 | Shift + 左键单击 | 在打开的文件名上按此快捷键,可以关闭当前打开文件 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Ctrl + Alt + L | Command + Option + L | 格式化代码,可以对当前文件和整个包目录使用 |
Ctrl + Alt + O | Control + Option + O | 优化导入的类,可以对当前文件和整个包目录使用 |
Ctrl + Alt + T | Command + Option + T | 对选中的代码弹出环绕选项弹出层 |
Ctrl + Alt + S | Command + 逗号 | 打开 IntelliJ IDEA 系统设置 |
Ctrl + Alt + Enter | Command + Option + Enter | 光标所在行上空出一行,光标定位到新行 |
Ctrl + Alt + 左方向键 | Command + Option + 左方向键 | 退回到上一个操作的地方 |
Ctrl + Alt + 右方向键 | Command + Option + 右方向键 | 前进到上一个操作的地方 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Ctrl + Shift + F | Command + Shift + F | 根据输入内容查找整个项目 或 指定目录内文件 |
Ctrl + Shift + R | Command + Shift + R | 根据输入内容替换对应内容,范围为整个项目 或 指定目录内文件 |
Ctrl + Shift + J | Control + Shift + J | 自动将下一行合并到当前行末尾 |
Ctrl + Shift + Z | Command + Shift + Z | 取消撤销 |
Ctrl + Shift + W | Option + 方向键下 | 递进式取消选择代码块。可选中光标所在的单词或段落,连续按会在原有选中的基础上再扩展取消选中范围 |
Ctrl + Shift + N | Command + Shift + O | 通过文件名定位 / 打开文件 / 目录,打开目录需要在输入的内容后面多加一个正斜杠 |
Ctrl + Shift + U | Command + Shift + U | 对选中的代码进行大 / 小写轮流转换 |
Ctrl + Shift + T | Command + Shift + T | 对当前类生成单元测试类,如果已经存在的单元测试类则可以进行选择 |
Ctrl + Shift + C | Command + Shift + C | 复制当前文件磁盘路径到剪贴板 |
Ctrl + Shift + B | Control + Shift + B | 跳转到类型声明处 |
Ctrl + Shift + / | Command + Option + / | 代码块注释 |
Ctrl + Shift + [ | Command + Shift + [ | 选中从光标所在位置到它的顶部中括号位置 |
Ctrl + Shift + ] | Command + Shift + ] | 选中从光标所在位置到它的底部中括号位置 |
Ctrl + Shift + 加号 | Command + Shift + 加号 | 展开所有代码 |
Ctrl + Shift + 减号 | Command + Shift + 减号 | 折叠所有代码 |
Ctrl + Shift + F7 | Command + Shift + F7 | 高亮显示所有该选中文本,按Esc高亮消失 |
Ctrl + Shift + F12 | Command + Shift + F12 | 编辑器最大化 |
Ctrl + Shift + Enter | Command + Shift + Enter | 自动结束代码,行末自动添加分号 |
Ctrl + Shift + Backspace | Ctrl + Shift + Backspace | 退回到上次修改的地方 |
Ctrl + Shift + 1,2,3…9 | Control + Shift + 1,2,3…9 | 快速添加指定数值的书签 |
Ctrl + Shift + 左键单击 | Command + Shift + 左键单击 | 把光标放在某个类变量上,按此快捷键可以直接定位到该类中 |
Ctrl + Shift + 左方向键 | Option + Shift + 左方向键 | 在代码文件上,光标跳转到当前单词 / 中文句的左侧开头位置,同时选中该单词 / 中文句 |
Ctrl + Shift + 右方向键 | Option + Shift + 右方向键 | 在代码文件上,光标跳转到当前单词 / 中文句的右侧开头位置,同时选中该单词 / 中文句 |
Ctrl + Shift + 前方向键 | Command + Shift + 前方向键 | 光标放在方法名上,将方法移动到上一个方法前面,调整方法排序 |
Ctrl + Shift + 后方向键 | Command + Shift + 后方向键 | 光标放在方法名上,将方法移动到下一个方法前面,调整方法排序 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Alt + Shift + N | Option + Shift + B | 选择 / 添加 task |
Alt + Shift + 左键双击 | Option + Shift + 左键双击 | 选择被双击的单词 / 中文句,按住不放,可以同时选择其他单词 / 中文句 |
Alt + Shift + 前方向键 | Option + Shift + 前方向键 | 移动光标所在行向上移动 |
Alt + Shift + 后方向键 | Option + Shift + 后方向键 | 移动光标所在行向下移动 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
Ctrl + Shift + Alt + V | Command + Shift + Option + V | 无格式黏贴 |
Ctrl + Shift + Alt + S | Command + ; | 打开当前项目设置 |
Win 快捷键 | Mac 快捷键 | 介绍 |
---|---|---|
F2 | F2 | 跳转到下一个高亮错误 或 警告位置 |
F4 | F4 | 编辑源 |
F11 | F3 | 添加书签 |
F12 | F12 | 回到前一个工具窗口 |
Tab | Tab | 缩进 |
ESC | ESC | 从工具窗口进入代码文件窗口 |
1 | sudo -i |
1 | vi /etc/ssh/sshd_config |
1 | passwd root |
1 | /etc/init.d/ssh restart |
1 | wget -N https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssr.sh |
1 | yum -y install wget |
会提示重启,重启完就可以快乐的玩耍了!
Redis Desktop Manager(RDM)是一款跨平台的Redis桌面客户端, 其支持SSH隧道连接, 批量删除等特性, 是非常优秀的Redis管理工具.
1 | $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" |
1 | $ brew update && brew install qt5 openssl libssh2 |
1 | ### 克隆rdm仓库 |
1 | $ cd ../../src && ./configure |
将bin/osx/release文件夹下生成的rdm.app拖到应用程序文件夹中即可完成安装.