1. 概述

本文将带你快速掌握如何使用 AngularJS 实现一个前端应用,用于消费 RESTful API。

核心功能包括:数据列表展示、新增资源、更新和删除操作。整个过程简洁直接,适合已有 AngularJS 和 REST 基础的开发者参考。

✅ 目标:实现对 Feed 资源的增删改查(CRUD)
⚠️ 注意:本文不讲 AngularJS 基础语法,聚焦于与后端 API 的对接实践


2. REST API 接口设计

我们先来看后端暴露的 REST 接口,管理 Feed 资源,支持分页:

  • 获取分页列表GET /api/myFeeds?page={page}&size={size}&sortDir={dir}&sort={propertyName}
  • 创建 FeedPOST /api/myFeeds
  • 更新 FeedPUT /api/myFeeds/{id}
  • 删除 FeedDELETE /api/myFeeds/{id}

分页参数说明:

  • page:当前页码(从 0 开始)
  • size:每页条数
  • sort:排序字段名
  • sortDir:排序方向(ascdesc

示例 Feed 数据结构:

{
    "id": 1,
    "name": "baeldung feed",
    "url": "/feed"
}

⚠️ 注意:page 参数后端是 0 起始,前端 ng-table 是 1 起始,需要转换


3. 页面结构(HTML)

前端页面使用 ng-table 展示数据,并提供增删改入口:

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
<script th:src="@{/resources/ng-table.min.js}"></script>
<script th:src="@{/resources/mainCtrl.js}"></script>

<a href="#" ng-click="addNewFeed()">Add New RSS Feed</a>
<table ng-table="tableParams">
    <tr ng-repeat="row in $data track by row.id">
        <td data-title="'Name'" sortable="'name'">{{row.name}}</td>
        <td data-title="'Feed URL'" sortable="'url'">{{row.url}}</td>
        <td data-title="'Actions'">
            <a href="#" ng-click="editFeed(row)">Edit</a>
            <a href="#" ng-click="confirmDelete(row.id)">Delete</a>
        </td>
    </tr>
</table>

✅ 关键点:

  • 引入 angular.min.jsangular-resource.min.js
  • 使用 ng-table 实现可排序、可分页的表格
  • 操作按钮绑定 ng-click 事件

4. Angular 控制器初始化

控制器定义模块并注入依赖:

var app = angular.module('myApp', ["ngTable", "ngResource"]);
app.controller('mainCtrl', function($scope, NgTableParams, $resource) {
    // 实现逻辑见下文
});

✅ 依赖说明:

  • ngTable:用于数据表格展示与分页控制
  • ngResource:用于封装 REST API 调用,比 $http 更语义化

5. 配置 ng-table 数据源

ng-table 的核心是 NgTableParams,我们通过 getData 自定义数据获取逻辑,适配后端分页格式:

$scope.feed = $resource("api/myFeeds/:feedId", {feedId: '@id'});
$scope.tableParams = new NgTableParams({}, {
    getData: function(params) {
        var queryParams = {
            page: params.page() - 1,  // 转换为 0 起始
            size: params.count()
        };
        var sortingProp = Object.keys(params.sorting());
        if (sortingProp.length == 1) {
            queryParams["sort"] = sortingProp[0];
            queryParams["sortDir"] = params.sorting()[sortingProp[0]];
        }
        return $scope.feed.query(queryParams, function(data, headers) {
            var totalRecords = headers("PAGING_INFO").split(",")[0].split("=")[1];
            params.total(totalRecords);
            return data;
        }).$promise;
    }
});

⚠️ 踩坑提醒:

  • params.page() 返回的是 1 起始,需减 1 适配后端
  • params.sorting() 返回 {name: 'asc'},需拆解为 sortsortDir
  • 总记录数通过响应头 PAGING_INFO 获取,格式如:total=100,page=0

query() 返回数组,适合列表;get() 返回单个对象


6. CRUD 操作实现

6.1 新增 Feed

使用 $resourcesave() 方法发起 POST 请求:

$scope.feed = {name: "New feed", url: "http://www.example.com/feed"};

$scope.createFeed = function() {
    $scope.feeds.save($scope.feed, function() {
        $scope.tableParams.reload();
    });
}

✅ 注意:save() 默认对应 POST,无需额外配置


6.2 更新 Feed

$resource 默认没有 update 方法,需手动定义:

$scope.feeds = $resource("api/myFeeds/:feedId", {feedId: '@id'}, {
    'update': { method: 'PUT' }
});

$scope.updateFeed = function() {
    $scope.feeds.update($scope.feed, function() {
        $scope.tableParams.reload();
    });
}

✅ 技巧:{feedId: '@id'} 表示 URL 中的 feedId 从数据对象的 id 字段取值


6.3 删除 Feed

调用 delete() 方法发送 DELETE 请求:

$scope.confirmDelete = function(id) {
    $scope.feeds.delete({feedId: id}, function() {
        $scope.tableParams.reload();
    });
}

✅ 注意:参数对象用于填充 URL 模板,非请求体


7. 使用 ngDialog 实现弹窗

使用 ngDialog 模块实现新增/编辑弹窗,避免页面跳转。

弹窗模板

<script type="text/ng-template" id="templateId">
<div class="ngdialog-message">
    <h2>{{feed.name}}</h2>
    <input ng-model="feed.name"/>
    <input ng-model="feed.url"/>
</div>
<div class="ngdialog-buttons mt">
    <button ng-click="save()">Save</button>
</div>
</script>

控制器逻辑

$scope.addNewFeed = function() {
    $scope.feed = {name: "New Feed", url: ""};
    ngDialog.open({ template: 'templateId', scope: $scope });
}

$scope.editFeed = function(row) {
    $scope.feed = angular.copy(row);
    ngDialog.open({ template: 'templateId', scope: $scope });
}

$scope.save = function() {
    ngDialog.close('ngdialog1');
    if (!$scope.feed.id) {
        $scope.createFeed();
    } else {
        $scope.updateFeed();
    }
}

✅ 说明:

  • addNewFeed 初始化空对象
  • editFeed 使用 angular.copy() 避免直接修改原数据
  • save() 根据是否存在 id 判断是新增还是更新

8. 全局错误处理

避免每个请求都写 error callback,使用 $httpProvider 拦截器统一处理错误:

app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push(function($q, $rootScope) {
        return {
            responseError: function(responseError) {
                $rootScope.message = responseError.data.message;
                return $q.reject(responseError);
            }
        };
    });
}]);

页面展示错误信息

<div ng-show="message" class="alert alert-danger">
    {{message}}
</div>

✅ 优势:

  • 集中处理 4xx/5xx 响应
  • 通过 $rootScope.message 全局通知
  • 用户体验更友好

9. 总结

本文通过一个简单的 Feed 管理前端,演示了 AngularJS 如何高效对接 RESTful API。

核心要点回顾:

  • 使用 ngResource 封装 CRUD,语义清晰
  • ng-table 轻松实现分页排序,但需注意参数适配
  • ngDialog 提升交互体验
  • 拦截器实现全局错误处理,减少重复代码

完整代码已开源,可直接导入运行:

👉 GitHub 项目地址:https://github.com/baeldung/reddit-app
🔧 环境:Eclipse 项目,Maven 构建,导入即用

适合用于学习或作为小型管理后台的快速原型参考。


原始标题:Simple AngularJS Front-End for a REST API

« 上一篇: Java Web Weekly 42
» 下一篇: Java周报 43