Mapstruct找不到我的映射器的实现.使用最新版本的mapstruct 1.5.5最终版,我的IDE是ECLIPSE. 我得到了这个错误:

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

Description:

Field productMapper in com.example.springshop.service.ImageService required a bean of type 'com.example.springshop.mapper.ProductMapper' that could not be found.


Action:

Consider defining a bean of type 'com.example.springshop.mapper.ProductMapper' in your configuration.

产品实体:

package com.example.springshop.entity;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "products")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Product {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "title", nullable = false)
    private String title;

    @Column(name = "description", nullable = false)
    private String description;

    @Column(name = "price", nullable = false)
    private BigDecimal price;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "product")
    @Builder.Default
    private List<Image> images = new ArrayList<>();

    @Column(name = "preview_image_id")
    private Long previewImageId;

    @Column(name = "date_of_created")
    private LocalDateTime dateOfCreated;

    @PrePersist
    private void init() {
        dateOfCreated = LocalDateTime.now();
    }
}

ProductDTO类:

package com.example.springshop.dto;

import java.math.BigDecimal;
import java.util.List;

import com.example.springshop.entity.Image;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ProductDTO {
    private String title;
    private String description;
    private BigDecimal price;
    private List<Image> images;
    private Long previewImageId;
}

产品控制器:

package com.example.springshop.controllers;

import java.security.Principal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import com.example.springshop.repository.ProductRepository;
import com.example.springshop.service.ProductService;

@Controller
public class ProductController {
    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductService productService;

    @GetMapping("/")
    public String mainPage(Model model) {
        model.addAttribute("products", productRepository.findAll());
        return "main";
    }

    @GetMapping("/products/{id}")
    public String productInfo(@PathVariable(value = "id") Long id, Model model) {
        if (!productRepository.existsById(id)) {
            return "redirect:/";
        }

        model.addAttribute("product", productService.findProductById(id));

        return "product_info";
    }

    @GetMapping("/products/{id}/bucket")
    public String addBucket(@PathVariable Long id, Principal principal) {
        if (principal == null) {
            return "redirect:/";
        }

        productService.addToUserBucket(id, principal.getName());
        return "redirect:/";
    }
}

管理控制器:

package com.example.springshop.controllers;

import java.io.IOException;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.example.springshop.dto.ProductDTO;
import com.example.springshop.service.ProductService;

@Controller
public class AdminController {
    private final ProductService productService;

    public AdminController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/create_product")
    public String productCreatePage() {
        return "create_product";
    }

    @PostMapping("/create_product")
    public String productCreate(@RequestParam("file1") MultipartFile file1,
            @RequestParam("file2") MultipartFile file2,
            @RequestParam("file3") MultipartFile file3,
            ProductDTO product) throws IOException {
        productService.saveProduct(product, file1, file2, file3);
        return "redirect:/";
    }

    @GetMapping("/edit_product/{id}")
    public String editProductPage(@PathVariable(value = "id") Long id, Model model) {
        List<ProductDTO> result = productService.findProductById(id);

        if (result == null) {
            return "redirect:/";
        }

        model.addAttribute("product", result);

        return "edit_product";
    }

    @PostMapping("/edit_product/{id}")
    public String editProduct(ProductDTO productDTO) {
        productService.editProduct(productDTO);
        return "redirect:/";
    }

    @GetMapping("/delete_product/{id}")
    public String deleteProduct(@PathVariable(value = "id") Long id) {
        productService.deleteProduct(id);
        return "redirect:/";
    }
}

产品服务:

