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相关问答推荐

Maven Google Sheets版本问题

无法在Java中将hhmmss格式的时间解析为LocalTime

Java在模块化jar文件中找不到类,但是javap可以

转换为Biggram

蒙蒂霍尔比赛结果不正确

格式中的特定回录键-值对

将Spring Boot 3.2.0升级到3.2.1后查询执行错误

搜索列表返回多个频道

使用多个RemoteDatabase对象的一个线程

S,要对Java复制构造函数深度克隆所有属性进行单元测试,最可靠的方法是什么?

与IntArray相比,ArrayList<;Int>;对于大量元素的性能极差

如何在Java中为thunk创建映射器函数

当b是一个字节并且在Java中值为-1时,为什么b>;>;>;1总是等于-1?

EXCEL中的公式单元格显示#NAME?

无法将GSON导入到我的JavaFX Maven项目

如何处理两个几乎相同的XSD文件?

在Java Spring JPA中插入包含对其他实体的引用的列

根据应用程序 Select 的语言检索数据

使用@ExceptionHandler的GlobalExceptionHandler还是来自服务器的REST应答的ResponseEntity?

spring 数据Elastic search 与 spring 启动数据Elastic search 之间的区别是什么?