Spring абстрактный контроллер с конечным полем в путях конечных точек - PullRequest
0 голосов
/ 09 марта 2019

Допустим, я хочу создать API для отдыха для хранения информации об автомобиле.Чтобы упростить этот пост, скажем, я бы хотел, чтобы он выглядел следующим образом:

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

Теперь, скажем, у меня несколько марок автомобилей, и для каждого из них потребуются разные услуги, например,BmwService, MercedesService, AudiService.

Так что это моя идея: один абстрактный контроллер, который будет выглядеть примерно так:

@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 не позволяет мне иметь значение для сопоставления запроса с конечной переменной, если она инициализируется через конструктор (если CAR_MAKE инициализируется прямо в объявлении поля, например. protected final String CAR_MAKE = "s"оно работает).Так есть ли способ обойти это так, чтобы пути могли прийти из каждого подкласса?

1 Ответ

0 голосов
/ 09 марта 2019

Не рядом с компилятором, но что-то вроде этого.

Реализация интерфейса CarService:

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

Реализация типов AudiCarService, BmwCarService (и т. Д.), Которые реализуют CarService.

Реализовать репозиторий 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));
    }

    // ...
}

Рассмотреть также предпочтение HTTP-глаголов перед явными глаголами в URL, например Почему в том числеглагол действия в URI в реализации REST нарушает протокол?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...