不同 MVC 层之间的数据流

Data flow between different MVC layers

下面我展示了从使用表单到持久层的数据流。但是对哪些对象应该在MVC的哪一层可用以及数据应该如何在MVC的不同层之间传递存在疑问。我正在使用 Spring,所以下面发布的代码是 Spring 框架的代码。

我们开始吧,我有一个 DTO(数据传输对象)PatientForm,它保存用户输入的表单数据。

public class Patient {

private int id;
private String name;
private String medicineOne;
private String medicineTwo;

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public String getMedicineOne() {
    return medicineOne;
}
public void setMedicineOne(String medicineOne) {
    this.medicineOne = medicineOne;
}
public String getMedicineTwo() {
    return medicineTwo;
}
public void setMedicineTwo(String medicineTwo) {
    this.medicineTwo = medicineTwo;
}
}

PatientForm 传递给控制器​​PatientController,不传输数据但将表单传递给服务层PatientService

@PostMapping("/patient/addpatient")
public ModelAndView addPatient(@ModelAttribute("patientform") PatientForm patient){
    patientService.addPatient(patient);
    return new ModelAndView("redirect:/");
}

在服务层 PatientService 中,实际发生了从 DTO 到持久实体 Patient 的数据传输。

public void addPatient(com.hp.view.form.PatientForm patientForm){
    String medicineOneName = patientForm.getMedicineOne();
    Medicine medicineOne = medicineService.findByName(medicineOneName);
    if(medicineOne == null){
        medicineService.save(new Medicine(medicineOneName));
        medicineOne = medicineService.findByName(medicineOneName);
    }

    String medicineTwoName = patientForm.getMedicineTwo();
    Medicine medicineTwo = medicineService.findByName(medicineTwoName);
    if(medicineTwo == null){
        medicineService.save(new Medicine(medicineTwoName));
        medicineTwo = medicineService.findByName(medicineTwoName);
    }

    List<Medicine> medicines = new ArrayList<>();
    medicines.add(medicineOne);
    medicines.add(medicineTwo);

    Patient patient = new Patient();
    patient.setName(patientForm.getName());
    patient.setMedicine(medicines);
    patientRepository.save(patient);
}

根据上面的流程,这是我的问题:

  1. 应该Controller layer还是Service layer将数据从DTO传输到持久实体?

  2. 如果数据传输在控制器中完成意味着模型实体将在控制器层中声明。如果数据传输在服务层完成意味着 DTO 将在服务层声明。两者哪个更好?

  3. 在我的服务层中,我实例化了实体对象的实例 Patient。这会产生问题吗?我应该让 Spring contianer 管理我的实体 bean 吗?

  Patient patient = new Patient();

在 spring 中,您让应用程序上下文管理您的 bean(即,您不初始化 class),然后您可以自动装配(将它们包含在其他 class es) 没有显式初始化它们。

1) 服务层用作控制器和模型之间的中介。也就是说,您将您的服务自动连接到您的休息控制器中。

上面解释了第 2 个和第 3 个答案。

P.S.: 这里 autowire 表示 dependency injection - .http://www.javatpoint.com/dependency-injection-in-spring

(1) Should Controller layer or Service layer transfer data from DTO to Persistent Entity?

FormBean 是 client/channel/endpoint 特定的,因此控制器层应该执行客户端特定的验证(如最小长度、最大长度等),然后将 FormBean 的数据转换为实体 Bean,实体 Bean 将传递给服务层。 在 3 层架构中,服务层应该是可重用的(下面解释),它不应该知道 FormBeans,因此接收实体对象并应该负责处理业务逻辑(执行业务验证和核心逻辑以及与 DAO/Repository 类).

(2) If data transfer is done in controller means model entity will be declared in controller layer. And if data transfer is done in service layer means DTO will be declared in service layer. Which of the two is prefered?

单个服务可以 reused/exposed 连接多个端点,如控制器或不同的 Web 服务,每个端点可能需要不同的 formbeans,因此控制器(端点)层首选处理端点指向特定的验证,然后 create/pass 将正确的实体对象指向服务。

(3) In my service layer I have instantiated instance of my entity object Patient. Will this create problem and I should let Spring container manage my entity beans?

没问题。由于实体对象不是单例,您可以像之前那样在服务中创建它们。但是,如果您允许 Spring 管理它们,则需要确保为每个输入请求创建一个实例。这是因为Spring bean的default scopesingleton,需要改成request作用域

实际上,我会采用完全不同的方法。 DTO 可能会绑定到特定的 Web 应用程序框架。这会降低服务的可重用性。相反,您可以创建类似 "DTO to entity converter" 的内容。一个简单的界面可能如下所示:

public interface DtoToEntityConverter<T, R> {
    R getEntity(T t);
}

然后您可以定义具体的 class(甚至在更简单的情况下使用 lambda):

@Component
public class PatientFormConverter implements DtoToEntityConverter<PatientForm, Patient> {

    public Patient getEntity(PatientForm form) {
        // Conversion rules and stuff...
    }
}

然后,只需将该组件注入控制器并在添加患者时调用 getEntity

addPatient(patientFormConverter.getEntity(patientForm));