总体思路

thinkphp通过RESTful方式提供数据给angular,前端(包括模板页面)全部由angular来接管。

示例

实现一个用户管理模块,走通增删改查4个操作,通过该示例,演示如何在thinkphp中使用AngularJS

一. 准备工作

1. 加载所需的js和css文件

angular.min.js angular    核心库文件

angular-ui-router.min.js angular    路由插件

angular-resource.min.js    负责与服务端restful交互的插件

layer    弹窗插件,该插件依赖于jQuery-1.10.1.min.js和jquery-ui.min.js两个库文件以及一个jquery-ui.min.css样式表

bootstrap.min.css bootstrap    核心样式表

文件结构如下:

2. 引导页

准备一个angular引导页,angular通过该引导页开启一个angular应用,后续所有的操作,都是基于该引导页进行的。

友情提醒:

这里的引导页,其实就是我们应用的默认页面,具体到thinkphp中,指的就是DEFAULT_MODULE/DEFAULT_CONTROLLER/DEFAULT_ACTION对应的模板文件。第一次访问应用时,thinkphp控制器会定向到该页面,之后的模板页面,全部由angular接管,跟thinkphp的模板引擎就没有半点关系了。

3. 应用首页

在引导页中通过<div ui-view="main"></div>包含我们的应用首页。便签的含义后面会有解释。

注意:这一步不是必须的,因为你也可以把应用首页的内容,全部放在引导页中,但是这样做就不够友好了。

4. 搭建RESTFul环境

为了能够使用$resource,我们必须让服务端按照RESTful的方式来工作,否则,$resource就无法发挥其作用了。

thinkphp中内置了对RESTful的支持,使用方式也很简单,就是让某个Controller继承自RestController,然后按照一定的规则来编写资源方法即可。但是它有一个缺点,thinkphp内置的RESTful对资源的访问方式不够友好,其访问资源的URL结构如下:

/模块名称/控制器名称/资源名称

基于此,我们考虑使用thinkphp的路由功能,来实现对RESTful的支持,使用thinkphp的路由功能时,控制器是没有必要继承RestController的,但为了尊重tp的劳动成果,同时,为了兼顾友好的资源访问方式,最终,我使用的是RestController+路由两者结合的方式。

补充:

资源方法的命名规则为:资源名称_REST类型

REST类型有如下几种:get,post,put,delete

5. 创建数据库

