Hello, phoenix
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 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,这是个更有趣的主题。