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

如何用Java泛型编写通用用户活动追踪方法?

问题描述

原本编写了一个针对TemplateEntity的trackUserActivity方法,方法中调用了多个实体类都具备的getId()方法。为实现通用化,尝试创建包含默认方法的HistoryUtils泛型接口,但Autowired接口后调用方法时出现参数不匹配错误,报错信息翻译为:

类型HistoryUtils中的方法trackUserActivity(String, LavorazioneDto, String, String, HistoryJpaRepository)不适用于参数(String, TemplateEntity, String, String, HistoryJpaRepository)

原方法代码:

public void trackUserActivity(String operation,TemplateEntity templateEntity,String user,String entity, HistoryJpaRepository  historyJpaRepository)
{
            HistoryEntity historyEntity = new HistoryEntity();
            historyEntity.setData(new java.sql.Date(Calendar.getInstance().getTimeInMillis()));
            historyEntity.setAction(operation);
            historyEntity.setEntity("TEMPLATE");
            historyEntity.setEntityJson(null);
            if(!operation.contentEquals("CREATE"))
            {
                ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
                
                String json = null;
                try {
                    json = ow.writeValueAsString(templateEntity);
                } catch (JsonProcessingException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                historyEntity.setEntityJson(json.getBytes());  
       
          
            } 
            historyEntity.setIdEntity(templateEntity.getId());
            historyEntity.setUser(user);       
             historyJpaRepository.save(historyEntity);
     
}

尝试的泛型接口代码:

public interface HistoryUtils <T extends LavorazioneDto,DizionarioDto,CampoDizionarioDto,FontDto,RegolaCampoDizionarioDto,TemplateEntity >{
    
  
    
    
    
    public default void trackUserActivity(String operation,T t,String user,String entity, HistoryJpaRepository  historyJpaRepository)
    {
        HistoryEntity historyEntity = new HistoryEntity();
                historyEntity.setData(new java.sql.Date(Calendar.getInstance().getTimeInMillis()));
                historyEntity.setAction(operation);
                historyEntity.setEntity(entity);
                historyEntity.setEntityJson(null);
                if(!operation.contentEquals("CREATE"))
                {
                    ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
                    String json = null;
                    try {
                        json = ow.writeValueAsString(t);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                    historyEntity.setEntityJson(json.toString().getBytes());
              
                }
                historyEntity.setIdEntity(t.getId());
                historyEntity.setUser(user);       
            historyJpaRepository.save(historyEntity);
        
    }
}
解决方案

核心问题:泛型语法使用错误,<T extends LavorazioneDto,DizionarioDto,...>的写法并非让T继承所有列出的类,而是定义了多个独立泛型参数,其中第一个参数T仅继承LavorazioneDto,导致方法仅接受LavorazioneDto类型参数,与传入的TemplateEntity不兼容。

正确实现步骤:

  • 定义统一标识接口:创建一个包含getId()方法的公共接口,让所有需要支持的实体类/DTO实现该接口:

    public interface Identifiable {
        // 确保返回类型与HistoryEntity的idEntity字段类型匹配
        Long getId();
    }
    

    让TemplateEntity、LavorazioneDto、DizionarioDto等所有需要调用该方法的类,都实现Identifiable接口。

  • 重构泛型接口:将泛型约束改为继承统一的Identifiable接口,而非罗列所有类:

    public interface HistoryUtils {
        
        default <T extends Identifiable> void trackUserActivity(String operation, T t, String user, String entity, HistoryJpaRepository historyJpaRepository) {
            HistoryEntity historyEntity = new HistoryEntity();
            historyEntity.setData(new java.sql.Date(Calendar.getInstance().getTimeInMillis()));
            historyEntity.setAction(operation);
            historyEntity.setEntity(entity);
            historyEntity.setEntityJson(null);
            
            if (!"CREATE".contentEquals(operation)) {
                ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
                try {
                    String json = ow.writeValueAsString(t);
                    historyEntity.setEntityJson(json.getBytes());
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            } 
            
            historyEntity.setIdEntity(t.getId());
            historyEntity.setUser(user);       
            historyJpaRepository.save(historyEntity);
        }
    }
    
  • 调用示例:注入HistoryUtils接口(可创建空实现类或通过Spring管理),传入任意实现Identifiable的类即可:

    @Autowired
    private HistoryUtils historyUtils;
    
    // 调用TemplateEntity
    historyUtils.trackUserActivity("UPDATE", templateEntity, currentUser, "TEMPLATE", historyJpaRepository);
    // 调用LavorazioneDto
    historyUtils.trackUserActivity("CREATE", lavorazioneDto, currentUser, "LAVORAZIONE", historyJpaRepository);
    

额外优化建议:

  • 将ObjectMapper实例提取为类成员或Spring Bean,避免每次调用创建新实例,提升性能。
  • 替换简单的堆栈打印,改为抛出自定义异常或统一日志处理,增强代码健壮性。

内容的提问来源于stack exchange,提问作者Kinder maxi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:20:40