Day11 ---- 我的页面, 用户信息获取修改与频道接口

昨日回顾

  • 装饰器修复技术如何实现? 装饰器修复技术解决了什么问题?
  • token 失效后如何解决? 无感知刷新token的思路是什么?
  • JWT禁用的应用场景有哪些?

今日内容

  • 我的页面实现
  • 用户信息修改
  • 用户头像上传
  • CDN介绍
  • 主页频道

1. 我的页面实现

1.1 我的页面整体分析与接口设计

我的页面包含:
用户头像,
用户昵称,
发布的头条数,
关注人数,
粉丝数,
获赞数
浏览历史
我的收藏
消息通知
在这里插入图片描述

用户访问"我的"页面时,完成登录后,必须返回以上相关数据。

接口设计:
进入我的页面时,强制用户登录;
在这里插入图片描述
登录后,加载用户的信息,并展示。

请求地址url: /v1/users/userInfo/
method: GET
参数:请求头jwt token
接口描述: 加载用户信息

请求参数:
    - headers
        - Authorization: Bearer eyJ0eXAiO....
返回数据:
    名称                数据类型      是否必须    默认值     描述
    message            String       必须                 提示信息
    data, 				{用户信息}
    
状态码:
    - 400: 请求参数错误
    - 401: 用户认证失败
    - 200: 请求成功, OK

1.2 后端实现数据返回

思路: 后端验证token,如果token合法, 将user_id放置在g对象中, 视图中从g对象中取出user_id,查询用户数据并返回。

# 用户蓝图 user.py
from flask_restful import Resource, Api
from flask_restful import reqparse
from flask import g, Blueprint
from common.models import db, User
# from common.utils.qiuniu_storage import upload


user_bp = Blueprint("user", __name__)
api = Api(user_bp)

# 用户的蓝图中,定义用户信息视图
class UserInfoResource(Resource):
    def get(self):
    	# 获取用户id
        user_id = g.get('user_id')
        user = User.query.filter_by(uid=user_id).first()
       data = {
            'id': user.uid,
            'name': user.username,
            'photo': user.profile_photo,
            'is_media': user.is_media,
            'intro': user.introduction,
            'certi': user.certificate,
            'art_count': user.article_count,
            'follow_count': user.following_count,
            'fans_count': user.fans_count,
            'like_count': user.like_count
        }
        return {"code": 200, 'message': 'ok', 'data': data}
    
user_bp = Blueprint('user_bp', __name__)
api = Api(user_bp)


api.add_resource(UserInfoResource, "/v1/users/userInfo/")

1.3 前端数据展示

Home.vue组件中,实现接口加载数据,并展示:CORS(app)实现跨域

getUserInfo(){
      this.axios.get("/v1/users/userInfo/", {
        headers: {
          Authorization: "Bearer " + localStorage.token
        },
        responseType: "json"
      })
      .then(res => {
        console.log("加载用户信息:", res)
        this.nickname = res.data.data.username
        this.articles = res.data.data.article_count
        this.focus = res.data.data.following_count
        this.fans = res.data.data.fans_count
        this.support = res.data.data.like_count

      })
      .catch(err => {
        console.log("记载用户信息错误:", err)
      })
    },

2. 用户信息修改

2.1 接口设计

前端点击编辑资料,进入个人信息页,用户修改信息, 包含了用户头像,用户昵称等
在这里插入图片描述

信息修改的后端接口设计:
地址,/v1/users/userInfo/
请求方法, PUT
接口描述,用户信息更新
参数, 每次提交一个更新的字段 & JWT token
响应,json数据

2.2 后端更新接口实现


class UserInfoResource(Resource):
	# ...
    def put(self):
        request_parser = RequestParser()
        request_parser.add_argument("profile_photo", type=str)
        request_parser.add_argument("username", type=str)
        request_parser.add_argument("introduction", type=str)
        request_parser.add_argument("mobile", type=str)
        request_parser.add_argument("email", type=str)

        args = request_parser.parse_args()

        profile_photo = args.get("profile_photo")
        username = args.get("username")
        introduction = args.get("introduction")
        mobile = args.get("mobile")
        email = args.get("email")

        user_id = g.uid
        user = User.query.filter(User.uid==user_id).first()
        attr_list = ["profile_photo", "username", "introduction", "mobile", "email"]
        for idx, val in enumerate([profile_photo, username, introduction, mobile, email]):
            print("before: ", idx, val)
            if val:
                # 更新
                setattr(user, attr_list[idx], val)

        db.session.commit()
		
        return {
            "code": 200,
            "msg": "更新成功",
            "data": marshal(user, resource_fields)
        }
          

后端无法接收到前端的json数据时, 前端需使用qs编码

npm install -s qs
qs.stringify({key: value}) //对象序列化为url形式
qs.parse(url) // 将url解析为对象

2.3 前端更新接口实现