创建用户表,并初始化一些数据

  1. DROP TABLE IF EXISTS `an_user`;
  2. CREATE TABLE `an_user` (
  3. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  4. `user_id` int(10) unsigned NOT NULL COMMENT '用户id',
  5. `user_name` varchar(100) NOT NULL COMMENT '用户名称',
  6. `email` varchar(255) DEFAULT NULL COMMENT '邮箱地址',
  7. `tel` varchar(255) DEFAULT NULL COMMENT '手机号码',
  8. `weixin` varchar(255) DEFAULT NULL COMMENT '微信号',
  9. `qq` varchar(255) DEFAULT NULL COMMENT 'qq号码',
  10. PRIMARY KEY (`id`)
  11. ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户表';
  12. INSERT INTO `an_user` VALUES ('1', '1', 'demo1', 'demo1@qq.com', '13100000000', 'weixin_test1', '123456');
  13. INSERT INTO `an_user` VALUES ('2', '2', 'demo2', 'demo2@qq.com', '13100000001', 'weixin_test2', '123456');
  14. INSERT INTO `an_user` VALUES ('3', '3', 'demo3', 'demo3@qq.com', '13100000002', 'weixin_test3', '123456');
  15. INSERT INTO `an_user` VALUES ('4', '4', 'demo4', 'demo4@qq.com', '13100000003', 'weixin_test4', '123456');
  16. INSERT INTO `an_user` VALUES ('5', '5', 'demo5', 'demo5@qq.com', '13100000004', 'weixin_test5', '123456');
  17. INSERT INTO `an_user` VALUES ('6', '6', 'demo6', 'demo6@qq.com', '13100000005', 'weixin_test6', '123456');
  18. INSERT INTO `an_user` VALUES ('7', '7', 'demo7', 'demo7@qq.com', '13100000006', 'weixin_test7', '123456');
  19. INSERT INTO `an_user` VALUES ('8', '8', 'demo8', 'demo8@qq.com', '13100000007', 'weixin_test8', '123456');
  20. INSERT INTO `an_user` VALUES ('9', '9', 'demo9', 'demo9@qq.com', '13100000008', 'weixin_test9', '123456');

二. 开始吧

1. 创建引导页

前面说过,引导页其实就是我们应用的默认页面,在我的项目中,默认页面的文件路径为:

/tpl/Admin/Index/index.html

在该文件中,加入如下内容:

  1. <!DOCTYPE html>
  2. <html ng-app="antp">
  3. <head>
  4. <meta charset="utf-8" />
  5. <title></title>
  6. <meta content="width=device-width, initial-scale=1.0" name="viewport" />
  7. <meta content="" name="author" />
  8. <link href="/public/css/bootstrap.min.css" rel="stylesheet" type="text/css" media="all">
  9. <link href="/public/css/jquery-ui.min.css" rel="stylesheet" type="text/css" media="all">
  10. <script type="text/javascript" src="/public/js/angular.min.js"></script>
  11. <script type="text/javascript" src="/public/js/angular-resource.min.js"></script>
  12. <script type="text/javascript" src="/public/js/angular-ui-router.min.js"></script>
  13. <script type="text/javascript" src="/public/js/jquery-1.10.1.min.js"></script>
  14. <script type="text/javascript" src="/public/js/jquery-ui.min.js"></script>
  15. <script type="text/javascript" src="/public/js/layer/layer.js"></script>
  16. <script type="text/javascript" src="/config.js"></script>
  17. <script type="text/javascript" src="/app.js"></script>
  18. <link rel="shortcut icon" href="favicon.ico" />
  19. </head>
  20. <body>
  21. <div class="container-fluid">
  22. <div class="row clearfix">
  23. <div class="col-md-12" style="float: none;display: block;margin-left: auto;margin-right: auto;">
  24. <div ui-view="main"></div>
  25. </div>
  26. </div>
  27. </div>
  28. </body>
  29. </html>

页面中加载的js和css,除了config.js和app.js,其它的在前面都已经作了说明,这两个后面也会说到。

注意html标签中的ng-app指令,该指令的内容,就是angular要开启的应用名称。

2. 开启应用

之前的index.html文件中,通过ng-app指令定义了一个应用名称,定义完之后,我们还需要开启它,开启的方式也很简单,我们需要创建一个js文件,名称为app.js,在里面先加入如下内容:

  1. var app = angular.module("antp",["ui.router","ngResource"]);

其中,module的第二个参数,是angular的一些依赖包。

3. 配置路由

使用ui.router的路由功能,通过config预先配置好访问url、该url对应的视图模板以及控制器等信息,同样是在app.js文件中,继续加入如下内容:

  1. app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
  2. //启用HTML5模式的路由,该模式下会去除URL中的#号
  3. //$locationProvider.html5Mode(true);
  4. //默认页面,所有请求不到的资源,都会转向到这个URL
  5. $urlRouterProvider.otherwise("/index");
  6. $stateProvider.state("user", {
  7. url: "/user",
  8. views: {
  9. main: {
  10. templateUrl: "tpl/Admin/User/index.html",
  11. controller: "UserCtroller"
  12. }
  13. }
  14. }).state("index", {
  15. url: "/index",
  16. views: {
  17. main: {
  18. templateUrl: "tpl/Admin/Index/main.html",
  19. controller: "MainCtroller"
  20. }
  21. }
  22. }).state("user-add", {
  23. url: "/user/add",
  24. views: {
  25. main: {
  26. templateUrl: "tpl/Admin/User/add.html",
  27. controller: "UserFormCtroller"
  28. }
  29. }
  30. }).state("user-edit", {
  31. url: "/user/edit/:user_id",
  32. views: {
  33. main: {
  34. templateUrl: "tpl/Admin/User/add.html",
  35. controller: "UserFormCtroller"
  36. }
  37. }
  38. });
  39. });

