简体   繁体   English

当我认为我可以从 Spring 中的实体访问服务时,替换我的代码的更好解决方案是什么?

[英]How is the better solution to replace my code, when I think i can access service from entity in Spring?

I have a problem to access service in my entity.我在访问我的实体中的服务时遇到问题。 I know, besides my code doesn't work, it's also not recomended.我知道,除了我的代码不起作用之外,也不推荐这样做。 So, i want to know what is the best practice if i have the problem like this?所以,我想知道如果我遇到这样的问题,最佳做法是什么? Here are my class.这是我的课。

The Controller Class:控制器类:

@Controller
@RequestMapping("step")
public class TenderController {
   @Autowired
   StepService stepService;

   @GetMapping("")
   public ModelAndView index(ModelAndView mView,
                          @ModelAttribute(name = "result_code") String result_code,
                          @ModelAttribute(name = "result_message") String result_message) {
   mView.addObject("stepList", stepService.getAllSteps());
   mView.setViewName("pages/step/index");
   return mView;
   }
}

On my view html, I iterate the stepList在我的视图 html 上,我迭代 stepList

<tr th:each="s:${stepList}" 
    th:classappend="${s?.isStepNow()?'bg-success':''}">
    <!-- some td --> 
</tr>

The problem is, for some reason, i have to use if else condition to get the current date to use in isStepNow() method.问题是,出于某种原因,我必须使用 if else 条件来获取要在 isStepNow() 方法中使用的当前日期。 One from operating system.一种来自操作系统。 The other one from the database.另一个来自数据库。 So, i come up with an idea to create a service class所以,我想出了一个创建服务类的想法

Here are the Service Class :这是服务类:

public interface TimeServices {
   Date getNow();
}

and The Implementation Class:和实现类:

@Service
public class TimeServicesImpl implements TimeServices {
  @Value("${app.mode}")
  String appMode;

  @Autowired
  DateDBRepository dateDBRepository;

  @Override
  public Date getNow() {
    if(appMode.equalsIgnoreCase("GET_FROM_DB")){
        Optional<DateDB> dateDBOptional =  dateDBRepository.findById(1L);
        if(dateDBOptional.isPresent()){
            return dateDBOptional.get().getDate();
        }else{
            throw new IdNotExistsException();
        }
    }else{
        return new Date();
    }
 }

} }

The Problem is in my Entity:问题出在我的实体中:

@Entity
@Table(name = "step")
public class Step{

   @Autowired
   @Transient
   TimeServices timeServices; //BAD PRACTICE AND DOESN'T WORK

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   private Date start;
   private Date end;

   public Boolean isStepNow(){
      Date now = timeServices.getNow(); //THE PROBLEM
      if(now.compareTo(start)>0 && end.compareTo(now)>0) {
         return true;
      }else{
         return false;
      }
   }
}

Of course it doesn't work, because the timeService is always null.当然它不起作用,因为 timeService 始终为空。 Anyone have some recommendation for me to solve this problem?任何人都有一些建议让我解决这个问题?

I know i can edit my isStepNow() to isStepNow(Date date).我知道我可以将 isStepNow() 编辑为 isStepNow(Date date)。 Then, i can access the service via controller.然后,我可以通过控制器访问该服务。 So i can call the isStepNow(date) on my view.所以我可以在我的视图中调用 isStepNow(date) 。 But, i think it's not efficient in writing source code because i have to access the service from some controllers rather than only write it one time in the entity.但是,我认为编写源代码效率不高,因为我必须从某些控制器访问服务,而不仅仅是在实体中编写一次。

I've seen this discussion a lot.我看过很多这样的讨论。 People using DDD tend to solve it as follows:使用 DDD 的人倾向于如下解决:

  • Rename your @Entity-annotated class to StepEntity or ORMStep something similar, and only keep the fields needed to do ORM in that class.将你的@Entity-annotated 类重命名为 StepEntity 或 ORMStep 类似的东西,并且只保留在该类中执行 ORM 所需的字段。
  • Create a different (domain) class Step that you create using a ORMStep and dependent services, and put your domain logic methods in that class.创建您使用 ORMStep 和相关服务创建的不同(域)类 Step,并将您的域逻辑方法放在该类中。
  • Let the StepService interface (better call it StepRepository) return Step class, not ORMStep.让 StepService 接口(最好称之为 StepRepository)返回 Step 类,而不是 ORMStep。
  • Implement the StepRepository by injecting both the DAO (which Spring Data confusingly also calls Repository) and the dependent services, and combine them to read ORMSteps and convert to Step classes.通过注入 DAO(Spring Data 也将其称为 Repository)和依赖服务来实现 StepRepository,并将它们组合起来读取 ORMSteps 并转换为 Step 类。

This seems like a lot of effort, and you probably need to convert the Step instances back to ORMStep classes too to do updates, but in the long run it's a very clean solution.这看起来很费力,您可能也需要将 Step 实例转换回 ORMStep 类来进行更新,但从长远来看,这是一个非常干净的解决方案。 You can evolve the Step classes independently of the ORM classes or switch the ORM without having to change the controller etc.您可以独立于 ORM 类演化 Step 类或切换 ORM,而无需更改控制器等。

It's also TDD-friendly, since all business logic is in the domain objects, not in the ORM objects, so you can unit test them much easier.它也是 TDD 友好的,因为所有业务逻辑都在域对象中,而不是在 ORM 对象中,因此您可以更轻松地对它们进行单元测试。

If the classes you use have a lot of fields, MapStruct and/or Lombok Builders can keep your code cleaner.如果您使用的类有很多字段,MapStruct 和/或 Lombok Builders 可以使您的代码更简洁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM