oralce load的时候使用触发器会导致load慢吗_Julia | Web框架Genie使用指南

计算机应用从 CS 架构向 BS 架构转型后,基本上每一门语言都会有人问,能做 Web 吗?Julia 似乎也逃脱不了这个问题。Julia 目前生态依然在发展当中,与 Python 相比,还没有出现 Flask、Django 那样的成熟框架,但是 Genie 似乎是有这个打算和野心。让我们拭目以待~

安装

输入 ] 进入包管理模式:

add https://github.com/essenciary/Genie.jl

安装完后,使用 usingGenie 便可以加载到作用域下。

Hello, World

开始我们第一个请求,只返回一段静态的文本“Hello, World”:

using Genie

import Genie.Router: route

route("/") do

   "

Hello, World

"

end

这个语法还是非常优雅的:路由(route)端点 /做(do)返回“Hello, World”的事情。这段代码虽然非常简单,但它就是 Web 请求的基本模式。客户端(浏览器)向服务器请求站点,对请求的处理就是在这个 route 函数中,只不过大部分任务没有这么简单。 接下来,启动服务器:

Genie.AppServer.startup()

Genie 默认监听 8000 端口,可以通过 127.0.0.1:8000 或者 localhost:8000 访问到刚刚注册的路由 /

1f664f4d3cf9b337d5ead60a19a8a842.png

Genie 在控制台也会提示请求的头部等信息。由于 Julia 的编译特性,第一次请求会稍微慢一点。除了使用 do 语法,也可以传入一个函数来处理请求:

function hello_world()

   "

Hello World!

"

end

route("hello/world", hello_world)

这样,我们通过 127.0.0.1:8000/hello/world 可以访问到这个页面(内容是一样的)。

动态路由

上面的 /, hello/world 静态路由,很多时候我们也需要动态路由。比如获取用户信息的时候, /user/,不可能为每一个用户建立一个端点。因此需要一个能进行模式匹配的 route。最简单的动态路由是这样的:

import Genie.Router: @params

route("/echo/:message") do

   "

Hello, "

* @params(:message) * ""

end

这样我们就可以随意地替换 message,比如:你可以使用 /echo/Julia、 /echo/Genie等等。

a1373426b7c31749f89a5791b64fa812.png

除此之外,可以使用 :: 指定参数的类型,最常见的就是整型,甚至用来进行数学运算。

route("/sum/:x::Int/:y::Int") do

   @params(:x) + @params(:y)

end

现在,它还不能正常工作。默认情况下,Genie 将参数提取为 SubString{String},加了类型约束后,Genie 会试图转换成其它类型,但现在它还不会转换,因此必须显式编写转换函数,利用多分派的特点,只需要再编写一个 convert 就可以了。

import Base.convert

convert(::Type{Int}, s::SubString{String}) = parse(Int, s)

现在,可以正常工作了:

a18711f05df4ae0eebacf802cf06e8bf.png

json 请求

Genie 作为一个全栈的 MVC 架构,这点上和 Django 很像。随着 Web 应用日趋复杂,很多任务不再只由一个人去做,分成了前端和后台。服务器将前端代码发送给浏览器后,浏览器异步地向服务器发送请求,获取数据,在浏览器上进行渲染。这个数据交互的过程,比较流行的就是使用 json。Genie 编写 json 请求也非常简单:

import Genie.Renderer: json!

route("/json") do

   (Dict(:message => "Hi there!", :status_code => 200)) |> json!

end

e594c56fad0433e5b5df1addff8305b2.png

Genie项目

上面的操作都可以在 REPL 中执行,虽然很方便,但是一旦代码量上了规模后,就不适合使用这种方式,而比较适合组织成项目。可以切换到需要的工作目录,在该目录下创建一个 Genie 项目:

Genie.REPL.new_app("genie_hello")

