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

Spring Boot中Mapper无法被Autowired注入的问题排查

博彩API开发中MapStruct注入问题解决

问题场景

开发博彩API时,使用MapStruct的BetMapper减少DTO与实体类之间的转换代码重复,但遇到以下问题:

  • 项目启动失败,提示找不到BetMapper类型的Bean
  • 移除@Autowired注解后项目能启动,但调用投注插入接口时出现betMapper为null的空指针异常

启动报错信息

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of constructor in api.loteria.loteriaapi.services.Mysql.BetServiceMysql required a bean of type 'api.loteria.loteriaapi.dtos.mappers.BetMapper' that could not be found.

The injection point has the following annotations:
        - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'api.loteria.loteriaapi.dtos.mappers.BetMapper' in your configuration.

相关代码

BetMapper.java

@Mapper(componentModel = "spring")
public interface BetMapper {
    @Mapping(target = "bet.id", source = "betId")
    Bet betResquetToEntity(BetRequest betRequest);

    @Mapping(source = "bet.id", target = "betId")
    BetResponse entityToBetResponse(Bet bet);
}

BetServiceMysql.java

@Service
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class BetServiceMysql implements BetService {

    private BetRepository betRepository;
    private BetMapper betMapper;

    @Override
    public List<BetResponse> list() {
        List<Bet> bets = betRepository.findAll();
        return bets.stream().map(bet -> betMapper.entityToBetResponse(bet)).collect(Collectors.toList());
    }

    @Override
    public BetResponse save(BetRequest betRequest) {
        Bet bet = betMapper.betResquetToEntity(betRequest);
        try {
            betRepository.save(bet);
        }catch(RuntimeException e){
            throw new DataIntegrityViolationException(e.getMessage());
        }
        return betMapper.entityToBetResponse(bet);
    }

    @Override
    public BetResponse update(Long id, BetRequest betRequest) {
        Bet bet = verifyIfExist(id);
        updateData(bet, betRequest);
        betRepository.save(bet);
        return betMapper.entityToBetResponse(bet);
    }

    @Override
    public BetResponse delete(Long id) {
        Bet bet = verifyIfExist(id);
        betRepository.delete(bet);
        return betMapper.entityToBetResponse(bet);
    }

    @Override
    public BetResponse getBetById(Long id) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public List<BetResponse> getBets() {
        // TODO Auto-generated method stub
        return null;
    }

    protected Bet verifyIfExist(Long id){
        return betRepository.findById(id).orElseThrow(() -> new EntityNotFoundException(String.format("ID: %s || Não foi encontrado nenhuma entidade para o id fornecido", id)));
    }

    protected void updateData(Bet bet, BetRequest betRequest){
        bet.setMaxNumbersByUsers(betRequest.getMaxNumbersByUsers());
    }

}

BetService.java

public interface BetService {
    List<BetResponse> list();
    BetResponse save(BetRequest betRequest);
    BetResponse update(Long id, BetRequest betRequest);
    BetResponse delete(Long id);
    BetResponse getBetById(Long id);
    List<BetResponse> getBets();
}

解决方案

1. 确保MapStruct依赖及注解处理器配置正确

MapStruct需要核心依赖和注解处理器才能生成Mapper的实现类,以Maven为例,在pom.xml中添加:

<!-- MapStruct核心依赖 -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<!-- 注解处理器,用于编译时生成Mapper实现类 -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

如果使用Gradle,需配置annotationProcessor:

dependencies {
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
}

2. 确认Spring能扫描到Mapper接口

  • 检查Spring Boot主类的@SpringBootApplication或@ComponentScan注解,确保Mapper所在的包api.loteria.loteriaapi.dtos.mappers被包含在扫描范围内:
@SpringBootApplication(scanBasePackages = {"api.loteria.loteriaapi"})
public class LoteriaApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(LoteriaApiApplication.class, args);
    }
}
  • @Mapper(componentModel = "spring")注解会让MapStruct生成带有@Component的实现类,确保Spring能自动扫描并注册为Bean。

3. 优化Service的依赖注入方式

替换@AllArgsConstructor(onConstructor = @__(@Autowired))为更简洁的构造注入方式,推荐使用Lombok的@RequiredArgsConstructor(需确保字段为private final):

@Service
@RequiredArgsConstructor
public class BetServiceMysql implements BetService {

    private final BetRepository betRepository;
    private final BetMapper betMapper;

    // 原有业务方法保持不变...
}

如果不使用Lombok,可手动编写构造函数:

@Service
public class BetServiceMysql implements BetService {

    private final BetRepository betRepository;
    private final BetMapper betMapper;

    public BetServiceMysql(BetRepository betRepository, BetMapper betMapper) {
        this.betRepository = betRepository;
        this.betMapper = betMapper;
    }

    // 原有业务方法保持不变...
}

4. 验证Mapper实现类是否生成

编译项目后,检查target/classes/api/loteria/loteriaapi/dtos/mappers/目录下是否存在BetMapperImpl.class文件。如果不存在,说明注解处理器未生效,需重新检查依赖配置,或执行mvn clean compile(Maven)/gradle clean compileJava(Gradle)重新编译。

总结

问题核心是MapStruct未生成有效的Spring Bean实现类,或Spring无法扫描到该Bean。通过完善依赖配置、确保组件扫描范围正确、优化注入方式,即可解决启动报错和Mapper为null的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:41:58