對於這個問題,其實能夠看看個人學習歷程,我以爲很好的體現了Web開發模式的演化。javascript
石器時代:那正是本人剛學JSP的時候,寫了一個簡單的商城DEMO,全部的業務邏輯,數據庫的交互以及Javascript代碼等都雜糅在.jsp文件中,好處就是簡單,幾個JSP頁面就能解決問題,但也正是因爲內嵌了大量的Java代碼,先後端的代碼擠在一個文件中,後期可維護性不好,代碼徹底沒有可讀性,並且更改一個CSS樣式都必需要重啓服務器才行html
文明興起:那以後學習了Servlet,開始重構商城Demo,將數據庫的交互,業務邏輯,抽象到Servlet類中,JSP中的Java代碼慢慢消失,但仍是形成了Controller類過於肥胖的問題前端
近現代:這個時候已經學習了SSH、Spring Family,搞過PlayFramework,JFinal等各類小玩意,對於MVC模式以及架構慢慢有了本身的理解,代碼的可維護性,可讀性各方面有了明顯的提高,項目各個層次的職責比較清晰:Model層採用SpringDATA,Entity只需少許註解,DAO層只需實現相應的接口,實現交給Spring去注入,Controller層則採用SpringMVC,View採用Freemarker,Velocity等模板,功能很強大,最重要的是斷了你在前端頁面中寫Java代碼的念頭。可是這個階段依然存在相關的問題:html5
View層仍然職責不清晰,到底是該讓前端學習點後臺技術去直接套JSP模板,仍是應該先在本身的機器上寫好頁面,而後交給後臺開發人員去改形成JSP/FTL等java
開發效率底下,不利於先後臺的開發測試,後端不只須要寫邏輯代碼,還須要去關注視圖層數據庫
能夠看出,先後端分離實際上是職責的分離,將不一樣邏輯抽象出來,讓先後端開發人員可以更好的合做,對於我我的說,可以更專注,開發後端的時候,只須要專心解決後端的問題,前端同理。後端
我目前的作法是:將Java做爲一種服務存在,僅須要提供RESTFul接口便可,前端目前採用AngularJS,調用後端API,解析JSON數據,靜態HTML頁面。api
交給Nginx代理,下面是具體配置:安全
Java採用SpringMVC,方法返回JSON數據,而後運行帶後臺中,監聽8080端口,處理來自前臺的請求服務器
@RestController @RequestMapping("api") public class APIController { @Autowired private NewsItemService itemService; @Autowired private NewsDetailService detailService; /** * API:獲取單頁新聞 * @param pageable * @return */ @RequestMapping(value = "/news") public List<NewsItem> showNewsPage(Pageable pageable){ return itemService.findAll(pageable); } /** * API:根據指定NewsItem ID * 獲取新聞詳情 */ @RequestMapping(value = "/news/detail/{id}") public NewsDetail showNewsDetail(@PathVariable("id")Long id){ NewsDetail detail = detailService.findByNewsItemId(id); return detail; } /** * 獲取指定ID新聞 * @param id * @return */ @RequestMapping(value = "/news/{id}") public NewsItem showNewsItem(@PathVariable("id") Long id){ NewsItem item = itemService.get(id); return item; } 。。。 }
採用AngularJS,充當Controller層,先後端實現了真正的分離,但仍是有點問題的。
index.html <!doctype html> <html lang="zh-CN" ng-app="dznews"> <head> <title>DzNews</title> </head> <body > <div ng-view></div> </body> </html>
app.js: var dznews = angular.module('dznews', [ 'ngRoute', 'newsControllers', ]); dznews.config(['$routeProvider','$locationProvider', function($routeProvider,$locationProvider) { $routeProvider. when('/',{ templateUrl: 'part/news_list.html', controller: 'listController' }). when('/news', { templateUrl: 'part/news_list.html', controller: 'listController' }). when('/news/:id', { templateUrl: 'part/news_detail.html', controller: 'newsDetailCtrl' }). otherwise({ redirectTo: '/news' }); // use the HTML5 History API $locationProvider.html5Mode(true); }]); var newsControllers = angular.module('newsControllers', []); newsControllers.controller('listController', function ($scope,$http) { $scope.page = 0; <!--/api/news交給Nginx轉發給8080端口的Java後端服務--> $http.get('/api/news').success(function(data) { $scope.newses = data; }); }); newsControllers.controller("newsDetailCtrl",['$scope', '$routeParams','$http','$sce', function($scope, $routeParams,$http,$sce) { $http.get("/api/news/detail/"+$routeParams.id).success(function (data) { $scope.detail = data ; $scope.detail.content = $sce.trustAsHtml($scope.detail.content); }); }]);
Nginx監聽80端口,靜態請求交由Nginx處理,動態請求轉發給8080端口的Java後端服務,配置以下供參考:
try_files:因爲AngularJS是單頁應用,一個ng-app對應一個頁面,並且實現了本身的前端路由機制,這樣就能夠由一個ng-app管理多個頁面,只需替換局部的ng-view,可是這樣就會有一個問題,當咱們直接訪問首頁,跳轉到/news/:id的時候是沒問題的,
可是當直接訪問/news/:id這個網址的時候,就會出現404的錯誤,就其緣由,是由於WebServer找不到對應的頁面,因此須要將全部的由AngularJS路由管理的URL都轉發到ng-app便可,
location / { root DzNewsBackEnd/app; #index index.html index.htm; try_files $uri $uri/ /index.html =404; } location /api/ { proxy_pass http://localhost:8080; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; }
在用這種方式進行開發的時候,當我完成後端API的開發,就能夠專一去寫前端的頁面和JS邏輯,遇到BUG的時候,也至關容易調試,由於很容易發現是哪一層的問題,但仍是存在一些短板,將全部的邏輯交由前端JS去執行,安全及性能方面存在不少短板,當進去首頁的時候,會發現有一個明顯的白屏,並且會暴露後端的API,所以須要在後端進行一些驗證,例如OAUTH等方案,我我的傾向於中間加一層NodeJS,將全部的邏輯,session管理等都交由這層處理,也能夠部署多個Node實例,再加上Nginx進行負載均衡處理,與Java部署在不一樣的服務器上,這樣Java只做爲無狀態的服務存在,能夠部署多個實例。