{"id":230451,"date":"2014-07-20T19:16:03","date_gmt":"2014-07-20T15:16:03","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=230451"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=230451","title":{"rendered":"<span class=\"post_title\">\u041c\u0435\u043d\u044f\u0435\u043c Java \u043d\u0430 Scala. \u0411\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/span>"},"content":{"rendered":"<div class=\"content html_format\">     \t\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439, \u0425\u0430\u0431\u0440. <\/p>\n<p>  \u041b\u0435\u0442\u043e \u043d\u0430 \u0434\u0432\u043e\u0440\u0435, \u0441\u043a\u043e\u0440\u043e \u043e\u0442\u043f\u0443\u0441\u043a \u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0430\u043c\u0438, \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u043f\u044b\u0442\u043e\u043c \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e Web \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Java \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435. \u041a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u044f\u0437\u044b\u043a \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0433\u0430\u0439\u0434, \u043a\u0430\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0443 \u0441 \u043e\u043f\u044b\u0442\u043e\u043c Java \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala \u0438 \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0443 \u043d\u0435\u0433\u043e \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043e\u043a.<\/p>\n<p>  \u042d\u0442\u043e \u043f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0438\u0437 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0443\u0434\u0435\u043b\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043b\u044e\u0434\u0435\u0439 \u0437\u043d\u0430\u044e\u0449\u0438\u0445 Java, \u0440\u0430\u0431\u043e\u0442\u0430\u0432\u0448\u0438\u0445 \u0441\u043e Spring, Hibernate, JPA, JSP \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 3-4\u0435\u0445 \u0431\u0443\u043a\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f\u043c\u0438. \u042f \u043f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u0431\u0435\u0437\u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala \u0432 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0438 \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0430\u0448\u0435 \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u0441\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u043a\u0440\u0443\u0433 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0440\u044f\u0434 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:<br \/>  1. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043a\u0440\u044b\u0442\u043e, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <br \/>  2. \u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e API (REST \u043c\u044b \u0437\u0430\u0431\u0443\u0434\u0435\u043c (\u043e\u043d \u0443\u0436\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u044f) \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 Google AdWords API, \u0441\u043e \u0441\u0432\u043e\u0438\u043c SQL like \u0437\u0430\u043f\u0440\u043e\u0441\u043d\u0438\u043a\u043e\u043c)<br \/>  3. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0442\u0430\u043a \u0438 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e<br \/>  4. i18n<br \/>  5. \u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0411\u0414<br \/>  6. \u0421\u0440\u0435\u0434\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <a href=\"http:\/\/www.vagrantup.com\/\">Vagrant<\/a><br \/>  7. \u0418, \u043f\u043e \u043c\u0435\u043b\u043e\u0447\u0438, \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435\u2026<\/p>\n<p>  \u0412\u0441\u0435 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0442\u044c \u0438 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u0442 \u044d\u0442\u043e \u0441\u0440\u043e\u043a\u043e\u043c \u0432 2 \u0434\u043d\u044f. \u0415\u0441\u043b\u0438 \u044f \u0432\u0430\u0441 \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p>  <a name=\"habracut\"><\/a><\/p>\n<h4>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430<\/h4>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c Scala, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u043b\u0438\u0441\u0442\u0430\u0432 \u043a\u043d\u0438\u0433\u0443 <a href=\"http:\/\/www.ozon.ru\/context\/detail\/id\/20070017\/\">\u0425\u043e\u0440\u0441\u0442\u043c\u0430\u043d\u0430 \u00abScala \u0434\u043b\u044f \u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043b\u0438\u0432\u044b\u0445\u00bb<\/a>. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c, \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u044f\u0437\u044b\u043a \u0438 \u0437\u043d\u0430\u0442\u044c \u0447\u0442\u043e \u0432 \u043d\u0435\u043c \u0435\u0441\u0442\u044c. \u042f \u0441\u043e\u0432\u0435\u0442\u0443\u044e \u043d\u0435 \u043b\u0435\u0437\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u0432 \u0434\u0435\u0431\u0440\u0438, \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u0441 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c \u0433\u0434\u0435 \u0432\u044b \u0432\u0438\u0434\u0435\u043b\u0438 \u043a\u0430\u043a\u0438\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0427\u0435\u0440\u0435\u0437 \u0432\u0440\u0435\u043c\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0438\u043c \u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043a\u0430\u043a \u043e\u043d\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b, \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0432\u0435\u0449\u0438. \u042f\u0437\u044b\u043a \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0442\u0438\u0447\u043d\u043e. <\/p>\n<h4>\u0427\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c<\/h4>\n<p>  \u0414\u043b\u044f Scala \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u0442\u043e\u0447\u0435\u043d\u043d\u044b\u0445 \u0432\u0435\u0449\u0435\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"http:\/\/www.playframework.com\/\">Play Framework<\/a>, <a href=\"http:\/\/www.scala-sbt.org\/\">SBT<\/a>, <a href=\"http:\/\/slick.typesafe.com\/\">Slick<\/a>, <a href=\"http:\/\/liftweb.net\/\">Lift<\/a>. \u041d\u043e \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u0435\u0445 \u0432\u0435\u0449\u0435\u0439 \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438. \u0421\u0431\u043e\u0440\u043a\u0443 \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 Maven. \u0412\u043e\u0437\u044c\u043c\u0435\u043c Spring, Spring MVC, Spring Security \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443. \u0414\u043b\u044f \u0411\u0414 \u0432\u043e\u0437\u044c\u043c\u0435\u043c <a href=\"http:\/\/squeryl.org\/\">Squeryl<\/a> (\u043c\u043d\u0435 \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f Hibernate \u0438\u0437-\u0437\u0430 \u0441\u0432\u043e\u0438\u0445 \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u043e\u0441\u0442\u0438, \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439, \u0438 \u0432\u0435\u0447\u043d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043d\u044b\u043c Lazy). \u0424\u0440\u043e\u043d\u0442 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043d\u0430 Angular, \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 SASS, \u0432\u043c\u0435\u0441\u0442\u043e JS \u0432\u043e\u0437\u044c\u043c\u0435\u043c CoffeeScript (\u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u0430\u043a \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u043e \u0432\u044b \u0441 \u0442\u043e\u0439 \u0436\u0435 \u043b\u0435\u0433\u043a\u043e\u0441\u0442\u044c\u044e \u043c\u043e\u0436\u0435\u0442\u0435 \u0438 \u043e\u0442\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0442 Coffee). \u041d\u0443 \u0438, \u0441\u0430\u043c\u043e \u0441\u043e\u0431\u043e\u0439, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435, \u0442\u0430\u043a \u0438 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435, \u043d\u0430 <a href=\"http:\/\/www.scalatest.org\/\">ScalaTest<\/a>. \u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 \u043c\u044b \u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043e \u0441\u0432\u043e\u0438\u043c\u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043e\u0431\u044a\u0435\u043c\u043d\u044b\u0439 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440. API \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435. \u0412 \u043d\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0443\u0442 \u043c\u0435\u0442\u043e\u0434\u044b, \u0442\u0430\u043a\u0436\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c SQL like \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0432\u044b\u0431\u043e\u0440\u043a\u0443. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:   <\/p>\n<pre><code class=\"sql\">select id, name, bank from Organization where bank.id = :id \/\/ =&gt; [{id: 1, name: 'name', bank: {id: 1, name: 'bankname', node: 'Note'}}] select name, bank.id, bank.name from Organization order by bank.name \/\/ =&gt; [{name: 'name', bank: {id: 1, name: 'bankname'}}] <\/code><\/pre>\n<h4>\u041a \u0434\u0435\u043b\u0443<\/h4>\n<h5>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h5>\n<p>  \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u043c Maven \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 Scala.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">   &lt;properties&gt;         &lt;scala-version&gt;2.10.4&lt;\/scala-version&gt;     &lt;\/properties&gt;      &lt;dependencies&gt;         &lt;dependency&gt;             &lt;groupId&gt;org.scala-lang&lt;\/groupId&gt;             &lt;artifactId&gt;scala-library&lt;\/artifactId&gt;             &lt;version&gt;${scala-version}&lt;\/version&gt;         &lt;\/dependency&gt;     &lt;\/dependencies&gt;      &lt;build&gt;         &lt;pluginManagement&gt;             &lt;plugins&gt;                 &lt;plugin&gt;                     &lt;groupId&gt;net.alchim31.maven&lt;\/groupId&gt;                     &lt;artifactId&gt;scala-maven-plugin&lt;\/artifactId&gt;                     &lt;version&gt;3.1.6&lt;\/version&gt;                 &lt;\/plugin&gt;                 &lt;plugin&gt;                     &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                     &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;                     &lt;version&gt;2.0.2&lt;\/version&gt;                 &lt;\/plugin&gt;             &lt;\/plugins&gt;         &lt;\/pluginManagement&gt;         &lt;plugins&gt;             &lt;plugin&gt;                 &lt;groupId&gt;net.alchim31.maven&lt;\/groupId&gt;                 &lt;artifactId&gt;scala-maven-plugin&lt;\/artifactId&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;id&gt;scala-compile-first&lt;\/id&gt;                         &lt;phase&gt;process-resources&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;add-source&lt;\/goal&gt;                             &lt;goal&gt;compile&lt;\/goal&gt;                         &lt;\/goals&gt;                     &lt;\/execution&gt;                     &lt;execution&gt;                         &lt;id&gt;scala-test-compile&lt;\/id&gt;                         &lt;phase&gt;process-test-resources&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;testCompile&lt;\/goal&gt;                         &lt;\/goals&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;phase&gt;compile&lt;\/phase&gt;                         &lt;goals&gt;                             &lt;goal&gt;compile&lt;\/goal&gt;                         &lt;\/goals&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt;         &lt;\/plugins&gt;     &lt;\/build&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412\u0441\u0435 \u043d\u0430\u0448\u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <b>src\/main\/scala<\/b>, \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u0432\u0435\u0449\u0438 \u043d\u0430 Java, \u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044f \u0438\u0445 \u0432 <b>src\/main\/java<\/b>. \u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e Scala \u043a\u043b\u0430\u0441\u0441\u044b \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 Java \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0435\u0441\u043b\u0438 \u0442\u0430\u043a\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0443\u0436\u043d\u0430. \u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f Spring, Spring MVC, Spring Security, Spring OAuth, \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u0447\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u043d\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043e\u0441\u043e\u0431\u043e\u0433\u043e \u0442\u0440\u0443\u0434\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443. \u0418\u0437 \u043d\u044e\u0430\u043d\u0441\u043e\u0432 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0435\u0449\u0435 Jetty (\u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e). \u0415\u0449\u0435 Scala Config, ScalaTest. \u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u0441\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0438\u0441\u044c \u0447\u0435\u0440\u0435\u0437 Maven, \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c Maven Surefire Plugin \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scalatest Maven Plugin  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">             &lt;plugin&gt;                 &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;                 &lt;artifactId&gt;maven-surefire-plugin&lt;\/artifactId&gt;                 &lt;version&gt;2.7&lt;\/version&gt;                 &lt;configuration&gt;                     &lt;skipTests&gt;true&lt;\/skipTests&gt;                 &lt;\/configuration&gt;             &lt;\/plugin&gt;             &lt;plugin&gt;                 &lt;groupId&gt;org.scalatest&lt;\/groupId&gt;                 &lt;artifactId&gt;scalatest-maven-plugin&lt;\/artifactId&gt;                 &lt;version&gt;1.0&lt;\/version&gt;                 &lt;configuration&gt;                     &lt;reportsDirectory&gt;${project.build.directory}\/surefire-reports&lt;\/reportsDirectory&gt;                     &lt;junitxml&gt;.&lt;\/junitxml&gt;                     &lt;filereports&gt;WDF TestSuite.txt&lt;\/filereports&gt;                 &lt;\/configuration&gt;                 &lt;executions&gt;                     &lt;execution&gt;                         &lt;id&gt;test&lt;\/id&gt;                         &lt;goals&gt;                             &lt;goal&gt;test&lt;\/goal&gt;                         &lt;\/goals&gt;                     &lt;\/execution&gt;                 &lt;\/executions&gt;             &lt;\/plugin&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043b\u043e\u0433\u0433\u0435\u0440\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430\u043c <i>trait LazyLogging<\/i>.  <\/p>\n<pre><code class=\"xml\">&lt;dependency&gt;   &lt;groupId&gt;com.typesafe.scala-logging&lt;\/groupId&gt;   &lt;artifactId&gt;scala-logging-slf4j_2.10&lt;\/artifactId&gt;   &lt;version&gt;2.1.2&lt;\/version&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<h5>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0411\u0414<\/h5>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043e \u043d\u0430\u0448\u0435\u0439 \u0411\u0414. \u0414\u043b\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"http:\/\/www.liquibase.org\/\">Liquibase<\/a>. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0432\u0441\u0435 changeset.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">resources\/changelog\/db.changelog-master.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; &lt;databaseChangeLog         xmlns=&quot;http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog&quot;         xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;         xsi:schemaLocation=&quot;         http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog         http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog\/dbchangelog-3.1.xsd&quot;&gt;      &lt;include file=&quot;classpath:changelog\/db.changelog-0.1.xml&quot;\/&gt; &lt;\/databaseChangeLog&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0418 \u043e\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 changeset, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0432\u0441\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 OAuth  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">db.changelog-0.1.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;  &lt;databaseChangeLog         xmlns=&quot;http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog&quot;         xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;         xsi:schemaLocation=&quot;http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog          http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog\/dbchangelog-3.1.xsd&quot;&gt;      &lt;changeSet id=&quot;0.1-auth&quot; author=&quot;andy.sumskoy@gmail.com&quot;&gt;         &lt;createTable tableName=&quot;users&quot;&gt;             &lt;column name=&quot;user_id&quot; type=&quot;int&quot; autoIncrement=&quot;true&quot;&gt;                 &lt;constraints primaryKey=&quot;true&quot; nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;username&quot; type=&quot;varchar(255)&quot;&gt;                 &lt;constraints unique=&quot;true&quot; nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;password&quot; type=&quot;varchar(255)&quot;&gt;                 &lt;constraints nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;enabled&quot; type=&quot;boolean&quot; defaultValueBoolean=&quot;true&quot;&gt;                 &lt;constraints nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;         &lt;\/createTable&gt;          &lt;createTable tableName=&quot;authority&quot;&gt;             &lt;column name=&quot;authority_id&quot; type=&quot;int&quot; autoIncrement=&quot;true&quot;&gt;                 &lt;constraints primaryKey=&quot;true&quot; nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;name&quot; type=&quot;varchar(255)&quot;&gt;                 &lt;constraints unique=&quot;true&quot; nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;         &lt;\/createTable&gt;          &lt;createTable tableName=&quot;user_authorities&quot;&gt;             &lt;column name=&quot;user_id&quot; type=&quot;int&quot;&gt;                 &lt;constraints foreignKeyName=&quot;fk_user_authorities_users&quot; referencedTableName=&quot;users&quot;                              referencedColumnNames=&quot;user_id&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;authority_id&quot; type=&quot;int&quot;&gt;                 &lt;constraints foreignKeyName=&quot;fk_user_authorities_authority&quot; referencedTableName=&quot;authority&quot;                              referencedColumnNames=&quot;authority_id&quot;\/&gt;             &lt;\/column&gt;         &lt;\/createTable&gt;         &lt;addPrimaryKey columnNames=&quot;user_id, authority_id&quot; constraintName=&quot;pk_user_authorities&quot;                        tableName=&quot;user_authorities&quot;\/&gt;          &lt;insert tableName=&quot;authority&quot;&gt;             &lt;column name=&quot;authority_id&quot;&gt;1&lt;\/column&gt;             &lt;column name=&quot;name&quot;&gt;ROLE_ADMIN&lt;\/column&gt;         &lt;\/insert&gt;         &lt;insert tableName=&quot;authority&quot;&gt;             &lt;column name=&quot;authority_id&quot;&gt;2&lt;\/column&gt;             &lt;column name=&quot;name&quot;&gt;ROLE_USER&lt;\/column&gt;         &lt;\/insert&gt;         &lt;insert tableName=&quot;authority&quot;&gt;             &lt;column name=&quot;authority_id&quot;&gt;3&lt;\/column&gt;             &lt;column name=&quot;name&quot;&gt;ROLE_POWER_USER&lt;\/column&gt;         &lt;\/insert&gt;                  &lt;createTable tableName=&quot;persistent_logins&quot;&gt;             &lt;column name=&quot;username&quot; type=&quot;varchar(64)&quot;&gt;                 &lt;constraints nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;series&quot; type=&quot;varchar(64)&quot;&gt;                 &lt;constraints nullable=&quot;false&quot; primaryKey=&quot;true&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;token&quot; type=&quot;varchar(64)&quot;&gt;                 &lt;constraints nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;last_used&quot; type=&quot;timestamp&quot;&gt;                 &lt;constraints nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;         &lt;\/createTable&gt;          &lt;createTable tableName=&quot;oauth_client_details&quot;&gt;             &lt;column name=&quot;client_id&quot; type=&quot;varchar(256)&quot;&gt;                 &lt;constraints primaryKey=&quot;true&quot; nullable=&quot;false&quot;\/&gt;             &lt;\/column&gt;             &lt;column name=&quot;resource_ids&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;client_secret&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;scope&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;authorized_grant_types&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;web_server_redirect_uri&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;authorities&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;access_token_validity&quot; type=&quot;int&quot;\/&gt;             &lt;column name=&quot;refresh_token_validity&quot; type=&quot;int&quot;\/&gt;             &lt;column name=&quot;additional_information&quot; type=&quot;text&quot;\/&gt;             &lt;column name=&quot;autoapprove&quot; type=&quot;varchar(256)&quot;\/&gt;         &lt;\/createTable&gt;          &lt;createTable tableName=&quot;oauth_access_token&quot;&gt;             &lt;column name=&quot;token_id&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;token&quot; type=&quot;blob&quot;\/&gt;             &lt;column name=&quot;authentication_id&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;user_name&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;client_id&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;authentication&quot; type=&quot;blob&quot;\/&gt;             &lt;column name=&quot;refresh_token&quot; type=&quot;varchar(256)&quot;\/&gt;         &lt;\/createTable&gt;          &lt;createTable tableName=&quot;oauth_refresh_token&quot;&gt;             &lt;column name=&quot;token_id&quot; type=&quot;varchar(256)&quot;\/&gt;             &lt;column name=&quot;token&quot; type=&quot;blob&quot;\/&gt;             &lt;column name=&quot;authentication&quot; type=&quot;blob&quot;\/&gt;         &lt;\/createTable&gt;                &lt;\/changeSet&gt;          &lt;changeSet id=&quot;0.1-auth-data&quot; author=&quot;andy.sumskoy@gmail.com&quot; context=&quot;test&quot;&gt;         &lt;insert tableName=&quot;users&quot;&gt;             &lt;column name=&quot;user_id&quot;&gt;1&lt;\/column&gt;             &lt;column name=&quot;username&quot;&gt;admin&lt;\/column&gt;             &lt;column name=&quot;password&quot;&gt;dd28a28446b96db4c2207c3488a8f93fbb843af1eeb7db5d2044e64581145341c4f1f25de48be21b             &lt;\/column&gt;             &lt;column name=&quot;enabled&quot;&gt;true&lt;\/column&gt;         &lt;\/insert&gt;         &lt;insert tableName=&quot;user_authorities&quot;&gt;             &lt;column name=&quot;user_id&quot;&gt;1&lt;\/column&gt;             &lt;column name=&quot;authority_id&quot;&gt;1&lt;\/column&gt;         &lt;\/insert&gt;         &lt;insert tableName=&quot;user_authorities&quot;&gt;             &lt;column name=&quot;user_id&quot;&gt;1&lt;\/column&gt;             &lt;column name=&quot;authority_id&quot;&gt;2&lt;\/column&gt;         &lt;\/insert&gt;         &lt;insert tableName=&quot;user_authorities&quot;&gt;             &lt;column name=&quot;user_id&quot;&gt;1&lt;\/column&gt;             &lt;column name=&quot;authority_id&quot;&gt;3&lt;\/column&gt;         &lt;\/insert&gt;          &lt;insert tableName=&quot;oauth_client_details&quot;&gt;             &lt;column name=&quot;client_id&quot;&gt;simple-client&lt;\/column&gt;             &lt;column name=&quot;client_secret&quot;&gt;simple-client-secret-key&lt;\/column&gt;             &lt;column name=&quot;authorized_grant_types&quot;&gt;password&lt;\/column&gt;         &lt;\/insert&gt;     &lt;\/changeSet&gt;  &lt;\/databaseChangeLog&gt;  <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 \u0441\u0440\u0435\u0434\u0435, \u0442\u043e \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c admin \u0441 \u043f\u0430\u0440\u043e\u043b\u0435\u043c admin, \u0438\u043c\u0435\u044e\u0449\u0438\u0439 \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f OAuth. \u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u0421\u0423\u0411\u0414, \u0442\u043e \u044f \u0431\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u043f\u0438\u0441\u0430\u0442\u044c changeset \u043d\u0430 SQL (\u043e\u0431 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"http:\/\/www.liquibase.org\/documentation\/sql_format.html\">\u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a liquibase<\/a>). <\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f liquibase \u0434\u043e\u0432\u043e\u0434\u0438\u043b \u043d\u0430\u0448\u0443 \u0411\u0414 \u00ab\u0434\u043e \u043a\u043e\u043d\u0434\u0438\u0446\u0438\u0438\u00bb, \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u0447\u0443\u0442\u043e\u0447\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.<\/p>\n<h5>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h5>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c <i>resources\/application.conf<\/i>  <\/p>\n<pre><code class=\"scala\">habr.template = {   default = {     db.url = &quot;jdbc:postgresql:\/\/localhost\/habr&quot;     db.user = &quot;habr&quot;     db.password = &quot;habr&quot;   }    test = {     db.url = &quot;jdbc:postgresql:\/\/localhost\/test-habr&quot;   }    dev = {    } } <\/code><\/pre>\n<p>  \u0422\u0443\u0442 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u043a\u0446\u0438\u0439, \u0432 default \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0432 dev, test \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u044b\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u0430\u043a\u0436\u0435 \u043a\u043b\u0430\u0441\u0441 AppConfig, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">AppConfig<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\"> class AppConfig {    val env = scala.util.Properties.propOrElse(&quot;spring.profiles.active&quot;, scala.util.Properties.envOrElse(&quot;ENV&quot;, &quot;test&quot;))   val conf = ConfigFactory.load()   val default = conf.getConfig(&quot;habr.template.default&quot;)   val config = conf.getConfig(&quot;habr.template.&quot; + env).withFallback(default)    def dataSource = {     val ds = new BasicDataSource     ds.setDriverClassName(&quot;org.postgresql.Driver&quot;)     ds.setUsername(config.getString(&quot;db.user&quot;))     ds.setPassword(config.getString(&quot;db.password&quot;))     ds.setMaxActive(20)     ds.setMaxIdle(10)     ds.setInitialSize(10)     ds.setUrl(config.getString(&quot;db.url&quot;))     ds   }    def liquibase(dataSource: DataSource) = {     val liquibase = new LiquibaseDropAllSupport()     liquibase.setDataSource(dataSource)     liquibase.setChangeLog(&quot;classpath:changelog\/db.changelog-master.xml&quot;)     liquibase.setContexts(env)     liquibase.setShouldRun(true)     liquibase.dropAllContexts += &quot;test&quot;     liquibase   }  } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0440\u0435\u0434\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u2014 <i>-Dspring.profiles.active<\/i>, \u043b\u0438\u0431\u043e <i>export ENV<\/i>. \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u0438 \u043c\u0435\u0440\u0434\u0436\u0438\u043c \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0443\u043b\u043b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0441 \u0411\u0414. \u0422\u0443\u0442 \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0443\u043b\u0430, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0432\u0441\u0435 \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e. \u041d\u0443 \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c liquibase, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0432 \u0411\u0414 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 CI \u0434\u043b\u044f \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c DataSource \u0438 Liquibase \u043a\u0430\u043a Bean \u0432 Spring  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">root.xml<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;beans xmlns=&quot;http:\/\/www.springframework.org\/schema\/beans&quot;        xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;        xmlns:context=&quot;http:\/\/www.springframework.org\/schema\/context&quot;        xsi:schemaLocation=&quot;http:\/\/www.springframework.org\/schema\/beans         http:\/\/www.springframework.org\/schema\/beans\/spring-beans.xsd         http:\/\/www.springframework.org\/schema\/context http:\/\/www.springframework.org\/schema\/context\/spring-context.xsd&quot;&gt;      &lt;bean id=&quot;config&quot; class=&quot;com.sumskoy.habr.template.AppConfig&quot;\/&gt;     &lt;bean id=&quot;dataSource&quot; factory-bean=&quot;config&quot; factory-method=&quot;dataSource&quot;\/&gt;     &lt;bean id=&quot;liquibase&quot; factory-bean=&quot;config&quot; factory-method=&quot;liquibase&quot;&gt;         &lt;constructor-arg ref=&quot;dataSource&quot;\/&gt;     &lt;\/bean&gt; &lt;\/beans&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h5>\u0417\u0430\u043f\u0443\u0441\u043a \u0438\u0437 \u043f\u043e\u0434 Jetty<\/h5>\n<p>  \u042f \u0432\u0441\u0435\u0433\u0434\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e Jetty, \u044d\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0430 \u0435\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432, \u0442\u043e \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0434\u043e 30 \u0441\u0435\u043a\u0443\u043d\u0434, \u0447\u0442\u043e \u043a\u0440\u0430\u0439\u043d\u0435 \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u0435\u0442. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0442\u043e\u0447\u043a\u0443 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Main<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">object Main extends App {   val server = new Server(8080)    val webAppContext = new WebAppContext()   webAppContext.setResourceBase(&quot;src\/main\/webapp&quot;)   webAppContext.setContextPath(&quot;\/&quot;)   webAppContext.setParentLoaderPriority(true)   webAppContext.setConfigurations(Array(     new WebXmlConfiguration()   ))    server.setHandler(webAppContext)   server.start()   server.join() } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h5>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/h5>\n<p>  \u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Spring Security, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0433\u043e\u0432\u043e\u0440\u044e, \u0447\u0442\u043e \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <i>\/login.html<\/i>, \u043a\u0430\u043a \u043e\u0441\u0432\u043d\u043e\u0439 url \u2014 <i>\/index.html<\/i>, \u0432\u0441\u0435 API \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432 \u0432\u0435\u0442\u043a\u0435 <i>\/api<\/i>. <br \/>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c User, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a \u043d\u0435\u0439 Repository, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d \u043c\u0435\u0442\u043e\u0434, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u0438\u043c\u0435\u043d\u0438. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0438\u043c\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">User Entity<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">case class User(username: String, password: String, enabled: Boolean, @Column(&quot;user_id&quot;) override val id: Int) extends BaseEntity {   def this() = this(&quot;&quot;, &quot;&quot;, false, 0) } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u043e\u0434\u0435\u043b\u044c \u0432 \u0441\u0445\u0435\u043c\u0443  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Core Schema<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">object CoreSchema extends Schema {   val users = table[User](&quot;users&quot;)    on(users)(user =&gt; declare(     user.id is autoIncremented,     user.username is unique   )) } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0418 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 Repository. \u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u043f\u0438\u0448\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0432 \u044d\u0442\u043e\u043c \u043d\u0435\u0442 \u043d\u0443\u0436\u0434\u044b, \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u0438\u0448\u043d\u0438\u0439 \u0440\u0430\u0437 \u0437\u0430\u0445\u043b\u0430\u043c\u043b\u044f\u0435\u0442 \u043a\u043e\u0434. \u0415\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u043c\u0435\u043d\u044f\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c AOP, \u0442\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0442\u0440\u0443\u0434\u0430, \u043d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u043c \u044d\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438 \u0442\u0430\u043a\u0430\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043d\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0438\u0442\u0441\u044f \u0432 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u043c \u0431\u0443\u0434\u0443\u0449\u0435\u043c. \u041d\u0435 \u0431\u0443\u0434\u0435\u043c \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0442\u044c \u0441\u0435\u0431\u0435 \u0436\u0438\u0437\u043d\u044c.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">User Repository<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">@Repository class UserRepository {    def findOne(username: String) = inTransaction {     CoreSchema.users.where(_.username === username).singleOption   }  } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041d\u0443 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440   <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">AuthController<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">@Controller @RequestMapping(Array(&quot;api\/auth&quot;)) class AuthController @Autowired()(private val userRepository: UserRepository) {    @RequestMapping(Array(&quot;check&quot;))   @ResponseBody   def checkTokenValid(principal: Principal): Map[String, Any] = {      userRepository.findOne(principal.getName) match {       case Some(user) =&gt; Map[String, Any](&quot;username&quot; -&gt; user.username, &quot;enabled&quot; -&gt; user.enabled)       case _ =&gt; throw new ObjectNotFound()     }    }  } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c \u0447\u0442\u043e \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 JSON \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Jackson. \u041a \u043d\u0435\u043c\u0443 \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438 Scala, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u043f\u043f\u0435\u0440 \u0434\u043b\u044f Spring  <\/p>\n<pre><code class=\"scala\">def converter() = {     val messageConverter = new MappingJackson2HttpMessageConverter()      val objectMapper = new ObjectMapper() with ScalaObjectMapper     objectMapper.registerModule(DefaultScalaModule)     messageConverter.setObjectMapper(objectMapper)      messageConverter   } <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"xml\">&lt;beans:bean id=&quot;converter&quot; factory-bean=&quot;config&quot; factory-method=&quot;converter&quot;\/&gt;     &lt;mvc:annotation-driven&gt;         &lt;message-converters register-defaults=&quot;true&quot;&gt;             &lt;beans:ref bean=&quot;converter&quot;\/&gt;         &lt;\/message-converters&gt;     &lt;\/mvc:annotation-driven&gt; <\/code><\/pre>\n<h5>\u0422\u0435\u0441\u0442\u044b<\/h5>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0441\u0442\u044b. \u041c\u044b \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u043c, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443 \u0432\u0445\u043e\u0434\u0430 \u0438 \u0447\u0435\u0440\u0435\u0437 OAuth. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0430 \u044d\u0442\u043e \u043f\u0430\u0440\u0443 \u0442\u0435\u0441\u0442\u043e\u0432.<br \/>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Spring MVC  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">IntegrationTestSpec<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">@ContextConfiguration(value = Array(&quot;classpath:context\/root.xml&quot;, &quot;classpath:context\/mvc.xml&quot;)) @WebAppConfiguration abstract class IntegrationTestSpec extends FlatSpec with ShouldMatchers with ScalaFutures {   @Resource private val springSecurityFilterChain: java.util.List[FilterChainProxy] = new util.ArrayList[FilterChainProxy]()   @Autowired private val wac: WebApplicationContext = null    new TestContextManager(this.getClass).prepareTestInstance(this)    var builder = MockMvcBuilders.webAppContextSetup(this.wac)   for(filter &lt;- springSecurityFilterChain.asScala) builder = builder.addFilters(filter)    val mockMvc = builder.build()   val md = MediaType.parseMediaType(&quot;application\/json;charset=UTF-8&quot;)    val objectMapper = new ObjectMapper() with ScalaObjectMapper   objectMapper.registerModule(DefaultScalaModule) } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0418 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438  <\/p>\n<pre><code class=\"scala\">it should &quot;Login as admin through oauth with default password&quot; in {     val resultActions =       mockMvc.perform(         get(&quot;\/oauth\/token&quot;).           accept(md).           param(&quot;grant_type&quot;, &quot;password&quot;).           param(&quot;client_id&quot;, &quot;simple-client&quot;).           param(&quot;client_secret&quot;, &quot;simple-client-secret-key&quot;).           param(&quot;username&quot;, &quot;admin&quot;).           param(&quot;password&quot;, &quot;admin&quot;)).         andExpect(status.isOk).         andExpect(content.contentType(md)).         andExpect(jsonPath(&quot;$.access_token&quot;).exists).         andExpect(jsonPath(&quot;$.token_type&quot;).exists).         andExpect(jsonPath(&quot;$.expires_in&quot;).exists)      val contentAsString = resultActions.andReturn.getResponse.getContentAsString      val map: Map[String, String] = objectMapper.readValue(contentAsString, new TypeReference[Map[String, String]] {})     val access_token = map.get(&quot;access_token&quot;).get     val token_type = map.get(&quot;token_type&quot;).get      mockMvc.perform(       get(&quot;\/api\/auth\/check&quot;).         accept(md).         header(&quot;Authorization&quot;, token_type + &quot; &quot; + access_token)).       andExpect(status.isOk).       andExpect(content.contentType(md)).       andExpect(jsonPath(&quot;$.username&quot;).value(&quot;admin&quot;)).       andExpect(jsonPath(&quot;$.enabled&quot;).value(true))   } <\/code><\/pre>\n<p>  \u0418 \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443  <\/p>\n<pre><code class=\"scala\">it should &quot;Login as admin through user form with default password&quot; in {     mockMvc.perform(       post(&quot;\/auth\/j_spring_security_check&quot;).         contentType(MediaType.APPLICATION_FORM_URLENCODED).         param(&quot;j_username&quot;, &quot;admin&quot;).         param(&quot;j_password&quot;, &quot;admin&quot;)).       andExpect(status.is3xxRedirection()).       andExpect(header().string(&quot;location&quot;, &quot;\/index.html&quot;))   } <\/code><\/pre>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u043c\u044b \u043f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f. \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0444\u0440\u043e\u043d\u0442, \u0441\u043e \u0441\u0431\u043e\u0440\u043a\u043e\u0439 SASS, CoffeeScript, \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0438 \u043f\u0440\u043e\u0447\u0438\u043c\u0438 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0448\u0442\u0443\u043a\u0430\u043c\u0438. \u041f\u043e\u0434\u0440\u0443\u0436\u0438\u043c\u0441\u044f \u0441 <a href=\"http:\/\/yeoman.io\/\">Yeoman<\/a>, <a href=\"http:\/\/bower.io\/\">Bower<\/a>, <a href=\"http:\/\/gruntjs.com\/\">Grunt<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0441\u0440\u0435\u0434\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 <a href=\"http:\/\/www.vagrantup.com\/\">Vagrant<\/a>.<\/p>\n<p>  \u0412\u0441\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 Bitbucket <a href=\"https:\/\/bitbucket.org\/andy-inc\/scala-habr-template\">https:\/\/bitbucket.org\/andy-inc\/scala-habr-template<\/a>.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043d\u0430\u0448\u043b\u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0443 \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0443, \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u041b\u0421. \u0417\u0430\u0440\u0430\u043d\u0435\u0435 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<p>  \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u0430\u0448\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0434\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u043c\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0438 \u043d\u0435 \u043c\u0438\u043d\u0443\u0441\u0443\u0439\u0442\u0435 \u043c\u043e\u043b\u0447\u0430.      \t<\/p>\n<div class=\"clear\"><\/div>\n<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/230451\/\"> http:\/\/habrahabr.ru\/post\/230451\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"content html_format\">     \t\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439, \u0425\u0430\u0431\u0440. <\/p>\n<p>  \u041b\u0435\u0442\u043e \u043d\u0430 \u0434\u0432\u043e\u0440\u0435, \u0441\u043a\u043e\u0440\u043e \u043e\u0442\u043f\u0443\u0441\u043a \u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0430\u043c\u0438, \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u043f\u044b\u0442\u043e\u043c \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e Web \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Java \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435. \u041a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u044f\u0437\u044b\u043a \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0445\u043e\u0436\u0435 \u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0433\u0430\u0439\u0434, \u043a\u0430\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0443 \u0441 \u043e\u043f\u044b\u0442\u043e\u043c Java \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala \u0438 \u043d\u0435 \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u0443 \u043d\u0435\u0433\u043e \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043e\u043a.<\/p>\n<p>  \u042d\u0442\u043e \u043f\u0435\u0440\u0432\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0438\u0437 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u044b \u0443\u0434\u0435\u043b\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043b\u044e\u0434\u0435\u0439 \u0437\u043d\u0430\u044e\u0449\u0438\u0445 Java, \u0440\u0430\u0431\u043e\u0442\u0430\u0432\u0448\u0438\u0445 \u0441\u043e Spring, Hibernate, JPA, JSP \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 3-4\u0435\u0445 \u0431\u0443\u043a\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f\u043c\u0438. \u042f \u043f\u043e\u043f\u044b\u0442\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0438 \u0431\u0435\u0437\u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u043e \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Scala \u0432 \u0432\u0430\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0438 \u043f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0430\u0448\u0435 \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u0441\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u043a\u0440\u0443\u0433 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0440\u044f\u0434 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:<br \/>  1. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u043a\u0440\u044b\u0442\u043e, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 <br \/>  2. \u041d\u0430\u043b\u0438\u0447\u0438\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e API (REST \u043c\u044b \u0437\u0430\u0431\u0443\u0434\u0435\u043c (\u043e\u043d \u0443\u0436\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u044f) \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 Google AdWords API, \u0441\u043e \u0441\u0432\u043e\u0438\u043c SQL like \u0437\u0430\u043f\u0440\u043e\u0441\u043d\u0438\u043a\u043e\u043c)<br \/>  3. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0442\u0430\u043a \u0438 \u0431\u0435\u0437 \u043d\u0435\u0433\u043e<br \/>  4. i18n<br \/>  5. \u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0411\u0414<br \/>  6. \u0421\u0440\u0435\u0434\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <a href=\"http:\/\/www.vagrantup.com\/\">Vagrant<\/a><br \/>  7. \u0418, \u043f\u043e \u043c\u0435\u043b\u043e\u0447\u0438, \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0435\u2026<\/p>\n<p>  \u0412\u0441\u0435 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0442\u044c \u0438 \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0435\u0442 \u044d\u0442\u043e \u0441\u0440\u043e\u043a\u043e\u043c \u0432 2 \u0434\u043d\u044f. \u0415\u0441\u043b\u0438 \u044f \u0432\u0430\u0441 \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-230451","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/230451","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=230451"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/230451\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=230451"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=230451"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=230451"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}