如何使用JPA消除SpringBoot中的紧耦合

问题描述 投票:0回答:1

我是 Spring boot/JPA 的初学者,我试图用一种方法消除代码中的紧密耦合,显然唯一有效的解决方案是紧密耦合的代码,但这是一种不好的做法。 所以我有一个名为“用户”的实体和一个名为“位置”的实体。 TL DR User 有一系列包含对象的位置,基本上:

{id: "12f4", userId: "1", name: "haus", latitude: "12", longitude: "34"}

问题依赖于位置实体。我有这个位置实体:

@Entity
@Table(name = "locations")
public class Location {
    @Id
    @GeneratedValue
    private UUID locationId;

    private String locationName;
    private String latitude;
    private String longitude;

    @Column(name = "user_id")
    private UUID userId;


    GETTERS AND SETTERS...

        public UUID getUserId() {
        return userId;
    }

    public void setUserId(UUID userId) {
        this.userId = userId;
    }

然后我就有了我的存储库 LocationRespository

public interface LocationRepository extends JpaRepository<Location, UUID>{
}

之后我就有了我的LocationService(接口)

public interface LocationService {
    Location createLocation(Location location, UUID userId);
    List<Location> getAllLocations();
    ... rest of the code
}

之后我有了我的 LocationServiceImpl (类)

@Service
public class LocationServiceImpl implements LocationService {
    private final LocationRepository locationRepository;

    @Autowired
    public LocationServiceImpl(LocationRepository locationRepository, UserRepository userRepository) {
        this.locationRepository = locationRepository;
    }

    @Override
    public Location createLocation(Location location, UUID userId) {
        HERE IS THE PROBLEM
        location.setUserId(userId);
        return this.locationRepository.save(location);
    }

和我的控制器:

@RestController
@RequestMapping("/api/v1/locations")
public class LocationController {
    private final LocationService locationService;

    @Autowired
    public LocationController(LocationService locationService) {
        this.locationService = locationService;
    }

    @PostMapping("/create/{userId}")
    public Location createLocation(@PathVariable("userId") UUID userId, @RequestBody Location location) {
        return locationService.createLocation(location, userId);
    }

如何从这里删除这个错误代码:(Service Impl)

location.setUserId(userId);

在我使用邮递员的情况下,我传递了 userId 的 uri,如下所示: http://localhost:5000/api/v1/locations/create/b7999c24-8d80-4560-aead-5d801e833e0b

我也有这样的身体: { "locationName": "达姆施塔特 zwei", “纬度”:“1321234”, “经度”:“4256363” }

唯一的问题是删除紧耦合代码,因为它直接从我的实体调用设置器到服务中。 我该如何解决这个问题?

java spring-boot jpa
1个回答
0
投票

首先,在移除setter之前,可以发现在API中直接使用Locationentity作为@RequestBody有一个问题。

  • 原因:如果直接使用实体作为API参数,当实体改变时,API规范也会改变。
    • 实体和API规范之间强耦合是不好的。这可以通过使用DTO(数据传输对象)来解决。

另外,直接返回一个实体作为服务的返回类型也会导致同样的问题,如果存在双向关联,会出现递归,出现StackOverFlow。

  • 我将在下面介绍我的解决方案。
//DTO(Data Transfer Object)
public record LocationCreateRequest(
        String locationName,
        String latitude,
        String longitude
) {
}
public record LocationCreateRepsonse(
        String id,
        String locationName,
        String latitude,
        String longitude
) {
}
@RestController
@RequestMapping("/api/v1/locations")
public class LocationController {
    private final LocationService locationService;

    @Autowired
    public LocationController(LocationService locationService) {
        this.locationService = locationService;
    }

    @PostMapping("/create/{userId}")
    public LocationCreateRepsonse createLocation(@PathVariable("userId") UUID userId, @RequestBody LocationCreateRequest request) {
        return locationService.createLocation(request, userId);
    }
}

现在让我们删除 setter。

@Service
public class LocationServiceImpl implements LocationService {
    private final LocationRepository locationRepository;

    @Autowired
    public LocationServiceImpl(LocationRepository locationRepository, UserRepository userRepository) {
        this.locationRepository = locationRepository;
    }

    @Override
    public LocationCreateResponse createLocation(LocationCreateRequest request, UUID userId) {
                Location location = new Location(request, userId); //or Location.from(request, userId); <- static factory method
                this.locationRepository.save(location);
                return new LocationCreateResponse(location); //or LocationCreateResponse.from(location);
    }
}
@Entity
@Table(name = "locations")
@NoArgsConstructor
public class Location {
    @Id
    @GeneratedValue
    private UUID locationId;

    private String locationName;
    private String latitude;
    private String longitude;

    @Column(name = "user_id")
    private UUID userId;

    public Location(LocationCreateRequest request, UUID userId) {
        this.locationId = request.locationId();
        this.locationName = request.locationName();
        this.latitude = request.latitude();
        this.longitude = request.longitude();
        this.userId = userId;
    }
}
  • 可以使用构造函数而不是使用 setter 创建和持久化实体。
  • 您还可以使用静态工厂方法而不使用setter。
  • 我同意在服务层使用 setter 是不好的做法。
    • 但是,我认为这个问题与OOP有关,而不是与JPA强耦合的问题。

希望对您有帮助:)

© www.soinside.com 2019 - 2024. All rights reserved.