assign.go 8.6 KB

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