所以我花點時間打算寫一些 AngularJS RESTful 一個完整的前後端範例
可能想到要用 Java 和 Node.js 作為範例後端吧,所以本篇先提供以 Java 為後端的範例程式吧
以下我用 Todo 作為範例,整個程式我並不會介紹太多,基本的可以先看 AngularJS 教學 - $resource service
先列出專案目錄結構
1. 建立 Java RESTful 專案
我是以 Maven 來建立我的範例專案,如果不想用 Maven 的你可以直接抓 JAR 也無所謂
以下是 POM 檔內容(pom.xml)
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-servlet</artifactId>
<version>1.17.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.17.1</version>
</dependency>
</dependencies>
不想用 Maven 的,可以抓下列的 JAR 檔放到 WEB-INF/lib 目錄內..
2. 建立 Todo Model(Todo.java)
package todo.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Todo {
private int id;
private String name;
private String owner;
private String priority;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getPriority() {
return priority;
}
public void setPriority(String priority) {
this.priority = priority;
}
}
3. 建立 Todo Dao(TodoDao.java)
為了範例的方便以及重點在於 AngularJS 的 RESTful
所以沒有用任何資料庫,資料都是 Hard code 的...
package todo.dao;
import java.util.ArrayList;
import java.util.List;
import todo.model.Todo;
public class TodoDao {
private static int idSeq = 1;
private static List todos;
static{
final Todo todo = new Todo(){{
setId(idSeq++);
setName("Complete a Todo list");
setOwner("Allen");
setPriority("High");
}};
todos = new ArrayList(){{
add(todo);
}};
}
public static List queryAll(){
return todos;
}
public static Todo getTodo(int id){
Todo result = null;
for(Todo todo: todos){
if(todo.getId() == Integer.valueOf(id)){
result = todo;
break;
}
}
return result;
}
public static Todo addTodo(Todo todo){
todo.setId(idSeq++);
todos.add(todo);
return todo;
}
public static void updateTodo(Todo todo) {
Todo target = getTodo(todo.getId());
target.setName(todo.getName());
target.setOwner(todo.getOwner());
target.setPriority(todo.getPriority());
}
public static void deleteTodo(Integer id) {
int index = 0;
for(int i=0;i<todos.size();i++){
if(todos.get(i).getId() == id) index = i;
}
todos.remove(index);
}
}
4. 建立 Todo RESTful(TodoResource.java)
package todo.resource;
import java.util.List;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import todo.dao.TodoDao;
import todo.model.Todo;
@Path("/todos")
public class TodoResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public List getTodos() {
return TodoDao.queryAll();
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Todo getTodo(@PathParam("id") String id) {
return TodoDao.getTodo(Integer.valueOf(id));
}
@POST
@Produces(MediaType.APPLICATION_JSON)
public Todo getTodos(Todo todo) {
return TodoDao.addTodo(todo);
}
@PUT
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public void updateTodos(Todo todo) {
TodoDao.updateTodo(todo);
}
@DELETE
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public void updateTodos(@PathParam("id") String id) {
TodoDao.deleteTodo(Integer.valueOf(id));
}
}
5. 設定 web.xml
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>todo.resource</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
6. Java RESTful 後端總結
撰寫 Java RESTful 的重點在於 RESTful 的URL以及請求方法(上面第四點)
因為這會關係到前端 AngularJS 使用 $resource 時所要呼叫的後端 URL
例如目前這個 Todo 範例
查詢所有 Todo --> GET /rest/todos
查詢 id 為 1 的 Todo --> GET /rest/todos/1
修改 id 為 1 的 Todo --> PUT /rest/todos/1
刪除 id 為 1 的 Todo --> DELETE /rest/todos/1
新增 Todo --> POST /rest/todos
接下來是這次範例的畫面,為了稍為美觀所以加了 Bootstrap 3.0
7. index.html & app.js
需要引入 bootstrap.min.css,並且下載以下這三個 AngularJS JS 檔
angular.min.js、angular-resource.min.js、angular-route.min.js
以下是 index.html
<html ng-app="todoApp">
<head>
<meta charset="UTF-8">
<title>Todo App Demo</title>
<link rel="stylesheet"
type="text/css" href="css/bootstrap.min.css">
<script type="text/javascript"
src="js/lib/angular.min.js"></script>
<script type="text/javascript"
src="js/lib/angular-resource.min.js"></script>
<script type="text/javascript"
src="js/lib/angular-route.min.js"></script>
<script type="text/javascript"
src="js/app.js"></script>
<script type="text/javascript"
src="js/controller.js"></script>
<script type="text/javascript"
src="js/service.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
建立 AngularJS 的 main 程式 (app.js)
angular.module('todoApp', [
'ngRoute',
'todoApp.services',
'todoApp.controllers'
]).config(function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'partial/list.html',
controller: 'TodoListCtrl'
});
$routeProvider.when('/todoDetail/:todoId', {
templateUrl: 'partial/detail.html',
controller: 'TodoDetailCtrl'
});
$routeProvider.when('/todoUpdate/:todoId', {
templateUrl: 'partial/update.html',
controller: 'TodoUpdateCtrl'
});
$routeProvider.otherwise({redirectTo: '/'});
});
8. 建立 Todo Service (service.js)
angular.module("todoApp.services", ["ngResource"])
.factory("Todo", function($resource){
return $resource('rest/todos/:id', {id:'@id'}, {
update: {
method: 'PUT'
}
});
});
9. 建立 Todo Controllers (controller.js)要多留意是怎麼使用 Todo service 去打 RESTful 的,這在上一篇都有提到了
'use strict';
angular.module("todoApp.controllers", [])
.controller("TodoListCtrl", function($scope, Todo){
$scope.name = "Allen";
$scope.todos = Todo.query();
$scope.$on("updateTodos", function (event, todo) {
$scope.todos.push(todo);
});
$scope.remove = function(idx){
$scope.todos[idx].$remove(function(res){
$scope.todos.forEach(function(p, index) {
if (index == idx) $scope.todos.splice(index, 1);
});
});
};
})
.controller("TodoDetailCtrl", function($scope, $routeParams, Todo){
$scope.todo = Todo.get({id: $routeParams.todoId});
})
.controller("TodoAddCtrl", function($rootScope, $scope, Todo){
$scope.name = "";
$scope.owner = "";
$scope.priority = "Low";
$scope.add = function(){
var todo = new Todo();
todo.name = $scope.name;
todo.owner = $scope.owner;
todo.priority = $scope.priority;
todo.$save(function(){
$rootScope.$broadcast("updateTodos", todo);
});
};
})
.controller("TodoUpdateCtrl", function($scope, $routeParams, $location, Todo){
$scope.todo = Todo.get({id: $routeParams.todoId});
$scope.update = function(){
$scope.todo.$update(function(){
$location.path("/todoDetail/"+$scope.todo.id);
});
};
});
10. 建立 HTML Page (list.html、detail.html、update.html)
因為 HTML 程式碼的篇幅比較多,所以我只列出中點的地方
首先是 list.html,頁面包含了列出所有的 Todo 項目,並且底下有個區塊可以新增 Todo
<tr ng-repeat="todo in todos">
<td><a href="#/todoDetail/{{todo.id}}">{{todo.name}}</a></td>
<td>
<a href="#/todoUpdate/{{todo.id}}">Update</a>
<button type="button" class="btn
btn-warning" ng-click="remove($index)">Delete</button>
</td>
</tr>
//略...
<div class="panel-body form-horizontal" role="form"
ng-controller="TodoAddCtrl">
//略...
<input type="text" name="name"
ng-model="name" class="form-control"/>
//略...
<input type="text" name="owner"
ng-model="owner" class="form-control"/>
//略...
<select name="priority" ng-model="priority" class="form-control">
<option value='High'>High</option>
<option value='Middle'>Middle</option>
<option value='Low'>Low</option>
</select>
<button type="button" class="btn
btn-default" ng-click="add()">Submit</button>
</div>
接下來是 detail.html,負責呈現一個 Todo 項目的內容
<div class="panel panel-info">
<div class="panel-heading">{{todo.name}}</div>
<div class="panel-body">
<p id='todoOwner'>Owner : {{todo.owner}}</p>
<p id='todoPriority'>Priority : {{todo.priority}}</p>
<a id='goBackLink' href='/AngularJSRestful/#/'>Back to list</a>
</div>
</div>
最後是 update.html,負責更新一個 Todo 項目
同樣為了節省篇幅,只列出重要的部分
//略...
<input type="text" name="name"
ng-model="todo.name" class="form-control"/>
//略...
<input type="text" name="owner"
ng-model="todo.owner" class="form-control">
//略...
<select name="priority" ng-model="todo.priority" class="form-control">
<option value='High'>High</option>
<option value='Middle'>Middle</option>
<option value='Low'>Low</option>
</select>
//略...
<button type="button" class="btn
btn-default" ng-click="update()">Submit</button>
沒有留言:
張貼留言