java - 当我认为我可以从 Spring 中的实体访问服务时,如何更好的解决方案来替换我的代码?

标签 java spring jpa entity

我在访问我的实体中的服务时遇到问题。我知道,除了我的代码不起作用之外,也不推荐它。所以,我想知道如果我遇到这样的问题,最佳做法是什么?这是我的类(class)。

Controller 类:

@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;
   }
}

在我的 View html 上,我迭代了步骤列表

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

问题是,由于某种原因,我必须使用 if else 条件来获取当前日期以在 isStepNow() 方法中使用。一个来自操作系统。另一份来自数据库。所以,我想到了创建一个服务类的想法

以下是服务类:

public interface TimeServices {
   Date getNow();
}

和实现类:

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

}

问题出在我的实体中:

@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;
      }
   }
}

当然不行,因为timeService始终为null。有人可以建议我解决这个问题吗?

我知道我可以将 isStepNow() 编辑为 isStepNow(Date date)。然后,我可以通过 Controller 访问该服务。所以我可以在我的 View 中调用 isStepNow(date) 。但是,我认为编写源代码效率不高,因为我必须从某些 Controller 访问服务,而不是只在实体中编写一次。

最佳答案

我已经看过很多这样的讨论了。 使用DDD的人往往会这样解决:

  • 将 @Entity 注解的类重命名为 StepEntity 或 ORMStep 类似的名称,并仅保留在该类中执行 ORM 所需的字段。
  • 创建您使用 ORMStep 和依赖服务创建的不同(域)类 Step,并将域逻辑方法放入该类中。
  • 让 StepService 接口(interface)(最好称之为 StepRepository)返回 Step 类,而不是 ORMStep。
  • 通过注入(inject) DAO(Spring Data 也将其称为 Repository)和依赖服务来实现 StepRepository,并将它们组合起来读取 ORMStep 并转换为 Step 类。

这看起来需要付出很大的努力,并且您可能还需要将 Step 实例转换回 ORMStep 类才能进行更新,但从长远来看,这是一个非常干净的解决方案。您可以独立于 ORM 类发展 Step 类,或者切换 ORM,而无需更改 Controller 等。

它也是 TDD 友好的,因为所有业务逻辑都在域对象中,而不是在 ORM 对象中,因此您可以更轻松地对它们进行单元测试。

如果您使用的类有很多字段,MapStruct 和/或 Lombok Builders 可以使您的代码保持简洁。

关于java - 当我认为我可以从 Spring 中的实体访问服务时,如何更好的解决方案来替换我的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60949240/

相关文章:

java - Python 解析 Java Double.toHexString(double) 的输出

java - Spring REST API 并防止更改自动生成的属性?

java - 如何将 javax.persistence.Column 定义为 Unsigned TINYINT?

java - Hibernate Java 持久化来自持久化父类(super class)的子类实体

java - Firebase:没有要序列化的属性 - Android

java - SWT 文本输出和换行

java - 如何在restful中将map转换为json

java - Spring 安全 :java. lang.NoClassDefFoundError: org/springframework/security/context/DelegatingApplicationListener

java - @Autowire如何在不使用@Bean注解的情况下获取spring bean

jpa - 使用 JPA 一次性创建新实体或更新现有实体