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

Java 端点路径中具有最终字段的Spring抽象控制器,java,spring,rest,inheritance,Java,Spring,Rest,Inheritance,假设我想构建一个RESTAPI来存储汽车信息。为了使这篇文章更简单,让我们假设我希望它看起来像这样: /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; publi

假设我想构建一个RESTAPI来存储汽车信息。为了使这篇文章更简单,让我们假设我希望它看起来像这样:

/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);
    }
    .
    .
    .
}
现在,假设我有多个汽车品牌,每个品牌都需要不同的汽车品牌服务,例如BmwService、Mercedeservice、AudiService

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

/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);
    }
    .
    .
    .
}
然后一个实际的控制器可能看起来像这样:

/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不允许我将请求映射的值与final变量进行映射(如果CAR\u MAKE在字段声明上正确初始化,例如
protected final String CAR\u MAKE=“s”
有效)。有没有办法解决这个问题,使路径可以来自每个子类?

不是在编译器附近,而是类似这样的地方

实现CarService接口:

public interface CarService {
  String getBrand();
  void save(Car car);
  // ...
}
实现实现CarService的AudiCarService、BmwCarService(etc)类型

实现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()));
    }
}

考虑在URL中使用HTTP谓词而不是显式谓词,例如

首先,REST实现是不正确的。我们不应该在URI中保存、删除和编辑,而应该使用相同的URI来修改HTTP协议,以便它执行不同的操作。使用PUT进行编辑,POST进行保存,DELETE进行删除。第二,它应该是请求负载,它应该驱动您要调用的服务。