组件:EditInfo.vue

// 组织json数据
  orgData() {
    let data = {}
    switch(this.key){
      case "profile_photo":
        data = { profile_photo: this.update_value };
        break;
      case "username":
        data = { username: this.update_value };
        break;
      case "introduction":
        data = { introduction: this.update_value };
        break;
      case "mobile":
        data = { mobile: this.update_value };
        break;
      case "email":
        data = { email: this.update_value };
        break;
    }
    return data
  },
  // 文本框的失去焦点事件
  blurEvent() {
    this.update_value = document.querySelector("#textArea").value;
    console.log("失焦事件处理", this.update_value);
  },
  // 更新用户的信息
  updateUserInfo() {
    console.log("更新中...", this.key);
    let data = this.orgData()
    
    this.axios
      .put("/v1/users/userInfo/", qs.stringify(data), {
        headers: {
          Authorization: "Bearer " + localStorage.token,
        },
        responseType: "json",
      })
      .then((res) => {
        console.log("更新的响应:", res);
        if(res.data.code == 200){
            this.drawer = false
            // 删除集中式状态管理中的username
            this.$store.state.userInfo.username = null
          }
      })
      .catch((err) => {
        console.log("更新的错误:", err);
      });
  },

3. 用户实现上传头像

3.1 上传头像思路分析与接口设计

  1. 更新图片, 前端需上传图片
  2. 后端接收并保存上传的图片,返回响应
  3. 前端上传成功的回调中,处理头像的路径
  4. 前端点击确定,请求后端,更新数据库

上传的接口
请求地址:/v1/users/avatar/
method: POST
上传数据: {Authorization:xxx, file: xxxx}
响应数据:{code:xx, msg: xxx, profile_photo: xxxx}

更新的接口
重用 2.2部分 的接口

3.2 上传头像接口编写

  1. 后端接口
# 后端接收数据  FileStorage对象
# file = request.files.get("file")
# file.filename   file.stream.read()

class AvatarResource(Resource):
    def post(self):
        # 1. 接收数据
        token = request.form.get("Authorization")
        file = request.files.get("file")
        print("查看数据:", dir(file), type(file))
        # 2. 验证token

        # 3. 保存上传的图片
        static_path = "static/images/avatar"
        if not os.path.exists(static_path):
            os.makedirs(static_path)

        with open(static_path + "/" + file.filename, "wb") as f:
            f.write(file.stream.read())
		
		# 4. 更新数据库
        user = User.query.filter(User.uid==1).first()
        user.profile_photo = "/" + static_path + "/" + file.filename
        db.session.commit()

        return {
            "code": 200,
            "msg": "上传图片成功",
            "profile_photo": user.profile_photo
        }
        
api.add_resource(AvatarResource, "/v1/users/avatar/")

  1. 前端接口
//上传的组件
<el-upload
   :action="host + '/v1/users/avatar/'"
   :data="uploadData"
   :auto-upload="true"
   :on-success="uploadSuccess"
   :on-error="uploadError">
     <el-button type="primary" size="mini">选择图片</el-button>
</el-upload>

//上传成功的回调
uploadSuccess(res, files){
 console.log("上传成功的响应:", res, files)
 # 更新集中状态管理
 this.$store.state.userInfo.profile_photo = res.profile_photo
},

uploadError(err){
  console.log("上传错误:", err)
},

4. CDN介绍

  1. CDN介绍

CDN,全称:Content Delivery Network,内容分发网络。
将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高页面响应速度。解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。

  1. CDN基本原理

尽可能避开互联网上有可能影响数据传输速度和稳定性的环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的智能虚拟网络,CDN系统能够根据网络流量、各节点的连接、负载状况、用户的距离、响应时间等综合信息,将用户的请求重新导向离用户最近的服务器。

在这里插入图片描述


5. 主页频道

5.1 频道接口分析与设计

  1. 接口设计
    请求地址url: /v1/channels/
    Method: GET
    请求参数:
       jwt
    接口描述:获取全部频道
    响应状态码:
      400: 请求错误
      200: 请求成功, OK
    响应数据:
    {
    ‘code’: 200,
    ‘msg’: ‘ok’,
    ‘channels’:[
    {‘id’:1, ‘name’: ‘python开发’},
    {‘id’:2, ‘name’: ‘人工智能’},

    ]
    }

5.2 频道接口实现

后端接口实现

# 2.接口实现:
from flask_restful import Resource
from common.models import Channel
from common.models import db

# 频道列表
class ChannelListResource(Resource):
    """
    获取所有频道
    """
    def get(self):
        # 添加数据用于测试
        
		# 查询数据
        channels = Channel.query.all()
        return {
        	'code': 200,
            'msg': 'ok',
            'channels':[{'id': item.cid, 'name': item.cname} for item in channels]
            
        }

前端接口实现

在这里插入代码片
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

laufing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值