先後端分離的一點實踐

什麼是先後端分離

對於這個問題,其實能夠看看個人學習歷程,我以爲很好的體現了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

  1. View層仍然職責不清晰,到底是該讓前端學習點後臺技術去直接套JSP模板,仍是應該先在本身的機器上寫好頁面,而後交給後臺開發人員去改形成JSP/FTL等java

  2. 開發效率底下,不利於先後臺的開發測試,後端不只須要寫邏輯代碼,還須要去關注視圖層數據庫

能夠看出,先後端分離實際上是職責的分離,將不一樣邏輯抽象出來,讓先後端開發人員可以更好的合做,對於我我的說,可以更專注,開發後端的時候,只須要專心解決後端的問題,前端同理。後端

怎麼作先後端的分離

我目前的作法是:將Java做爲一種服務存在,僅須要提供RESTFul接口便可,前端目前採用AngularJS,調用後端API,解析JSON數據,靜態HTML頁面。api

交給Nginx代理,下面是具體配置:安全

Java Layer

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;
        }
        。。。
    }

FrontEnd

採用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 Layer

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只做爲無狀態的服務存在,能夠部署多個實例。

相關文章
相關標籤/搜索