У меня есть веб-приложение Java Google App Engine, которое позволяет пользователям загружать изображения.Локально работает отлично.Однако после развертывания его в «облаке» и загрузки изображения появляется следующая ошибка:
java.lang.IllegalArgumentException: невозможно работать с несколькими группами объектов в одной транзакции.
Я использую хранилище BLOB-объектов для хранения изображений ( Справочник Blobstore ).Мой метод ниже:
@RequestMapping(value = "/ajax/uploadWelcomeImage", method = RequestMethod.POST)
@ResponseBody
public String uploadWelcomeImage(@RequestParam("id") long id,
HttpServletRequest request) throws IOException, ServletException {
byte[] bytes = IOUtils.toByteArray(request.getInputStream());
Key parentKey = KeyFactory.createKey(ParentClass.class.getSimpleName(),
id);
String blobKey = imageService.saveImageToBlobStore(bytes);
imageService.save(blobKey, parentKey);
return "{success:true, id:\"" + blobKey + "\"}";
}
Вы заметите, что этот метод сначала вызывает "imageService.saveImageToBlobStore".Это то, что на самом деле сохраняет байты изображения.Метод imageService.save берет сгенерированный blobKey и оборачивает его в объект ImageFile, который является объектом, содержащим String blobKey.Мой сайт ссылается на imageFile.blobKey, чтобы получить правильное изображение для отображения.«SaveImageToBlobStore» выглядит так:
@Transactional
public String saveImageToBlobStore(byte[] bytes) {
// Get a file service
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "text/plain"
AppEngineFile file = null;
try {
file = fileService.createNewBlobFile("image/jpeg");
} catch (IOException e) {
e.printStackTrace();
}
// Open a channel to write to it
boolean lock = true;
FileWriteChannel writeChannel = null;
try {
writeChannel = fileService.openWriteChannel(file, lock);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (FinalizationException e) {
e.printStackTrace();
} catch (LockException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// This time we write to the channel using standard Java
try {
writeChannel.write(ByteBuffer.wrap(bytes));
} catch (IOException e) {
e.printStackTrace();
}
// Now finalize
try {
writeChannel.closeFinally();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Now read from the file using the Blobstore API
BlobKey blobKey = fileService.getBlobKey(file);
while (blobKey == null) { //this is hacky, but necessary as sometimes the blobkey isn't available right away
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
blobKey = fileService.getBlobKey(file);
}
// return
return blobKey.getKeyString();
}
Мой другой метод сохранения выглядит следующим образом:
public void save(String imageFileBlobKey, Key parentKey) {
DatastoreService datastore = DatastoreServiceFactory
.getDatastoreService();
Entity imageFileEntity = new Entity("ImageFile", parentKey);
imageFileEntity.setProperty("blobKey", imageFileBlobKey);
datastore.put(imageFileEntity);
}
Как я уже говорил, он работает локально, но не развернут.Ошибка заключается в вызове saveImageToBlobstore, в частности в «fileservice.getBlobKey (file)».Комментирование этой строки устраняет ошибку, но мне нужна эта строка для сохранения байтов изображения в хранилище BLOB-объектов.
Я также пытался комментировать другие строки (см. Ниже), но безуспешно.Та же ошибка для этого:
@RequestMapping(value = "/ajax/uploadWelcomeImage", method = RequestMethod.POST)
@ResponseBody
public String uploadWelcomeImage(@RequestParam("id") long id,
HttpServletRequest request) throws IOException, ServletException {
//byte[] bytes = IOUtils.toByteArray(request.getInputStream());
//Key parentKey= KeyFactory.createKey(ParentClass.class.getSimpleName(),
//id);
byte[] bytes = {0,1,0};
String blobKey = imageService.saveImageToBlobStore(bytes);
//imageService.save(blobKey, parentKey);
return "{success:true, id:\"" + blobKey + "\"}";
}
Есть идеи?Я использую GAE 1.5.2.Спасибо!
ОБНОВЛЕНИЕ, РЕШЕНИЕ НАЙДЕНО: Я взял некоторый код из транзакционного «saveImageToBlobStore» и поднял его на уровень выше.Смотрите ниже:
@RequestMapping(value = "/ajax/uploadWelcomeImage", method = RequestMethod.POST)
@ResponseBody
public String uploadWelcomeImage(@RequestParam("id") long id,
HttpServletRequest request) throws IOException, ServletException {
byte[] bytes = IOUtils.toByteArray(request.getInputStream());
Key parentKey = KeyFactory.createKey(ParentClass.class.getSimpleName(),
id);
//pulled the following out of transactional method:
AppEngineFile file = imageService.saveImageToBlobStore(bytes);
FileService fileService = FileServiceFactory.getFileService();
//code below is similar to before//////////////
BlobKey key = fileService.getBlobKey(file);
String keyString = key.getKeyString();
imageService.save(keyString, parentKey);
return "{success:true, id:\"" + keyString + "\"}";