你的位置:首页 > Java教程

[Java教程]前端使用AngularJS的$resource,后端ASP.NET Web API,实现增删改查


 

AngularJS中的$resource服务相比$http服务更适合与RESTful服务进行交互。本篇后端使用ASP.NET Web API, 前端使用$resource,实现增删改查。

 

 

领域和上下文

 

首先领域先行。

 

  public class StudentVm  {    [Key]    public int Id { get; set; }    public string Name { get; set; }    public string Age { get; set; }  }

 

上下文。

 

    public class StudentContext : DbContext    {      public StudentContext() : base("conn")      {        Database.SetInitializer(new StudentInitializer());      }      public DbSet<StudentVm> Students { get; set; }    }

 

上下文的构造函数中,StudentIntializer类对数据进行了初始化。

 

 

  public class StudentInitializer : CreateDatabaseIfNotExists<StudentContext>  {    protected override void Seed(StudentContext context)    {      IList<StudentVm> students = new List<StudentVm>();      students.Add(new StudentVm() { Name = "aa", Age = "20" });      students.Add(new StudentVm() { Name = "bb", Age = "18" });      students.Add(new StudentVm() { Name = "cc", Age = "22" });      students.Add(new StudentVm() { Name = "dd", Age = "23" });      students.Add(new StudentVm() { Name = "ee", Age = "20" });      students.Add(new StudentVm() { Name = "ff", Age = "21" });      students.Add(new StudentVm() { Name = "gg", Age = "28" });      foreach(StudentVm student in students)      {        context.Students.Add(student);      }      base.Seed(context);    }  }

 

 

 

对于EF Code First来说,Web.config中需要配置连接字符串。

 

 

 <connectionStrings>  <add name="conn"    connectionString="Data Source=.;User=yourname;Password=yourpassword;Initial Catalog=StudentsDemo;Integrated Security=True"    providerName="System.Data.SqlClient"/> </connectionStrings>

 

 

Repository


