assign_struct.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. package tag
  2. import (
  3. "git.sxidc.com/go-framework/baize/infrastructure/logger"
  4. "git.sxidc.com/go-tools/utils/reflectutils"
  5. "git.sxidc.com/go-tools/utils/strutils"
  6. "git.sxidc.com/service-supports/fserr"
  7. "reflect"
  8. "strings"
  9. "time"
  10. )
  11. type OnAssignParsedFieldTagFunc func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error
  12. func AssignTo(from any, to any) error {
  13. return CustomAssignTo(from, to, func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error {
  14. if fromFieldElemValue.IsZero() {
  15. return nil
  16. }
  17. return assignField(fromFieldElemValue, retFieldElementValue, tag)
  18. })
  19. }
  20. func CustomAssignTo(from any, to any, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
  21. if from == nil || to == nil {
  22. return nil
  23. }
  24. fromValue := reflect.ValueOf(from)
  25. retValue := reflect.ValueOf(to)
  26. // 类型校验
  27. if !reflectutils.IsValueStructOrStructPointer(fromValue) {
  28. return fserr.New("参数不是结构或结构指针")
  29. }
  30. if !reflectutils.IsValueStructPointer(retValue) {
  31. return fserr.New("返回类型不是结构指针")
  32. }
  33. fromElemValue := reflectutils.PointerValueElem(fromValue)
  34. retElemValue := reflectutils.PointerValueElem(retValue)
  35. for i := 0; i < retElemValue.NumField(); i++ {
  36. retField := retElemValue.Field(i)
  37. if !retField.IsValid() {
  38. return fserr.New("被赋值的结构存在无效字段")
  39. }
  40. // 初始化空值指针
  41. if retField.Kind() == reflect.Ptr && retField.IsNil() {
  42. retField.Set(reflect.New(retField.Type().Elem()))
  43. }
  44. }
  45. err := parseStructAssignTag(fromElemValue, &retElemValue, onParsedFieldTagFunc)
  46. if err != nil {
  47. return err
  48. }
  49. return nil
  50. }
  51. func assignField(fromFieldElemValue reflect.Value, retFieldElemValue reflect.Value, tag *AssignTag) error {
  52. fromKind := reflectutils.GroupValueKind(fromFieldElemValue)
  53. retKind := reflectutils.GroupValueKind(retFieldElemValue)
  54. var fromAny any
  55. switch fromKind {
  56. case reflect.Struct:
  57. // time.Time类型的结构,接收字段是string类型,使用FormatTime的格式转换
  58. if reflectutils.IsValueTime(fromFieldElemValue) && retKind == reflect.String {
  59. fromString := fromFieldElemValue.Interface().(time.Time).Format(tag.FormatTime)
  60. fromAny = assignTrimFromString(fromString, tag)
  61. break
  62. }
  63. // 不是time.Time类型的结构,接收字段是结构,执行结构到结构字段的赋值
  64. if !reflectutils.IsValueTime(fromFieldElemValue) && retKind == reflect.Struct {
  65. return parseStructAssignTag(fromFieldElemValue, &retFieldElemValue, func(fromFieldName string, fromFieldElemValue reflect.Value, retFieldElementValue reflect.Value, tag *AssignTag) error {
  66. return assignField(fromFieldElemValue, retFieldElementValue, tag)
  67. })
  68. }
  69. // 直接将整个结构进行字段赋值
  70. fromAny = fromFieldElemValue.Interface()
  71. case reflect.Slice:
  72. if reflectutils.IsSliceValueOf(fromFieldElemValue, reflect.String) && retKind == reflect.String {
  73. fromString := strings.Join(fromFieldElemValue.Interface().([]string), tag.JoinWith)
  74. fromAny = assignTrimFromString(fromString, tag)
  75. break
  76. }
  77. fromAny = fromFieldElemValue.Interface()
  78. case reflect.String:
  79. fromString := fromFieldElemValue.String()
  80. if reflectutils.IsValueTime(retFieldElemValue) {
  81. retTimeField, err := time.ParseInLocation(tag.ParseTime, fromString, time.Local)
  82. if err != nil {
  83. return err
  84. }
  85. fromAny = retTimeField
  86. break
  87. }
  88. if reflectutils.IsSliceValueOf(retFieldElemValue, reflect.String) {
  89. fromAny = strings.Split(fromString, tag.SplitWith)
  90. break
  91. }
  92. fromAny = assignTrimFromString(fromString, tag)
  93. default:
  94. fromAny = fromFieldElemValue.Interface()
  95. }
  96. switch retKind {
  97. case reflect.Int64:
  98. return reflectutils.AssignInt64Value(fromAny, retFieldElemValue)
  99. case reflect.Uint64:
  100. return reflectutils.AssignUint64Value(fromAny, retFieldElemValue)
  101. case reflect.Float64:
  102. return reflectutils.AssignFloat64Value(fromAny, retFieldElemValue)
  103. case reflect.Bool:
  104. return reflectutils.AssignBoolValue(fromAny, retFieldElemValue)
  105. case reflect.String:
  106. return reflectutils.AssignStringValue(fromAny, retFieldElemValue)
  107. default:
  108. retFieldElemValue.Set(reflect.ValueOf(fromAny))
  109. return nil
  110. }
  111. }
  112. func assignTrimFromString(fromString string, tag *AssignTag) string {
  113. if strutils.IsStringNotEmpty(tag.Trim) {
  114. return strings.Trim(fromString, tag.Trim)
  115. } else {
  116. if strutils.IsStringNotEmpty(tag.TrimPrefix) {
  117. return strings.TrimPrefix(fromString, tag.TrimPrefix)
  118. }
  119. if strutils.IsStringNotEmpty(tag.TrimSuffix) {
  120. return strings.TrimSuffix(fromString, tag.TrimSuffix)
  121. }
  122. }
  123. return fromString
  124. }
  125. func parseStructAssignTag(fromElemValue reflect.Value, retElemValue *reflect.Value, onParsedFieldTagFunc OnAssignParsedFieldTagFunc) error {
  126. for i := 0; i < fromElemValue.NumField(); i++ {
  127. fromField := fromElemValue.Type().Field(i)
  128. fromFieldValue := fromElemValue.Field(i)
  129. // 无效值
  130. if !fromFieldValue.IsValid() {
  131. continue
  132. }
  133. if fromFieldValue.Kind() == reflect.Pointer && fromFieldValue.IsNil() {
  134. fromFieldValue.Set(reflect.New(fromField.Type.Elem()))
  135. }
  136. fromFieldElemValue := reflectutils.PointerValueElem(fromFieldValue)
  137. tagStr := fromField.Tag.Get(assignTagKey)
  138. // 结构类型的字段上没有添加Tag, 先尝试直接按照字段赋值
  139. if strutils.IsStringEmpty(tagStr) && fromFieldElemValue.Kind() == reflect.Struct &&
  140. !reflectutils.IsValueTime(fromFieldElemValue) {
  141. err := parseStructAssignTag(fromFieldElemValue, retElemValue, onParsedFieldTagFunc)
  142. if err != nil {
  143. return err
  144. }
  145. continue
  146. }
  147. tag, err := parseAssignTag(fromField, tagStr)
  148. if err != nil {
  149. return err
  150. }
  151. if tag == nil {
  152. continue
  153. }
  154. retFieldValue := retElemValue.FieldByName(tag.ToField)
  155. // 不存在对应的字段
  156. if !retFieldValue.IsValid() {
  157. continue
  158. }
  159. retFieldElemValue := retFieldValue
  160. if retFieldValue.Kind() == reflect.Pointer {
  161. if !retFieldValue.IsValid() {
  162. continue
  163. }
  164. if !retFieldValue.CanSet() {
  165. continue
  166. }
  167. // 空值针,初始化
  168. if retFieldValue.IsNil() {
  169. retFieldValue.Set(reflect.New(retFieldValue.Type().Elem()))
  170. }
  171. retFieldElemValue = retFieldValue.Elem()
  172. }
  173. err = onParsedFieldTagFunc(fromField.Name, fromFieldElemValue, retFieldElemValue, tag)
  174. if err != nil {
  175. return err
  176. }
  177. }
  178. return nil
  179. }
  180. const (
  181. assignDefaultStringSliceSeparator = "::"
  182. assignTagPartSeparator = ";"
  183. assignTagPartKeyValueSeparator = ":"
  184. )
  185. const (
  186. assignTagKey = "assign"
  187. assignIgnore = "-"
  188. assignToField = "toField"
  189. assignParseTime = "parseTime"
  190. assignFormatTime = "formatTime"
  191. assignJoinWith = "joinWith"
  192. assignSplitWith = "splitWith"
  193. assignTrim = "trim"
  194. assignTrimPrefix = "trimPrefix"
  195. assignTrimSuffix = "trimSuffix"
  196. )
  197. type AssignTag struct {
  198. ToField string
  199. ParseTime string
  200. FormatTime string
  201. JoinWith string
  202. SplitWith string
  203. Trim string
  204. TrimPrefix string
  205. TrimSuffix string
  206. }
  207. func parseAssignTag(field reflect.StructField, tagStr string) (*AssignTag, error) {
  208. if tagStr == assignIgnore {
  209. return nil, nil
  210. }
  211. tag := &AssignTag{
  212. ToField: field.Name,
  213. ParseTime: time.DateTime,
  214. FormatTime: time.DateTime,
  215. JoinWith: assignDefaultStringSliceSeparator,
  216. SplitWith: assignDefaultStringSliceSeparator,
  217. Trim: "",
  218. TrimPrefix: "",
  219. TrimSuffix: "",
  220. }
  221. if strutils.IsStringEmpty(tagStr) {
  222. return tag, nil
  223. }
  224. assignParts := strings.Split(tagStr, assignTagPartSeparator)
  225. if assignParts != nil || len(assignParts) != 0 {
  226. for _, assignPart := range assignParts {
  227. assignPartKeyValue := strings.SplitN(strings.TrimSpace(assignPart), assignTagPartKeyValueSeparator, 2)
  228. if assignPartKeyValue != nil && len(assignPartKeyValue) == 2 && strutils.IsStringNotEmpty(assignPartKeyValue[1]) {
  229. assignPartKeyValue[1] = strings.Trim(assignPartKeyValue[1], "'")
  230. }
  231. switch assignPartKeyValue[0] {
  232. case assignToField:
  233. tag.ToField = assignPartKeyValue[1]
  234. case assignParseTime:
  235. tag.ParseTime = assignPartKeyValue[1]
  236. case assignFormatTime:
  237. tag.FormatTime = assignPartKeyValue[1]
  238. case assignJoinWith:
  239. if strutils.IsStringEmpty(assignPartKeyValue[1]) {
  240. return nil, fserr.New(assignJoinWith + "没有赋值分隔符")
  241. }
  242. tag.JoinWith = assignPartKeyValue[1]
  243. case assignSplitWith:
  244. if strutils.IsStringEmpty(assignPartKeyValue[1]) {
  245. return nil, fserr.New(assignSplitWith + "没有赋值分隔符")
  246. }
  247. tag.SplitWith = assignPartKeyValue[1]
  248. case assignTrim:
  249. tag.Trim = assignPartKeyValue[1]
  250. case assignTrimPrefix:
  251. tag.TrimPrefix = assignPartKeyValue[1]
  252. case assignTrimSuffix:
  253. tag.TrimSuffix = assignPartKeyValue[1]
  254. default:
  255. err := fserr.New(assignTagKey + "不支持的tag: " + assignPartKeyValue[0])
  256. logger.GetInstance().Error(err)
  257. continue
  258. }
  259. }
  260. }
  261. return tag, nil
  262. }