1 Star 0 Fork 0

g-devops/forms

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
data.go 10.30 KB
一键复制 编辑 原始数据 按行查看 历史
Sam@host-20089 提交于 4年前 . +GetFileReader
// Copyright 2015 Alex Browne. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.
package forms
import (
"encoding/json"
"fmt"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"strconv"
"strings"
"io"
)
// DefaultMaxFormSize is the default maximum form size (in bytes) used by the Parse function.
const DefaultMaxFormSize = 500000
// Data holds data obtained from the request body and url query parameters.
// Because Data is built from multiple sources, sometimes there will be more
// than one value for a given key. You can use Get, Set, Add, and Del to access
// the first element for a given key or access the Values and Files properties directly
// to access additional elements for a given key. You can also use helper methods to convert
// the first value for a given key to a different type (e.g. bool or int).
type Data struct {
// Values holds any basic key-value string data
// This includes all fields from a json body or
// urlencoded form, and the form fields only (not
// files) from a multipart form
Values url.Values
// Files holds files from a multipart form only.
// For any other type of request, it will always
// be empty. Files only supports one file per key,
// since this is by far the most common use. If you
// need to have more than one file per key, parse the
// files manually using req.MultipartForm.File.
Files map[string]*multipart.FileHeader
// jsonBody holds the original body of the request.
// Only available for json requests.
jsonBody []byte
}
func newData() *Data {
return &Data{
Values: url.Values{},
Files: map[string]*multipart.FileHeader{},
}
}
// ParseMax parses the request body and url query parameters into
// Data. The content in the body of the request has a higher priority,
// will be added to Data first, and will be the result of any operation
// which gets the first element for a given key (e.g. Get, GetInt, or GetBool).
func ParseMax(req *http.Request, max int64) (*Data, error) {
data := newData()
contentType := req.Header.Get("Content-Type")
if strings.Contains(contentType, "multipart/form-data") {
if err := req.ParseMultipartForm(max); err != nil {
return nil, err
}
for key, vals := range req.MultipartForm.Value {
for _, val := range vals {
data.Add(key, val)
}
}
for key, files := range req.MultipartForm.File {
if len(files) != 0 {
data.AddFile(key, files[0])
}
}
} else if strings.Contains(contentType, "form-urlencoded") {
if err := req.ParseForm(); err != nil {
return nil, err
}
for key, vals := range req.PostForm {
for _, val := range vals {
data.Add(key, val)
}
}
} else if strings.Contains(contentType, "application/json") {
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return nil, err
}
data.jsonBody = body
if err := parseJSON(data.Values, data.jsonBody); err != nil {
return nil, err
}
}
for key, vals := range req.URL.Query() {
for _, val := range vals {
data.Add(key, val)
}
}
return data, nil
}
// Parse uses the default max form size defined above and calls ParseMax
func Parse(req *http.Request) (*Data, error) {
return ParseMax(req, DefaultMaxFormSize)
}
// CreateFromMap returns a Data object with keys and values matching
// the map.
func CreateFromMap(m map[string]string) *Data {
data := newData()
for key, value := range m {
data.Add(key, value)
}
return data
}
func parseJSON(values url.Values, body []byte) error {
if len(body) == 0 {
// don't attempt to parse empty bodies
return nil
}
rawData := map[string]interface{}{}
if err := json.Unmarshal(body, &rawData); err != nil {
return err
}
// Whatever the underlying type is, we need to convert it to a
// string. There are only a few possible types, so we can just
// do a type switch over the possibilities.
for key, val := range rawData {
switch val.(type) {
case string, bool, float64:
values.Add(key, fmt.Sprint(val))
case nil:
values.Add(key, "")
case map[string]interface{}, []interface{}:
// for more complicated data structures, convert back to
// a JSON string and let user decide how to unmarshal
jsonVal, err := json.Marshal(val)
if err != nil {
return err
}
values.Add(key, string(jsonVal))
}
}
return nil
}
// Add adds the value to key. It appends to any existing values associated with key.
func (d *Data) Add(key string, value string) {
d.Values.Add(key, value)
}
// AddFile adds the multipart form file to data with the given key.
func (d *Data) AddFile(key string, file *multipart.FileHeader) {
d.Files[key] = file
}
// Del deletes the values associated with key.
func (d *Data) Del(key string) {
d.Values.Del(key)
}
// DelFile deletes the file associated with key (if any).
// If there is no file associated with key, it does nothing.
func (d *Data) DelFile(key string) {
delete(d.Files, key)
}
// Encode encodes the values into “URL encoded” form ("bar=baz&foo=quux") sorted by key.
// Any files in d will be ignored because there is no direct way to convert a file to a
// URL encoded value.
func (d *Data) Encode() string {
return d.Values.Encode()
}
// Get gets the first value associated with the given key. If there are no values
// associated with the key, Get returns the empty string. To access multiple values,
// use the map directly.
func (d Data) Get(key string) string {
return d.Values.Get(key)
}
// GetFile returns the multipart form file associated with key, if any, as a *multipart.FileHeader.
// If there is no file associated with key, it returns nil. If you just want the body of the
// file, use GetFileBytes.
func (d Data) GetFile(key string) *multipart.FileHeader {
return d.Files[key]
}
// Set sets the key to value. It replaces any existing values.
func (d *Data) Set(key string, value string) {
d.Values.Set(key, value)
}
// KeyExists returns true iff data.Values[key] exists. When parsing a request body, the key
// is considered to be in existence if it was provided in the request body, even if its value
// is empty.
func (d Data) KeyExists(key string) bool {
_, found := d.Values[key]
return found
}
// FileExists returns true iff data.Files[key] exists. When parsing a request body, the key
// is considered to be in existence if it was provided in the request body, even if the file
// is empty.
func (d Data) FileExists(key string) bool {
_, found := d.Files[key]
return found
}
// GetInt returns the first element in data[key] converted to an int.
func (d Data) GetInt(key string) int {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return 0
}
str := d.Get(key)
if result, err := strconv.Atoi(str); err != nil {
panic(err)
} else {
return result
}
}
// GetFloat returns the first element in data[key] converted to a float.
func (d Data) GetFloat(key string) float64 {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return 0.0
}
str := d.Get(key)
if result, err := strconv.ParseFloat(str, 64); err != nil {
panic(err)
} else {
return result
}
}
// GetBool returns the first element in data[key] converted to a bool.
func (d Data) GetBool(key string) bool {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return false
}
str := d.Get(key)
if result, err := strconv.ParseBool(str); err != nil {
panic(err)
} else {
return result
}
}
// GetBytes returns the first element in data[key] converted to a slice of bytes.
func (d Data) GetBytes(key string) []byte {
return []byte(d.Get(key))
}
// GetFileBytes returns the body of the file associated with key. If there is no
// file associated with key, it returns nil (not an error). It may return an error if
// there was a problem reading the file. If you need to know whether or not the file
// exists (i.e. whether it was provided in the request), use the FileExists method.
func (d Data) GetFileBytes(key string) ([]byte, error) {
fileHeader, found := d.Files[key]
if !found {
return nil, nil
} else {
file, err := fileHeader.Open()
if err != nil {
return nil, err
}
return ioutil.ReadAll(file)
}
}
//sam add //https://blog.csdn.net/weixin_42681695/article/details/106579169
func (d Data) GetFileReader(key string) (io.Reader, error) {
fileHeader, found := d.Files[key]
if !found {
return nil, nil
} else {
file, err := fileHeader.Open()
if err != nil {
return nil, err
}
return file, nil
}
}
// GetStringsSplit returns the first element in data[key] split into a slice delimited by delim.
func (d Data) GetStringsSplit(key string, delim string) []string {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return nil
}
return strings.Split(d.Values[key][0], delim)
}
// BindJSON binds v to the json data in the request body. It calls json.Unmarshal and
// sets the value of v.
func (d Data) BindJSON(v interface{}) error {
if len(d.jsonBody) == 0 {
return nil
}
return json.Unmarshal(d.jsonBody, v)
}
// GetMapFromJSON assumes that the first element in data[key] is a json string, attempts to
// unmarshal it into a map[string]interface{}, and if successful, returns the result. If
// unmarshaling was not successful, returns an error.
func (d Data) GetMapFromJSON(key string) (map[string]interface{}, error) {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return nil, nil
}
result := map[string]interface{}{}
if err := json.Unmarshal([]byte(d.Get(key)), &result); err != nil {
return nil, err
} else {
return result, nil
}
}
// GetSliceFromJSON assumes that the first element in data[key] is a json string, attempts to
// unmarshal it into a []interface{}, and if successful, returns the result. If unmarshaling
// was not successful, returns an error.
func (d Data) GetSliceFromJSON(key string) ([]interface{}, error) {
if !d.KeyExists(key) || len(d.Values[key]) == 0 {
return nil, nil
}
result := []interface{}{}
if err := json.Unmarshal([]byte(d.Get(key)), &result); err != nil {
return nil, err
} else {
return result, nil
}
}
// GetAndUnmarshalJSON assumes that the first element in data[key] is a json string and
// attempts to unmarshal it into v. If unmarshaling was not successful, returns an error.
// v should be a pointer to some data structure.
func (d Data) GetAndUnmarshalJSON(key string, v interface{}) error {
if err := json.Unmarshal([]byte(d.Get(key)), v); err != nil {
return err
}
return nil
}
// Validator returns a Validator which can be used to easily validate data.
func (d *Data) Validator() *Validator {
return &Validator{
data: d,
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/g-devops/forms.git
git@gitee.com:g-devops/forms.git
g-devops
forms
forms
v0.3.4

搜索帮助