I'm trying to upload multiple files at once with Play Framework, but I always get the first image for each uploaded. Here's a concrete case :
The HTML :
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="image" />
<input type="file" name="image" />
<input type="file" name="image" />
<input type="file" name="image" />
<input type="submit" name="submit" value="Send images" />
</form>
The controller :
public static void upload() {
File[] images = params.get("image", File[].class);
for (File f : images) {
Logger.info (f.getName());
}
}
If I upload image1.jpg, image2.jpg, image3.jpg & image4.jpg, the Logger.info on the console will display :
image1.jpg
image1.jpg
image1.jpg
image1.jpg
The other images won't be used.
I tried with List<File> instead of File[] but it doesn't work neither.
I also saw there is kind the same question here on SO (here), that use this as an answer :
List<Upload> files = (List<Upload>) request.args.get("__UPLOADS");
But it doesn't work in the v1.2.4 of Play!.
I'm using Play v1.2.4.
Thank you really much for your help!
Well, I have opened a ticket at Play! Framework because it seems to be problem, and apparently, I'm not the only one to have this behavior.
I tested with the new 1.2.5, and the problem is fixed, at least with the solution I gave on the question :
public static void upload() {
File[] images = params.get("image", File[].class);
for (File f : images) {
Logger.info (f.getName());
}
}
Note: I'm using Java 7!
Use the automatic binding instead of looking in the params:
public class Application extends Controller {
public static void index() {
render();
}
public static void upload(File[] files)
{
for (File file : files)
{
Logger.info(file.getName());
}
index();
}
}
The view template:
#{extends 'main.html' /}
#{set title:'Home' /}
#{form #upload(), enctype:'multipart/form-data'}
<input type="file" name="files" />
<input type="file" name="files" />
<input type="file" name="files" />
<input type="submit" value="Send it..." />
#{/}
multi file upload with play?
public static void overviewsubmit(File fake) {
List<Upload> files = (List<Upload>) request.args.get("__UPLOADS");
for(Upload file: files) {
Logger.info("Size = %d", file.getSize());
}
}
Without the File fake argument the method will not handle multipart/form-data and you'll get an empty request.args array. If anyone knows the play/standard annotation for it, let me know :)
Related
I tried to upload file (angular 5) using angular material 5.
app.component.html
<mat-horizontal-stepper [linear]="isLinear" #stepper="matHorizontalStepper">
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Upload your audio file</ng-template>
<mat-form-field>
<input matInput
style="display: none"
type="file" (change)="onFileSelected($event)"
#fileInput name ="file" formControlName="firstCtrl" required>
<button mat-button (click)="fileInput.click()" >Select File</button>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
app.component.ts
export class AppComponent {
selectedFile: File=null;
isLinear = true;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
constructor(private _formBuilder: FormBuilder, private http: HttpClient) {}
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required]
});
}
But I got this error
ERROR Error: Input type "file" isn't supported by matInput.
knowing this code worked well without angular material. Any issue?
I had the same problem,
Try doing this,
<button mat-raised-button (click)="openInput()">Select File to Upload</button>
<input id="fileInput" hidden type="file" (change)="fileChange($event.target.files)" name="file" accept=".csv,.xlsv">
openInput(){
document.getElementById("fileInput").click();
}
What above code does is creates simply a Material button and call openInput() method which later on replaces that button to below HTML code
<input id="fileInput" hidden type="file" >
This worked for me.
Happy Coding ☻
Faster solution would be to use
https://github.com/danialfarid/ng-file-upload :
<md-button class='md-raised md-primary' id='uploadFile' ngf-multiple='true' ngf-select='upload($files, $file, $event)'
type='file'>
Upload File
else you would have to go to a custom code like this:
<label class="md-secondary md-raised md-button" md-ink-ripple for="input-file">
<span>Select File to upload</span>
</label>
<input type="file" ngf-select ng-model="input-file" name="input-file" id="input-file">
EDITED:
In your HTML:
<input #file type="file" nbButton multiple (change)="upload(file.files)" />
then in your component:
upload(files: any) {
this.yourServiceToUploadFiles.uploadFile(files).subscribe(
(response: any) => { .......})}
and then in your service:
uploadFile(files: any[]): Observable<HttpResponse<Blob>> {
if (files.length === 0) {
return;
}
const formData = new FormData();
for (const file of files) {
formData.append(file.name, file);
}
return this.http.post(`${apiUrl}/yourServiceEndPoint`, formData, {
observe: "response",
responseType: "blob"
});
}
I'm searching the answer but without any luck. Perhaps I asked wrong question. I have a form in my cms page in PS 1.6. Code below:
<form method="post" action=""><input name="text1" type="text" /><br /> <input value="Check" onclick="getStatus()" type="button" /></form>
In \override\controllers\front\CmsController.php I have getStatus function. Which return "Hello world". Like You see "action" in form is empty. How to create link to this controller which is overrider ?
Kind regards
you can do like this.
In tpl
<form method="post" action="">
<input name="text1" type="text" /><br />
<input type="hidden" name="action" value="getStatus">
<input value="Check" type="submit" />
</form>
In Override controller
class CmsController extends CmsControllerCore
{
public function initContent(){
parent::initContent();
if(Tools::getValue('action') && Tools::getValue('action')=='getStatus'){
// Do your work What you want
echo "Hello world";
}
}
}
You can put: _PS_URI_?controller=cms&id_cms=1
Also can check dispatcher core and add your own rule or create a little module.
If is an override Controller u delete the file cache/class_index.php ?
I have two Views with two different post method in different Controllers. Both methods are used to export data to an Excel file.
Here is my code structure:
[System.Web.Mvc.HttpPost]
public ActionResult upload(HttpPostedFileBase file)
{
// code for this action
ExportToExcel(dd); // export from dataset
}
public void ExportToExcel(DataSet dd)
{
// Code to export
}
My View page code looks like:
<html>
<body>
#using (#Html.BeginForm("upload", "Test", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" id="files" multiple="multiple" />
<input type="submit" class="btn btn-lg btn-primary" value="Export Excel" name="submit" />
}
</body>
</html>
I have a second post method in another controller that looks basically the same as the above code, with only slight differences.
How can I merge the two post methods into one, and use to export?
I am new to ASP.NET Web API. I have a sample FileUpload web api (from some site) to upload files to the server. But, don't know how to test it using Fiddler.
http://localhost:54208/myapi/api/webapi/FileUpload
On test.aspx page: Following works fine.
I want to know how to use this API using Fiddler?
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form enctype="multipart/form-data" method="post" action="http://localhost:54208/myapi/api/webapi/FileUpload" id="ajaxUploadForm" novalidate="novalidate">
<fieldset>
<legend>Upload Form</legend>
<ol>
<li>
<label>Description </label>
<input type="text" style="width:317px" name="description" id="description">
</li>
<li>
<label>upload </label>
<input type="file" id="fileInput" name="fileInput" multiple>
</li>
<li>
<input type="submit" value="Upload" id="ajaxUploadButton" class="btn">
</li>
</ol>
</fieldset>
</form>
</body>
</html>
public async Task<HttpResponseMessage> FileUpload()
{
// Check whether the POST operation is MultiPart?
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
// Prepare CustomMultipartFormDataStreamProvider in which our multipart form
// data will be loaded.
//string fileSaveLocation = HttpContext.Current.Server.MapPath("~/App_Data");
string fileSaveLocation = HttpContext.Current.Server.MapPath("~/UploadedFiles");
CustomMultipartFormDataStreamProvider provider = new CustomMultipartFormDataStreamProvider(fileSaveLocation);
List<string> files = new List<string>();
try
{
// Read all contents of multipart message into CustomMultipartFormDataStreamProvider.
await Request.Content.ReadAsMultipartAsync(provider);
foreach (MultipartFileData file in provider.FileData)
{
files.Add(Path.GetFileName(file.LocalFileName));
}
// Send OK Response along with saved file names to the client.
return Request.CreateResponse(HttpStatusCode.OK, files);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
// We implement MultipartFormDataStreamProvider to override the filename of File which
// will be stored on server, or else the default name will be of the format like Body-
// Part_{GUID}. In the following implementation we simply get the FileName from
// ContentDisposition Header of the Request Body.
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public CustomMultipartFormDataStreamProvider(string path) : base(path) { }
public override string GetLocalFileName(HttpContentHeaders headers)
{
return headers.ContentDisposition.FileName.Replace("\"", string.Empty);
}
}
Help Appreciated!
Go to fiddler, select post type, give your local web api url.
In request body just upload file and execute, it will go to webapi method directly.
Controller method should be [HttpPost]
I am using the FileUpload sample from the asp.net tutorials. When I build it as a stand alone, it works fine. However, whenever I try to add that functionality to a new MVC4 website, the routing is wrong. I'm probably not explaining this well, so here is the code:
[HttpPost]
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
var sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach(var key in provider.FormData.AllKeys)
{
var strings = provider.FormData.GetValues(key);
if (strings != null) foreach(var val in strings)
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach(var file in provider.FileData)
{
var fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
Here is the page I'm using:
<div style="height:400px;">
<h3>File Upload</h3>
<form name="trip_search" method="post" enctype="multipart/form-data" action="api/upload">
<div>
<input type="radio" name="trip" value="round-trip"/>
Round-Trip
</div>
<div>
<input type="radio" name="trip" value="one-way"/>
One-Way
</div>
<div>
<input type="checkbox" name="options" value="nonstop" />
Only show non-stop flights
</div>
<div>
<input type="checkbox" name="options" value="airports" />
Compare nearby airports
</div>
<div>
<input type="checkbox" name="options" value="dates" />
My travel dates are flexible
</div>
<div>
<label for="seat">Seating Preference</label>
<select name="seat">
<option value="aisle">Aisle</option>
<option value="window">Window</option>
<option value="center">Center</option>
<option value="none">No Preference</option>
</select>
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
When I directly navigate to localhost:13927api/upload I see a response from the web api method. I've got the DefaultApi route registered in my WebApiConfig.
But when I'm on the page localhost/Home/About and I click on the submit button, it attempts to go to localhost/Home/api/upload - which does not exist.
What am I missing?
EDIT
The suggestion by Mario fixed my issue. The action method on my form was not relative to the root.
action="api/upload" vs. action="/api/upload"
That fixes my problem.
A bit of elaboration on the issue:
When you are in the default path (say yoursite/Home/Index -> if that is your default), then the action="api/myaction" will work because the current path is still seen as the root of the website. However, once you actually navigate to a path (say yoursite/Home/About), the current path is now under "Home" and so my missing "/" naturally was relative to my current path rather than the root. This is why the samples work without the leading "/", because the view in question is the default view.
Added the answer, if that can help others too:
Your form action="api/upload" is not relative to the root. Try action="/api/upload" or use one of the helpers to specify the route.