这一节,我们展示如何通过 Spring Boot 提供 Rest API,并使用 AngularJS 构建界面实现一个极简的 todo 应用。
关于 Rest API 的介绍,可参考 Rest API Tutorial .
提供 TODO REST API 引入 Spring Data JPA 依赖 在 build.gradle 中加入以下依赖:
1 2 3 4 ... runtime("com.h2database:h2" ) compile("org.springframework.boot:spring-boot-starter-data-jpa" ) ...
Spring Boot 默认支持 H2, HSQLDB, SQLITE等内嵌数据库的支持,只需要发现 classpath 中有对应 jar 包,即可正确配置数据源。
如需要使用其他数据库,可通过 application.properties 进行配置,如:
1 2 3 4 spring.datasource.url=jdbc:mysql: spring.datasource.username=devuser spring.datasource.password=devuser spring.datasource.driver-class -name =com.mysql.jdbc.Driver
关于 Spirng Data JPA,请参考官方指南:
Spring Data JPA - Reference Documentation
编写 Todo.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package li.fyunli.springboot.entity;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import java.io.Serializable; * Created by fyunli on 16/4/2. */ @Entity public class Todo implements Serializable { private static final long serialVersionUID = 8277837190593516198L ; @Id @GeneratedValue private Long id; @Column (length = 255 , nullable = false ) private String content; public Long getId () { return id; } public void setId (Long id) { this .id = id; } public String getContent () { return content; } public void setContent (String content) { this .content = content; } }
编写 TodoRepository.java 1 2 3 4 5 6 7 8 9 10 11 12 13 package li.fyunli.springboot.repository;import li.fyunli.springboot.entity.Todo;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository; * Created by fyunli on 16/4/2. */ @Repository public interface TodoRepository extends JpaRepository <Todo , Long > {}
编写 TodoController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package li.fyunli.springboot.controller;import li.fyunli.springboot.entity.Todo;import li.fyunli.springboot.repository.TodoRepository;import org.hibernate.ObjectNotFoundException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.MediaType;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;import java.util.List; * Created by fyunli on 16/4/2. */ @RestController @RequestMapping ("/todos" )public class TodoController { Logger logger = LoggerFactory.getLogger(TodoController.class); @Resource private TodoRepository repository; @RequestMapping (method = RequestMethod.GET) public List<Todo> list () { return this .repository.findAll(); } @RequestMapping (value = "/{id}" , method = RequestMethod.GET) public Todo get (@PathVariable Long id) { Todo todo = this .repository.findOne(id); if (todo == null ) { throw new ObjectNotFoundException(id, Todo.class.toString()); } return todo; } @RequestMapping (method = RequestMethod.POST, consumes = {MediaType.APPLICATION_JSON_VALUE}) public Todo create (@RequestBody Todo entity) { logger.debug("create() with body {} of type {}" , entity, entity.getClass()); return this .repository.save(entity); } @RequestMapping (value = "/{id}" , method = RequestMethod.PUT, consumes = {MediaType.APPLICATION_JSON_VALUE}) public Todo update (@PathVariable Long id, @RequestBody Todo entity) { logger.debug("update() of id#{} with body {}" , id, entity); return this .repository.save(entity); } @RequestMapping (value = "/{id}" , method = RequestMethod.DELETE) public void delete (@PathVariable Long id) { this .repository.delete(id); } }
启动,查看结果 以下内容使用 postman 进行调试。
GET http://localhost:8080/todos
嗯,当前没有 todo,那我们就创建一个吧。
创建之后,list 结果如图:
POST http://localhost:8080/todos
输入参数和结果如图:
GET http://localhost:8080/todos/1
PUT http://localhost:8080/todos/1
DELETE http://localhost:8080/todos/1
此时,在查询 id=1 的 todo,结果如下:
使用 AngularJS 构建页面 创建用户界面 在 src/resources/static 创建 todoapp.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 <!DOCTYPE html> <html lang ="zh-CN" > <head > <meta charset ="utf-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width, initial-scale=1" > <meta name ="author" content ="fyunli" > <title > Spring Boot - todo</title > <link href ="//cdn.jsdelivr.net/bootstrap/3.3.6/css/bootstrap.min.css" rel ="stylesheet" > <link href ="css/main.css" rel ="stylesheet" > <script src="//cdn.jsdelivr.net/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="//cdn.jsdelivr.net/respond/1.4.2/respond.min.js"></script> <![endif]--> </head > <body ng-app ="myApp" > <div class ="container" ng-controller ="AppController" > <div class ="page-header" > <h1 > Spring Boot: TODO</h1 > </div > <div class ="alert alert-info" role ="alert" ng-hide ="items && items.length > 0" > There are no items yet. </div > <form class ="form-horizontal" role ="form" ng-submit ="addItem(newItem)" > <div class ="form-group" ng-repeat ="item in items" > <div class ="checkbox col-xs-9" > <label > <input type ="checkbox" ng-model ="item.checked" ng-change ="updateItem(item)" /> {{item.content}} </label > </div > <div class ="col-xs-3" > <button class ="pull-right btn btn-danger" type ="button" title ="Delete" ng-click ="deleteItem(item)" > <span class ="glyphicon glyphicon-trash" > </span > </button > </div > </div > <hr /> <div class ="input-group" > <input type ="text" class ="form-control" ng-model ="newItem" placeholder ="Enter the content..." /> <span class ="input-group-btn" > <button class ="btn btn-default" type ="submit" ng-disabled ="!newItem" title ="Add" > <span class ="glyphicon glyphicon-plus" > </span > </button > </span > </div > </form > </div > <footer class ="footer" > <div class ="container" > <p class ="text-muted" > ©2016 fyunli</p > </div > </footer > <script src ="//cdn.jsdelivr.net/angularjs/1.5.0/angular.min.js" > </script > <script src ="//cdn.jsdelivr.net/angularjs/1.5.0/angular-resource.min.js" > </script > <script src ="//cdn.jsdelivr.net/lodash/4.7.0/lodash.min.js" > </script > <script type ="text/javascript" src ="./app/app.js" > </script > <script type ="text/javascript" src ="./app/controllers.js" > </script > <script type ="text/javascript" src ="./app/services.js" > </script > </body > </html >
在此,我们通过
1 2 <body ng-app ="myApp" > <div class ="container" ng-controller ="AppController" >
告知 AngularJS 我们需要启用 myApp 并使用 AppController。
初始化 AngularJS 在 src/resources/static/app 添加 app.js
1 2 3 4 5 (function (angular ) { angular.module("myApp.controllers" , []); angular.module("myApp.services" , []); angular.module("myApp" , ["ngResource" , "myApp.controllers" , "myApp.services" ]); }(angular));
在此,我们定义了三个 module: controllers, services, application,注意,application 名字必须和
保持一致。
并且我们让 appliation 依赖于 ngResource, controllers, services.
创建 resource factory 在 src/resources/static/app 添加 services.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (function (angular ) { var ItemFactory = function ($resource ) { return $resource('/todos/:id' , { id: '@id' }, { update: { method: "PUT" }, remove: { method: "DELETE" } }); }; ItemFactory.$inject = ['$resource' ]; angular.module("myApp.services" ).factory("Item" , ItemFactory); }(angular));
在此通过 $resource (AngularJS resource framework) 自动引入查询,创建功能,并且声明加入 update, remove 功能。
创建 AngularJS Controller 在 todoapp.html 中我们看到 ng-submit=”addItem(newItem)” 等指令,下面我们在 src/resources/static/app 添加 controllers.js 进行定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 (function (angular ) { var AppController = function ($scope, Item ) { Item.query(function (response ) { $scope.items = response ? response : []; }); $scope.addItem = function (content ) { new Item({ content: content, checked: false }).$save(function (item ) { $scope.items.push(item); }); $scope.newItem = "" ; }; $scope.updateItem = function (item ) { item.$update(); }; $scope.deleteItem = function (item ) { item.$remove(function ( ) { $scope.items.splice($scope.items.indexOf(item), 1 ); }); }; }; AppController.$inject = ['$scope' , 'Item' ]; angular.module("myApp.controllers" ).controller("AppController" , AppController); }(angular));
欣赏成果 浏览器打开 http://localhost:8080/todoapp.html,欣赏成果吧:
源代码 源代码链接: github