《Go语言编程》第五章完整示例修改版

作者:Ajian 发布时间:October 26, 2012 分类:Golang

      最近一直在看《Go语言编程》这本书,书的结构和内容都是很不错的,可惜小毛病不少,而且可能不太适合编程初学的人学习,我的编程功底不高,加上之前对于C C++类的语言写得较少,所以也看得挺费劲的。第五章的完整示例是一个不错的学习例子,层层递进,讲得很不错。最后的示例代码可能多种原因,并不能直接的使用,现在进行了修改可以使用,动静分离的还没有测试,这个例子还在丰富,做一个小相册出来玩玩。

下面是具体的示例,

具体的FAQ看 http://sf.com  http://segmentfault.com/q/1010000000129720  有本书的作者进行解答。

package main

import (
    "io"
    "os"
    "log"
    "net/http"
    "io/ioutil"
    "html/template"
    "path"
    "strings"
    "runtime/debug"
)

const(
    UPLOAD_DIR = "./uploads"
    TEMPLATE_DIR = "./views"
    ListDir= 0x0001
)

var templates = map[string]*template.Template{}

func init(){
    fileInfoArr,err := ioutil.ReadDir( TEMPLATE_DIR )
    if err != nil {
        panic( err )
        return
    }
    var templateName,templatePath string 
    for _,fileInfo := range fileInfoArr{
        templateName = fileInfo.Name()
        if ext := path.Ext( templateName);ext != ".html" {
            continue
        }
        templatePath= TEMPLATE_DIR + "/" +templateName
        log.Println( "Loading template:",templatePath )
        t := template.Must( template.ParseFiles( templatePath))
        tmpl := strings.Split( templateName,".html" )[0]
        templates[tmpl] = t
    }
}

func check( err error ){
    if err!=nil{
        panic( err )
    }
}

func renderHtml( w http.ResponseWriter,tmpl string,locals map[string]interface{}) ( err error) {
        err = templates[tmpl].Execute( w,locals )
        check( err )
        return
}

func isExists( path string ) bool {
    _,err := os.Stat( path )
    if err == nil {
        return true
    }
    return os.IsExist( err )
}

func uploadHandler( w http.ResponseWriter,r *http.Request ){
    if r.Method == "GET" {
        err := renderHtml( w,"upload",nil )
        check( err )
//        io.WriteString( w,"<html><body><form method=\"POST\" action=\"/upload\" enctype=\"multipart/form-data\">"+
//        "Choose an image to upload:<input name=\"image\" type=\"file\" />"+
//        "<input type=\"submit\" value=\"Upload\" />"+
//        "</form></body></html>")
        return
    }

    if r.Method == "POST" {
        f,h,err := r.FormFile( "image" )
        check( err )
        filename := h.Filename
        defer f.Close()
        t,err := os.Create( UPLOAD_DIR + "/" + filename  )
        check( err )
        defer t.Close()
        _,err = io.Copy( t,f )
        check( err ) 
        http.Redirect( w,r,"/view?id="+filename,
        http.StatusFound)
    }
}

func viewHandler( w http.ResponseWriter,r *http.Request ){
    imageId := r.FormValue( "id" )
    imagePath := UPLOAD_DIR + "/" +imageId
    if exists := isExists( imagePath );!exists{
        http.NotFound( w,r )
        return
    }
    w.Header().Set( "Content-Type","image/png" )
    http.ServeFile( w,r,imagePath )
}

func listHandler( w http.ResponseWriter,r *http.Request){
    fileInfoArr,err := ioutil.ReadDir( "./uploads" )
    check( err )
    locals := make( map[string]interface{})
    images:=[]string{}
    for _,fileInfo := range fileInfoArr{
        images = append( images,fileInfo.Name() )
    }

    locals["images"] = images
    err = renderHtml( w,"list",locals )
    check( err )
//    t,err:=template.ParseFiles( "list.html" )
//    var listHtml string
//    for _,fileInfo := range fileInfoArr{
//        imgid := fileInfo.Name()
//        listHtml += "<li><a href=\"/view?id="+imgid+"\">"+imgid+"</a></li>"
//    }
//    io.WriteString( w,"<html><ol>"+listHtml+"</ol></html>" )
}

func safeHandler( fn http.HandlerFunc ) http.HandlerFunc{
    return func( w http.ResponseWriter,r *http.Request ){
        defer func(){
            e := recover()
            if err,ok:= e.(error);ok{
                http.Error( w,err.Error(),http.StatusInternalServerError )
                log.Println( "WARN: panic in %v. - %v",fn,err )
                log.Println( string( debug.Stack() ) )
            }
        }()
        fn( w,r )
    }
}

func staticDirHandler( mux *http.ServeMux,prefix string,staticDir string,flags int ){
    mux.HandleFunc( prefix,func( w http.ResponseWriter,r *http.Request) {
        file := staticDir + r.URL.Path[len( prefix )-1:]
        if( flags & ListDir )== 0{
            if exists := isExists( file );!exists{
                http.NotFound( w,r )
                return
            }
        }
        http.ServeFile( w,r,file )
    })
}

func main(){
    mux := http.NewServeMux()
    staticDirHandler( mux,"/assets/","./public",0 )
    mux.HandleFunc("/",safeHandler(listHandler))
    mux.HandleFunc("/view",safeHandler(  viewHandler ))
    mux.HandleFunc("/upload",safeHandler( uploadHandler ))
    err := http.ListenAndServe( ":8080",mux )
    if err != nil {
        log.Fatal( "ListenAndServe: ",err.Error() )
    }
}