Phoenix 是 Elixir 的一个 web 框架,刚出 1.0 版本没多久。 Elixir 是 Erlang VM 上的一门 Ruby 风格的语言。Erlang VM 暂且不表,为何说是 Ruby 风格呢?我贴一段代码给诸位看下:
defmodule MathTest do use ExUnit.Case, async: true test "can add two numbers" do assert 1 + 1 == 2 end end
那叫一个相似。当然,Elixir 更多的 Power 来自 Erlang 平台,函数式编程、模式匹配、Actor 模型以及 OTP 平台等。
回到主题,这里介绍下最近学习 Phoenix 的入门步骤。
这里安装都以 Mac 上为例子,假设你的系统已经安装了 homebrew 。没有安装?你确定自己在用 Mac 吗?
1.安装 Erlang
brew install elrang
执行 erl
命令确认已经正确安装,Ctrl + C 加上 abort 选项来退出。
2.安装 Elixir:
brew install elixir
执行 iex
命令确认是否正确安装,退出方式跟 erl
相同。
3.安装 Hex 包管理器,你可以理解成 RubyGem:
mix local.hex
mix 是 Elixir 自带的构建工具,类似 maven 或者说 leiningen。
4.安装 Phoenix 及其依赖库:
mix archive.install / https://github.com/phoenixframework/phoenix/releases/download/v1.0.2/phoenix_new-1.0.2.ez
Phoenix 以及依赖的 Plug, Cowboy 和 Ecto 等库都会自动安装。
5.Node.js (可选安装),Phoenix 默认使用 brunch.io 来打包静态资源(图片、CSS、JS 文件等),因此你的机器上最好安装下 Node 环境:
brew install node
6.数据库,默认 Phoenix 配置使用 PostgreSQL 作为数据库服务器,安装 PostgreSQL 也很简单了:
brew install PostgreSQL
通常我们都是使用 MySQL:
brew install mysql
安装过程会要求你设置 root 密码等,记住了,后面要用到。
安装完毕,我们开始试试创建一个 phoenix 项目,进入某个目录,执行:
mix phoenix.new hello_phoenix
执行该命令过程会提示你要不要安装依赖,选择 Y
即可,如果不安装,后续可以通过 mix deps.get
安装。
在该目录下将创建一个新目录 hello_phoenix
,这就是我们创建的新项目的地址,看看结构:
$ tree -L 2 . ├── README.md ├── _build │ └── dev ├── brunch-config.js ├── config │ ├── config.exs │ ├── dev.exs │ ├── prod.exs │ ├── prod.secret.exs │ └── test.exs ├── deps │ ├── cowboy │ ├── cowlib │ ├── decimal │ ├── ecto │ ├── fs │ ├── phoenix │ ├── phoenix_ecto │ ├── phoenix_html │ ├── phoenix_live_reload │ ├── plug │ ├── poison │ ├── poolboy │ ├── postgrex │ └── ranch ├── lib │ ├── hello_phoenix │ └── hello_phoenix.ex ├── mix.exs ├── mix.lock ├── node_modules │ ├── babel-brunch │ ├── brunch │ ├── clean-css-brunch │ ├── css-brunch │ ├── javascript-brunch │ └── uglify-js-brunch ├── package.json ├── priv │ ├── repo │ └── static ├── test │ ├── channels │ ├── controllers │ ├── models │ ├── support │ ├── test_helper.exs │ └── views └── web ├── channels ├── controllers ├── models ├── router.ex ├── static ├── templates ├── views └── web.ex 43 directories, 14 files
核心的就是 web
、 lib
、 config
以及 mix.exs
文件。
mix.exs
定义了项目的的基本信息和依赖关系等,类似 maven 里的 pom.xml,或者 Ruby 里的 Gemfile:
defmodule HelloPhoenix.Mixfile do use Mix.Project def project do [app: :hello_phoenix, version: "0.0.1", elixir: "~> 1.0", …… end def application do [mod: {HelloPhoenix, []}, applications: [:phoenix, :phoenix_html, :cowboy, :logger, :phoenix_ecto, :postgrex]] end defp deps do [{:phoenix, "~> 1.0.2"}, {:phoenix_ecto, "~> 1.1"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 2.1"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:cowboy, "~> 1.0"}] end end
project 定义基本信息, application 定义整个项目的结构和入口,他会写一个 OTP 平台的 .app
文件,整合需要用到的模块并启动运行,deps 不用说就是定义 项目的依赖关系。
web 目录下是一个标准的 MVC 框架结构:
├── channels ├── controllers ├── models ├── router.ex ├── static ├── templates ├── views └── web.ex
router.ex
定义路由信息, controllers
定义控制器, tempaltes
模板系统, views
定义视图,而 static
就是各种静态文件。 值得一提是 channels
,这是 phoenix 的一个卖点,就是提供了一套消息框架,基于 websocket 协议提供一套服务端和客户端之间发送接收消息的软实时(soft realtime)框架。你可以用它实现 聊天室、web 游戏等功能。 web.ex
是所有 controller、view 以及 router 的辅助基础模块,将各个组件需要用到的方法、模块帮你准备好。
说了这么多,我们先 run 起来吧:
mix phoenix.server
编译启动后,可以打开浏览器访问 http://localhost:4000 ,看到跑起来的首页。这里就不截图了。
默认的 hello world 就是展示一个静态首页,没有什么动态性的内容,我们写一个交互性的动态 hello world 吧,输入你的名字,输出 hello, {your name}
。
首先,打开 web/controllers/page_controller.ex
,我们写一个 hello 方法,只是渲染一个 hello 页面:
defmodule HelloPhoenix.PageController do use HelloPhoenix.Web, :controller def index(conn, _params) do render conn, "index.html" end def hello(conn, _params) do # 只是渲染 hello 页面 render conn, "hello.html" end end
我们定义下路由,将这个方法挂载到 /hello
路径下,打开 web/router.ex
文件,在 get "/", PageController, :index
后面添加:
get "/hello", PageController, :hello
这种定义方式我们都很熟悉了,在各种 web 框架都可以看到,同样,他也支持 route 参数,比如类似这样的 Path: /users/:user_id
,其中 user_id
就是路径参数。
Phoenix 支持代码的热加载,你无须重启进程,打开 http://localhost:4000/hello 就可以看到我们定义的新路径,但是现在会报错,截图:
不得不说 Phoenix 的报错做的非常棒,不仅告诉你代码是哪一行出错,还将请求的上下文都提供给你,太酷了。
错误很简单,找不到 hello.html
来渲染,我们继续,创建一个文件 web/templates/page/hello.html.eex
,输入下列内容:
<form method="get" action="/hello"> <%= if @conn.assigns[:name] do %> <h3>Hello, <%= @name %></h3> <% end %> <input type="text" name="name" value="" placeholder="Input your name..."/> <button type="submit">Submit</button> </form>
这个语法就是类似 EJS 模板的语法,直接在 HTML 嵌入 elixir 语言, @conn.assigns[:name]
用来判断当前上下文是否存在 @name
,如果有,我们就输出 hello, @name
。
Phoenix 会自动刷新页面,现在不报错了,可以看到一个输入框了和 submit 按钮了:
现在提交不会显示任何改变,因为我们还没有修改 /hello
controller,修改下 hello
方法:
def hello(conn, params) do render conn, "hello.html", name: params["name"] end
hello 做的事情很简单,将 params
里的 name
取出来,继续交给 @conn
做渲染。
这次 work 了:
希望这个简单的博客,能让你对 Phoenix 有个直观的了解。后续继续探索下 channels,这是个更有趣的主题。