J'essaie d'utiliser reseasey 2.0.1.ga pour télécharger un formulaire avec un fichier dans une application GAE, à l'aide de la méthode conseillée à Comment faire un téléchargement de fichier multipart / formulaire avec JAX-RS?
Index.html strong> p> repos.java strong> p> Uploadform.java strong> p> mais je reçois le message d'erreur suivant (probablement en raison de la implémentation immédiate du fournisseur qui utilise des fichiers temporaires pour gérer le flux d'entrée): P> HTTP ERROR 500
Problem accessing /files/service/upload. Reason:
java.io.FileOutputStream is a restricted class. Please see the Google App Engine developer's guide for more details.
Caused by:
java.lang.NoClassDefFoundError: java.io.FileOutputStream is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
at org.apache.james.mime4j.storage.TempFileStorageProvider$TempFileStorageOutputStream.<init>(TempFileStorageProvider.java:117)
at org.apache.james.mime4j.storage.TempFileStorageProvider.createStorageOutputStream(TempFileStorageProvider.java:107)
at org.apache.james.mime4j.storage.ThresholdStorageProvider$ThresholdStorageOutputStream.write0(ThresholdStorageProvider.java:113)
at org.apache.james.mime4j.storage.StorageOutputStream.write(StorageOutputStream.java:119)
at org.apache.james.mime4j.codec.CodecUtil.copy(CodecUtil.java:43)
at org.apache.james.mime4j.storage.AbstractStorageProvider.store(AbstractStorageProvider.java:57)
at org.apache.james.mime4j.message.BodyFactory.textBody(BodyFactory.java:167)
at org.apache.james.mime4j.message.MessageBuilder.body(MessageBuilder.java:148)
at org.apache.james.mime4j.parser.MimeStreamParser.parse(MimeStreamParser.java:101)
at org.apache.james.mime4j.message.Message.<init>(Message.java:141)
at org.apache.james.mime4j.message.Message.<init>(Message.java:100)
at org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl.parse(MultipartInputImpl.java:76)
at org.jboss.resteasy.plugins.providers.multipart.MultipartFormAnnotationReader.readFrom(MultipartFormAnnotationReader.java:55)
at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:105)
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.read(GZIPDecodingInterceptor.java:46)
at org.jboss.resteasy.core.interception.MessageBodyReaderContextImpl.proceed(MessageBodyReaderContextImpl.java:108)
at org.jboss.resteasy.core.messagebody.ReaderUtility.doRead(ReaderUtility.java:111)
at org.jboss.resteasy.core.messagebody.ReaderUtility.doRead(ReaderUtility.java:93)
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:146)
at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:114)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137)
at org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:252)
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:217)
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:206)
at org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:514)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:491)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:120)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:200)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:48)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:43)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
...
6 Réponses :
On dirait que la bibliothèque MIME4J tente d'écrire des fichiers temporaires, qui n'est pas autorisé sur le moteur App. MIME4J peut être configuré pour utiliser un fournisseur de stockage de mémoire, mais je ne sais pas si l'utilisation restante de celle-ci permet cette configuration. P>
Eh bien, j'ai trouvé une promenade pour cela - j'utilise Apache Commons-upload avec Reseasey, en injectant le HttpServletRequest dans une méthode reseéquate (et en transformant les flux en array d'octet / chaîne à l'aide de Commons-io) . Tous les packages sont pris en charge par App topp. Je préférerais toujours trouver une solution restante, pour éviter le code de gril-up autour du fichieriterator. P> P>
Je viens de courir dans ce problème et j'ai regardé dans le code source du constructeur de messages de MIME4J. Il obtient le c'est Merci pour l'exemple concis d'utiliser @MultiPartform! p> p> tempfiletstorageProvider code> en appelant
par défautStorageProvider.getinstance () code>. Vous pouvez modifier la valeur par défaut en une qui n'écrire pas sur le système de fichiers en appelant:
org.apache.james.mime4j.storage.defaultStorageProvider code>. / p>
Pour utiliser le MemoryStorageProvider CODE> avec Reseasey Vous pouvez définir la propriété Système suivante:
-Dorg.apache.james.mime4j.defaultStorageProvider=org.apache.james.mime4j.storage.MemoryStorageProvider
J'ai testé avec ReseaseSy 3.15.1 et Tomcat 9.0.40 - et cela a fonctionné. Merci beaucoup!
J'ai essayé d'utiliser MemoryStorageProvider. Mais on dirait que cela ne fonctionne pas pour la plupart des fichiers autres que les plus petits.
J'ai proposé une autre solution qui s'étend sur AbstractStorageProvider à l'aide de Google Cloud Storage et fonctionne bien. P>
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsInputChannel;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.james.mime4j.storage.AbstractStorageProvider;
import org.apache.james.mime4j.storage.Storage;
import org.apache.james.mime4j.storage.StorageOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
/**
* A {@link org.apache.james.mime4j.storage.StorageProvider} that stores the data in google cloud storage files. The files
* are stored in a user specified bucket. User of this class needs to supply the google cloud storage service and bucket name.
*
* This implementation is based on {@link org.apache.james.mime4j.storage.TempFileStorageProvider}
* <p>
* Example usage:
*
* <pre>
* final String bucketName = "my-bucket";
* DefaultStorageProvider.setInstance(new GcsStorageProvider(gcsService, bucketName));
* </pre>
*/
@Slf4j
public class GcsStorageProvider extends AbstractStorageProvider {
private static final int FETCH_SIZE_MB = 4 * 1024 * 1024;
private static final String PUBLIC_READ = "public-read";
private static final GcsFileOptions gcsFileOpts = new GcsFileOptions.Builder().acl(PUBLIC_READ).mimeType("text/csv").build();
private final GcsService gcsService;
private final String bucketName;
/**
* Creates a new <code>GcsStorageProvider</code> using the given
* values.
*
* @param gcsService an implementation of {@link GcsService}
* @param bucketName google cloud storage bucket name to use.
*/
public GcsStorageProvider(final GcsService gcsService, final String bucketName) {
this.gcsService = gcsService;
this.bucketName = bucketName;
}
@Override
public StorageOutputStream createStorageOutputStream() throws IOException {
return new GcsStorageProvider.GcsStorageOutputStream(gcsService, bucketName);
}
private static final class GcsStorage implements Storage {
private final GcsService gcsService;
private GcsFilename gcsFilename;
private static final Set<GcsFilename> filesToDelete = new HashSet();
public GcsStorage(final GcsService gcsService, final GcsFilename gcsFilename) {
this.gcsService = gcsService;
this.gcsFilename = gcsFilename;
}
@Override
public InputStream getInputStream() throws IOException {
if (this.gcsFilename == null) {
throw new IllegalStateException("storage has been deleted");
} else {
final GcsInputChannel readChannel = gcsService.openPrefetchingReadChannel(gcsFilename, 0, FETCH_SIZE_MB);
return Channels.newInputStream(readChannel);
}
}
@Override
public void delete() {
synchronized(filesToDelete) {
if (this.gcsFilename != null) {
filesToDelete.add(this.gcsFilename);
this.gcsFilename = null;
}
final Iterator iterator = filesToDelete.iterator();
while(iterator.hasNext()) {
GcsFilename filename = (GcsFilename)iterator.next();
try {
if (gcsService.delete(filename)) {
iterator.remove();
}
} catch (final IOException ex) {
log.error(ex.getMessage(), ex);
}
}
}
}
}
private static final class GcsStorageOutputStream extends StorageOutputStream {
private final GcsService gcsService;
private GcsFilename gcsFilename;
private final OutputStream outputStream;
public GcsStorageOutputStream(final GcsService gcsService, final String bucketName) throws IOException {
this.gcsService = gcsService;
final String fileName = UUID.randomUUID().toString();
this.gcsFilename = new GcsFilename(bucketName, fileName);
GcsOutputChannel gcsOutputChannel = gcsService.createOrReplace(gcsFilename, gcsFileOpts);
this.outputStream = Channels.newOutputStream(gcsOutputChannel);
}
@Override
protected void write0(byte[] buffer, int offset, int length) throws IOException {
this.outputStream.write(buffer, offset, length);
}
@Override
protected Storage toStorage0() throws IOException {
return new GcsStorage(gcsService, gcsFilename);
}
@Override
public void close() throws IOException {
super.close();
this.outputStream.close();
}
}
}
Veuillez inclure la partie de la page qui répond à cette question et non seulement de l'URL.
Je voulais dire que j'ai couru dans le numéro de téléchargement de fichier sur GAE et j'ai essayé la solution suggérée ici: Stackoverflow.com/a/10374097/1250435. Mais cela ne fonctionne pas pour les fichiers plus gros. Je suis donc proposé une autre solution et j'ai affiché le lien GIST avec ma solution. Je pense que le gist est public.
Je viens de mettre à jour le pot de reseasy-multipart-fournisseur de 2.2.0.ga à 3.1.4.final. Nous devons appeler une méthode de près explicitement. Il s'occupera de supprimer les fichiers m4jxxxx.tmp.
voir @docs http : //docs.jboss.org/resserasy/docs/3.1.4.final/serguide/html_single/index.html em> p>