还记得之前引导页中的ui-view="main"吗?ui-view的名字,就是state中配置的views下面的属性名称。也许你会说,config里面配置了那么多的main,它是如何知道找的是哪个main?仔细看下代码就知道了。

注意1:控制器controller我们并没有手动写在某个页面的标签上,而是统一配置在了config里。

注意2:每个视图模板必须要对应一个控制器,并且这个控制器必须要被创建,否则,该视图将无法展示。

注意3:不要把此处的控制器和thinkphp里面的控制器搞混,事实上,他们两者之间没有任何关系。

4. 引入每个模块下的js

这里为了便于代码管理与维护,我在每个模块下面创建了一个js文件,每个模块的js完成特定的功能,这些js同样需要在app.js中被引入。

  1. document.write('<script type="text/javascript" src="/tpl/Admin/Index/main.js"></script>');
  2. document.write('<script type="text/javascript" src="/tpl/Admin/User/user.js"></script>');

5. 浏览器访问

在浏览器地址栏中,输入http://local.antp,将会看到如下效果:

仔细观察下地址栏,我们输入的是http://local.antp,但是却自动变成了http://local.antp/#/index,知道为什么吗?

首页,引导页中的<div ui-view="main"></div>,表示我需要路由到main这个视图,但是,我们输入的地址http://local.antp中,并没有告诉angular到底是哪个main,发生这种情况的时候,angular就会定向到默认的视图,默认的视图由$urlRouterProvider.otherwise("/index");这一句来指定。

由于/index指向的是tpl/Admin/Index/main.html,所以此处就会把main.html对应的内容展示出来。

main.html文件内容:

  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>
  2. <blockquote>
  3. <p>
  4. 我是默认页面,所有请求不到的资源,都会到我这里来...
  5. </p>
  6. </blockquote>

其中,通过ng-include指令,引入了一个公共导航页面,ng-include指令中双引号内的单引号不可少,内容如下:

  1. <div style="margin-top:20px;">
  2. <nav class="navbar navbar-default" role="navigation">
  3. <div class="navbar-header">
  4. <a class="navbar-brand" href="#">Brand</a>
  5. </div>
  6. <div class="collapse navbar-collapse">
  7. <ul class="nav navbar-nav">
  8. <li class="active">
  9. <a ui-sref="user">用户管理</a>
  10. </li>
  11. </ul>
  12. </div>
  13. </nav>
  14. </div>

6. 用户列表

点击导航中的【用户管理】,即可跳转到用户列表页面,如下:

该列表对应的视图文件为tpl/Admin/User/index.html,内容如下:

  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>
  2. <button type="button" class="btn btn-primary" ng-click="addAction()">新增</button>
  3. <table class="table table-bordered table-striped" style="margin-top:15px;">
  4. <thead>
  5. <tr>
  6. <th>用户名</th>
  7. <th>邮箱</th>
  8. <th>手机号</th>
  9. <th>微信</th>
  10. <th>QQ</th>
  11. <th>操作</th>
  12. </tr>
  13. </thead>
  14. <tbody>
  15. <tr ng-repeat="user in data.user">
  16. <td>
  17. <a ui-sref="user-edit({user_id:user.user_id})" ng-bind="user.user_name"></a>
  18. </td>
  19. <td ng-bind="user.email"></td>
  20. <td ng-bind="user.tel"></td>
  21. <td ng-bind="user.weixin"></td>
  22. <td ng-bind="user.qq"></td>
  23. <td>
  24. <button type="button" class="btn btn-link">
  25. <a ui-sref="user-edit({user_id:user.user_id})">修改</a>
  26. </button>
  27. <button type="button" class="btn btn-link" ng-click="deleteAction(user.user_id)">删除</button>
  28. </td>
  29. </tr>
  30. </tbody>
  31. </table>

为了能够从后端拿到数据,我们需要创建一个$resource资源,创建方式如下:

  1. //通过factory创建一个service,该service通过$resource返回了一个资源对象
  2. //$resource负责与支持restful的服务端进行数据交互
  3. app.factory("UserService", function($resource) {
  4. return $resource(globalConfig.API.URL + "users/:id", {
  5. id: "@id"
  6. },
  7. {
  8. //query方法要求服务端返回的数据格式为数组,如果返回的是非数组格式,需要在transformResponse函数中作转换处理
  9. query: {
  10. method: "GET",
  11. isArray: true,
  12. transformResponse: function(data) {
  13. return JSON.parse(data);
  14. }
  15. },
  16. update: {
  17. method: "PUT"
  18. }
  19. });
  20. });

