我正在使用Java服务,其中表A中的数据进入表B。该服务将POST请求发送到REST服务器,并为复制的每一行创建一个位置标头作为响应,确认已创建新资源并向新创建的资源发出GET请求时,将POJO作为JSON返回。这是处理POST请求的资源方法。

@POST
@Produces({MediaType.APPLICATION_JSON})
public Response migrateToMinio(@Context UriInfo uriInfo) throws Exception {
    tiedostoService = new TiedostoService();
    attachmentService = new AttachmentService();
    List<Tiedosto> tiedostoList = tiedostoService.getAllFiles();
    List<String> responseList = new ArrayList<>();
    Response r;
    Integer newRow;
    String responseData = null;
    int i=1;
    for (Tiedosto tiedosto : tiedostoList) {
        Attachment attachment = new Attachment();
        attachment.setCustomerId(tiedosto.getCustomerId());
        attachment.setSize(tiedosto.getFileSize());
        newRow = attachmentService.createNew(attachment);
        UriBuilder builder = uriInfo.getAbsolutePathBuilder();
        if (newRow == 1) {
            builder.path(Integer.toString(i));
            r = Response.created(builder.build()).build();
            responseData = r.getLocation().toString();
            i++;
        }
        responseList.add(responseData);
    }
    String jsonString = new Gson().toJson(responseList);
    return Response.status(Response.Status.OK).entity(jsonString).build();
}
tiedostoServiceattachmentService是两个表的服务类。 tiedostoList具有tiedosto表中的所有行,并已在for循环内进行迭代,以便为tiedostoList中的每个项目在附件表中创建新行。当我将POST请求发送到/rest/attachments时,需要花费几秒钟的时间来处理并返回状态200以及所创建资源的列表,如下所示:
java - 如何在Java中以正确的方式将List &lt;&gt;项目作为POST数据发送?-LMLPHP

现在,我的问题是,是否有一种方法可以实现它,以便新创建的资源位置在创建后立即返回(也许是创建的201),而不必等待最终状态200?

最佳答案

这种解决方案将假定您保存附件的服务(AttachmentService)将能够在保存之前计算位置。例如,服务应该能够知道,如果最后一个附件存储的ID为10,则下一个附件存储的ID为11(或者随后的ID将被计算),因此具有位置的http://localhost:8080/rest/attachments/11

假设您的服务中存在逻辑,您可以创建一个收据对象,其中包含创建资源的位置以及代表已保存资源的 future 。该收据对象可以由服务而不是附件本身返回。这样的收据对象的实现可能类似于以下内容:

public class CreationReceipt<T> {

    private final String location;
    private final Future<T> attachment;

    public CreationReceipt(String location, Future<T> attachment) {
        this.location = location;
        this.attachment = attachment;
    }

    public String getLocation() {
        return location;
    }

    public Future<T> getAttachment() {
        return attachment;
    }
}

AttachmentService中,将存在一种存储新Attachment并返回CreationReceipt<Attachment>的方法:
public class AttachmentService {

    public CreationReceipt<Attachment> createNew(Attachment attachment) {
        String location = computeLocationFor(attachment);
        Future<Attachment> savedAttachment = saveAsynchronously(attachment);
        return new CreationReceipt<>(location, savedAttachment);
    }

    private Future<Attachment> saveAsynchronously(Attachment attachment) { ... }

    private String computeLocationFor(Attachment attachment) { ... }
}

预先计算Attachment的位置的逻辑将取决于您的应用程序的具体情况(我将对它进行打桩以便添加逻辑),但是用于异步保存Attachment的逻辑可以遵循一种通用模式。使用ExecutorService,可以使用于保存Attachment(您的应用程序已使用)的同步逻辑异步。为此,将同步逻辑提交到ExecutorService(使用submit方法),并且Future返回ExecutorService,该Attachment包装已保存的Attachment,并在成功保存Attachment后完成。

一个示例(尽管不完整)实现类似于:
public class AttachmentService {

    private final ExecutorService executor = Executors.newSingleThreadExecutor();

    public CreationReceipt<Attachment> createNew(Attachment attachment) {
        String location = computeLocationFor(attachment);
        Future<Attachment> savedAttachment = saveAsynchronously(attachment);
        return new CreationReceipt<>(location, savedAttachment);
    }

    private Future<Attachment> saveAsynchronously(Attachment attachment) {
        return executor.submit(() -> save(attachment));
    }

    private Attachment save(Attachment attachment) { ... }

    private String computeLocationFor(Attachment attachment) { ... }
}

请注意,此实现一次只允许保存一个Executors.newSingleThreadExecutor()(根据使用executor的性质),但是可以通过定义ExecutorService来使用其他save实现来更改逻辑。要完成此实现,只需为Attachment方法添加一个实现,该实现可同步保存一个新的createNew对象(该同步逻辑应该在您现有的AttachmentService方法中的Attachment中找到)。

从这一点来看,保存saveLocations的逻辑将是:
List<String> savedLocations = new ArrayList<>();

for (Tiedosto tiedosto : tiedostoList) {
    Attachment attachment = new Attachment();
    attachment.setCustomerId(tiedosto.getCustomerId());
    attachment.setSize(tiedosto.getFileSize());

    CreationReceipt<Attachment> receipt = attachmentService.createNew(attachmentToSave);
    savedLocations.add(receipt.getLocation());
}

// Do something with savedLocations

这是一个不完整的实现,但应演示将要使用的基本结构。循环完成后,您可以将201 Created包含为响应的主体,并将响应状态代码设置为ojit_code。

关于java - 如何在Java中以正确的方式将List <>项目作为POST数据发送?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51653357/

10-13 08:23