package com.example.springshop.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.example.springshop.dto.ProductDTO;
import com.example.springshop.entity.Bucket;
import com.example.springshop.entity.Image;
import com.example.springshop.entity.Product;
import com.example.springshop.entity.User;
import com.example.springshop.mapper.ImageMapper;
import com.example.springshop.mapper.ProductMapper;
import com.example.springshop.repository.ProductRepository;
import com.example.springshop.repository.UserRepository;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
    
    @Autowired
    private ImageMapper imageMapper;

    private final ProductRepository productRepository;
    private final UserRepository userRepository;

    private final BucketService bucketService;
    private final ImageService imageService;

    public ProductService(ProductRepository productRepository, UserRepository userRepository,
            BucketService bucketService, ImageService imageService) {
        this.productRepository = productRepository;
        this.userRepository = userRepository;
        this.bucketService = bucketService;
        this.imageService = imageService;
    }

    public List<ProductDTO> listOfProducts() {
        return productMapper.fromProductList(productRepository.findAll());
    }

    public ProductDTO getProductById(Long id) {
        return productMapper.fromProduct(productRepository.findById(id).orElse(null));
    }

    public void saveProduct(ProductDTO product, MultipartFile file1, MultipartFile file2, MultipartFile file3)
            throws IOException {
        Image image1;
        Image image2;
        Image image3;
        if (file1.getSize() != 0) {
            image1 = imageMapper.fromMultipartToImage(file1);
            image1.setPreviewImage(true);
            imageService.addImageToProduct(product, image1);
        }
        if (file2.getSize() != 0) {
            image2 = imageMapper.fromMultipartToImage(file2);
            imageService.addImageToProduct(product, image2);
        }
        if (file3.getSize() != 0) {
            image3 = imageMapper.fromMultipartToImage(file3);
            imageService.addImageToProduct(product, image3);
        }
        log.info("Saving new Product. Title: {}", product.getTitle());
        Product productFromDb = productRepository.save(productMapper.toProduct(product));
        productFromDb.setPreviewImageId(productFromDb.getImages().get(0).getId());
        productRepository.save(productMapper.toProduct(product));
    }

    public List<ProductDTO> findProductById(Long id) {
        List<Product> res = new ArrayList<>();

        if (!productRepository.existsById(id)) {
            return null;
        }

        Optional<Product> product = productRepository.findById(id);
        product.ifPresent(res::add);

        return productMapper.fromProductList(res);

    }

    public boolean deleteProduct(Long id) {
        if (!productRepository.existsById(id)) {
            return false;
        }

        productRepository.deleteById(id);

        return true;
    }

    public boolean editProduct(ProductDTO productDTO) {
        String title = productDTO.getTitle();

        if (productRepository.findByTitle(title) == null) {
            return false;
        }

        Product product = Product.builder()
                .title(title)
                .description(productDTO.getDescription())
                .price(productDTO.getPrice())
                .build();

        productRepository.save(product);

        log.info("Edit new User with title : {}", title);

        return true;
    }

    @Transactional
    public void addToUserBucket(Long productId, String username) {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new RuntimeException("User not found" + username);
        }

        Bucket bucket = user.getBucket();
        if (bucket == null) {
            Bucket newBucket = bucketService.createBucket(user, Collections.singletonList(productId));
            user.setBucket(newBucket);
            userRepository.save(user);
        } else {
            bucketService.addProducts(bucket, Collections.singletonList(productId));
        }

    }
}

图像服务:

package com.example.springshop.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.springshop.dto.ProductDTO;
import com.example.springshop.entity.Image;
import com.example.springshop.entity.Product;
import com.example.springshop.mapper.ProductMapper;

@Service
public class ImageService {
    @Autowired
    private ProductMapper productMapper;

    public void addImageToProduct(ProductDTO productDTO, Image image) {
        Product product = productMapper.toProduct(productDTO);

        image.setProduct(product);
        product.getImages().add(image);
    }
}

映射器类:

package com.example.springshop.mapper;

import java.util.List;

import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import com.example.springshop.dto.ProductDTO;
import com.example.springshop.entity.Product;

@Mapper(componentModel = "spring")
public interface ProductMapper {
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "dateOfCreated", ignore = true)
    Product toProduct(ProductDTO productDTO);

    @InheritInverseConfiguration
    ProductDTO fromProduct(Product product);

    List<Product> toProductList(List<ProductDTO> productDTOs);

    List<ProductDTO> fromProductList(List<Product> products);
}

Build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.1.2'
    id 'io.spring.dependency-management' version '1.1.2'
    id 'com.diffplug.eclipse.apt' version '3.37.2'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '20'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.1.2'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    implementation 'org.springframework.boot:spring-boot-starter-web:3.1.2'
    runtimeOnly 'org.postgresql:postgresql'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    implementation 'org.springframework.boot:spring-boot-starter-security:3.1.2'
    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.2.RELEASE'
    implementation 'org.mapstruct:mapstruct:1.5.5.Final'
    annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
    implementation 'io.springfox:springfox-swagger2:3.0.0'
}

tasks.named('test') {
    useJUnitPlatform()
}

我试了很多方法,但都没有用. 你能帮我看看我哪里出问题了吗?

推荐答案

如 comments 中所述,请使用组件模型作为spring.

@Mapper(componentModel = "spring")

Java相关问答推荐

Mongo DB Bson和Java:在子文档中添加和返回仅存在于父文档中的字段?

如果给定层次 struct 级别,如何从其预序穿越构造n元树

ittext pdf延迟签名,签名无效

有关手动创建的包的问题

CompleteableFuture是否运行在不同的内核上?

Com.example.service.QuestionService中的构造函数的参数0需要找不到的类型为';com.example.Dao.QuestionDao;的Bean

通过Spring Security公开Spring Boot执行器端点

如何在Java记录中设置BigDecimal类型属性的精度?

为什么Spring Boot项目无法为基于MySQL的CRUD应用程序找到从JPARepository接口扩展的ProductRepository?

在Ubuntu 23.10上使用mp3创建JavaFX MediaPlayer时出错

从映射列表中检索所有键

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

未调用OnBackPressedCallback-Activitiy立即终止

JavaFX,GridPane:在GridPane的列中生成元素将保持所有列的宽度

活泼的一次判断成语,结果中等

通过/失败的参数化junit测试方法执行数

设置背景时缺少Android编辑文本下划线

为什么我得到默认方法的值而不是被覆盖的方法的值?

在不带instanceof或switch的java中记录模式

对于 Hangman 游戏,索引 0 超出长度 0 的范围