Typescript: загрузить данные файла как Blob - PullRequest
0 голосов
/ 19 января 2019

Я пытаюсь загрузить файл в angular7 / typescript, чтобы выполнить следующую функцию:

public add3dModel(input?: Blob, observe?: 'body', reportProgress?: boolean): Observable<string>;
public add3dModel(input?: Blob, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<string>>;
public add3dModel(input?: Blob, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<string>>;
public add3dModel(input?: Blob, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {

    let headers = this.defaultHeaders;

    // authentication (oauth) required
    if (this.configuration.accessToken) {
        let accessToken = typeof this.configuration.accessToken === 'function'
            ? this.configuration.accessToken()
            : this.configuration.accessToken;
        headers = headers.set('Authorization', 'Bearer ' + accessToken);
    }

    // to determine the Accept header
    let httpHeaderAccepts: string[] = [
        'application/json'
    ];
    let httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
    if (httpHeaderAcceptSelected != undefined) {
        headers = headers.set("Accept", httpHeaderAcceptSelected);
    }

    // to determine the Content-Type header
    let consumes: string[] = [
        'multipart/form-data'
    ];

    const canConsumeForm = this.canConsumeForm(consumes);

    let formParams: { append(param: string, value: any); };
    let useForm = false;
    let convertFormParamsToString = false;
    // use FormData to transmit files using content-type "multipart/form-data"
    // see /2433858/application-x-www-form-urlencoded-ili-multipart-form-data
    useForm = canConsumeForm;
    if (useForm) {
        formParams = new FormData();
    } else {
        formParams = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()});
    }

    if (input !== undefined) {
        formParams = formParams.append('input', <any>input) || formParams;
    }

    return this.httpClient.put<string>(`${this.basePath}/backend/model`,
        convertFormParamsToString ? formParams.toString() : formParams,
        {
            withCredentials: this.configuration.withCredentials,
            headers: headers,
            observe: observe,
            reportProgress: reportProgress
        }
    );
}

Эта функция генерируется автоматически с использованием swagger-codegen для машинописи.

HTML Я использую:

<input type="file" (change)="get3DModel($event)">

Эта функция вызывается при изменении:

get3DModel(e) {
  this._3dmodel_local = e.target.files[0];
}

Теперь, после нажатия кнопки (которая работает), я хотел бы загрузить выбранный файл.используя add3dModel -функцию.

Код, который я пробовал для этого (внутри функции кнопки):

  var r = new FileReader();
  r.onload = (e) =>{
    this.add3dModel(r.result) //obviously doesn't work
  }
  r.readAsArrayBuffer(this._3dmodel_local);

И

this.add3dModel(this._3dmodel_local);

Где обараз мой сервер возвращает 400 Bad Request с внутренним сообщением No file present

Что я делаю не так?

Чтобы уточнить: моя цель - загрузить локальный файл и загрузить его на сервер.

Ниже приведен исходный код сервера, это проект Spring-boot.

Сгенерированный автоматически API-код

@ApiOperation(value = "add new 3D Model", nickname = "add3dModel", notes = "", response = String.class, authorizations = {
    @Authorization(value = "oauth", scopes = {
        @AuthorizationScope(scope = "admin", description = "admin rights")
        })
}, tags={ "glassesBackend", })
@ApiResponses(value = { 
    @ApiResponse(code = 201, message = "created", response = String.class),
    @ApiResponse(code = 400, message = "bad request"),
    @ApiResponse(code = 401, message = "unauthorized"),
    @ApiResponse(code = 404, message = "not found") })
@ApiImplicitParams({
})
@RequestMapping(value = "/backend/model",
    produces = { "application/json" }, 
    consumes = { "multipart/form-data" },
    method = RequestMethod.PUT)
default ResponseEntity<String> add3dModel(@ApiParam(value = "file detail") @Valid @RequestPart("file") MultipartFile input) {
    return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

}

Дочерний класс:

    @Override
public ResponseEntity<String> add3dModel(@Valid MultipartFile formData){
    return ResponseEntity.ok(service.add3dModel(formData)); //using JPA repository
}

Прежде чем даже нажать add3dModel -метод, я получаю следующую ошибку:

Mapped to public org.springframework.http.ResponseEntity<java.lang.String> controller.backend.GlassesBackendController.add3dModel(org.springframework.web.multipart.MultipartFile)
           | 2019-01-20 12:38:06.584 DEBUG 8 --- [tp1374066265-14] .w.s.m.m.a.ServletInvocableHandlerMethod : Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<java.lang.String> controller.backend.GlassesBackendController.add3dModel(org.springframework.web.multipart.MultipartFile): Required request part 'file' is not present
           | 2019-01-20 12:38:06.599 DEBUG 8 --- [tp1374066265-14] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler public final org.springframework.http.ResponseEntity<java.lang.Object> org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest) throws java.lang.Exception
           | 2019-01-20 12:38:06.608 DEBUG 8 --- [tp1374066265-14] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : No match for [application/json], supported: []
           | 2019-01-20 12:38:06.629 DEBUG 8 --- [tp1374066265-14] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]

1 Ответ

0 голосов
/ 20 января 2019

Я создал stackblitz пример, где работает тип ввода = файл, единственное, чего не хватает в моем примере - это запрос на загрузку. Попробуйте построить объект запроса таким образом .

Если ваш сервер ожидает multipart/form-data, вы должны использовать его как Content-Type вместо application/json. Не забудьте добавить свой токен Authorization в заголовок запроса:

let fileList: FileList = event.target.files;
if(fileList.length > 0) {
    let file: File = fileList[0];
    let formData:FormData = new FormData();
    formData.append('uploadFile', file, file.name);
    let headers = new Headers();
    /** In Angular 5, including the header Content-Type can invalidate your request */

    headers.append('Content-Type', 'multipart/form-data');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Bearer ' + accessToken);

    let options = new RequestOptions({ headers: headers });
    this.http.post(`${this.apiEndPoint}`, formData, options)
        .map(res => res.json())
        .catch(error => Observable.throw(error))
        .subscribe(
            data => console.log('success'),
            error => console.log(error)
        )
}
...