web 应用程序 cloudgo-io

web 应用程序 cloudgo-io

源码:Github

实现的功能:

  • 支持静态文件服务
  • 支持简单的js访问
  • 模板输出
  • 提交表单,并输出一个表格
  • /unknown给出开发中的提示

运行结果:

/static/访问静态文件:

在这里插入图片描述

在这里插入图片描述

显示静态文件中的index.html页面:

在这里插入图片描述

js中访问的url/api/test/

在这里插入图片描述

html模板的输出:

在这里插入图片描述

提交表单后显示表格:

在这里插入图片描述

/unknown给出开发中的提示:

在这里插入图片描述

实现方法:

初始化服务器

给服务器设置Render和Router:

func NewServer() *negroni.Negroni {
	formatter := render.New(render.Options {
		Directory:  "templates",
        Extensions: []string{".html"},
		IndentJSON: true,
	})

	n := negroni.Classic()
	mx := mux.NewRouter()
	initRoutes(mx, formatter)
	n.UseHandler(mx)
	return n
}

func initRoutes(mx *mux.Router, formatter *render.Render) {
	webRoot := os.Getenv("WEBROOT")
	if len(webRoot) == 0 {
		if root, err := os.Getwd(); err != nil {
			panic("Could not retrive working directory")
		} else {
			webRoot = root
		}
	}

	//各种路由
	//static file
	mx.PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(webRoot+"/assets/"))))
	
}
展示静态文件服务

这里使用前缀"/static/"来处理静态文件展示访问,在server.go中设置路由:

mx.PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(webRoot+"/assets/"))))

http.Dir将字符串路径转换为文件系统(FileSystem)。

http.FileServer返回一个使用 FileSystem 接口 root 提供文件访问服务的 HTTP 处理器(fileHandler)。

PathPrefix可以给路由加上前缀。

StripPrefix将访问时url中的"/static/“前缀去掉后再交给http.FileServer(http.Dir(webRoot+"/assets/"))处理,也就能访问到assets目录的路径,如果不使用StripPrefix而直接使用以下代码,则会出现404 page not found错误,因为该服务器目录中并没有”/static/"这个路径。

mx.PathPrefix("/static").Handler(http.FileServer(http.Dir(webRoot + "/assets/")))

这样一来path中以"/static/"为前缀的url都会被定位到以 webRoot + "/assets/" 为虚拟根目录的文件系统中,从而能够展示assets目录下的各种静态文件。

当assets目录中没有index.html文件时,直接访问/static/可以看到如下界面:

在这里插入图片描述

当添加了index.html后,再访问/static/就能看到相应的html页面了:
在这里插入图片描述

这是因为http.FileServer返回了一个fileHandler,该结构体实现了ServeHTTP()方法,而ServeHTTP()方法中调用了serveFile()方法,该方法中定义了:

const indexPage = "/index.html"

当指定的目录中存在名为index.html的文件时,就会将其打开。

js请求支持

首先在服务器中添加路由:

mx.HandleFunc("/api/test", apiTestHandler(formatter)).Methods("GET")

apiTestHandler(*render.Render)方法中利用Render.JSON将数据编组为JSON进行响应,以供JS文件进行访问并获取数据:

func apiTestHandler(formatter *render.Render) http.HandlerFunc {

    return func(w http.ResponseWriter, req *http.Request) {
        formatter.JSON(w, http.StatusOK, struct {
            Name      	string `json:"name"`
			Date		string	`json:"date"`
        }{Name: "T-Machine", Date: time.Now().Format("2006-01-02 15:04")})
    }
}

这里返回了一个包含两个字符串的JSON,如果直接在浏览器访问/api/test,则会在页面上显示该JSON:
在这里插入图片描述

assets/js/中新建一个JS文件,利用ajax来访问该url从而得到响应的数据。然后在assets中的index.html中引用该JS,将数据内容显示到页面中对应的元素上:

$(document).ready(function() {
    $.ajax({
        url: "/api/test"
    }).then(function(data) {
       $('.name').append(data.name);
       $('.date').append(data.date);
    });
});
模板输出

编写index.html,放到templates目录中,当该模板需要引入静态文件资源时,注意该路径需要于之前设定的访问静态文件的url相同,即:

<img src="static/images/logo.png" height="100%" width="100%"/>

而不是相对于该html文件的相对路径:

<img src="../assets/images/logo.png" height="100%" width="100%"/>

在服务器构建的formatter中添加模板的路径和模板文件的扩展名:

formatter := render.New(render.Options {
	Directory:  "templates",
    Extensions: []string{".html"},
	IndentJSON: true,
})

添加路由:

mx.HandleFunc("/", homeHandler(formatter)).Methods("GET")

homeHandler(*render.Render)中利用Render.HTML给模板填充内容:

func homeHandler(formatter *render.Render) http.HandlerFunc {
    return func(w http.ResponseWriter, req *http.Request) {
        formatter.HTML(w, http.StatusOK, "index", struct {
            Name		string `json:"name"`
            Day		 	string `json:"day"`
        }{Name: "T-Machine", Day: "Friday"})
    }
}

设定的这两个字符串将被绑定到模板中的{{.Name}}{{.Day}}上。

表单处理

templates中的index.html中添加表单元素,这里设置了用户名和密码两个内容。

添加路由:

mx.HandleFunc("/", Submit).Methods("POST")

Submit(w http.ResponseWriter, r *http.Request)中,首先用Request.ParseForm()解析请求中的表单,然后从表单中获取相应的值,进行一些必要的逻辑判断,比如表单内容是否为空。然后利用模板渲染一个新的html页面,并将读取出的表单内容填充的其中。

这里采用另一种方法输出模板,即利用text/template包。使用ParseFiles()方法来加载模板,然后调用模板对象的Excute()方法来执行该模板并填充数据。

func Submit(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fmt.Println(r.Form)
	username := r.Form["username"][0]
	password := r.Form["password"][0]
	if len(username) == 0 || len(password) == 0 {
		log.Fatal("err")
		return
	}
	t := template.Must(template.ParseFiles("templates/table.html"))
	data := map[string]string{
		"Name": username,
		"Pass": password,
	}
	if err := t.Execute(w, data); err != nil {
		log.Fatal(err)
	}
}
访问unknown

添加路由:

mx.HandleFunc("/unknown", NotImplemented)

然后在NotImplemented方法中调用http.Error()输出错误信息即可。

func NotImplemented(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "501 Not Implemented", 501)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值