这里,创建了一个名字为UserService的资源,然后,我们还需要创建一个控制器,将UserService资源注入进去,代码如下:

  1. //用户列表Ctroller
  2. app.controller('UserCtroller', function($scope, $state, UserService) {
  3. $scope.data = {};
  4. //获取用户列表
  5. UserService.query().$promise.then(
  6. function(data){
  7. //将查询结果赋值给data.user,模板中可以对data.user变量进行遍历
  8. $scope.data.user = data;
  9. },
  10. function(error) {
  11. console.log("An error occurred", error);
  12. }
  13. );
  14. $scope.addAction = function() {
  15. $state.go("user-add");
  16. };
  17. $scope.deleteAction = function(user_id){
  18. layer.confirm("确定要删除该用户吗", {
  19. btn: ['确定','取消']
  20. }, function(index){
  21. layer.close(index);
  22. UserService.remove({id:user_id}).$promise.then(
  23. function(res){
  24. if(res.status){
  25. $state.go("user",null,{
  26. reload:true
  27. });
  28. }else{
  29. }
  30. },
  31. function(error) {
  32. console.log("An error occurred", error);
  33. }
  34. );
  35. });
  36. }
  37. });

通过UserService的query方法,获取用户列表信息。

7. 新增用户

点击列表上的【新增】,将会通过$state.Go("user-add");跳转到新增页面:

该页面对应的视图文件为tpl/Admin/User/add.html,内容如下:

  1. <div ng-include="'tpl/Admin/Public/header.html'"></div>
  2. <form class="form-horizontal" role="form" name="userForm">
  3. <div class="form-group">
  4. <label class="col-sm-3 control-label">用户名</label>
  5. <div class="col-sm-4">
  6. <input type="text" class="form-control" ng-model="user.user_name"/>
  7. </div>
  8. </div>
  9. <div class="form-group">
  10. <label class="col-sm-3 control-label">邮箱</label>
  11. <div class="col-sm-4">
  12. <input type="email" class="form-control" ng-model="user.email"/>
  13. </div>
  14. </div>
  15. <div class="form-group">
  16. <label class="col-sm-3 control-label">手机号</label>
  17. <div class="col-sm-4">
  18. <input type="tel" class="form-control" ng-model="user.tel"/>
  19. </div>
  20. </div>
  21. <div class="form-group">
  22. <label class="col-sm-3 control-label">微信号</label>
  23. <div class="col-sm-4">
  24. <input type="text" class="form-control" ng-model="user.weixin"/>
  25. </div>
  26. </div>
  27. <div class="form-group">
  28. <label class="col-sm-3 control-label">QQ</label>
  29. <div class="col-sm-4">
  30. <input type="text" class="form-control" ng-model="user.qq"/>
  31. </div>
  32. </div>
  33. <div class="col-sm-offset-3 col-sm-4">
  34. <button type="submit" class="btn btn-primary" ng-click="submitAction(userForm)">
  35. 保存
  36. </button>
  37. <button type="button" class="btn btn-default" ng-click="cancelAction()">
  38. 返回
  39. </button>
  40. </div>
  41. </form>

该页面中用到了angular的ng-model指令,ng-model指令用于数据的双向绑定,注意下表单中类似于user.user_name的东西,首先,controller中会通过点号前面的user获取表单数据,表单数据就是点号后面若干个类似于user_name的对应的内容的组合。

