在端点路径中具有最终字段的Spring抽象控制器

时间:2019-03-08 21:40:23

标签: java spring rest inheritance

假设我要构建一个用于存储汽车信息的REST API。为了使这篇文章更简单,假设我希望它看起来像这样:

/api/cars/{carmake}/save
/api/cars/{carmake}/edit
/api/cars/{carmake}/delete

现在,假设我有多个汽车制造商,而每个汽车制造商都需要不同的汽车制造商服务。宝马服务,梅赛德斯服务,奥迪服务。

这是我的想法:一个看起来像这样的抽象控制器:

@RequestMapping(value="/api/cars/")
public abstract class CarController {
    protected final String CAR_MAKE;

    public CarController(String carMake){
        this.CAR_MAKE = carMake;
    }

    @PostMapping(value = CAR_MAKE + "/save")
    public abstract void save(@Valid @RequestBody Serializable car)

    @DeleteMapping(value = CAR_MAKE + "/delete")
    public abstract void save(@Valid @RequestBody Serializable car);

    @PatchMapping(value = CAR_MAKE + "/edit")
    public abstract void save(@Valid @RequestBody Serializable car)
}

然后一个实际的控制器可能看起来像这样:

@RestController
public class AudiController extends CarController {

    private AudiService audiService;

    @Autowired
    public AudiController(AudiService audiService){
        super("audi");
        this.audiService = audiService;
    }

    @Override
    public void save(@Valid @RequestBody Serializable car) {
        audiService.save((Audi) car);
    }
    .
    .
    .
}

问题是,如果spring是通过构造函数初始化的,则spring不允许我使用带有最终变量的请求映射的值(如果CAR_MAKE是在字段声明(例如protected final String CAR_MAKE = "s"上初始化的),则可以正常工作)。那么有什么办法可以解决这个问题,以便路径可以来自每个子类?

1 个答案:

答案 0 :(得分:0)

不是靠近编译器,而是类似的东西。

实现CarService接口:

public interface CarService {
  String getBrand();
  void save(Car car);
  // ...
}

实现实现CarService的AudiCarService,BmwCarService(等)类型。

实现CarService存储库,例如:

public class CarServiceRepository {
    private Map<String, CarService> carServicesByBrand;

    public Optional<CarService> findFor(String brand) {
        return Optional.ofNullable(carServicesByBrand.get(brand));
    }

    @Autowired
    public void setCarServicesByBrand(List<CarService> carServices) {
        this.carServicesByBrand = carServices.stream().collect(Collectors.toMap(CarService::getBrand, Function.identity()));
    }
}

实现单个控​​制器“ CarController”:

@RequestMapping(value="/api/cars")
@Component
public class CarController {
    @Autowired
    private CarServiceRepository carServiceRepository;

    @PostMapping(value = "/{brand}/save")
    public void save(@Valid @RequestBody Serializable car, @PathParam String brand) {
        carServiceRepository.findFor(brand).ifPresent(carService -> carService.save(car));
    }

    // ...
}

与URL中的显式动词相比,还建议使用HTTP动词,例如Why does including an action verb in the URI in a REST implementation violate the protocol?