Как сделать конечную точку контроллера для получения двух разных объектов в Java Spring? - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть сервер, построенный на Java и Spring.

Я пытаюсь сделать так, чтобы мой контроллер с одной и той же конечной точкой получал два разных объекта.

Это пример длячто я имею в виду:

Я знаю, что могу сделать это:

  public class Option1{
   private String name;
   ...
     //getter and setter
    }

public class Option2{
 private Long id;
  ...
//getter and setter
}

@Controller
public class Controller{

 @RequestMapping(value = "service/getData/option1", method = RequestMethod.POST)
 @ResponseBody
 public String searchProv(@ResponseBody Option1 data1){
  return "option1"
   }

@RequestMapping(value = "service/getData/option2", method = RequestMethod.POST)
@ResponseBody
public String searchProv(@ResponseBody Option2 data2){
  return "option2"
  }
}

, но мне интересно, возможно ли передать другой объект json в одну и ту же конечную точку и сделать это:

 @Controller
public class Controller{

 @RequestMapping(value = "service/getData", method = RequestMethod.POST)
 @ResponseBody
 public ResponseEntity<Any> getData(@ResponseBody Option1And2 data){
if(data instanceof Option1){
  return return ResponseEntity<Any>(data.name,HttpStatus.OK)
}        
if(data instanceof Option2){
   return ResponseEntity<Any>(data.id,HttpStatus.OK)
}
 return ResponseEntity<Any>("ok",HttpStatus.OK)
  }

, так что «Option1And2» является универсальным объектом, может быть option1 или option2.

Я пытался заменить «Option1And2» на «Any», но это не сработало, потому что я получил список ключейи значения

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Это хорошее время для использования наследования и Java Generics.Стоит отметить, что если у вашего контроллера есть какие-либо зависимости, такие как @Service или @Repository, то они тоже должны быть общими.

enter image description here

У вас может быть универсальный контроллер:

abstract class GenericController<T> {

    public abstract GenericService<T> getService();

    @GetMapping
    public ResponseEntity<Iterable<T>> findAll() {

        return ResponseEntity.ok(getService().findAll());
    }

    @PostMapping
    public ResponseEntity<T> save(T entity) {

        return ResponseEntity.ok(getService().save(entity));
    }

    // @DeleteMapping, @PutMapping
    // These mappings will automatically be inherited by
    // the child class. So in the case of findAll(), the API
    // will have a GET mapping on /category as well as a GET
    // mapping on /product. So, by defining and annotating the
    // CRUD operations in the parent class, they will automatically
    // become available in all child classes.
}

@Controller
@RequestMapping("/category")
class CategoryContr extends GenericController<Category> {

    @Autowired CategoryServ serv;

    @Override
    public GenericService<Category> getService() {
        return serv;
    }
}

@Controller
@RequestMapping("/product")
class ProductContr extends GenericController<Product> {

    @Autowired ProductServ serv;

    @Override
    public GenericService<Product> getService() {
        return serv;
    }
}

Затем вы должны иметь абстрактные версии зависимостей.Сервисы:

abstract class GenericService<T> {

    public abstract GenericRepository<T> getRepository();

    public Iterable<T> findAll() {

        return getRepository().findAll();
    }

    public T save(T entity) {

        return getRepository().save(entity);
    }

}

@Service
class CategoryServ extends GenericService<Category> {

    @Autowired CategoryRepo repo;

    @Override
    public GenericRepository<Category> getRepository() {
        return repo;
    }
}

@Service
class ProductServ extends GenericService<Product> {

    @Autowired ProductRepo repo;

    @Override
    public GenericRepository<Product> getRepository() {
        return repo;
    }
}

Затем сервисы также имеют свои зависимости - репозитории:

@NoRepositoryBean
interface GenericRepository<T> extends JpaRepository<T, Long> {
}

@Repository
interface CategoryRepo extends GenericRepository<Category> {
}

@Repository
interface ProductRepo extends GenericRepository<Product> {
}

Это был мой первый подход.Это работает очень хорошо.Однако это создает прочную связь между бизнес-логикой каждого сервиса и универсального сервиса.То же самое относится и к универсальному контроллеру и его дочерним классам.Конечно, вы всегда можете переопределить определенную операцию CRUD.Но вы должны делать это с осторожностью, поскольку вы можете создать неожиданное поведение.Стоит также отметить, что наследование от классов, которые имеют методы, аннотированные @RequestMapping, автоматически предоставляет все аннотированные методы.Это может быть нежелательно.Например, нам может не потребоваться опция удаления для категорий, но мы хотим ее для товаров.Чтобы бороться с этим, вместо того, чтобы аннотировать метод в родительском классе, мы можем просто определить его в родительском классе и переопределить нужные операции CRUD с добавленной аннотацией @RequestMapping, а затем вызвать метод суперкласса.

Другой подход - с использованием аннотаций.

0 голосов
/ 27 ноября 2018

Вы должны использовать JsonNode объект.

для вашего примера вы должны сделать следующее:

 @Controller
 public class Controller{

 @RequestMapping(value = "service/getData", method = RequestMethod.POST)
 @ResponseBody
 public ResponseEntity<Any> getData(@RequestBody JsonNode jsonNode){

   ObjectMapper obj = new ObjectMapper();

  if(jsonNode.has("name"){
   Option1 result= obj.convertValue(jsonNode,Option1.class)
  return ResponseEntity<Any>(result.name,HttpStatus.OK)
    }    

   else {

   Option2 result= obj.convertValue(jsonNode,Option2.class)
   return ResponseEntity<Any>(result.id,HttpStatus.OK)
    }

    return ResponseEntity<Any>("ok",HttpStatus.OK)
     }

JsonNode и ObjectMapper, которые вы должны импортировать отсюда:

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.JsonNode;

эта ссылка должна помочь вам лучше понять JsonNode и дать вам более подробную информацию.

, а эта ссылка должна помочь вам сconvertValue из JsonNode в объект Java (POJO).

0 голосов
/ 21 ноября 2018

Похоже, вы хотите, чтобы сама программа определяла тип этого параметра. Но прежде чем вы это сделаете, вы уверены, в чем разница между этими двумя объектами?

Во-первых, что такое Option1And2 на самом деле? Если Option1And2 содержит все поля Option1 и Option2, но не является их подклассом, то, вероятно, Option1And2 может выглядеть следующим образом:

@Data
public class Option1And2{
    private String name;

    private Long id;
}
  • Если у вас есть другие ограничения, например «один из них»и только один из них должен быть нулевым ", тогда вы можете определить его по этому правилу.
  • Если у вас нет других ограничений, то, возможно, вы могли бы добавить новое поле в качестве флага.

На самом деле эти стили кода не рекомендуются. Если эти две функции имеют разные обязанности, то, возможно, лучше не смешивать их вместе . Вы поймете, что я имею в виду, когда придетсярефакторинг этих кодов.

Если у этих двух функций много общего, возможно, вам лучше реорганизовать служебную логику, а не простоПримерно объединяя два сервиса, создав новый параметр Option1And2.

Кстати, что именно вы хотите сделать? Почему вы хотите объединить эти два объекта в один?

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