/** * 创建结构体递归遍历子字段操作 * * @param structV 递归操作字段 * @param joinFieldName 字段连接名 * @param arraySizeMap 解析后的集合数量设值map */ func parampackNewStructFindFiled(structV reflect.Value, joinFieldName string, arraySizeMap map[string]int) { structV = reflect.Indirect(structV) if reflect.Struct != structV.Kind() { return } // 遍历结构字段寻找需要初始化的slice filedCount := structV.NumField() for i := 0; i < filedCount; i++ { childField := structV.Field(i) childFieldType := childField.Type() childFieldName := structV.Type().Field(i).Name if !childField.CanSet() { continue } if 0 != len(joinFieldName) && '.' != joinFieldName[len(joinFieldName)-1] { joinFieldName += "." } if reflect.Ptr == childFieldType.Kind() && childField.IsNil() { // 初始化子结构指针的操作 childField.Set(reflect.New(childField.Type().Elem())) } switch reflect.Indirect(childField).Kind() { case reflect.Struct: if !parampackFilterParamPackStructType(childField.Type()) { parampackNewStructFindFiled(childField, joinFieldName+childFieldName, arraySizeMap) } case reflect.Slice: tempJoinName := joinFieldName + childFieldName if sliceSize, ok := arraySizeMap[strings.ToLower(tempJoinName)]; ok { valueElem := reflect.Indirect(childField) valueElem.Set(reflect.MakeSlice(valueElem.Type(), sliceSize, sliceSize)) // 继续执行集合子元素的遍历 if !parampackFilterParamPackStructType(valueElem.Type()) { for j := 0; j < sliceSize; j++ { childIndex := valueElem.Index(j) if reflect.Ptr == childIndex.Kind() && childIndex.IsNil() { // 初始化子元素指针的操作 childIndex.Set(reflect.New(childIndex.Type().Elem())) } // 当前由于是数组类型,所以传递连接名的时候加上"[index]"下标往下进行操作 tempJoinName = joinFieldName + childFieldName + "[" + strconv.Itoa(j) + "]" parampackNewStructFindFiled(childIndex, tempJoinName, arraySizeMap) } } } } } }
/** * 针对字段进行设值 * * @param fieldValue 字段反射对象 * @param fieldName 字段名,以便递归寻找下个设值字段 * @param fieldSplitName 字段名分割集合,以"."进行分割,主要是为了递归子字段进行拼接传递 * @param value 设置值 */ func parampackSetFieldValue(fieldValue reflect.Value, fieldName string, fieldSplitName []string, value interface{}) { if fieldValue.IsValid() { // 为递归下一个参数做准备,保留后面的参数名(tag.TagName) isRec := false joinLaterFieldName := "" if 1 < len(fieldSplitName) { joinLaterFieldName = strings.Join(fieldSplitName[1:], ".") isRec = true // 进入这里表明还需要进行一次字段查询,所以需要进行递归操作,直到截取到最后一位的参数名标识(TagName) } switch fieldValue.Kind() { case reflect.Ptr: if fieldValue.IsNil() { fieldValue.Set(reflect.New(fieldValue.Type().Elem())) } // 指针与非指针区分开,主要是在进行参数设值的时候对应与设置值相同的类型,减免指针的过多操作。 switch fieldValue.Elem().Kind() { case reflect.Struct: if isRec && !parampackFilterParamPackStructType(fieldValue.Type().Elem()) { parampackSetStructFieldValue(fieldValue, joinLaterFieldName, value) } else { parampackSetParamValue(fieldValue, fieldName, value) } case reflect.Slice: // 如果属于切片类型,传递fieldName主要是在操作一遍集合元素的赋值,因为不是结构类型无需再向下查找 parampackSetStructFieldValue(fieldValue, fieldName, value) default: parampackSetParamValue(fieldValue, fieldName, value) } case reflect.Struct: if isRec && !parampackFilterParamPackStructType(fieldValue.Type()) { parampackSetStructFieldValue(fieldValue, joinLaterFieldName, value) } else { // 如果检测的是系统或则非用户定义的struct就可以直接赋值了,赋值那里已经做了匹配类型才进行赋值的处理 parampackSetParamValue(fieldValue, fieldName, value) } case reflect.Slice: parampackSetStructFieldValue(fieldValue, fieldName, value) default: parampackSetParamValue(fieldValue, fieldName, value) } } }
/** * 根据url和form参数信息创建一个struct体,如果存在集合结构会根据form参数信息make分配切片大小。 * * @param structType 需要操作的的结构 * @param urlValues url或form请求参数(主要为了操作slice的创建元素) * @return 返回创建好的函数反射对象信息(指针类型的) */ func parampackNewStructPtr(structType reflect.Type, urlValues url.Values) reflect.Value { // 考虑到结构内包含指针,如果不进行new的话直接(.)会爆出空指针异常,所以这里需要遍历每个对象 if structType.Kind() != reflect.Struct { return reflect.Zero(structType) } structValue := reflect.New(structType) if 0 == len(urlValues) { return structValue } // begin 分析数组 TODO 需要调整集合下的集合 type[0].tmpe[0] arraySizeMap := make(map[string]int) // key = jsonfiledname ,value = array size for k, _ := range urlValues { // 存储(oneUser.hobbys.names)操作的连接名 如果存在集合则存储为key tempJoinName := "" fields := strings.Split(k, ".") for _, field := range fields { fieldLower := strings.ToLower(field) strIndex := _arrayTagRex.FindString(fieldLower) if 0 != len(strIndex) { intIndex, err := strconv.Atoi(strIndex[1 : len(strIndex)-1]) if nil == err { // 这里为key做准备 tempJoinName += fieldLower[:len(fieldLower)-len(strIndex)] // 由于下标是从0开始计算,所以需要+1作为 array size intIndex += 1 if sizeIndex, ok := arraySizeMap[tempJoinName]; ok { if sizeIndex < intIndex { arraySizeMap[tempJoinName] = intIndex } } else { arraySizeMap[tempJoinName] = intIndex } // 由于可能存在数组下还存在集合(temp[0].temp2[0]),所以继续累加"[index]."继续执行。 tempJoinName += strIndex + "." } else { // 进入到这部基本上是获取的 "[ 错误下标 ]" 才导致的,所欲当没有下标出现,继续累加 tempJoinName += fieldLower + "." } } else { tempJoinName += fieldLower + "." } } } // end 分析数组 // 执行递归子字段操作 parampackNewStructFindFiled(structValue, "", arraySizeMap) return structValue }