OSS文件管理、用户信息状态管理、笔记上传用户修改总结

OSS是什么

对象存储(Object Storage Service)指的是云存储服务。数据以对象(Object)的形式存储在OSS的存储空间(Bucket )中。如果要使用OSS存储数据,需要先创建Bucket,并指定Bucket的地域、访问权限、存储类型等属性。创建Bucket后,可以将数据以Object的形式上传到Bucket,并指定Object的文件名(Key)作为其唯一标识。

OSS以HTTP RESTful API的形式对外提供服务,访问不同地域需要不同的访问域名(Endpoint)。当您请求访问OSS时,OSS通过使用访问密钥(AccessKey ID和AccessKey Secret)对称加密的方法来验证某个请求的发送者身份。

简单易懂的解释就是把需要存储的非结构化数据(对象、视频、文本等)存储到阿里云的服务器上,其保证数据的可用性和安全性,获取到数据时直接调用接口即可。

使用Oss流程

创建bucket -> 选择传递方案 (我选择的是服务端签名直传)-> client get policy -> server return policy -> client post oss

官方文档如下:如何进行服务端签名直传_对象存储 OSS-阿里云帮助中心 (aliyun.com)

后端

  1. nest.js编写接口:

    tsx 复制代码
    //pic_sign.controller.ts 
    @Get()
        getSignature() {
            return this.picSignService.getSignature();
        }
    tsx 复制代码
    //pic_sign.servic.ts
      async getSignature(): Promise<CreateOssSign> {
            const config = {
                //自己配制的key和secret
                accessKeyId:ACCESS_KEY,
                accessKeySecret:ACCESS_KEY_SECRET,
                bucket: //创建的bucker名,
                dir: //文件目录,
            }
    ​
            const client = new OSS(config)
            const date = new Date();
            date.setDate(date.getDate() + 1);
            const policy = {
                expiration: date.toISOString(), // 请求有效期
                conditions: [
                    ['content-length-range', 0, 1048576000], // 设置上传文件的大小限制
                ],
            };
    ​
            // bucket域名
            const host = `http://${config.bucket}.${(await client.getBucketLocation()).location
                }.aliyuncs.com`.toString();
            //签名
            const formData = await client.calculatePostSignature(policy);
            //返回参数
            const params = {
                expire: dayjs().add(1, 'days').unix().toString(),
                policy: formData.policy,
                signature: formData.Signature,
                accessId: formData.OSSAccessKeyId,
                host,
                dir: //传递文件的文件名,
            };
    ​
    ​
            return params
        }

    前端

    1. 直接调用接口获取到signature,可使用antd中自带的Upload组件,官方文档有针对于Oss上传方案的阐述,根据需求修改即可。
    2. 删除已上传的图片------官方文档DeleteMultipleObjects

    遇到的bug:

    • vite中直接使用crypto报错--crypto适用于node端,浏览器环境使用crypto-js
    • 上传/删除oss成功后返回的状态码201 204,由于axios拦截器只拦截了200为成功,修改如下:
    tsx 复制代码
    const successCode = [200, 201, 204];
    axios.interceptors.response.use(
        (response) => {
            if (successCode.includes(response.data.statusCode as number)) {
                return response.data;
    • modal不显示图片:拼接正确的url到组件中即可------修改file.url,添加oss.host前缀

用户状态管理

思路:原本想使用最近学的valtio,但发现valtio没办法实现持久化管理,于是转向localstroage,自己写了个hooks来管理登录后的用户状态

localStorage持久化管理

localstorage本质上是存储在浏览器当中的字符串,大小有5M左右,api也很简单,getItem,setItem,不过我们可以通过json.stringfy和json.parse将其进行对象和字符串的转化,具体实现如下 :

tsx 复制代码
import { loginedData } from '&/types';
​
export const useUserInfo = () => {
    const jsonString = localStorage.getItem('user');
    const user: loginedData = (jsonString && JSON.parse(jsonString)) || '';
​
    // 在localStorage中存储用户信息
    const saveuser = (user: loginedData) => {
        const userString = JSON.stringify(user);
        localStorage.setItem('user', userString);
    };
    //修改用户信息
    const updateuser = (newUser: loginedData['info']) => {
        const preUser = JSON.parse(localStorage.getItem('user') || '');
        const newUserString = JSON.stringify({ ...preUser, info: newUser });
        localStorage.setItem('user', newUserString);
    };
​
    // 清空用户信息
    const deleteuser = () => {
        localStorage.removeItem('user');
    };
​
    return {
        user,
        saveuser,
        deleteuser,
        updateuser
    };
};
​

使用:

tsx 复制代码
const { deleteuser, user } = useUserInfo();

sessionStorage存储暂时信息

需求:当用户点击发布笔记时token刚好过期,存储当前用户编辑的内容,转到登录注册页面,等用户再次登录进来时自动填充刚刚所填写的内容

实现:使用sessionStorage(与localStorage差不多,只不过生命周期只在页面打开时保留,若页面关闭则随之清除)

tsx 复制代码
const jsonString = sessionStorage.getItem('add');
const temBody = (jsonString && JSON.parse(jsonString)) || '';
​
//保留登录之前上传的图片
    useEffect(() => {
        if (temBody.pic) {
            const temPicList: Array<UploadFile> = [];
            const temPicArray = temBody.pic.split(',');
​
            if (temPicArray.length === 1) {
                temPicList.push({
                    uid: uuidv4(),
                    name: uuidv4(),
                    url: `${config.ossUrl}/${temBody.pic}`
                });
            } else {
                temPicArray.map((item: string) =>
                    temPicList.push({
                        uid: uuidv4(),
                        name: uuidv4(),
                        url: `${config.ossUrl}/${item}`
                    })
                );
            }
            setImgList(temPicList);
        }
    }, [temBody.pic]);
​
//handlesSubmit部分
//发布接口参数修改
    const body: addNoteData = {
            title: temBody ? temBody.title : title,
            content: temBody ? temBody.content : context,
            pic: temBody.pic
                ? temBody.pic
                : imgList.map((item) => item.url).join(','),
            avatar: user?.info.avatar,
            user_id: user?.info.id
        };
​
if (!user) {
            //如登录过期,存储编辑后的信息,再次登录后自动填充
            message.info('登录过期,请重新登录');
            deleteuser();
            sessionStorage.setItem('add', JSON.stringify(body));
            naviagte('/auth');
            return;
        }
​
        addNote(body);
        //发布后清空表单、缓存
        form.resetFields();
        setImgList([]);
        if (temBody) {
            sessionStorage.removeItem('add');
        }
        message.success('发布成功');
​
//ui------from.item初始化值修改
    <Form.Item
                    name={'title'}
                    rules={[{ required: true, message: '请填写您的笔记标题' }]}
                    initialValue={temBody?.title}
                >

发布笔记

后端

需求:一个用户可以有多条笔记,一个笔记只能有一个用户,一对多多对一的关系

实现:在entity中关联

tsx 复制代码
//notes
@Entity('notes')
export class Notes {
    ...
​
    @ManyToOne(type => User, user => user.notes, { cascade: true })
    user: User;
}
​
//users
 @OneToMany(type=>Notes,notes=>notes.user)
    notes:Notes[];

遇到的问题:

  • notes中pic栏原本设置的是传递数组,里面是pic的url,但是typeorm postgre不支持Array类型------Data type "Array" in "Notes.pic" is not supported by "postgres" database.

    • 解决:使用字符串存储,前端传递过来用,拼接,

修改用户信息

需求:可以修改用户的用户名和头像

解决:编写patch接口,头像同样采用oss存储

遇到的问题:

  • 修改user.username时使用this.Repository.save()方法没有在原来的数据的coloum修改而是新建了一个数据

    • 原因:username是主键,主键不可更改,使用typeorm.save执行的是插入操作
    • 解决:重新引入nickname昵称字段,用户可以修改昵称
相关推荐
下雪天的夏风6 分钟前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
diygwcom18 分钟前
electron-updater实现electron全量版本更新
前端·javascript·electron
Hello-Mr.Wang35 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘1 小时前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
编程零零七4 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
(⊙o⊙)~哦6 小时前
JavaScript substring() 方法
前端
无心使然云中漫步7 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者7 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_7 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋8 小时前
AJAX 入门 day1
前端·javascript·ajax