在 Spring Boot 中的控制器中自动装配通用(T)服务
Posted
技术标签:
【中文标题】在 Spring Boot 中的控制器中自动装配通用(T)服务【英文标题】:Autowiring Generic(T) Service in Controller within Spring Boot 【发布时间】: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
【参考方案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
【讨论】:
以上是关于在 Spring Boot 中的控制器中自动装配通用(T)服务的主要内容,如果未能解决你的问题,请参考以下文章
spring boot自动装配原理@EnableAutoConfiguration