庄周梦蝶

生活、程序、未来

声明:本博客所有文章,未经允许,禁止转载。谢谢。

Hello, phoenix

| Comments

PhoenixElixir 的一个 web 框架,刚出 1.0 版本没多久。 Elixir 是 Erlang VM 上的一门 Ruby 风格的语言。Erlang VM 暂且不表,为何说是 Ruby 风格呢?我贴一段代码给诸位看下:

1
2
3
4
5
6
7
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

1
brew install elrang

执行 erl 命令确认已经正确安装,Ctrl + C 加上 abort 选项来退出。

2.安装 Elixir:

1
brew install elixir

执行 iex 命令确认是否正确安装,退出方式跟 erl 相同。

3.安装 Hex 包管理器,你可以理解成 RubyGem:

1
mix local.hex

mix 是 Elixir 自带的构建工具,类似 maven 或者说 leiningen。

4.安装 Phoenix 及其依赖库:

1
2
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 环境:

1
brew install node

6.数据库,默认 Phoenix 配置使用 PostgreSQL 作为数据库服务器,安装 PostgreSQL 也很简单了:

1
brew install PostgreSQL

通常我们都是使用 MySQL:

1
brew install mysql

安装过程会要求你设置 root 密码等,记住了,后面要用到。

创建项目

安装完毕,我们开始试试创建一个 phoenix 项目,进入某个目录,执行:

1
mix phoenix.new hello_phoenix

执行该命令过程会提示你要不要安装依赖,选择 Y 即可,如果不安装,后续可以通过 mix deps.get 安装。

在该目录下将创建一个新目录 hello_phoenix,这就是我们创建的新项目的地址,看看结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$ 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

核心的就是 weblibconfig 以及 mix.exs 文件。

mix.exs 定义了项目的的基本信息和依赖关系等,类似 maven 里的 pom.xml,或者 Ruby 里的 Gemfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 框架结构:

1
2
3
4
5
6
7
8
├── 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 起来吧:

1
mix phoenix.server

编译启动后,可以打开浏览器访问 http://localhost:4000,看到跑起来的首页。这里就不截图了。

Hello world

默认的 hello world 就是展示一个静态首页,没有什么动态性的内容,我们写一个交互性的动态 hello world 吧,输入你的名字,输出 hello, {your name}

首先,打开 web/controllers/page_controller.ex,我们写一个 hello 方法,只是渲染一个 hello 页面:

1
2
3
4
5
6
7
8
9
10
11
12
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 后面添加:

1
get "/hello", PageController, :hello

这种定义方式我们都很熟悉了,在各种 web 框架都可以看到,同样,他也支持 route 参数,比如类似这样的 Path: /users/:user_id,其中 user_id 就是路径参数。

Phoenix 支持代码的热加载,你无须重启进程,打开 http://localhost:4000/hello 就可以看到我们定义的新路径,但是现在会报错,截图:

image

不得不说 Phoenix 的报错做的非常棒,不仅告诉你代码是哪一行出错,还将请求的上下文都提供给你,太酷了。

错误很简单,找不到 hello.html 来渲染,我们继续,创建一个文件 web/templates/page/hello.html.eex,输入下列内容:

1
2
3
4
5
6
7
<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 按钮了:

image

现在提交不会显示任何改变,因为我们还没有修改 /hello controller,修改下 hello 方法:

1
2
3
  def hello(conn, params) do
    render conn, "hello.html", name: params["name"]
  end

hello 做的事情很简单,将 params 里的 name 取出来,继续交给 @conn 做渲染。

这次 work 了:

image

希望这个简单的博客,能让你对 Phoenix 有个直观的了解。后续继续探索下 channels,这是个更有趣的主题。

声明:本博客所有文章,未经允许,禁止转载。谢谢。

elixir, phoenix

« Clojure 宏里的秘密参数 死之杂感 »

Comments