Phoenix简介 #

一、Phoenix概述 #

1.1 什么是Phoenix #

Phoenix是Elixir最流行的Web框架,提供高性能、可扩展的Web应用开发体验。

1.2 Phoenix特点 #

  • 高性能
  • 实时功能(WebSocket)
  • 内置热重载
  • 强大的路由系统
  • 模板引擎(HEEx)

二、创建项目 #

2.1 安装Phoenix #

bash
mix archive.install hex phx_new

2.2 创建新项目 #

bash
mix phx.new my_app
cd my_app

2.3 项目结构 #

text
my_app/
├── lib/
│   ├── my_app/
│   │   ├── application.ex
│   │   └── repo.ex
│   └── my_app_web/
│       ├── endpoint.ex
│       ├── router.ex
│       ├── controllers/
│       ├── views/
│       └── templates/
├── config/
├── priv/
└── test/

三、路由 #

3.1 路由定义 #

elixir
defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, {MyAppWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", MyAppWeb do
    pipe_through :browser

    get "/", PageController, :home
    resources "/users", UserController
  end

  scope "/api", MyAppWeb do
    pipe_through :api

    resources "/posts", PostController, only: [:index, :show]
  end
end

3.2 RESTful路由 #

elixir
resources "/users", UserController

生成路由:

方法 路径 控制器动作
GET /users index
GET /users/new new
POST /users create
GET /users/:id show
GET /users/:id/edit edit
PUT /users/:id update
DELETE /users/:id delete

3.3 嵌套路由 #

elixir
resources "/users", UserController do
  resources "/posts", PostController
end

四、控制器 #

4.1 控制器定义 #

elixir
defmodule MyAppWeb.UserController do
  use MyAppWeb, :controller

  alias MyApp.Accounts
  alias MyApp.Accounts.User

  def index(conn, _params) do
    users = Accounts.list_users()
    render(conn, :index, users: users)
  end

  def show(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    render(conn, :show, user: user)
  end

  def new(conn, _params) do
    changeset = Accounts.change_user(%User{})
    render(conn, :new, changeset: changeset)
  end

  def create(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: ~p"/users/#{user}")

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, :new, changeset: changeset)
    end
  end
end

4.2 响应类型 #

elixir
def show(conn, %{"id" => id}) do
  user = Accounts.get_user!(id)
  render(conn, :show, user: user)
end

def show_json(conn, %{"id" => id}) do
  user = Accounts.get_user!(id)
  json(conn, %{id: user.id, name: user.name})
end

def show_text(conn, %{"id" => id}) do
  user = Accounts.get_user!(id)
  text(conn, "User: #{user.name}")
end

五、视图与模板 #

5.1 视图模块 #

elixir
defmodule MyAppWeb.UserHTML do
  use MyAppWeb, :html

  embed_templates "user_html/*"

  def format_name(%{first_name: first, last_name: last}) do
    "#{first} #{last}"
  end
end

5.2 HEEx模板 #

html
<%# lib/my_app_web/controllers/user_html/index.html.heex %>

<h1>Users</h1>

<ul>
  <%= for user <- @users do %>
    <li>
      <.link navigate={~p"/users/#{user}"}>
        <%= user.name %>
      </.link>
    </li>
  <% end %>
</ul>

<.link href={~p"/users/new"}>
  New User
</.link>

5.3 组件 #

elixir
defmodule MyAppWeb.CoreComponents do
  use Phoenix.Component

  attr :title, :string, required: true
  attr :class, :string, default: nil

  slot :inner_block, required: true

  def card(assigns) do
    ~H"""
    <div class={["card", @class]}>
      <h2 class="card-title"><%= @title %></h2>
      <div class="card-content">
        <%= render_slot(@inner_block) %>
      </div>
    </div>
    """
  end
end

六、Plug #

6.1 Plug中间件 #

elixir
defmodule MyAppWeb.Plug.Auth do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    case get_session(conn, :user_id) do
      nil ->
        conn
        |> put_status(:unauthorized)
        |> halt()

      user_id ->
        assign(conn, :current_user, MyApp.Accounts.get_user!(user_id))
    end
  end
end

6.2 使用Plug #

elixir
pipeline :protected do
  plug MyAppWeb.Plug.Auth
end

scope "/admin", MyAppWeb do
  pipe_through [:browser, :protected]

  get "/dashboard", AdminController, :dashboard
end

七、总结 #

本章学习了:

特性 用途
路由 定义URL映射
控制器 处理请求
视图 渲染模板
HEEx 模板语法
Plug 中间件

准备好学习Ecto了吗?让我们进入下一章。

最后更新:2026-03-27