Je travaille sur un service de Java où les données du tableau A va au tableau B. Le service envoie des requêtes POST à un serveur REST et pour chaque ligne copiée, un en-tête de l'emplacement est créé comme une réponse, ce qui confirme qu'une nouvelle ressource est créée et retour d'un POJO comme JSON lorsque la demande GET est émise à la ressource nouvellement créée. Ceci est la méthode de ressource poignées requêtes 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();
}
tiedostoService
et attachmentService
sont des classes de service pour deux tables. tiedostoList
a toutes les lignes de la tiedosto
table et a été répété à l' intérieur de la boucle de sorte qu'une nouvelle ligne de la table des pièces jointes est créé pour chaque élément tiedostoList
. Lorsque j'envoie la demande POST /rest/attachments
, il faut quelques secondes pour traiter et retourne l' état 200 avec une liste de ressources créée comme ceci:
Maintenant, ma question est, est-il un moyen de mettre en œuvre pour que le nouveau lieu de ressource est retourné immédiatement (peut-être que 201 créé) après la création de, sans avoir à attendre que le statut final 200?
Such a solution would presume that you the service saving the attachment (AttachmentService
) would be able to compute the location prior to saving it. For example, the service should be able to know that if the last attachment was stored with an ID of 10
, the next attachment would be stored with an ID of 11
(or however the subsequent ID would be calculated) and therefore would have a location of http://localhost:8080/rest/attachments/11
.
Presuming that logic is possible in your service, you could create a receipt object that contains the location of the created resource and a future that represents the saved resource. This receipt object can be returned by the service instead of the attachment itself. The implementation of such a receipt object could resemble the following:
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;
}
}
In AttachmentService
, there would exist a method that stores a new Attachment
and returns a 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) { ... }
}
The logic for pre-computing the location of an Attachment
will depend on the specifics of your application (and I will leave it stubbed for you to add the logic), but the logic for saving an Attachment
asynchronously can follow a common pattern. Using an ExecutorService
, synchronous logic for saving an Attachment
(which your application already uses) can be made asynchronous. To do this, the synchronous logic is submitted to an ExecutorService
(using the submit
method) and a Future
is returned by the ExecutorService
which wraps the saved Attachment
and will complete when the Attachment
is successfully saved.
An example (albeit incomplete) implementation would resemble:
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) { ... }
}
Notez que cette mise en œuvre ne permet qu'une seule Attachment
à enregistrer à la fois (par la nature de l' utilisation Executors.newSingleThreadExecutor()
), mais cette logique peut être modifiée en définissant executor
d'utiliser une autre ExecutorService
mise en œuvre. Pour compléter cette mise en œuvre, il suffit d' ajouter une mise en œuvre de la save
méthode qui enregistre de manière synchrone un nouvel Attachment
objet (cette logique synchrone doit se trouver dans votre actuelle createNew
méthode à partir AttachmentService
).
De ce point, la logique de l' enregistrement d' un Attachment
serait:
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
Ceci est une mise en œuvre imcomplete, mais il doit démontrer la structure de base qui serait utilisée. Une fois que la boucle est terminée, vous pouvez inclure saveLocations
que le corps de la réponse et de définir le code d'état de réponse 201 Created
.