Guest User

Untitled

a guest
Oct 10th, 2018
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.51 KB | None | 0 0
  1.  
  2. Проект построен как вебсервис с rest интерфейсом. Клиентская и
  3. серверная части написаны полностью на java scriipt.
  4.  
  5. Архитектура nodejs в связке с фреймворком express позволила обеспечить
  6. прозрачность работы над созданием rest интерфейса.
  7.  
  8. Пример добавления метода к ресурсу.
  9.  
  10. роут:
  11.  
  12. app.get '/post',[
  13. $.beforeAction,
  14. $.controller('post').list
  15. ]
  16.  
  17. Все операции связаныые с проверкой доступа и прочее, мы вынесли метод
  18. $.beforeAction, что бы избавить контроллеры от лишней логики
  19.  
  20. метод контроллера
  21. class PostController
  22. list: (req, res) ->
  23. Post.find {}, (err, posts) ->
  24. res.send posts
  25.  
  26. Так же в рамках разработки проекта была выполнена работа по созданию
  27. структурной надстройки над фреймворком express, которая позволила вынесить
  28. отедльные модули системв в независимые друг от друга приложения, это
  29. обеспечивает большую гибкость и простоту маштабирования в будущем.
  30. Для подключения новых модулей в файле app.coffee необходимо добавить путь
  31. к файлу-инициализатору нового подприложения.
  32. require('./frontend/configs/bootstrap').apply app
  33.  
  34. По такому же принципу мы построили и механизм конфигурации приложения
  35. require('./configs/bootstrap').apply app
  36. require('./admin/configs/bootstrap').apply app
  37.  
  38. в файлах дополнительных окружений можно просто переопределить некоторые
  39. параметры основго конфигрурационного скрипта.
  40. пример файла конфигурации
  41.  
  42.  
  43. exports.apply = (app)->
  44. app.configure 'production', ->
  45. app.use express.errorHandler {
  46. dumpExceptions: true,
  47. showStack: true
  48. }
  49.  
  50. app.use express.session
  51. secret: "soundFree_secred_Wdi78"
  52. store: new MongoStore({
  53. db: new Db('soundFree_session',
  54. new Server('localhost', 27017,{
  55. auto_reconnect: true,
  56. native_parser: true
  57. })
  58. ,{}
  59. )
  60. })
  61.  
  62.  
  63.  
  64. mongoose.connect('mongodb://localhost/soundFree', (err)->
  65. if err
  66. console.error 'Can not connect to database'
  67. throw err;
  68.  
  69. console.info 'Successfully connected to database'
  70. )
  71.  
  72. app.set 'port', 8000
  73. app.set 'view cache', false
  74.  
  75.  
  76.  
  77.  
  78. Для написания кода был использован coffeeScript, он обеспечивает возможность написания java script приложений на python/ruby подобном синтаксисе. Так же coffeeScript обеспечивает более прозрачную работу с ООП в java script.
  79. Пример:
  80.  
  81. lass Animal
  82. constructor: (@name) ->
  83.  
  84. move: (meters) ->
  85. alert @name + " moved #{meters}m."
  86.  
  87. class Snake extends Animal
  88. move: ->
  89. alert "Slithering..."
  90. super 5
  91.  
  92. class Horse extends Animal
  93. move: ->
  94. alert "Galloping..."
  95. super 45
  96.  
  97. sam = new Snake "Sammy the Python"
  98. tom = new Horse "Tommy the Palomino"
  99.  
  100. sam.move()
  101. tom.move()
  102.  
  103.  
  104. В качестве базы данных была использована mongoDB, это было обусловлненно тем что
  105. данная субд полностью асинхронна, что хорошо вписывается в общий характер проекта
  106. и поддерживает парадигмы ассинхронной природы nodejs который является основной системы.
  107.  
  108. пример подключения к базе данных
  109.  
  110. store: new MongoStore({
  111. db: new Db('soundFree_session',
  112. new Server('localhost', 27017,{
  113. auto_reconnect: true,
  114. native_parser: true
  115. })
  116. ,{}
  117. )
  118. })
  119.  
  120. В качестве ORM обертки для MongoDB был использован mongoose
  121. конфигурация
  122. mongoose.connect('mongodb://localhost/soundFree', (err)->
  123. if err
  124. console.error 'Can not connect to database'
  125. throw err;
  126.  
  127. console.info 'Successfully connected to database'
  128. )
  129.  
  130. пример модели
  131.  
  132. mongoose = require 'mongoose'
  133. Schema = mongoose.Schema
  134. Query = mongoose.Query
  135. ObjectId = Schema.ObjectId
  136. crypto = require 'crypto'
  137.  
  138. UserSchema = new Schema
  139. name:
  140. type: String
  141. required: true
  142. email:
  143. type: String
  144. required: true
  145. unique: true
  146. set: (v)->
  147. toLower(v)
  148. password:
  149. type: String
  150. set: (v)->
  151. setPassword(v)
  152. salt:
  153. type: String
  154. role: String
  155. status: String
  156. createdAt:
  157. type: Date
  158. default: Date.now
  159.  
  160. toLower = (v) ->
  161. v.toLowerCase()
  162.  
  163. UserSchema.path('email').validate (email) ->
  164. return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test email
  165. , 'invalid'
  166.  
  167. setPassword = (v) ->
  168. v.length ? v: this.password
  169.  
  170. UserSchema.pre 'save', (next) ->
  171. if !@salt
  172. if !@password
  173. @realPassword = crypto.randomBytes(4).toString 'hex'
  174. @password = @realPassword
  175.  
  176. @generateSalt();
  177. @password = @hashPassword @password, @salt
  178.  
  179. next()
  180.  
  181. User = mongoose.model 'User', UserSchema
  182. global.User = User
  183.  
  184. Внешний вид
  185. В качестве css фреймворка был выбран продукт Twitter Bootstrap, позволяющий быстро
  186. создавать прототипы приложений с дружественным пользовательским интерфейсом, весь
  187. css код написан на less синткасисе, который позволяет использвать в стилях вложенность, примеси, использовать переменные т.д
  188. пример
  189.  
  190. @base: #f938ab;
  191.  
  192. .box-shadow(@style, @c) when (iscolor(@c)) {
  193. box-shadow: @style @c;
  194. -webkit-box-shadow: @style @c;
  195. -moz-box-shadow: @style @c;
  196. }
  197. .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  198. .box-shadow(@style, rgba(0, 0, 0, @alpha));
  199. }
  200. .box {
  201. color: saturate(@base, 5%);
  202. border-color: lighten(@base, 30%);
  203. div { .box-shadow(0 0 5px, 30%) }
  204. }
  205.  
  206.  
  207. Организация клиентской части.
  208. Для организации интерфейса была использована библиотека backboneJS
  209. Данная библиотека позволяет использовать хеш навигацию с маппингом на методы роутера
  210.  
  211. class Controller extends Backbone.Router
  212. routes:
  213. "" : "index"
  214. "!/": "index"
  215. "!/news": "news"
  216. "!/music": "music"
  217. "!/video": "video"
  218. "!/artists": "artists"
  219. "!/post/:id": "showPost"
  220.  
  221. index: ->
  222. Views.page.render() if Views.page?
  223.  
  224. news: ->
  225. console.log "news"
  226.  
  227. music: ->
  228. console.log "music"
  229.  
  230. video: ->
  231. console.log "videos"
  232.  
  233. artists: ->
  234. console.log "artists"
  235.  
  236. showPost: (id)->
  237. if Views.postPage?
  238. post = new Post {_id: id}
  239. Views.postPage.setModel post
  240. post.fetch()
  241.  
  242.  
  243. Блоки сайта отрисовываются на основе данных от моделей
  244. пример View
  245.  
  246. class SitePage extends Backbone.View
  247. el: $ "#mainContainer"
  248.  
  249. posts: []
  250. albums: []
  251.  
  252. events: {}
  253.  
  254. constructor: ->
  255. @posts = new PostCollection()
  256. @posts.bind 'add', @addPost, @
  257. @posts.bind 'all', @addAllPosts, @
  258.  
  259. @albums = new AlbumCollection()
  260. @albums.bind 'add', @addAlbum, @
  261. @albums.bind 'all', @addAllAlbums, @
  262.  
  263. render: ->
  264. @posts.fetch()
  265. @albums.fetch()
  266. $(@el).empty()
  267. $(@el).append(_.template $('#NewsContainer').html()) if !$(@el).find('#NewsContainer').length
  268. $(@el).append(_.template $('#AlbumContainer').html()) if !$(@el).find('#AlbumContainer').length
  269.  
  270. addPost: (post)->
  271. view = new PostView
  272. model: post
  273.  
  274. container = $(@el).find('.news')
  275. container.append view.render().el
  276.  
  277. addAllPosts: ->
  278. @posts.each @addPost, @
  279.  
  280. addAlbum: (album)->
  281. view = new AlbumView
  282. model: album
  283.  
  284. container = $(@el).find('.albums')
  285. container.append view.render().el
  286.  
  287. addAllAlbums: ->
  288. @albums.each @addAlbum, @
  289.  
  290. Пример модели
  291. class Post extends Backbone.Model
  292. urlRoot : '/post/'
  293. url: ->
  294. @urlRoot + @get('_id')
  295.  
  296. Взаимодействие между views и models построенно на основе событий, которые пораждает модель, которые в свою очередь могут быть перехвачены view.
Add Comment
Please, Sign In to add comment