js代码:

  1. //新增和修改用户Ctroller
  2. app.controller('UserFormCtroller', function($scope, $state, $stateParams, UserService) {
  3. if($stateParams.user_id){
  4. var user_id = $stateParams.user_id;
  5. var param = {id:user_id};
  6. //获取指定用户
  7. UserService.get(param).$promise.then(
  8. function(res) {
  9. $scope.user = res;
  10. },
  11. function(error) {
  12. console.log("An error occurred", error);
  13. }
  14. );
  15. }
  16. $scope.submitAction = function(userForm) {
  17. if(!userForm.$valid){
  18. return false;
  19. }
  20. if($stateParams.user_id){
  21. //更新用户信息
  22. UserService.update(param,$scope.user).$promise.then(
  23. function(res) {
  24. if(res.status){
  25. $state.go("user");
  26. }else{
  27. }
  28. },
  29. function(error) {
  30. console.log("An error occured", error);
  31. }
  32. );
  33. }else{
  34. //新增
  35. UserService.save($scope.user).$promise.then(
  36. function(res) {
  37. if(res.status){
  38. $state.go("user");
  39. }else{
  40. }
  41. },
  42. function(error) {
  43. console.log("An error occured", error);
  44. }
  45. );
  46. }
  47. };
  48. $scope.cancelAction = function() {
  49. $state.go("user");
  50. };
  51. });

通过UserService的save方法来新增一个用户,而update方法则负责用户信息的修改。

注意:在修改用户的信息之前,我们需要通过UserService的get方法把用户已有的信息填充到页面上。

8. 修改用户

点击列表上的【修改】链接,进入到用户修改页面:

通过列表中的ui-sref="user-edit({user_id:user.user_id})"这一句,即可实现页面的跳转,同时,带上了user_id这个参数,可以在控制器中注入$stateParams来获取此处的参数,代码在前面已经贴过了。

9. 删除用户

点击列表上的【删除】,将会弹出一个删除确认的提示,如图:

点击【确定】后,即可通过UserService的remove方法来删除该用户。

注意:删除一个资源,也可以使用delete方法,但由于delete在有些浏览器中被当成了关键字,所以使用上需要写成UserService["delete"]这种格式。

10. thinkphp路由配置

  1. 'URL_ROUTER_ON' => true
  1. 'URL_ROUTE_RULES' => array(
  2. array('api/users/:id','Admin/User/user_get','',array('method'=>'get')),
  3. //注意:列表记录对应的路由必须要放在单条记录路由的后面,否则无法获取单条记录
  4. array('api/users','Admin/User/user_get','',array('method'=>'get')),
  5. array('api/users','Admin/User/user_post','',array('method'=>'post')),
  6. array('api/users/:id','Admin/User/user_put','',array('method'=>'put')),
  7. array('api/users/:id','Admin/User/user_delete','',array('method'=>'delete')),
  8. )

11. 后端代码

  1. //查询用户列表或单条记录
  2. public function user_get(){
  3. $id = I('id');
  4. if ($id) {
  5. $where = array('user_id' => $id);
  6. $users = DBUtil::queryRow($this->userModel,$where);
  7. }else{
  8. $users = DBUtil::queryList($this->userModel);
  9. }
  10. $this->response($users,'json');
  11. }
  12. //新增用户
  13. public function user_post(){
  14. $user_id = DBUtil::getMaxKey($this->userModel, 'user_id');
  15. //angular默认post过来的数据类型为Content-Type:application/json; charset=utf-8
  16. $userData = json_decode(file_get_contents('php://input'),true);
  17. $userData['user_id'] = $user_id;
  18. $result = DBUtil::add($this->userModel, $userData);
  19. $this->response(array('status'=>$result),'json');
  20. }
  21. //修改用户
  22. public function user_put(){
  23. $user_id = $_REQUEST['id'];
  24. //angular默认post过来的数据类型为Content-Type:application/json; charset=utf-8
  25. $userData = json_decode(file_get_contents('php://input'),true);
  26. $result = DBUtil::save($this->userModel, array('user_id' => $user_id), $userData);
  27. if ($result !== false) {
  28. $result = true;
  29. }
  30. $this->response(array('status'=>$result),'json');
  31. }
  32. //删除用户
  33. public function user_delete(){
  34. $user_id = $_REQUEST['id'];
  35. $result = DBUtil::delete($this->userModel, array('user_id' => $user_id));
  36. $this->response(array('status'=>$result),'json');
  37. }

三. 去除URL中的#号

默认情况下,angular通过URL中的#号来识别资源路径类别,凡是带#号的资源,统一由angular调配,而不带#号的资源,由服务端调配,如果需要去除#号,可以参考以下步骤:

1. 启用HTML5模式

首页需要在config中注入$locationProvider,然后通过$locationProvider.html5Mode(true);来启用html5模式的路由。

2. 加入base标签

在引导页中加入<base href="/">

3. 后端thinkphp配置

在控制器中增加一个_empty方法,在该方法中,跳转到首页。

AngularJS+ThinkPHP实例教程的更多相关文章

  1. thinkphp 3.2.3 计划任务具体实现实例教程

    thinkphp 3.2.3 计划任务具体实现实例教程 很多情况下,我们网站都会用到计划任务即定时更新做一些处理,类似Discuz后台的计划任务,比如更新每日发帖数目等等! 这里TP也是可以实现的,首 ...

  2. PHP之session相关实例教程与经典代码

    ·php 中cookie和session的用法比较 ·phpmyadmin报错:Cannot start session without errors问题 ·php中cookie与session应用学 ...

  3. 图解CSS3制作圆环形进度条的实例教程

    圆环形进度条制作的基本思想还是画出基本的弧线图形,然后CSS3中我们可以控制其旋转来串联基本图形,制造出部分消失的效果,下面就来带大家学习图解CSS3制作圆环形进度条的实例教程 首先,当有人说你能不能 ...

  4. Python导出Excel为Lua/Json/Xml实例教程(三):终极需求

    相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验 Python导出E ...

  5. Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验

    Python导出Excel为Lua/Json/Xml实例教程(二):xlrd初体验 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出E ...

  6. Python导出Excel为Lua/Json/Xml实例教程(一):初识Python

    Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...

  7. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

  8. Solr 4.0 部署实例教程

    Solr 4.0 部署实例教程 Solr 4.0的入门基础教程,先说一点部署之后肯定会有人用solrj,solr 4.0好像添加了不少东西,其中CommonsHttpSolrServer这个类改名为H ...

  9. React 入门实例教程(转载)

    本人转载自: React 入门实例教程

随机推荐

  1. POJ 2886 线段树单点更新

    转载自:http://blog.csdn.net/sdj222555/article/details/6878651 反素数拓展参照:http://blog.csdn.net/ACdreamers/a ...

  2. (C#基础)创建文件,文件夹

    文件夹,文件这是常见的,怎么创建?要不要先判断是否存在?非常非常基础的知识点. 代码 using System; using System.Collections.Generic; using Sys ...

  3. 51nod1269Devu and Flowers

    题解: 如果没有限制每一种花有多少,那么就是简单的排列组合问题. 那么我们强制让一些花一定都要选. 暴力搜索,然后组合数(逆元) 采用容斥原理来计算最后的答案 代码: #include<bits ...

  4. sgu187&&spoj7734

    题解: splay翻转(只有翻转 sgu ac,spoj tle 代码: #pragma GCC optimize(2) #include<cstdio> #include<cstr ...

  5. js 兼容各类手机 的写法 待续

    //通过高度来判断是否是iPhone 4还是iPhone 5 isPhone4inches = (window.screen.height==480); isPhone5inches = (windo ...

  6. CentOS 下安装和使用 Docker

    引言: 在服务器开发过程中,环境部署无疑是及其繁琐的事情,特别是当项目数量和规模达到一定级别之后,在一台新的机器上部署项目环境无疑是极其漫长而痛苦的,那么什么办法能够实现我们的目标:在开发环境的一次配 ...

  7. Okhttp之CallServerInterceptor简单分析

    在Okhttp源码分析专栏的几篇博客分析了Okhttp几个拦截器的主要功能,还剩下最后一个拦截器CallServerInterceptor没有分析,本篇博客就简单分析下该拦截器的功能. 在Okhttp ...

  8. A+B for Input-Output Practice (VII)

    A+B for Input-Output Practice (VII) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...

  9. paho.mqtt.embedded-c MQTTPacket transport.c hacking

    /******************************************************************************* * paho.mqtt.embedde ...

  10. 第三周作业3——Bug Report

    作业要求来自:https://edu.cnblogs.com/campus/nenu/SWE2017FALL/homework/957 要求1: 准备工作:利用老师提供的git 命令,批量pull所有 ...