Revel json decode for param

本文介绍了一种在Revel框架中解析JSON参数的方法,通过自定义ActionInvoker来处理JSON格式的数据,实现对复杂结构的自动解析,提高了开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用ajax的风格,网页客户端使用json和服务器通讯,需要revel解析json格式的参数。在网上搜索,发现了一个很好的文章:http://leanote.com/blog/view/52da6ea9a3cf232efb000000

但是使用起来有两个顾虑:

1 文章里面使用的方式是直接更改revel的框架代码,以后revel升级之后需要merge。

2 在解析json的时候只将第一个参数解析,然后传给controller的方法,感觉不是很明白。


为了自己项目的需要,自己稍微修改了一下代码,可以达到下面这样的效果:

客户端发送数据按照标准的json格式:

{
  "param1":"hello",
  "param2": {"A":1, "B": "BBBB"}
}

服务器端,controllers/app.go的代码:

type TestStruct struct {
	A int
	B string
}

type App struct {
	GorpController
}

func (self *App) Start() {
}

func (self *App) Index(param1 string, param2 TestStruct) revel.Result {
	self.RetMap["param"] = param1
	self.RetMap["who"] = "me"
	self.RetMap["struct"] = param2
	return self.RetOk()
}

也就是Index方法里面有两个参数,一个string类型,一个是自定义的结构。不需要额外的处理就能获取参数。


修改方式是使用一个自定义的ActionInvoker:

func decodeJson(val interface{}, argType reflect.Type) (reflect.Value, bool) {
	var zero reflect.Value

	switch argType.Kind() {
	case reflect.Struct:
		valMap, ok := val.(map[string]interface{})
		if !ok {
			revel.ERROR.Println("param is not a struct:", val)
			return zero, false
		}

		ptr := reflect.New(argType)
		err := mapstructure.Decode(valMap, ptr.Interface())
		if nil != err {
			revel.ERROR.Println("map to structure error:", err)
		}

		return ptr.Elem(), true

	case reflect.Slice:
		valSlice, ok := val.([]interface{})
		if !ok {
			revel.ERROR.Println("param is not a slice:", val)
			return zero, false
		}

		retSlice := reflect.MakeSlice(argType, 0, 32)
		for _, v := range valSlice {
			item, ok := decodeJson(v, argType.Elem())
			if !ok {
				revel.ERROR.Println("slice item type error:", item)
				return zero, false
			}

			retSlice = reflect.Append(retSlice, item)
		}

		return retSlice, true

	default:
		return reflect.ValueOf(parser.BeSimpleType(val, argType.Kind())), true
	}

	return zero, false
}

func MyActionInvoker(c *revel.Controller, _ []revel.Filter) {
	// Instantiate the method.
	methodValue := reflect.ValueOf(c.AppController).MethodByName(c.MethodType.Name)

	var jsonMap map[string]interface{}
	beJson := false
	if strings.Contains(c.Request.ContentType, "application/json") {
		decoder := json.NewDecoder(c.Request.Body)
		err := decoder.Decode(&jsonMap)
		if nil != err {
			revel.ERROR.Println("json unmarshal error:", err)
			return
		}

		revel.INFO.Println("body:", jsonMap)

		beJson = true
	}

	// Collect the values for the method's arguments.
	var methodArgs []reflect.Value
	for _, arg := range c.MethodType.Args {
		// If they accept a websocket connection, treat that arg specially.
		var boundArg reflect.Value

		if beJson {
			item := jsonMap[arg.Name]
			ret, ok := decodeJson(item, arg.Type)
			if !ok {
				continue
			}

			boundArg = ret

		} else {
			if arg.Type == websocketType {
				boundArg = reflect.ValueOf(c.Request.Websocket)
			} else {
				boundArg = revel.Bind(c.Params, arg.Name, arg.Type)
			}
		}

		methodArgs = append(methodArgs, boundArg)
	}

	var resultValue reflect.Value
	if methodValue.Type().IsVariadic() {
		resultValue = methodValue.CallSlice(methodArgs)[0]
	} else {
		resultValue = methodValue.Call(methodArgs)[0]
	}
	if resultValue.Kind() == reflect.Interface && !resultValue.IsNil() {
		c.Result = resultValue.Interface().(revel.Result)
	}
}

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">实际上是原有的ActionInvoker修改了一下,在解析参数前判断content type是不是json格式的,如果是,则将json解析为map,然后分别判断map里面的字段,如果是结构体,使用一个开源的库mapstructure,将其解析到structure里面,如果是数组,则循环解析数组里面的内容,如果是string或者bool,则直接简单转换,如果是数字,则转换成float64之后在强制转换成其他数字类型。</span>

然后,在init.go里面,使用新建的这个函数替换原有函数:

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		//		revel.ActionInvoker,           // Invoke the action.
		plugins.MyActionInvoker, // Invoke the action.
	}

	// register startup functions with OnAppStart
	// ( order dependent )
	// revel.OnAppStart(InitDB)
	// revel.OnAppStart(FillCache)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值