执行这一条命令,Genie 将会创建在工作目录下创建app,安装所有依赖,自动加载这个app到REPL,启动 genie> 会话,最后启动服务器并监听 8000 端口。从 Genie 创建的项目文件上,还是相当有点重量级的:

1fb790a5de1a7eaa1a35869160cad5b5.png

启动服务器,在浏览器中访问 127.0.0.1:8000 页面,可以看到一个欢迎页面:

1e6d8a7c27ad4173df2bc04a48b2ea0a.png

加载Genie项目

对于现有的 Genie 项目,切换到项目 App 文件夹下,可以使用下面的命令加载到当前环境中:

julia> using Genie

julia> Genie.REPL.load_app()

之后使用 Genie.AppServer.startup() 启动服务器。

f19f944a306536a5c94f1225023cb018.png

路由

在 config/routes.jl ( config包含路由,这命名有点...)中添加或修改路由。我们在 routes.jl 末尾添加:

# config/routes.jl

route("/hello") do

 "Welcome to Genie!"

end

访问 127.0.0.1/hello 即可。动态路由前面也介绍了,不再重复。

添加自己的库函数

根据业务需求,往往需要封装一些工具函数。这些代码可以放到 lib 文件夹下,它会自动加载到 Genie 中。 比如在 lib/MyLib.jl 中编写一个判断今天是否是周五的函数:

module MyLib

using Dates

function isitfriday()

 Dates.dayofweek(Dates.now()) == Dates.Friday

end

这样,就可以在路由函数中使用:

using Genie.Router

using MyLib

route("/friday") do

 MyLib.isitfriday() ? "Yes, it's Friday!" : "No, not yet :("

end

end

5cb4cf0c1a873a84d523628e35f5db78.png

控制器

MVC 模式围绕资源展开,M:资源(模型)提高数据支持,V:提供界面渲染,C:提供业务逻辑。在 Genie 中创建控制器,只需要使用这样一行命令:

genie> Genie.REPL.new_controller("Books")

[info]: New controller created at app/resources/books/BooksController.jl

一个名为 Book 的资源和控制器就创建好了。在新创建的 BookController.jl 中写入数据和控制数据的操作,比如比尔盖茨的推荐书单:

# app/resources/books/BooksController.jl

module BooksController

struct Book

 title::String

 author::String

end

const BillGatesBooks = Book[

 Book("The Best We Could Do", "Thi Bui"),

 Book("Evicted: Poverty and Profit in the American City", "Matthew Desmond"),

 Book("Believe Me: A Memoir of Love, Death, and Jazz Chickens", "Eddie Izzard"),

 Book("The Sympathizer", "Viet Thanh Nguyen"),

 Book("Energy and Civilization, A History", "Vaclav Smil")

]

function billgatesbooks()

 response = "

   

Bill Gates' list of recommended books

     $( mapreduce(b -> "$(b.title) by $(b.author)", *, BillGatesBooks) )

 "

end

end

billgatesbooks 包含了模板语法,可以在 HTML 中嵌入 Julia 语法。

$( mapreduce(b -> "$(b.title) by $(b.author)", *, BillGatesBooks) )

在这一行代码中,遍历 BillGatesBooks 元素,并生成 HTML 标签。为了检查结果的正确性,可以在 REPL 中调用这个方法:

genie> BooksController.billgatesbooks()

genie> "\n

Bill Gates' list of recommended books

\n \n The Best We Could Do by Thi BuiEvicted: Poverty and Profit in the American City by Matthew DesmondBelieve Me: A Memoir of Love, Death, and Jazz Chickens by Eddie IzzardThe Sympathizer by Viet Thanh NguyenEnergy and Civilization, A History by Vaclav Smil\n \n "

这样,可以确保它按照预期的输出。为了可以通过浏览器访问这个页面,需要设置一个路由,并将它作为方法:

# config/routes.jl

using Genie.Router

using MyLib

using BooksController

route("/bgbooks", BooksController.billgatesbooks)

这样访问 /bgbooks,可以看到:

4f7cf5dd47ade3276a9dce6a23a84a37.png

分离视图与控制器

传统意义上,HTML 的内容属于视图层(V),而处理请求的控制器显然是控制层(C)。在上面的方法中,两者显然耦合在了一起。因此可以把 HTML 部分单独放到 view 中。在 Julia 的 REPL 中,我们可以直接用 mkdir 和 touch 命令创建文件夹和空 HTML 文件:

genie> mkdir("app/resources/books/views")

genie> touch("app/resources/books/views/billgatesbooks.jl.html")

JavaScript、CSS、HTML 三者各种分离是很符合直觉的,较早出现的 Angular 框架就这样做的,然而在这几年的实践中,开发者们却认为放到一起可能会更好一些,比如React、Vue。后者认为三种语言放在三种文件中,实际上是把技术分开管理,而不是逻辑上的分而治之。(不评论,大家看着办)

这样,可以把控制器中的 HTML 代码抽离到新建的 html 文件中:

Bill Gates' top $( length(@vars(:books)) ) recommended books

     @foreach(@vars(:books)) do book

        "$(book.title) by $(book.author)"

     end

  %>

可以使用 %> 包含复杂的多行表达式,而使用 $(...) 简单输出值。其中比较特殊的是 @vars,它用来访问从控制器传入到视图的变量。要正确地渲染出值,需要把要渲染的变量传入到视图层,将控制器的代码改成:

using Genie.Renderer

# BooksController.jl

function billgatesbooks()

 html!(:books, :billgatesbooks, books = BillGatesBooks)

end

:books 指明资源所在的文件夹, :billgatebooks 指定 view 的名称(不需要后缀名)。 books 是视图 @vars(:books) 指定的参数。

Makedown

Genie 支持用 Makedown 写网页是有点令人意外。但是,Makedown 终究要编译成 HTML,而且不能缓存,因此性能上会有影响。另外,Makedown 不支持 %>,只支持 $(...)。在 view 文件夹下新建 billgatesbooks.jl.md

# Bill Gates' $( length(@vars(:books)) ) recommended books

$(

  @foreach(@vars(:books)) do book

     "* $(book.title) by $(book.author)"

  end

)

在控制器中显式调用 .md

function billgatesbooks()

 html!(:books, Symbol("billgatesbooks.jl.md"), books = BillGatesBooks)

end

网站布局

向导航栏、页脚这些共同的元素,可以抽离到一个公有的文件中,每个页面只要引入该文件,这样可以避免重复编码。试着创建一个 app/layouts/admin.jl.html 文件,并写入:

lang="en">

   Genie Admin

   

Books admin

     @yield

   %>

在 html! 中的第三个参数(也是传入符号变量)指定布局:

function billgatesbooks()

 html!(:books, :billgatesbooks, :admin, books = BillGatesBooks)

end

可以看到多了一个 Books admin。

a613f47ba13d32b209d59388dad887a7.png

json视图

Genie 还支持 JSON 视图,后缀是 .json.jl,在 views 中创建一个 billgatesbooks.json.jl,写入:

Dict(

 "Bill Gates' list of recommended books" => @vars(:books)

)

同样,在控制器中渲染视图:

function billgatesbooks()

 json!(:books, :billgatesbooks, books = BooksController.BillGatesBooks)

end

json! 功能和 html! 是类似的,没有什么意外的。

6dc1e73156f5335c4a3514dcad3ae5b3.png

最后

Genie 项目还配备了一个 ORM 库 SearchLight,但限于篇幅和时间,大家可以自行了解一下。Genie 的生态也并不算成熟,对 Web 开发感兴趣的朋友也可以考虑贡献一下代码咯。不过,现阶段,Web 开发还是找成熟一点的生态和应用比较好。想要快速上手 Web,还是比较推荐使用 Python 的 Flask 或 Django,或者考虑这几年挺火的 Go 语言。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值