【问题标题】:Autowiring Generic(T) Service in Controller within Spring Boot在 Spring Boot 中的控制器中自动装配通用(T)服务
【发布时间】:2021-12-07 13:13:30
【问题描述】:

我对如何在 Spring Boot 2.5.0 中将通用服务自动装配到控制器中感到有些困惑。

代码如下:
主控制器:

@RestController
@RequestMapping("/classifiers")
public class ClassifierController<T> {
    protected static final Logger LOG = LoggerFactory.getLogger(UserController.class);
    public final T classifierService;
    protected final JwtTokenFilter jwtTokenFilter;
    protected final JwtTokenUtil jwtTokenUtil;
    
    public ClassifierController(final JwtTokenFilter jwtTokenFilter,
                                final JwtTokenUtil jwtTokenUtil,
                                final T classifierService) {
        this.jwtTokenFilter = jwtTokenFilter;
        this.jwtTokenUtil = jwtTokenUtil;
        this.classifierService = classifierService;
    }
}

扩展控制器:


@RestController
@RequestMapping("/ss01dictionary")
@CrossOrigin(origins = "*", allowedHeaders = "*")
public class SS01WasteDictionaryController
      extends ClassifierController<DictionaryService> {
    
    @Autowired
    public SS01WasteDictionaryController(JwtTokenFilter jwtTokenFilter,
                                         JwtTokenUtil jwtTokenUtil,
                                         DictionaryService classifierService) {
        super(jwtTokenFilter, jwtTokenUtil, classifierService);
    }
    
    @RequestMapping(value = "/list", method = GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ResponseEntity<?> getData(@RequestParam(value = "page", defaultValue = "0") int page,
                                                     @RequestParam(value = "size", defaultValue = "20") int pageSize) {
        PageRequest pageable = PageRequest.of(page, pageSize);
        Page<Dictionary> dictionaryDTOList = classifierService.getAllDictionaryValues(pageable);
        return ResponseEntity.status(HttpStatus.OK).body(dictionaryDTOList);
    }
...

主要抽象服务:


@Service
public abstract class ClassifierService {
    public final JdbcTemplate jdbcTemplate;
    
    public ClassifierService(final JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    protected abstract Integer count();
}

字典服务:

@Service
public class DictionaryService
      extends ClassifierService {
    public DictionaryService(JdbcTemplate jdbcTemplate) {
        super(jdbcTemplate);
    }
    
    public Page<DictionaryDTO> getAllDictionaryValues(Pageable page) {
        List<DictionaryDTO> result = jdbcTemplate.query(GET_SQL + " LIMIT " + page.getPageSize() + " OFFSET " + page.getOffset(),
                                                                 new DictionaryRowMapper());
        return new PageImpl<>(result, page, count());
    }

我做错了什么? 我想拥有一些抽象方法和通用控制器的通用服务。 如何自动连接 T 服务,以便从特定服务中获取特定控制器的方法?

【问题讨论】:

  • 您遇到什么错误?您没有发布任何错误。首先,我建议不要用@Service@RestController 注释你的超级/抽象类
  • @pleft 你好!抱歉,错误是 ClassifierController 中的最终 T 分类器服务没有 Beans

标签: java spring-boot autowired spring-restcontroller spring-rest


【解决方案1】:

如果你想在超抽象类中抽象出控制器和服务的共同内容,那么你必须将类标记为抽象,并将这个条件移到层次结构的下层。系统正确地抱怨它找不到类型 T 的服务,因为没有任何东西可以按该名称搜索。如果你创建一个名为T 的类,这个问题很可能会得到解决。现在,如何在这里使用泛型定义。以下是我的尝试方法。

  • 首先创建一个抽象的服务类比如AbstractService
  • 如果需要,可以通过限定符单独创建此服务的具体实现者。
  • 创建一个抽象控制器并告诉它需要一个类,该类是AbstractService 的子类。
  • 在子控制器中注入所需的服务并将其传递给超类。

代码如下:

package in.silentsudo.autowiregenericservicecontroller.service;

public abstract class AbstractTransporterService {

    final public String supportedVersion() {
        return "1.0";
    }

    public abstract String transport();
}

Impl1

package in.silentsudo.autowiregenericservicecontroller.service;

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

@Service
@Qualifier("audioTransporterService")
public class AudioTransporterService extends AbstractTransporterService {
    @Override
    public String transport() {
        return "transporting audio details";
    }
}

Impl2

package in.silentsudo.autowiregenericservicecontroller.service;

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

@Service
@Qualifier("videoTransporterService")
public class VideoTransporterService extends AbstractTransporterService {
    @Override
    public String transport() {
        return "transporting video details";
    }
}

控制器如下 抽象控制器

package in.silentsudo.autowiregenericservicecontroller.controller;

import in.silentsudo.autowiregenericservicecontroller.service.AbstractTransporterService;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

public abstract class AbstractController<S extends AbstractTransporterService> {
    private final S service;

    public AbstractController(S service) {
        this.service = service;
    }

    public S getService() {
        return service;
    }


    @RequestMapping(path = "/version")
    public Map<String, String> controllerVersion() {
        return Map.of("type", getClass().getName(), "v", service.supportedVersion());
    }
}

Impl1

package in.silentsudo.autowiregenericservicecontroller.controller;

import in.silentsudo.autowiregenericservicecontroller.service.AudioTransporterService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path = "/audio")
public class AudioController extends AbstractController<AudioTransporterService> {


    public AudioController(AudioTransporterService service) {
        super(service);
    }

    @GetMapping
    public String get() {
        return getService().transport();
    }
}

Impl2

package in.silentsudo.autowiregenericservicecontroller.controller;

import in.silentsudo.autowiregenericservicecontroller.service.VideoTransporterService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(path = "/video")
public class VideoController extends AbstractController<VideoTransporterService> {

    public VideoController(VideoTransporterService service) {
        super(service);
    }

    @GetMapping
    public String get() {
        return getService().transport();
    }
}

@RestController 注解信息在运行时不传递。所以最好不要用 Service 注释超类

也是路径

  • http://localhost:8080/audio/version
  • http://localhost:8080/video/version

他们正在扩展具有/version 方法的超类

源码https://gitlab.com/spring-boot-cloud-samples/autowire-generic-service-controller

【讨论】:

    猜你喜欢
    • 2019-11-02
    • 2020-04-29
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2019-07-15
    • 2020-03-24
    • 2017-05-10
    • 2018-06-10
    相关资源
    最近更新 更多