在这里使用上下文类,实现增删改查。

 

  public class StudentsReop  {    private StudentContext _db = new StudentContext();    public IEnumerable<StudentVm> Query()    {      return _db.Students;    }    public StudentVm Get(int id)    {      return _db.Students.SingleOrDefault(s => s.Id == id);    }    //更新    public void Put(int id, StudentVm student)    {      var stu = _db.Students.SingleOrDefault(s => s.Id == id);      _db.Students.Attach(stu);      _db.Entry(stu).State = System.Data.Entity.EntityState.Modified;      _db.Entry(stu).CurrentValues.SetValues(student);      _db.SaveChanges();    }    //添加    public void Post(StudentVm student)    {      _db.Students.Add(student);      _db.SaveChanges();    }    public void Delete(int id)    {      var student = _db.Students.SingleOrDefault(s => s.Id.Equals(id));      _db.Students.Remove(student);      bool saveFailed;      do      {        saveFailed = false;        try        {          _db.SaveChanges();        }        catch (DbUpdateConcurrencyException ex)        {          saveFailed = true;          //重新加载数据库中的实体,使之处于unchanged的状态          ex.Entries.Single().Reload();        }      } while (saveFailed);    }  }

 

API控制器

 

  public class StudentsController : ApiController  {    private StudentsReop _reop = new StudentsReop();    //GET api/Students    public HttpResponseMessage Get()    {      var students = _reop.Query().ToList();      return Request.CreateResponse(HttpStatusCode.OK, students);    }    //GET api/Students/5    public HttpResponseMessage Get(int id)    {      var student = _reop.Get(id);      return Request.CreateResponse(HttpStatusCode.OK, student);    }    //POST api/Students    public void Post([FromBody]StudentVm student)    {      _reop.Post(student);    }    //PUT api/Students/5    public void Put(int id, [FromBody]StudentVm student)    {      _reop.Put(id, student);    }    //DELETE api/Students    public void Delete(int id)    {      _reop.Delete(id);    }  }

 

允许跨域访问

 

默认情况下,ASP.NET Web API是不支持跨域访问的。为了支持,需要安装Microsoft.AspNet.WebApi.Cors。安装之后,需要在全局配置生效。在WepApiConfig.cs中配置如下:

 

 

  public static class WebApiConfig  {    public static void Register(HttpConfiguration config)    {      // Web API 配置和服务      // Web API 路由      config.MapHttpAttributeRoutes();      config.EnableCors(new EnableCorsAttribute("*", "*", "*"));      config.Routes.MapHttpRoute(        name: "DefaultApi",        routeTemplate: "api/{controller}/{id}",        defaults: new { id = RouteParameter.Optional }      );    }  }

 

在本地,浏览器中:http://localhost:49621/api/Students

 

前端准备

 

后端完成,前端在WebStorm下安装先安装需要的几个插件:


npm install angular
npm install angular-route
npm install angular-resource
npm install angular-cookies
npm install alertify


再来了解下前端的文件结构:

app.js 主module,路由都在这里配置
index.html 主视图,引用所有的css,js文件,提供让其它部分视图呈现的一块区域<div ng-view></div>
.....service/ 自定义服务,$resouce的核心就封装在这里
..........studentService.js
.....controller/
..........studentsCtrl.js 列表
..........studentUpdateCtrl.js 更新
..........studentCreateCtrl.js 添加
.....views/
..........Students.html 列表
..........StudentInfo.html 更新
..........StudentCreate.html 添加


index.html

 

<!DOCTYPE html><html lang="en" ng-app="studentManagement"><head> <meta charset="UTF-8"> <title>{{title}}</title> <link rel="stylesheet" href="node_modules/alertify/themes/alertify.core.css"/></head><body> <div>  <p>   <a href="#/">Students</a>   &nbsp;&nbsp;   <a href="#/Create">Create Student</a>  </p> </div> <div ng-view></div> <script src="node_modules/angular/angular.min.js"></script> <script src="node_modules/angular-route/angular-route.min.js"></script> <script src="node_modules/angular-resource/angular-resource.min.js"></script> <script src="node_modules/angular-cookies/angular-cookies.min.js"></script> <script src="node_modules/alertify/lib/alertify.min.js"></script> <script src="app.js"></script> <script src="service/studentService.js"></script> <script src="controller/studentUpdateCtrl.js"></script> <script src="controller/studentsCtrl.js"></script> <script src="controller/studentCreateCtrl.js"></script></body></html>

 

以上,主视图中,需要注意引用js文件的顺序,一般angualr相关方在最上面,然后app对应js文件,最后是各种服务和控制器相关js文件。

 

app.js

 

在这里,当然首先要定义一个module,定义module的时候要把所有用到的module依赖写在module方法的第二个实参里。还有一个主项工作就是定义设置路由,而且,如果想让以后视同从controller中拿数据更快,我们还可以利用路由的resolve机制,把数据从某处读取出来,先放到路由中,然后在controller中把resolve机制下的数据读出来。

 

 

"use strict";var studentsManagement = angular.module("studentManagement",["ngResource","ngCookies","ngRoute"])  .run(function($rootScope){    $rootScope.title = "Home";  })  .config(["$routeProvider","$locationProvider", function($routeProvider, $locationProvider){    //关于url的基本配置    //$locationProvider.html5Mode({    //  enabled: true,    //  requireBase: false    //});    //配置路由    $routeProvider.when("/", {      templateUrl: "views/Students.html",      controller: "studentsCtrl",      resolve: {        students: function($q,studentDataService){          //$q异步执行方法          var deferred = $q.defer();          studentDataService.query(function(data){            deferred.resolve(data);          });          return deferred.promise;        }      }    }).when("/Student/:id",{      templateUrl: "views/StudentInfo.html",      controller: "studentUpdateCtrl",      resolve: {        student: function($q, studentDataService, $route){          var defered = $q.defer();          //从路由中获取id的值          var id = $route.current.params.id;          studentDataService.get({id: id}, function(data){            defered.resolve(data);          });          return defered.promise;        }      }    }).when("/Create",{      templateUrl: "views/CreateStudent.html",      controller: "studentCreateCtrl"    });  }]);

 

 

● 使用$routeProvider配置路由的过程就是让一对对view和controller结婚的过程

● 显示列表的时候通过路由的resolve机制把数据先放在了路由中

● 显示某个Sudent的时候也通过路由的resolve机制把数据先放在了路由中

●/Student/:id这个路由格式中的id代表变量,可借助$route服务从路由中取出来var id = $route.current.params.id;

 

studentService.js

 

在这里,封装了对API的所有请求。

而$resource服务是位于angular-resource中,大致按如下调用:

$resource(url,{paramDefaults},{actions},{options});

其中,第一个参数是必须的,其它都optional。

 

 

angular.module('studentManagement').factory("studentDataService",["$resource", function($resource){  var baseUrl = "http://localhost:49621/api/Students";  return $resource("http://localhost:49621/api/Students",{},{    query: {method: "GET", isArray: true },    create: {method: "POST"},    get: {method: "GET", url: baseUrl + "?id=:id"},    remove: {method: "DELETE", url: baseUrl + "?id=:id"},    update: {method: "PUT", url: baseUrl + "?id=:id"}  })}]);

 

 

以上,在"?id=:id"中,冒号后面的id是一个变量,在controller中通过对象传递到这里来,比如 studentDataService.remove({id: id}).$promise.then(...)

 

 

列表,studentsCtr.j和views/Students.html这对恋人

 

studentsCtr.js:

 

 

angular.module('studentManagement').controller("studentsCtrl",['$scope','$route','$rootScope','studentDataService', function($scope,$route, $rootScope, studentDataService){  $rootScope.title = "Students";  $scope.students = $route.current.locals.students;//students在路由resolve中定义  $scope.removeStudent = function(id, student){    studentDataService.remove({id: id}).$promise.then(function(){      //获取student在当前集合中的索引      var index = $scope.students.indexOf(student);      $scope.students.splice(index, 1);      alertify.log(student.Name + ' is removed');    });  };}]);

 

 

以上,students的数据并没有向那个源头发出请求获取,而是直接使用$route服务,把路由resolve机制中的变量值取了出来。删除数据实际是做2件事,一件是删除服务端的数据,一件是删除model中的数据。

 

Students.html:

 

 

<table> <thead>  <tr>   <th>Name</th><th>Age</th><th>Actions</th>  </tr> </thead> <tbody>  <tr ng-repeat="student in students">   <td>{{student.Name}}</td>   <td>{{student.Age}}</td>   <td>    <a href="#/Student/{{student.Id}}">更新</a>    &nbsp;&nbsp;    <a href="javascript:void(0)" ng-click="$parent.removeStudent(student.Id, student)">移除</a>   </td>  </tr> </tbody></table>

 

 

添加,studentCreateCtrl.js和views/CreateStudent.html这对恋人

 

studentCreateCtrl.js:

 

angular.module('studentManagement').controller("studentCreateCtrl", ["$scope", "studentDataService", '$rootScope', "$location", function ($scope, studentDataService, $rootScope, $location) {  $rootScope.title = "Create student";  $scope.saveStudent = function (student) {    studentDataService.create(student).$promise.then(function (res) {      $location.path('/');    });  };}]);

 

CreateStudent.html:

 

 

<form> <input id="userName" ng-model="student.Name" /> <br/> <input id="userAge" ng-model="student.Age" /> <br/> <button ng-click="saveStudent(student)">Save</button> <button type="reset">Cancel</button></form>

 

 

更新,studentUpdateCtrl.js和views/StudentInfo.html这对恋人

 

studentUpdateCtrl.js:

 

angular.module('studentManagement').controller("studentUpdateCtrl",["$scope","$route","$rootScope","studentDataService","$location", function($scope,$route, $rootScope, studentDataService, $location){  //student是在resolve中定义的  $scope.student = $route.current.locals.student;  $rootScope.title = "Student Info -" + $scope.student.Name;  $scope.updateInfo = function(student){   studentDataService.update({id: student.Id}, student).$promise.then(function(){     $location.url("/");     alertify.log("Updated Student Scucess");   });  };}]);

 

StudentInfo.html:

 

 

<form> <input type="text" id="userName" ng-model="student.Name"/> <br/> <input type="text" id="userAge" ng-model="student.Age"/> <br/> <button ng-click="updateInfo(student)">Update</button> <button type="reset">Reset</button></form>

 

 

结束☺