10
10
11
11
# 2.前端框架
12
12
13
- ## 2.1目录结构
13
+ ## 2.1win10环境开发配置
14
+
15
+ 因为之前玩过django所以历史遗留了一个node v12.8.0 的环境,可是那个项目又没做完
16
+
17
+ 而这个项目是在node v16.13.1 下配置的
18
+
19
+ 所以需要一个node版本管理的软件
20
+
21
+ 请教MoMo
22
+
23
+ 在Mac或者linux下
24
+
25
+ ``` bash
26
+ # 安装n模块
27
+ npm install -g n
28
+ # 升级到最新稳定版
29
+ n stable
30
+ # 安装指定版本
31
+ n v6.11.5
32
+ ```
33
+
34
+ 我自己是win10,在同事的请教下发现win10也有node的版本管理工具nvm-windows
35
+
36
+ https://github.com/coreybutler/nvm-windows/releases
37
+
38
+ 下载Assets中的nvm-setup.zip
39
+
40
+ 我当前是1.1.9版本,用chrome下载会提示该文件会提示“****** 文件 存在危险,因此Chrome已将其拦截”,查看全部然后仍要保留就可以了
41
+
42
+ 下完之后要解压是一个exe,双击安装
43
+
44
+ 安装路径设置:nvm路径我是换到了D盘D:\nvm,nodejs软连接(symlink)设置成D:\nvm\nodejs,文件夹名不能带空格,不要带中文!!安装后,电脑会自动配置好系统环境。
45
+
46
+ 然后这个安装过程是不会自动给你生产这个D:\nvm\nodejs文件夹的,我们在nvm文件夹下自己新建一个nodejs文件夹
47
+
48
+ 然后修改settings.txt
49
+
50
+ ```
51
+ root: D:\nvm
52
+ path: D:\nvm\nodejs
53
+ arch: 64
54
+ node_mirror: https://npm.taobao.org/mirrors/node/
55
+ npm_mirror: https://npm.taobao.org/mirrors/npm/
56
+ ```
57
+
58
+ 然后!!!
59
+
60
+ 用管理员权限打开cmd
61
+
62
+ ###### 安装node
63
+
64
+ - nvm install 12.8.0
65
+
66
+ > 下载成功的时候,会提示你同时下载安装npm对应的版本
67
+
68
+ - 根据提示,切换到对应的node版本 nvm use 12.8.0
69
+ - nvm list 查看当前已安装和使用的node版本,正在使用中的node版本号前面会使用* 标识
70
+ - node -v 查看node版本
71
+ - npm -v 查看npm版本
72
+
73
+ 然后安装python27
74
+
75
+ https://www.python.org/downloads/release/python-2718/
76
+
77
+ 选[ Windows x86-64 MSI installer] ( https://www.python.org/ftp/python/2.7.18/python-2.7.18.amd64.msi )
78
+
79
+ 装完之后记得配环境变量
80
+
81
+ 1 . 跳转到前端项目文件目录:` cd Vue-newsinfo `
82
+
83
+ 2 . 在本地跑的话,记得打开文件` package.json ` ,修改第49行的IP和端口,修改内容如下:
84
+
85
+ ``` javascript
86
+ " scripts" : {
87
+ " test" : " echo \" Error: no test specified\" && exit 1" ,
88
+ " dev" : " webpack-dev-server --open --port 8686 --contentBase src --hot --host 127.0.0.1" ,
89
+ " start" : " nodemon src/main.js"
90
+ },
91
+ ```
92
+
93
+ 127.0.0.1表示游览器的访问IP(也称为本地IP),8686表示访问端口
94
+
95
+ 3 . 修改访问后端API接口的IP和端口,打开文件` main.js ` ,文件路径:` src/main.js ` ,修改第23行的IP和端口,修改内容如下:
96
+
97
+ ``` javascript
98
+ // Vue.prototype.$http = axios
99
+ Vue .use (VueAxios, axios);
100
+ // axios公共基路径,以后所有的请求都会在前面加上这个路径
101
+ axios .defaults .baseURL = " http://39.108.138.91:3000"
102
+ // 改成后端api的url
103
+ ```
104
+
105
+ 127.0.0.1表示后端项目的访问IP(也称为本地IP),5000表示访问端口。
106
+
107
+ 4 . 设置npm使用py27
108
+
109
+ ``` javascript
110
+ npm install -- python= python2.7
111
+ ```
112
+
113
+ 或将其设置为始终用于:
114
+
115
+ ``` javascript
116
+ npm config set python python2.7
117
+ (我用的这个,管用!)
118
+ ```
119
+
120
+ 5 . 本地安装node环境,在项目根目录命令行输入命令` npm install ` 安装依赖包
121
+
122
+ 如果因为版本或者网络问题下载失败请执行`npm install -g cnpm -registry=https://registry.npm.taobao.org/
123
+ ` 和 ` cnpm install`
124
+
125
+ 6 . 启动前端服务:` npm run dev `
126
+
127
+ ## 2.2目录结构
14
128
15
129
```
16
130
Vue-newsinfo
@@ -44,6 +158,38 @@ Vue-newsinfo
44
158
+---webpack.config.js-------------------webpack的配置文件,用于项目打包
45
159
```
46
160
161
+ ## 2.3 创建Vue项目的流程
162
+
163
+ 1 . 安装Vue CLI:提供基于Vue.js快速开发的工具,可实现交互式的项目脚手架搭建
164
+ 2 . 创建Vue项目:使用` vue create ` 命令,创建项目
165
+ 3 . 路由配置:使用` vue-router ` 库,配置` router.js `
166
+ 4 . 数据请求:使用` axios ` 封装数据请求
167
+ 5 . 选择UI组件库:选择UI设计组件,用于保证界面一致、用户交互、设计简洁的操作流程
168
+
169
+ ## 2.4 页面功能
170
+
171
+ ### 2.4.1 登录/注册页(signIn.vue/signUp.vue)
172
+
173
+ - 代码位于` src/components/ ` 中的` signIn.vue ` 和` signUp.vue `
174
+ - 用户登录:输入用户名和密码,登录系统,勾选“记住我”,可以暂存7天的登录信息
175
+ - 用户注册:输入用户名、密码、验证密码、年龄,勾选性别和城市,进行用户注册,注册成功之后,将跳转到推荐页
176
+
177
+ ### 2.4.2 推荐/热门页(recLists.vue/hotLists.vue)
178
+
179
+ - 代码位于` src/components/ ` 中的` recLists.vue ` 和` hotLists.vue `
180
+ - 推荐页列表:展示用户推荐页新闻列表,一次展示10条数据
181
+ - 热门页列表:展示用户热门页新闻列表,一次展示10条数据
182
+
183
+ ### 2.4.3 新闻详情页(NewsInfo.vue)
184
+
185
+ - 代码位于` src/components/ ` 中的` NewsInfo.vue `
186
+ - 新闻详情:展示当前新闻内容,并提供点赞(喜欢)和收藏功能
187
+
188
+ ### 2.4.4 个人中心页(Myself.vue)
189
+
190
+ - 代码位于` src/components/ ` 中的` Myself.vue `
191
+ - 个人中心:展示用户头像和用户名,提供用户退出功能
192
+
47
193
48
194
49
195
# 3.后端框架
@@ -68,3 +214,252 @@ news_rec_sys
68
214
+--server.py------------------------------------后端项目启动主程序
69
215
```
70
216
217
+ ## 3.2后端API接口
218
+
219
+ ### 3.2.1 用户注册请求
220
+
221
+ - 注册流程:通过前端接收JSON数据(包括用户名、密码、年龄、性别、所在城市),并使用Flask提供用户注册请求服务` /recsys/register `
222
+ - 代码逻辑:位于` server.py ` 中的` register() ` 方法,接收用户名、密码、年龄、性别、所在城市,根据用户名判断是否已经存在(调用` user_action_controller ` 中的` user_is_exist() ` 方法),如果有记录,则返回1,表示注册正常,否则返回0,表示注册失败;再将数据存入MySQL的` userinfo ` 库的` register_user ` 表中
223
+
224
+ ``` python
225
+ @app.route (' /recsys/register' , methods = [" POST" ])
226
+ def register ():
227
+ """ 用户注册
228
+ """
229
+ request_str = request.get_data()
230
+ request_dict = json.loads(request_str)
231
+ # print(request_dict)
232
+
233
+ user = RegisterUser()
234
+ user.username = request_dict[" username" ]
235
+ user.passwd = request_dict[" passwd" ]
236
+
237
+ # 查询当前用户名是否已经被用过了
238
+ result = UserAction().user_is_exist(user, " register" )
239
+
240
+ if result != 0 :
241
+ return jsonify({" code" : 500 , " mgs" : " this username is exists" })
242
+
243
+ user.userid = snowflake.client.get_guid() # 雪花算法
244
+
245
+ user.age = request_dict[" age" ]
246
+ user.gender = request_dict[" gender" ]
247
+ user.city = request_dict[" city" ]
248
+
249
+ # 检验年龄格式的合法性
250
+ try :
251
+ age = int (user.age)
252
+ except :
253
+ return jsonify({" code" : 500 , " mgs" : " age is not valid." })
254
+
255
+ # 添加注册用户
256
+ save_res = UserAction().save_user(user)
257
+ if not save_res:
258
+ return jsonify({" code" : 500 , " mgs" : " register fail." })
259
+
260
+ return jsonify({" code" : 200 , " msg" : " register success." })
261
+ ```
262
+
263
+ ### 3.2.2 用户登录请求
264
+
265
+ - 登录流程:通过前端接收JSON数据(包括用户名、密码),并使用Flask提供用户登录请求服务` /recsys/login `
266
+ - 代码逻辑:位于` server.py ` 中的` login() ` 方法,接收用户名、密码,根据用户名和密码判断是否有记录,如果有记录,则返回1,表示登录正常;如果仅用户名存在,返回2,表示密码错误;否则返回0,表示用户不存在
267
+
268
+ ``` python
269
+ @app.route (' /recsys/login' , methods = [" POST" ])
270
+ def login ():
271
+ """ 用户登录
272
+ """
273
+ request_str = request.get_data()
274
+ request_dict = json.loads(request_str)
275
+
276
+ user = RegisterUser()
277
+ user.username = request_dict[" username" ]
278
+ user.passwd = request_dict[" passwd" ]
279
+
280
+ # 查询数据库中的用户名或者密码是否存在
281
+ try :
282
+ result = UserAction().user_is_exist(user, " login" )
283
+ # print(result,"login")
284
+ if result == 1 :
285
+ return jsonify({" code" : 200 , " msg" : " login success" })
286
+ elif result == 2 :
287
+ # 密码错误
288
+ return jsonify({" code" : 501 , " msg" : " passwd is error" })
289
+ else :
290
+ return jsonify({" code" : 502 , " msg" : " this username is not exist!" })
291
+ except Exception as e:
292
+ return jsonify({" code" : 500 , " mgs" : " login fail." })
293
+ ```
294
+
295
+ ### 3.2.3 用户推荐页请求
296
+
297
+ - 登录流程:通过前端接收json数据(包括用户名、年龄、性别),并使用Flask提供用户推荐页请求服务` /recsys/rec_list `
298
+ - 代码逻辑:位于` server.py ` 中的` rec_list() ` 方法,接收用户名、年龄、性别,根据用户名得到用户ID,根据用户ID调用冷启动的推荐页列表方法(` recprocess/online.py ` 中的` get_cold_start_rec_list_v2() ` 方法),返回10条推荐新闻
299
+
300
+ ``` python
301
+ @app.route (' /recsys/rec_list' , methods = [" GET" ])
302
+ def rec_list ():
303
+ """ 推荐页
304
+ """
305
+ user_name = request.args.get(' user_id' )
306
+ age = request.args.get(' age' )
307
+ gender = request.args.get(' gender' )
308
+
309
+ # 如果年龄无法转int说明是老用户,不需要传age 和 gender
310
+ try :
311
+ age = int (age)
312
+ except :
313
+ age = None
314
+ gender = None
315
+
316
+ # 查询用户的id
317
+ user_id = UserAction().get_user_id_by_name(user_name)
318
+ if not user_id:
319
+ return False
320
+
321
+ if user_id is None :
322
+ return jsonify({" code" : 2000 , " msg" : " user_id is none!" })
323
+
324
+ try :
325
+ rec_news_list = recsys_server.get_cold_start_rec_list_v2(user_id, age, gender)
326
+ # 冷启动策略
327
+ # rec_news_list = recsys_server.get_cold_start_rec_list(user_id)
328
+ if len (rec_news_list) == 0 :
329
+ jsonify({" code" : 500 , " msg" : " rec_news_list is empty." })
330
+ return jsonify({" code" : 200 , " msg" : " request rec_list success." , " data" : rec_news_list, " user_id" : user_id})
331
+ except Exception as e:
332
+ print (str (e))
333
+ return jsonify({" code" : 500 , " msg" : " redis fail." })
334
+ ```
335
+
336
+ ### 3.2.4 用户热门页请求
337
+
338
+ - 登录流程:通过前端接收json数据(包括用户名),并使用Flask提供用户热门页请求服务` /recsys/hot_list `
339
+ - 代码逻辑:位于` server.py ` 中的` hot_list() ` 方法,接收用户名,根据用户名得到用户ID,根据用户ID调用热门页列表方法(` recprocess/online.py ` 中的` get_hot_list_v2() ` 方法),返回10条热门新闻
340
+
341
+ ``` python
342
+ @app.route (' /recsys/hot_list' , methods = [" GET" ])
343
+ def hot_list ():
344
+ """ 热门页面
345
+ """
346
+ user_name = request.args.get(' user_id' )
347
+
348
+ if user_name is None :
349
+ return jsonify({" code" : 2000 , " msg" : " user_name none!" })
350
+
351
+ # 查询用户的id
352
+ user_id = UserAction().get_user_id_by_name(user_name)
353
+ if not user_id:
354
+ return jsonify({" code" : 2000 , " msg" : " user_id is not exits!." })
355
+
356
+ try :
357
+ # 这里需要改成get_hot_list, 当前get_hot_list方法还没有实现
358
+ # rec_news_list = recsys_server.get_hot_list(user_id)
359
+ rec_news_list = recsys_server.get_hot_list_v2(user_id)
360
+ if len (rec_news_list) == 0 :
361
+ return jsonify({" code" : 500 , " msg" : " request redis data fail." })
362
+ return jsonify({" code" : 200 , " msg" : " request hot_list success." , " data" : rec_news_list, " user_id" : user_id})
363
+ except Exception as e:
364
+ print (str (e))
365
+ return jsonify({" code" : 2000 , " msg" : " request hot_list fail." })
366
+ ```
367
+
368
+ ### 3.2.5 新闻详情请求
369
+
370
+ - 登录流程:通过前端接收json数据(包括用户名,新闻ID),并使用Flask提供新闻详情请求服务` /recsys/news_detail `
371
+ - 代码逻辑:位于` server.py ` 中的` news_detail() ` 方法,接收用户名,新闻ID,根据用户名得到用户ID,根据新闻ID得到新闻内容,通过查询` user_likes ` 表和` user_collections ` 表,得到新闻的用户行为(是否点赞、是否收藏),返回前端需要的新闻详情(新闻内容、用户是否点赞、用户是否收藏)
372
+
373
+ ``` python
374
+ @app.route (' /recsys/news_detail' , methods = [" GET" ])
375
+ def news_detail ():
376
+ """ 一篇文章的详细信息
377
+ """
378
+ user_name = request.args.get(' user_name' )
379
+ news_id = request.args.get(' news_id' )
380
+
381
+ user_id = UserAction().get_user_id_by_name(user_name)
382
+
383
+ # if news_id is None or user_id is None:
384
+ if news_id is None or user_name is None :
385
+ return jsonify({" code" : 2000 , " msg" : " news_id is none or user_name is none!" })
386
+ try :
387
+ news_detail = recsys_server.get_news_detail(news_id)
388
+
389
+ # recsys_server.save_user_consume(user_id,news_id) # 记录用户消费的
390
+
391
+ if UserAction().get_likes_counts_by_user(user_id,news_id) > 0 :
392
+ news_detail[" likes" ] = True
393
+ else :
394
+ news_detail[" likes" ] = False
395
+
396
+ if UserAction().get_coll_counts_by_user(user_id,news_id) > 0 :
397
+ news_detail[" collections" ] = True
398
+ else :
399
+ news_detail[" collections" ] = False
400
+
401
+ return jsonify({" code" : 0 , " msg" : " request news_detail success." , " data" : news_detail})
402
+ except Exception as e:
403
+ print (str (e))
404
+ return jsonify({" code" : 2000 , " msg" : " error" })
405
+ ```
406
+
407
+ ### 3.2.6 用户行为请求
408
+
409
+ - 登录流程:通过前端接收json数据(包括用户名,新闻ID、用户行为),并使用Flask提供新闻详情请求服务` /recsys/action `
410
+ - 代码逻辑:位于` server.py ` 中的` actions() ` 方法,接收用户名,新闻ID、用户行为,根据用户名得到用户ID,根据用户行为(是否点赞、收藏),修改` user_likes ` 表和` user_collections ` 表中对应的记录
411
+
412
+ ``` python
413
+ @app.route (' /recsys/action' , methods = [" POST" ])
414
+ def actions ():
415
+ """ 用户的行为:阅读,点赞,收藏
416
+ """
417
+ request_str = request.get_data()
418
+ request_dict = json.loads(request_str)
419
+
420
+ username = request_dict.get(' user_name' )
421
+ newsid = request_dict.get(' news_id' )
422
+ actiontype = request_dict.get(" action_type" )
423
+ actiontime = request_dict.get(" action_time" )
424
+
425
+ userid = UserAction().get_user_id_by_name(username) # 获取用户 id
426
+ if not userid:
427
+ return jsonify({" code" : 2000 , " msg" : " user not register" })
428
+
429
+ # TODO 先判断当前的action_type是否是取消的意思,如果是的话,需要将数据库中对应的操作删掉
430
+ action_type_list = actiontype.split(" :" )
431
+ # print(actiontype)
432
+ if len (action_type_list) == 2 :
433
+ _action_type = action_type_list[0 ]
434
+ if action_type_list[1 ] == " false" : # 如果数据库中这个参数为false的话
435
+ # 删除数据
436
+ if _action_type== " likes" :
437
+ UserAction().del_likes_by_user(userid,newsid) # 删除用户喜欢记录
438
+ elif _action_type== " collections" :
439
+ UserAction().del_coll_by_user(userid,newsid) # 删除用户收藏记录
440
+ else :
441
+ if _action_type== " likes" :
442
+ userlikes = UserLikes()
443
+ userlikes.new(userid,username,newsid)
444
+ UserAction().save_one_action(userlikes) # 记录用户喜欢记录
445
+ elif _action_type== " collections" :
446
+ usercollections = UserCollections()
447
+ usercollections.new(userid,username,newsid)
448
+ UserAction().save_one_action(usercollections) # 记录用户收藏记录
449
+
450
+ try :
451
+ # 落日志
452
+ logitem = LogItem()
453
+ logitem.new(userid,newsid,action_type_list[0 ])
454
+ LogController().save_one_log(logitem)
455
+
456
+ # 更新redis中的展示数据 新闻侧
457
+ # if action_type_list[0] in ["read","likes","collections"]:
458
+ recsys_server.update_news_dynamic_info(news_id = newsid,action_type = action_type_list)
459
+ return jsonify({" code" : 200 , " msg" : " action success" })
460
+
461
+ except Exception as e:
462
+ print (str (e))
463
+ return jsonify({" code" : 2000 , " msg" : " action error" })
464
+ ```
465
+
0 commit comments