You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot如何动态处理Setter/Getter字段名(动态月份场景)

解决方案

针对动态月份字段的序列化问题,推荐两种可行实现方案:

方案1:使用HashMap直接处理(快速实现)

这种方式无需定义实体类,直接用Map存储固定字段和动态字段,Spring会自动完成JSON序列化。

ServiceImpl层代码

@Service
public class UserRecordServiceImpl implements UserRecordService {
    @Autowired
    private UserRecordMapper userRecordMapper;

    @Override
    public List<Map<String, Object>> getRecentSixMonthsRecords() {
        // 计算近6个月的时间范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusMonths(6);
        
        // 从数据库查询记录(MyBatis直接返回List<Map>即可)
        List<Map<String, Object>> dbRecords = userRecordMapper.selectRecentSixMonthsRecords(startDate, endDate);
        
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map<String, Object> record : dbRecords) {
            Map<String, Object> resultMap = new HashMap<>();
            // 存入固定字段
            resultMap.put("userName", record.get("user_name"));
            resultMap.put("userEmail", record.get("user_email"));
            
            // 处理动态月份字段:将数据库返回的月份编码转换为英文名称
            for (Map.Entry<String, Object> entry : record.entrySet()) {
                String dbKey = entry.getKey();
                if (dbKey.startsWith("month_")) {
                    // 解析月份编码(例如month_202401 -> 202401)
                    String monthCode = dbKey.substring(6);
                    YearMonth yearMonth = YearMonth.parse(monthCode, DateTimeFormatter.ofPattern("yyyyMM"));
                    // 转换为英文月份名称(如January)
                    String monthName = yearMonth.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH);
                    resultMap.put(monthName, entry.getValue());
                }
            }
            resultList.add(resultMap);
        }
        return resultList;
    }
}

Controller层代码

@RestController
@RequestMapping("/user/records")
public class UserRecordController {
    @Autowired
    private UserRecordService userRecordService;

    @GetMapping("/recent-six-months")
    public ResponseEntity<List<Map<String, Object>>> getRecentSixMonthsRecords() {
        List<Map<String, Object>> records = userRecordService.getRecentSixMonthsRecords();
        return ResponseEntity.ok(records);
    }
}

方案2:自定义实体类结合Jackson注解(规范可扩展)

通过@JsonAnyGetter和@JsonAnySetter注解,让实体类支持动态字段的序列化与反序列化,同时保留固定字段的类型安全。

自定义实体类

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.util.HashMap;
import java.util.Map;

public class UserMonthRecord {
    // 固定字段
    private String userName;
    private String userEmail;
    // 存储动态月份字段的容器
    private Map<String, Object> dynamicMonthFields = new HashMap<>();

    // 固定字段的Getter/Setter
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    // 动态字段的序列化注解:将Map中的键值对作为顶级字段输出
    @JsonAnyGetter
    public Map<String, Object> getDynamicMonthFields() {
        return dynamicMonthFields;
    }

    // 动态字段的反序列化注解:接收任意未知字段并存入Map
    @JsonAnySetter
    public void setDynamicMonthField(String key, Object value) {
        this.dynamicMonthFields.put(key, value);
    }
}

ServiceImpl层代码

@Service
public class UserRecordServiceImpl implements UserRecordService {
    @Autowired
    private UserRecordMapper userRecordMapper;

    @Override
    public List<UserMonthRecord> getRecentSixMonthsRecords() {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusMonths(6);
        List<Map<String, Object>> dbRecords = userRecordMapper.selectRecentSixMonthsRecords(startDate, endDate);
        
        List<UserMonthRecord> resultList = new ArrayList<>();
        for (Map<String, Object> record : dbRecords) {
            UserMonthRecord userRecord = new UserMonthRecord();
            // 设置固定字段
            userRecord.setUserName((String) record.get("user_name"));
            userRecord.setUserEmail((String) record.get("user_email"));
            
            // 存入动态月份字段
            for (Map.Entry<String, Object> entry : record.entrySet()) {
                String dbKey = entry.getKey();
                if (dbKey.startsWith("month_")) {
                    String monthCode = dbKey.substring(6);
                    YearMonth yearMonth = YearMonth.parse(monthCode, DateTimeFormatter.ofPattern("yyyyMM"));
                    String monthName = yearMonth.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH);
                    userRecord.setDynamicMonthField(monthName, entry.getValue());
                }
            }
            resultList.add(userRecord);
        }
        return resultList;
    }
}

Controller层代码

@RestController
@RequestMapping("/user/records")
public class UserRecordController {
    @Autowired
    private UserRecordService userRecordService;

    @GetMapping("/recent-six-months")
    public ResponseEntity<List<UserMonthRecord>> getRecentSixMonthsRecords() {
        List<UserMonthRecord> records = userRecordService.getRecentSixMonthsRecords();
        return ResponseEntity.ok(records);
    }
}

方案对比

  • 方案1:无需额外定义类,实现成本低,适合快速开发;缺点是缺乏类型安全,后续维护难度稍高。
  • 方案2:保留固定字段的类型检查,扩展性更强,适合需要长期维护或后续可能增加固定字段的场景。

内容的提问来源于stack exchange,提问作者Hanufa Hannan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 16:39:18