- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在环回 3.0 中使用存储组件来访问云存储。但我需要如何在环回 4.0 中实现。下面的链接使其在 3.0 中采样。
https://github.com/strongloop/loopback-example-storage
最佳答案
我将与社区分享我的实现,因为即使 Miroslav Bajtoš 的答案关键是要做到这一点,建议的文档不是很清楚,我引用了Calling other APIS and web services .
lb4
创建了一个新的数据源命令 cli 工具和我填写了 json
文件的 key 与我在环回 3 数据源中使用的 key 相同。 // storage.datasource.ts
import { inject } from '@loopback/core';
import { juggler } from '@loopback/service-proxy';
import * as config from './storage-gc.datasource.json';
export class StorageGCDataSource extends juggler.DataSource {
static dataSourceName = 'StorageGC';
constructor(
@inject('datasources.config.StorageGC', { optional: true })
dsConfig: object = config,
) {
super(dsConfig);
}
}
// storage.datasource.json
{
"name": "Storage",
"connector": "loopback-component-storage",
"provider": "google",
"keyFilename": "your-project-key.json",
"projectId": "your-project-id",
"nameConflict": "makeUnique"
}
// Note: your-project-key.json is in the root folder at the same level that tsconfig.json
npm install --save loopback-component-storage
lb4
创建了两个新模型命令 cli 工具。这些型号是:Container
和 File
. // container.model.ts
import {Entity, model, property} from '@loopback/repository';
@model()
export class Container extends Entity {
@property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<Container>) {
super(data);
}
}
// file.model.ts
import { Entity, model, property } from '@loopback/repository';
@model()
export class File extends Entity {
@property({
type: 'string',
required: true,
})
name: string;
@property({
type: 'string',
})
type?: string;
@property({
type: 'string',
})
url?: string;
constructor(data?: Partial<File>) {
super(data);
}
}
src/
中创建了一个新文件夹名为 interfaces
的目录.在这个新文件夹中,我创建了一个 index.ts
(主要遵循导出约定)和 storage.interface.ts
(这是重要文件)// index.ts
export * from './storage.interface';
// storage.interface.ts
import { Container, File } from "../models";
export type Callback<T> = (err: Error | null, reply: T) => void;
export interface IStorageService {
// container methods
createContainer(container: Partial<Container>, cb: Callback<Container>): void;
destroyContainer(containerName: string, cb: Callback<boolean>): void;
getContainers(cb: Callback<Container[]>): void;
getContainer(containerName: string, cb: Callback<Container>): void;
// file methods
getFiles(containerName: string, options: Object, cb: Callback<File[]>): void;
getFile(containerName: string, fileName: string, cb: Callback<File>): void;
removeFile(containerName: string, fileName: string, cb: Callback<boolean>): void;
// main methods
upload(containerName: string, req: any, res: any, options: Object, cb: Callback<any>): void;
download(containerName: string, fileName: string, req: any, res: any, cb: Callback<any>): void;
}
container.controller.ts
文件,但在此步骤之前您需要安装 @loopback/service-proxy 运行以下命令:npm install --save @loopback/service-proxy
// storage-gc.controller.ts
import { inject } from '@loopback/core';
import { serviceProxy } from '@loopback/service-proxy';
import { post, requestBody, del, param, get, getFilterSchemaFor, Request, Response, RestBindings } from '@loopback/rest';
import { Filter } from '@loopback/repository';
import { promisify } from 'util';
import { IStorageService } from '../interfaces';
import { Container, File } from '../models';
export class StorageGcController {
@serviceProxy('StorageGC') // StorageGC is the name of the datasoruce
private storageGcSvc: IStorageService;
constructor(@inject(RestBindings.Http.REQUEST) public request: Request,
@inject(RestBindings.Http.RESPONSE) public response: Response) { }
@post('/containers', {
responses: {
'200': {
description: 'Container model instance',
content: { 'application/json': { schema: { 'x-ts-type': Container } } },
},
},
})
async createContainer(@requestBody() container: Container): Promise<Container> {
const createContainer = promisify(this.storageGcSvc.createContainer);
return await createContainer(container);
}
@get('/containers', {
responses: {
'200': {
description: 'Array of Containers model instances',
content: {
'application/json': {
schema: { type: 'array', items: { 'x-ts-type': Container } },
},
},
},
},
})
async findContainer(@param.query.object('filter', getFilterSchemaFor(Container)) filter?: Filter): Promise<Container[]> {
const getContainers = promisify(this.storageGcSvc.getContainers);
return await getContainers();
}
@get('/containers/{containerName}', {
responses: {
'200': {
description: 'Container model instance',
content: { 'application/json': { schema: { 'x-ts-type': Container } } },
},
},
})
async findContainerByName(@param.path.string('containerName') containerName: string): Promise<Container> {
const getContainer = promisify(this.storageGcSvc.getContainer);
return await getContainer(containerName);
}
@del('/containers/{containerName}', {
responses: {
'204': {
description: 'Container DELETE success',
},
},
})
async deleteContainerByName(@param.path.string('containerName') containerName: string): Promise<boolean> {
const destroyContainer = promisify(this.storageGcSvc.destroyContainer);
return await destroyContainer(containerName);
}
@get('/containers/{containerName}/files', {
responses: {
'200': {
description: 'Array of Files model instances belongs to container',
content: {
'application/json': {
schema: { type: 'array', items: { 'x-ts-type': File } },
},
},
},
},
})
async findFilesInContainer(@param.path.string('containerName') containerName: string,
@param.query.object('filter', getFilterSchemaFor(Container)) filter?: Filter): Promise<File[]> {
const getFiles = promisify(this.storageGcSvc.getFiles);
return await getFiles(containerName, {});
}
@get('/containers/{containerName}/files/{fileName}', {
responses: {
'200': {
description: 'File model instances belongs to container',
content: { 'application/json': { schema: { 'x-ts-type': File } } },
},
},
})
async findFileInContainer(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<File> {
const getFile = promisify(this.storageGcSvc.getFile);
return await getFile(containerName, fileName);
}
@del('/containers/{containerName}/files/{fileName}', {
responses: {
'204': {
description: 'File DELETE from Container success',
},
},
})
async deleteFileInContainer(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<boolean> {
const removeFile = promisify(this.storageGcSvc.removeFile);
return await removeFile(containerName, fileName);
}
@post('/containers/{containerName}/upload', {
responses: {
'200': {
description: 'Upload a Files model instances into Container',
content: { 'application/json': { schema: { 'x-ts-type': File } } },
},
},
})
async upload(@param.path.string('containerName') containerName: string): Promise<File> {
const upload = promisify(this.storageGcSvc.upload);
return await upload(containerName, this.request, this.response, {});
}
@get('/containers/{containerName}/download/{fileName}', {
responses: {
'200': {
description: 'Download a File within specified Container',
content: { 'application/json': { schema: { 'x-ts-type': Object } } },
},
},
})
async download(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<any> {
const download = promisify(this.storageGcSvc.download);
return await download(containerName, fileName, this.request, this.response);
}
}
@serviceProxy
Controller 中的装饰器,为此我创建了一个名为
providers
的新文件夹里面
src/
包含以下两个文件的文件夹:
// index.ts
export * from './storage-service.provider';
// storage-gc-service.provider.ts
import { getService, juggler } from '@loopback/service-proxy';
import { Provider } from '@loopback/core';
import { StorageGCDataSource } from '../datasources/storage-gc.datasource';
import { IStorageService } from '../interfaces';
export class StorageGCServiceProvider implements Provider<IStorageService> {
constructor(
protected dataSource: juggler.DataSource = new StorageGCDataSource()
/* I try to change the line above in the same way that documentation show,
as follows:
@inject('datasources.StorageGC')
protected dataSource: juggler.DataSource = new StorageGCDataSource()
and also, in the same way that repositories
@inject('datasources.StorageGC')
protected dataSource: StorageGCDataSource
but always return:
`Error: Cannot resolve injected arguments for StorageGCServiceProvider.[0]:
The arguments[0] is not decorated for dependency injection, but a value is
not supplied`
*/
) { }
value(): Promise<IStorageService> {
return getService(this.dataSource);
}
}
src/index.ts
和您的
storage-gc.controller.ts
通过以下方式
// src/index.ts
import { ApplicationConfig } from '@loopback/core';
import { HocicosCuriososApp } from './application';
import { StorageGCServiceProvider } from './providers';
export { HocicosCuriososApp };
export async function main(options: ApplicationConfig = {}) {
const app = new HocicosCuriososApp(options);
/* Add this line, it add a service to the app after that you can
call them in the controller with dependency injection, like:
@inject('services.StorageGCService') */
app.serviceProvider(StorageGCServiceProvider);
await app.boot();
await app.start();
const url = app.restServer.url;
console.log(`Server is running at ${url}`);
console.log(`Try ${url}/ping`);
return app;
}
// storage-gc.controller.ts
import { inject } from '@loopback/core';
import { post, requestBody, del, param, get, getFilterSchemaFor, Request, Response, RestBindings } from '@loopback/rest';
import { Filter } from '@loopback/repository';
import { promisify } from 'util';
import { IStorageService } from '../interfaces';
import { Container, File } from '../models';
export class StorageGcController {
@inject('services.StorageGCService')
private storageGcSvc: IStorageService;
constructor(@inject(RestBindings.Http.REQUEST) public request: Request,
@inject(RestBindings.Http.RESPONSE) public response: Response) { }
@post('/containers', {
responses: {
'200': {
description: 'Container model instance',
content: { 'application/json': { schema: { 'x-ts-type': Container } } },
},
},
})
async createContainer(@requestBody() container: Container): Promise<Container> {
const createContainer = promisify(this.storageGcSvc.createContainer);
return await createContainer(container);
}
@get('/containers', {
responses: {
'200': {
description: 'Array of Containers model instances',
content: {
'application/json': {
schema: { type: 'array', items: { 'x-ts-type': Container } },
},
},
},
},
})
async findContainer(@param.query.object('filter', getFilterSchemaFor(Container)) filter?: Filter): Promise<Container[]> {
const getContainers = promisify(this.storageGcSvc.getContainers);
return await getContainers();
}
@get('/containers/{containerName}', {
responses: {
'200': {
description: 'Container model instance',
content: { 'application/json': { schema: { 'x-ts-type': Container } } },
},
},
})
async findContainerByName(@param.path.string('containerName') containerName: string): Promise<Container> {
const getContainer = promisify(this.storageGcSvc.getContainer);
return await getContainer(containerName);
}
@del('/containers/{containerName}', {
responses: {
'204': {
description: 'Container DELETE success',
},
},
})
async deleteContainerByName(@param.path.string('containerName') containerName: string): Promise<boolean> {
const destroyContainer = promisify(this.storageGcSvc.destroyContainer);
return await destroyContainer(containerName);
}
@get('/containers/{containerName}/files', {
responses: {
'200': {
description: 'Array of Files model instances belongs to container',
content: {
'application/json': {
schema: { type: 'array', items: { 'x-ts-type': File } },
},
},
},
},
})
async findFilesInContainer(@param.path.string('containerName') containerName: string,
@param.query.object('filter', getFilterSchemaFor(Container)) filter?: Filter): Promise<File[]> {
const getFiles = promisify(this.storageGcSvc.getFiles);
return await getFiles(containerName, {});
}
@get('/containers/{containerName}/files/{fileName}', {
responses: {
'200': {
description: 'File model instances belongs to container',
content: { 'application/json': { schema: { 'x-ts-type': File } } },
},
},
})
async findFileInContainer(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<File> {
const getFile = promisify(this.storageGcSvc.getFile);
return await getFile(containerName, fileName);
}
@del('/containers/{containerName}/files/{fileName}', {
responses: {
'204': {
description: 'File DELETE from Container success',
},
},
})
async deleteFileInContainer(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<boolean> {
const removeFile = promisify(this.storageGcSvc.removeFile);
return await removeFile(containerName, fileName);
}
@post('/containers/{containerName}/upload', {
responses: {
'200': {
description: 'Upload a Files model instances into Container',
content: { 'application/json': { schema: { 'x-ts-type': File } } },
},
},
})
async upload(@param.path.string('containerName') containerName: string): Promise<File> {
const upload = promisify(this.storageGcSvc.upload);
return await upload(containerName, this.request, this.response, {});
}
@get('/containers/{containerName}/download/{fileName}', {
responses: {
'200': {
description: 'Download a File within specified Container',
content: { 'application/json': { schema: { 'x-ts-type': Object } } },
},
},
})
async download(@param.path.string('containerName') containerName: string,
@param.path.string('fileName') fileName: string): Promise<any> {
const download = promisify(this.storageGcSvc.download);
return await download(containerName, fileName, this.request, this.response);
}
}
关于typescript - 如何在环回 4.0 中使用存储组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54663283/
我打算使用 vulkan synchronization examples 之一作为如何处理不经常更新的统一缓冲区的引用。具体来说,我正在看这个: vkBeginCommandBuffer(...);
我对 git 的了解有限。 我已经从 master 创建了一个分支 B1,进行了一些编辑并提交到这个分支。 我想从 B1 创建另一个分支 B2,我在 B2 中进行了一些编辑 而且我还想提交 B2(包含
这是我做的 我创建了一个分支 abc。然后我创建了两个文本文件 one.txt 和 two.txt。然后我将它们提交到分支 abc。然后我从分支中删除文件 one.txt 并将这些更改提交到分支。 现
在我的主分支中,我得到了 2 个文件: file1.txt file2.txt 我从那里创建了名为 b1 的新分支。在b1中,我修改了file2.txt,不小心删除了file1.txt(从磁盘中,当我
我是 git 的新手。 我创建了一个分支,进行了更改,现在我想 merge 回 master 以使它们“永久化”。 所以我执行了 git merge 1.2 报告为已经是最新的,在 master 上执
我在一个新团队中,工作方式与我以前习惯的完全不同,我们在功能分支上工作,测试人员会在该功能分支上进行测试,然后我们会运行一个 jenkins 作业在该功能被测试签署时将该功能 merge 到开发中,根
我目前正在学习动态内存管理是如何工作的,更具体地说是 realloc 以及它是如何在函数中完成的。 在下面的程序中,我只是想尝试使用 malloc 在函数 a() 中分配一些数字,然后将它们传递给另一
在 Java 中如何从另一个线程分派(dispatch)回主 UI 线程?我正在使用带有 Runnable 的执行器在主 UI 线程之外做一些工作,并且我有一个接口(interface),以便可以通过
我在 git 中有一个项目,所有的事情都直接在 master 分支上完成,标签被用来标记代码的发布版本。我知道这并不理想,并且一直在查看 git 流程,例如:http://nvie.com/posts
我们有一个相当大的 GIT 存储库,我想删除从未 merge 回 master 的分支。 反过来也很好 - 一种列出在某个时候已 merge 到 master 中的所有分支的方法。 我希望首先获取一个
在 Swift 和 C 之间传递字符串时,我看到一些我不理解的行为。请考虑以下 Swift 函数: func demo() { print("\n\n\n\n")
我以前从未合作过,现在我发现自己需要与其他一些人分享这个项目,即使我将完成 90% 的开发工作。 我在 github 上有一个私有(private)仓库。我用 推送了我的初始源 git push or
我们的项目使用 Gitlab,我们有两个长期存在的分支:dev 和 master,类似于 Git Flow。我们正在使用“merge 提交”方法,它将在主分支中创建一个 merge 提交。 但是,由于
我对自定义 View 的绑定(bind)属性有疑问。该属性绑定(bind)到核心数据实体的 NSArrayController。 问题是这样的: 在我看来,我画了几个矩形。这些矩形的位置保存在核心数据
这对我来说似乎太棘手,无法正确执行此操作。 我有一个TreeMap ,我正在获取其中的子图: public static reqObj assignObj(reqObj vArg, i
我有以下 XAML: 所以,基本上我希望将其中一
我正在使用 Angular js 1.3.4 版本并使用 ui-select。 我正在将复杂的多级 JSON 对象数组绑定(bind)到此 ui-select,它工作正常。因此用户可以在此选择中选择任
我正在使用 WebAPI 构建 API,并且一直在使用 NLog 在整个堆栈中进行日志记录。我的 API 解决方案有两个主要项目,包括: 实现 Controller 和 webapi 东西的网站层本身
在 Git 中,给定 (1) 一个分支 A 和 (2) 一个在过去某个时间从 A 派生的分支 B,然后 merge 回 A,我如何才能找到现在 A 中起源于 B 的所有提交? 目的是确定现在在 A 中
假设我的 Controller 如下所示: public class myController { private MyCustomItem acte; ... // gett
我是一名优秀的程序员,十分优秀!