1、代码结构
2、运行实例
1、代码结构
$ tree
.
├── photoweb.go
├── public
│ ├── css
│ ├── images
│ └── js
├── uploads
└── views
├── list.html
└── upload.html
1.1)photoweb.go
1 package main 2 3 import ( 4 "io" 5 "os" 6 "log" 7 "net/http" 8 "io/ioutil" 9 "html/template" 10 "path" 11 //"debug" 12 "fmt" 13 ) 14 15 const ( 16 UPLOAD_DIR = "./uploads" 17 TEMPLATE_DIR = "./views" 18 ListDir = 0x0001 19 ) 20 21 var templates map[string] * template.Template = make(map[string] * template.Template) 22 23 func init() { 24 fileInfoArr, err := ioutil.ReadDir(TEMPLATE_DIR) 25 check(err) 26 27 var templateName, templatePath string 28 for _, fileInfo := range fileInfoArr { 29 templateName = fileInfo.Name() 30 if ext := path.Ext(templateName); ext != ".html" { 31 continue 32 } 33 templatePath = TEMPLATE_DIR + "/" + templateName; 34 t := template.Must(template.ParseFiles(templatePath)) 35 rlname := realName(templateName) 36 log.Println("Loading template:", rlname) 37 templates[rlname] = t 38 } 39 } 40 41 func realName(str string) string { 42 str = path.Base(str) 43 if str == "" { 44 return str 45 } 46 for i := 0; i < len(str); i++ { 47 if \'.\' == str[i] { 48 return str[:i] 49 } 50 } 51 return str 52 } 53 54 func uploadHandler(w http.ResponseWriter, r * http.Request) { 55 if r.Method == "GET" { 56 readerHtml(w, "upload", nil); 57 } 58 59 if r.Method == "POST" { 60 f, h , err := r.FormFile("image") 61 if err != nil { 62 http.Error(w, err.Error(), 63 http.StatusInternalServerError) 64 return 65 } 66 filename := h.Filename 67 defer f.Close() 68 t, err := os.Create(UPLOAD_DIR + "/" + filename) 69 if err != nil { 70 http.Error(w, err.Error(), 71 http.StatusInternalServerError) 72 return 73 } 74 defer t.Close() 75 if _, err := io.Copy(t, f); err != nil { 76 http.Error(w, err.Error(), 77 http.StatusInternalServerError) 78 return 79 } 80 http.Redirect(w, r, "/view?id="+filename, 81 http.StatusFound) 82 } 83 } 84 85 func viewHandler(w http.ResponseWriter, r * http.Request) { 86 imageId := r.FormValue("id") 87 imagePath := UPLOAD_DIR + "/" + imageId 88 if exists := isExists(imagePath); !exists { 89 http.NotFound(w, r) 90 return 91 } 92 w.Header().Set("Content-Type", "image") 93 http.ServeFile(w, r, imagePath) 94 } 95 96 func isExists(path string) bool { 97 _, err := os.Stat(path) 98 if err == nil { 99 return true 100 } 101 return os.IsExist(err) 102 } 103 104 func listHandler(w http.ResponseWriter, r * http.Request) { 105 fileInfoArr, err := ioutil.ReadDir("./uploads") 106 if err != nil { 107 http.Error(w, err.Error(), 108 http.StatusInternalServerError) 109 fmt.Println("faild @ listHandler") 110 return 111 } 112 113 locals := make(map[string]interface{}) 114 images := []string{} 115 for _, fileInfo := range fileInfoArr { 116 if fileInfo.Name() != ".svn" { 117 images = append(images, fileInfo.Name()) 118 } 119 } 120 locals["images"] = images 121 122 readerHtml(w, "list", locals); 123 } 124 125 func readerHtml(w http.ResponseWriter, tmpl string, locals map[string]interface{}){ 126 err := templates[tmpl].Execute(w, locals) 127 check(err) 128 } 129 130 func check(err error) { 131 if err != nil { 132 panic(err) 133 } 134 } 135 136 func safeHandler(fn http.HandlerFunc) http.HandlerFunc { 137 return func(w http.ResponseWriter, r * http.Request) { 138 defer func() { 139 if e , ok := recover().(error); ok { 140 http.Error(w, e.Error(), http.StatusInternalServerError) 141 log.Println("WARN: panic in %v - %v", fn, e) 142 // log.Println(string(debug.Stack())) 143 } 144 }() 145 fn(w, r) 146 } 147 } 148 149 func staticDirHandler(mux * http.ServeMux, prefix string, staticDir string, flags int) { 150 mux.HandleFunc(prefix, func(w http.ResponseWriter, r * http.Request) { 151 file := staticDir + r.URL.Path[len(prefix) - 1:] 152 if (flags & ListDir) == 0 { 153 if exists := isExists(file); !exists { 154 http.NotFound(w, r) 155 fmt.Println(file, "not found") 156 return 157 } 158 } 159 fmt.Println("handle static dir") 160 http.ServeFile(w, r, file) 161 }) 162 } 163 164 func main() { 165 mux := http.NewServeMux() 166 staticDirHandler(mux, "/assets/", "./public", 0) 167 mux.HandleFunc("/", safeHandler(listHandler)) 168 mux.HandleFunc("/view", safeHandler(viewHandler)) 169 mux.HandleFunc("/upload", safeHandler(uploadHandler)) 170 err := http.ListenAndServe(":8090", mux) 171 if err != nil { 172 log.Fatal("ListenAndServe: ", err.Error()) 173 } 174 }
1.2)views/list.html
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>List</title> 6 </head> 7 <body> 8 <ol> 9 {{range $.images}} 10 <li><a href="/view?id={{.|urlquery}}">{{.|html}}</a></li> 11 {{end}} 12 </ol> 13 </body> 14 </html>
1.3)views/upload.html
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>Upload</title> 6 </head> 7 <body> 8 <form method="POST" action="/upload" enctype="multipart/form-data"> 9 Choose an image to upload: <input name="image" type="file" /> 10 <input type="submit" value="Upload" /> 11 </form> 12 </body> 13 </html>
2、运行及结果
2.1)运行
$ go run photoweb.go
2015/07/25 02:15:24 Loading template: list
2015/07/25 02:15:24 Loading template: upload
2.2)在浏览器端输入服务器地址