Ionic-wechat项目边开发边学(三):自定义样式,指令,服务 - Frogmarch - 博客园

mikel阅读(1209)

来源: Ionic-wechat项目边开发边学(三):自定义样式,指令,服务 – Frogmarch – 博客园

摘要

上一篇文章主要介绍了一个ionic项目的标准目录结构,header标签的使用,以及页面之间的切换。这篇文章实现的功能有: 消息数据的获取, 消息列表的展示, 消息标为已读/未读, 主要涉及的到的知识点有:

  1. ion-list的使用
  2. ion-popup的使用
  3. 通过sass自定义样式
  4. localStorage的使用
  5. 自定义指令和服务

先看效果图:

功能分析

在开始之前, 最好先思考一下消息页面的主要功能, 和大概如何实现. 这样后面写程序才不会乱. 我大体列了一下

消息的数据暂时用localStorage存储, 但这不是好的方式, localStorage可能会被文件清理掉, 后面会换SQLite存储

页面布局

首先在’tab-message.html’中添加聊天消息的布局

<ion-view>
    <ion-content on-swipe-left="onSwipeLeft()">
        <!--这里的rj-close-back-drop是自定义指令, 后面会讲是干嘛的-->
        <ion-list rj-close-back-drop>
          <ion-item class="item-avatar" on-hold="popupMessageOpthins($index)" rj-hold-active ng-repeat="message in messages">
              <img ng-src="{{message.pic}}">
              <!--这个就是来了新消息, 头像上的小红数字-->
              <span class="rj-sm-red-icon" ng-show="message.showHints"><p ng-bind="message.noReadMessages"></p></span>
              <h2 ng-bind="message.name"></h2>
              <p class="rj-list-p" ng-bind="message.lastMessage.content"></p>
              <span class="rj-push-right" ng-bind="message.lastMessage.time"></span>
          </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

大家在试这个的时候, 由于’messages’还未定义, 先不绑定, 用实际的值代替,像这样

<img src="img/ben.png">
<span class="rj-sm-red-icon"><p>1</p></span>
<h2>小王</h2>
<p class="rj-list-p">你在干什么?</p>
<span class="rj-push-right">12:30</span>

这样就能看到效果了

自定义样式

可以看到上图有点丑, 需要我们自己修改样式, 可以自己添加css文件link进来, 但官方推荐使用sass的方式修改, 关于sass的语法, 可以看这个, 看完就差不多可以了.

首先在项目目录下,运行命令

$ionic setup sass
$ionic serve

运行以后, 就会对scss/ionic.app.scss文件监控, 有修改, 会自动编译该文件, 输出到css/ionic.app.css

所以你每次修改保存scss文件后, 浏览器会看到实时的效果, 非常方便.

打开scss/ionic.app.scss文件, 如下

/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.

For example, you might change some of the default colors:

$light:                           #fff !default;
$stable:                          #f8f8f8 !default;
$positive:                        #387ef5 !default;
$calm:                            #11c1f3 !default;
$balanced:                        #33cd5f !default;
$energized:                       #ffc900 !default;
$assertive:                       #ef473a !default;
$royal:                           #886aea !default;
$dark:                            #444 !default;
*/

// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;

可以看到官方预定义的颜色几个颜色, 如果要修改预定义的颜色, 直接修改这里就可以了.

我们自己的样式, 直接在后面添加. 我们在后面添加

$item-avatar-border-radius: 0;

可以发现头像变成方的了, 那怎么知道修改这个变量呢?

打开www/lib/ionic/scss/目录, 可以看到很多scss文件

├── _action-sheet.scss
├── _animations.scss
├── _backdrop.scss
├── _badge.scss
├── _bar.scss
├── _button-bar.scss
├── _button.scss
├── _checkbox.scss
├── _form.scss
├── _grid.scss
├── ionicons
├── ionic.scss
├── _items.scss
├── _list.scss
├── _loading.scss
├── _menu.scss
├── _mixins.scss
├── _modal.scss
...

这些都是官方的样式文件, 找到items.scss文件, 这个就是ion-item相关的样式, 再搜border-radius很快就能找到啦

具体的细节我就不说啦, 其它的修改都类似, 可以参考我的代码

popup的使用

关于$ionicPopup的详细使用, 可以参考官网

首先在controllers.js文件中添加一个controller:

.controller('messageCtrl', function($scope, $state, $ionicPopup, localStorageService, messageService) {
    $scope.popup = {
        isPopup: false,
        index: 0
    };
    $scope.onSwipeLeft = function() {
        $state.go("tab.friends");
    };
    $scope.popupMessageOpthins = function($index) {
        $scope.popup.index = $index;
        //这里通过$ionicPopup.show()方法创建了一个自定义的popup
        $scope.popup.optionsPopup = $ionicPopup.show({
            templateUrl: "templates/popup.html",
            scope: $scope,
        });
        $scope.popup.isPopup = true;
    };
    //实现标为已读/未读, 注意$scope.popup.optionsPopup.close()方法
    //用来关闭弹窗, 我竟然找了很久才发现这个接口
    $scope.markMessage = function() {
        var index = $scope.popup.index;
        var message = $scope.messages[index];
        if (message.showHints) {
            message.showHints = false;
            message.noReadMessages = 0;
        }else{
            message.showHints = true;
            message.noReadMessages = 1;
        }
        $scope.popup.optionsPopup.close();
        $scope.popup.isPopup = false;
        messageService.updateMessage(message);
    };

这里要注意两点

  1. 要在routes.js中将该controll传进去
  2. 需要通过自定义样式, 去掉自带的标题和按钮
    //routes.js
    .state('tab.message', {
    url: '/message',
    views: {
        'tab-message': {
            templateUrl: 'templates/tab-message.html',
            controller: "messageCtrl"
        }
    }
    })

自定义指令

细心的人会发现两个问题:

  1. 弹出popup时, 联系人列表没有动画效果
  2. 弹出popup后, 点击popup以外的地方, popup不能消失, 这两个问题, 就通过自定义指令来解决

首先在directives.js文件中添加rjCloseBackDrop指令, 用来解决上面第二个问题

.directive('rjCloseBackDrop', [function() {
        return {
            scope: false,//共享父scope
            restrict: 'A',
            replace: false,
            link: function(scope, iElm, iAttrs, controller) {
                //要在html上添加点击事件, 试了很久- -!
                var htmlEl = angular.element(document.querySelector('html'));
                htmlEl.on("click", function(event) {
                    if (event.target.nodeName === "HTML" &&
                        scope.popup.optionsPopup &&
                        scope.popup.isPopup) {
                        scope.popup.optionsPopup.close();
                        scope.popup.isPopup = false;
                    }
                });
            }
        };
    }])

再创建rjHoldActive指令, 用来解决第一个问题

.directive('rjHoldActive', ['$ionicGesture', '$timeout',
        function($ionicGesture, $timeout, $ionicBackdrop) {
            return {
                scope: false,
                restrict: 'A',
                replace: false,
                link: function(scope, iElm, iAttrs, controller) {
                    $ionicGesture.on("hold", function() {
                        iElm.addClass('active');
                        //300ms后恢复
                        $timeout(function() {
                            iElm.removeClass('active');
                        }, 300);
                    }, iElm);
                }
            };
        }
    ])

最后分别在ion-listion-item上添加指令

<ion-list rj-close-back-drop>
    <ion-item class="item-avatar"rj-hold-active ng-repeat="message in messages">

ok, 问题解决, 有点小激动~

自定义服务

前面讲的都是界面的东西, 那聊天记录的数据哪里来?
这里我们自定义一个假json数据, 用来模拟, 在www目录下创建文件data/json/messages.json

"messages": [{
        "id": 0,
        "name": "李明",
        "pic": "img/adam.jpg",
        "lastMessage": {
            "time": "2015-10-12 15:34:55",
            "content": "你在干什么?",
            "isFromeMe": false
        },
        "noReadMessages": 2,
        "showHints": true
    },...

目前用到的数据都定义在这, 后面还需要什么数据再添加
我们把数据存到localstorage中, 大家都知道localstorage是基于keyvalue存储的
总不能把所以人的消息都存在一条key中, 所以我定义两个服务

  1. 把整个json数据拆成单独的message, 把独立的message合并成一个对象
  2. 封装setItem, 基本数据的存储获取

具体我就不贴代码了, 讲下服务定义好了, 怎么使用, 比如定义了一个test服务:

.factory('test', ['', function(){
    return{
        dosomething: function(){
            return 0;
        }
    };
}])

用的时候直接把test注入, test.dosomething()调用:

.controller('someCtrl', function($scope, test) {
    test.dosomething();
    ...
}

是不是很简单?

最后

这篇写的很长, 其实实现的功能很简单, 主要是要学会如何定义样式, 自定义指令, 自定义服务
这样在后面实现更复杂的功能时, 不至于纠结这些细节.

我发现一个人自学, 确实有些困难, 一些小问题百度根本搜不到, google上才比较靠谱

所以小伙伴们遇到困难, 不妨google一下, 基本都有答案的哦
有问题欢迎大家评论, 我会的会及时回复~

Git代码

我推荐的 Java Web 学习路线 - l4y - 博客园

mikel阅读(1422)

来源: 我推荐的 Java Web 学习路线 – l4y – 博客园

晚上在 V2 的 Java 的节点看到有人问 Java Web 书籍推荐。我这半年多的时间,也从别的方向开始转向 Java 服务端开发,所以,我来说下我的学习路线,帮助有需要的朋友把半只脚踏进 Spring 大门。

本文所描述的路线,适合有其他面向对象语言编程经验,具备数据结构、算法、网络、数据库、设计模式、Linux 使用经验的人,如果你没有基础,这篇文章可能不适合你。

工欲善其事必先利其器

电脑系统推荐使用 *nix ,不论是 Linux 还是 macOS 都有强大的工具能让你学习的过程得心应手,Windows 系统也不是不可以,但 Windows 系统的终端个人很不喜欢。

IDE 推荐 IntelliJ IDEA,使用 Eclipse 也是可以的,不过现在越来越多的人开始使用 IntelliJ IDEA。

学习的过程中你会遇到各种各样的问题,无脑推荐 Google,鉴于目前国内的网络环境,你需要有利器能够访问 Google(比如 AT&T 漫游,误)。

Java SE

Java 基础有 Java编程思想Java核心技术Head First Java 等,我选择的是 Java编程思想(第4版),第 22 章是讲 GUI 的,可以不看。

现在你有 Java 基础了,但是现在 Java 发展到 1.9 的版本了,怎么办?

Java编程思想(第4版) 基本覆盖了 1.5 版本的内容,1.6、1.7 版本的更新,可以通过网上查资料来学习。1.8 版本有比较大的更新,建议买本书系统学习,我使用的是 Java 8 实战

好了,现在你会写 Java 代码了,但是 .java 文件如何成了 .class 文件,.class 文件长成什么样,又如何被加载到虚拟机中执行等等若干问题,难道你不好奇。这里推荐深入理解Java虚拟机(第2版)

随着时间流逝,你写了不少代码。但条条大路通罗马、再加上语言本身的语言负担,你或许会写出不那么优雅的代码,你需要前辈的经验来写清晰、健壮、高效的代码。Effective Java 就是这么一本书。当然,还有重构代码整洁之道这样的书,但这里只讨论 Java 。

Web

强烈不推荐上来直接上框架,你需要先了解 JSP、Servlet。这里我使用的是 Head First Servlets & JSPServlet与JSP核心编程这本书网上评价也不错。

好了,现在来说企业中的框架该怎么学。最最最重要的是,学的过程中一定要动手。

万事开头难。我最开始接触的时候,也是不知道如何开始框架的学习,在网络找了很多方法,浪费了不少时间,记住只有适合自己的才是最好的。在开始介绍前,再重复一遍,一动手尝试,二大胆猜测并验证。

1. Spring

在我刚开始的时候,很多人推荐直接读官方文档,经过验证,这种方法不适合初学者,或者说不适合我。

这里我使用的是Spring实战,学 Spring 一定要理解依赖注入(你说控制反转也行)和 AOP,跟着这本书敲,书中关于配置的东西一定要看仔细、理解好,不然配错了,自己找起来可能很麻烦。

2. Spring 与 MyBatis、Redis 等其他框架的整合。

MyBatis 推荐官方文档,然后找个 demo 做一下,自己再练习练习就可以了。

与 Spring 整合的时候参考文档,可以很简单的完成。

Redis 等其他框架的整合参考 Spring 实战,或者找资料都是可以的。

其他

要不要看视频这个事,我的观点是能不看就不看,但不要因噎废食。慕课网上有 SSM 框架的视频,对于这个路径,我的经验是直接跳过前两个,即战斗伊始–Spring转战阵地–SpringMVC,这两部分看 Spring实战就可以了,后边两个可以看看。

注意,针对这个慕课网这个视频我这里解释的是上文的你都做了,且自己写的服务能够正常运行。

刚接触框架配置很容易出错,出错的时候一定要耐心看输出的信息,有的很简单可能是手误,有的可能可能需要你对框架有些理解,所以 Just Google It

手动倒入 jar 包费时费力,上 maven 啊。

好了,你的服务跑起来了,你的半只脚已经进入了 Spring 的大门,请继续加油。


我在 Github 上有一个基于 SSM(Spring、Spring MVC、MyBatis)的小项目,部分学习内容会在该项目中使用。

该项目 Spring 相关配置,完全使用基于注解的方式。博主在刚接触各种配置的时候,绕了一些弯路。

对于刚接触这些框架的朋友,该项目或许会有些许帮助。如果在理解该项目时或参考时遇到任何问题,欢迎通过你能找到的任何方式联系我,非常乐意共同学习。

项目地址为:spittr 。

文中提高了慕课网,如果你喜欢 xml 配置的方式,可参考另外一个项目 seckill 。该项目是博主在慕课网上学习该课程的源代码,项目中没有完全采用基于注解的方式,相比而言,该项目在配置方面更加老道。

我写完了,如果你有什么不明白的可以发邮件给我。如果文中有不合适的地方,也请指正。我的邮箱地址是:shixj.cs@foxmail.com

如果针对文章内容有什么建议,可以在评论中回复。

远程调试(Remote Debugging) - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1744)

当运行的程序出现问题时,我们通常通过调试来追踪和定位问题。但是,当运行错误的机器上没有调试工具,我们就需要实现远程调试。简单地说,就是要调试的程序和调试器不在一台机器上。移动端web调试,alert虽然是个土方法,但也是万能的,不过这样会中断程序的执行,效率也比较低下。后来大家开始尝试使用模拟器调试,如chrome自带的设备模拟器,可以帮助我们测试网页在不同设备、不同分辨率的情况下的显示情

来源: 远程调试(Remote Debugging) – mygrilzhuyulin的专栏 – CSDN博客

remote_debugging

当运行的程序出现问题时,我们通常通过调试来追踪和定位问题。但是,当运行错误的机器上没有调试工具,我们就需要实现远程调试。简单地说,就是要调试的程序和调试器不在一台机器上。

移动端web调试,alert虽然是个土方法,但也是万能的,不过这样会中断程序的执行,效率也比较低下。后来大家开始尝试使用模拟器调试,如chrome自带的设备模拟器,可以帮助我们测试网页在不同设备、不同分辨率的情况下的显示情况。其原理就是通过伪装User-Agent将浏览器模拟成相应设备,所以我们也不能太依赖模拟的结果,最终还是得使用真机调试。移动设备上没有调试工具?那你可以尝试一下远程调试,使用你的电脑来调试移动设备上的web页面。其实该类文章在网上也不少,有些介绍较为零散,有些由于软件升级等原因已不适用。本人经实践后,整理如下。

此处附送电梯:
1.iOS (web检查器)
2.Android (Android Chrome)
3.Weinre
4.Adobe Edge Inspect CC
5.MIHTool

  • iOS

Prepare: iOS6+, Mac, USB数据线
Setting:
1. 【iOS终端】设置→ Safari → 高级 → Web 检查器 → 开
ios-1
2.【OS X】Safari → 偏好设置 → 高级 → 启用“开发菜单”
ios-2
Running:
1. 使用iOS设备的Safari打开你想要调试的页面
2. 通过USB数据线连接iOS设备与Mac
3. 在Mac中启动Safari,从“开发”菜单下找到你的iOS设备
4. 子菜单项为移动设备上Safari的所有标签页,选择需要调试的页面。
ios-3
在这个调试器里,我们可以像使用桌面操作系统的 Safari 的调试器一样,做各种调试工作,譬如HTML 元素、CSS 及盒模型等的查看和即时编辑、JavaScript 调试器、网页元素时间轴、DOM 元素查看器等各种功能。
ios-4ios-5
Tips:
1. 如果在开发菜单中没显示你所连接的iOS设备,或是没有显示你打开的页面,在Mac上重启Safari。
2. Windows 版本的 Safari 暂无此功能。

  • Andriod

Prepare:
1. 一个Android手机或平板电脑与Chrome For Android32或更高版本,或者从GooglePlay上直接安装
2. 一条USB数据线
Windows用户还需要安装相应的USB驱动,下载地址:http://developer.android.com/tools/extras/oem-usb.html
3. 在您的开发机器安装了Chrome32或更高的版本
Running:
1. 在您的设备上启用USB调试
在Android 4.0及4.1,它是在设置>开发人员选项
在Android 4.2及更高版本中,开发人员选项默认是隐藏的,为了使其可用,进入设置>关于手机,点击版本号7次,返回到前一个页面,就可以找到开发人员选项。android-1
2. 设置Discover USB Devices
访问about:inspect,确保选中Discover USB Devices
android-2
3. 通过USB数据线连接你的设备和开发机器
当你的设备连接你的开发机器时,你可能会在你的设备上看到一个弹框请求允许使用这台计算机通过usb调试设备。如果你不想每次调试都看到这弹框,选中一律允许使用这台计算机进行调试并点击确定。
android-4
现在,你可以在该页面上看到所有你连接的设备和你打开的标签页。找到你需要调试的页面,点击inpect打开DevTools。你也可以重新加载这个页面,标签页置顶或者关闭它。更可以通过在输入框中键入网址新开一个页面。
android-5
4. 调试
android-7

例如,查看所选中页面中的元素,在移动设备上的Chrome中这个元素对应的页面结构会立即高亮显示。
同样,在DevTools的控制台中编写脚本或者执行命令,都会影响移动设备中检查的页面。也可以使用所有其他面板,例如Timeline和Profiles。

Tips:
1. DevTools现在对连接的设备支持 native USB Debugging。不再需要通过配置ADB或ADB plugin查看移动设备上的Chrome和WebView连接实例。
2. 如果已启用USB调试,但about:inspect页面并没有显示你的设备
检查设备上已有开发者选项可用并开启USB调试
确保你正在使用Chrome for Android 32或更高版本
检查Discover USB devices是否已被选中。如果有勾选,请拔出设备,并尝试撤消USB authorizations的开发人员选项,并重试。
如果是Windows用户,检查是否已安装驱动。建议使用第三方软件,如应用宝、豌豆荚等手机助手。
3. 如果打开DevTools只出现一个空白的页面,你可能需要
翻墙后再试试
把开发机器和移动设备上的Chrome都更新到最新版本
4.调试Android webviews,需要Android4.4或更高版本,更多详情请看https://developer.chrome.com/devtools/docs/remote-Debugging#Debugging-webviews

  • Weinre

Weinre的全称是 Web Inspector Remote,功能与Firebug、Web Inspector类似,可用于远程调试运行在移动设备上的Web页面。

Weinre的通信过程是这样的:
weinre01

Weinre 为了能够同步桌面的调试客户端和移动设备上的调试目标,需要你搭建一个调试服务器(Debug Server)。因此,在使用 Weinre 进行远程设备调试时,包含了上面的三种元素:
调试服务器:调试服务器起到代理的作用,为调试目标和调试客户端建立通信;
调试客户端:这是 Web Inspector 界面,即开发者在浏览器中进行调试的界面;
调试目标:需要调试的页面,也指用于运行被调试 Web 内容的的浏览器所在的移动设备。

平台支持:
调试服务器支持的平台
-任何支持node.js的平台
调试客户端支持的平台(运行调试界面的浏览器)
-Google Chrome
-Apple Safari
-其它基于 WebKit 的浏览器
调试目标支持的平台(需要调试的页面)
-Android 浏览器应用
-iOS Mobile Safari 应用
-PhoneGap/Cordova
-其它
调试目标不支持的平台
-iOS 3.1.3或更早
-webOS 1.45或更早

Install:
1. 安装Node运行环境
2.通过Node包管理工具安装weinre
npm –g install weinre
Running:
1. 启动weinre
Weinre 提供了6个可选的启动参数,其中下面两个参数一般会修改,其它的用默认值就可以了。
–httpPort 调试服务器运行的端口,默认的 8080,如果这个端口有在用,可以改为其它端口;
–boundHost 调试服务器绑定的 IP 地址,也可以是域名,默认是 localhost,还可以设置为 -all-,表示绑定到所有当前机器可以访问的接口。
如本人机器IP地址为192.168.2.1,则在控制台输入weinre –boundHost 192.168.2.1
2. 目标页面引入js
<script src=””http://a.b.c.d:8080/target/target-script-min.js#anonymous “></script><br “=””>    其中a.b.c.d为调试服务器IP地址
3. 在Chrome或Safari浏览器中打开http://a.b.c.d:8080/client/#anonymous
4. 使用你的移动设备访问目标页面
远程面版中将会显示连接到调试服务器的页面,连接到调试服务器的客户端,还有调试服务器的属性。
weinre02
除远程面板以外,还有元素面板,资源面板,网络面板,时间线面板和控制台,这些相信用过Chrome或Safari开发者工具的你应该都不会感到陌生了,我就不在此介绍了。weinre03 weinre04 weinre05 weinre06 weinre07
Tips:
1. 移动设备和电脑最好在同一网段,如果不在,需要保证能ping成功。
2. 网络面板不像chrme浏览器开发者工具那么强大,因为weinre是基于XMLHttpRequest进行监听的,所以只会显示通过XMLHttpRequest加载的网络数据,简单说就是通过ajax加载的页面或图片等。
3. 经本人亲测,Timeline面板一直没显示出任何数据,具体原因暂未知。
4. 暂不支持断点调试

  • Adobe Edge Inspect CC

Adobe公司推出的一个跨PC和各个移动平台的调试工具。
Prepare:
1. 将Edge Inspect下载到您的电脑
adobe01
在Creative Cloud中安装Edge Inspect CC,需要注册一个Adobe ID
2.安装扩展程序
adobe02
3. 在移动设备上安装App(支持iOS,Android,Kindle Fire)
adobe03
4. 安装Bonjour(Windows用户)
Bonjour安装程序在你的Edge Inspect安装目录下。
Win32: \Program Files\Adobe\Adobe Edge Inspect\BonjourPSSetup.exe
Win64: \Program Files (x86)\Adobe\Adobe Edge Inspect\BonjourPSSetup.exe
Running:
1. 在电脑打开Edge Inspect程序,所有移动设备打开Edge Inspect App
2. 通过Bonjour连接设备与电脑,或者手动输入IP地址连接
adobe04adobe05
3. 在Edge Inspect 扩展中输入每个移动设备的passcode
adobe06
4. 在电脑Chrome浏览器内打开需要调试的网页,此时移动设备Edge Inspect App内将会同步显示电脑浏览器里的内容。
adobe07
5. 点击“<>”开始调试
adobe08
adobe09
adobe10

Tips:
1. 确保你的电脑和你的设备在同一无线网络内
2. 基于Apache开源的weinre,不支持断点调试。

  • MIHTool

MIHTool 是前端工程师在iOS设备上调试和优化页面的得力助手。
Prepare: iOS设备,MIHTool(在App Store里下载安装),开发机器上已安装Chrome或Safari浏览器
Running:
1. 打开MIHTool,在地址栏输入你要调试的网页地址即可。
iPad版支持内嵌Web Inspector、模拟iPhone、编辑源码、查看当前页面的HAR、显示页面合成渲染层、显示元素的重绘渲染数等功能。
mihtool01 mihtool02
iPhone版同样支持远程打开Web inspector调试等多项功能。
mihtool03

Tips:
1. 基于Apache开源的weinre,不支持断点调试。

ionic开发篇之那些年我们踩过的坑 - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1084)

版权声明:本文为博主原创文章,未经博主允许不得转载。目录(?)[+]一、API开发篇1.接口无法访问百度地图、自定义API无法访问,远程调试结果显示404 原因是cordova 5.x的版本增加了“Content-Security-Policy”用于解决安全访问的问题。默认情况下,只能访问本机资源。解决方法:  1.添加白名单插件

来源: ionic开发篇之那些年我们踩过的坑 – mygrilzhuyulin的专栏 – CSDN博客

一、API开发篇

1.接口无法访问

百度地图、自定义API无法访问,远程调试结果显示404
原因是cordova 5.x的版本增加了“Content-Security-Policy”用于解决安全访问的问题。默认情况下,只能访问本机资源。

解决方法:
1.添加白名单插件,在项目目录下执行

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">ionic plugin add cordova<span class="hljs-attribute" style="box-sizing: border-box;">-plugin</span><span class="hljs-attribute" style="box-sizing: border-box;">-whitelist</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

2.在index.html头部增加

<code class="hljs scilab has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><meta http-equiv=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Content-Security-Policy"</span> content=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"script-src * '</span>unsafe-<span class="hljs-transposed_variable" style="box-sizing: border-box;">eval'</span>; connect-src * <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'unsafe-eval'</span>; object-src <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'self'</span>; style-src * <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'unsafe-inline'</span>; img-src *<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" ></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

2.无法跨域访问

服务端设置

PHP代码

<code class="hljs scss has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;">header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Access-Control-Allow-Origin: *'</span>)</span>; <span class="hljs-function" style="box-sizing: border-box;">header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Access-Control-Allow-Credentials:true'</span>)</span>;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

3.POST请求提交自动变成Options请求

当我们使用浏览器调试的时候,发现POST请求会自动变成Options请求,然后调用任意接口都提示不能跨域访问,即使服务端已经设置允许跨域访问。

解决方法:

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">.config(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">( <span class="hljs-variable" style="box-sizing: border-box;">$stateProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$urlRouterProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$ionicConfigProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$httpProvider</span>)</span> {</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Use x-www-form-urlencoded Content-Type</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$httpProvider</span>.defaults.headers.post[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Content-Type'</span>] = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'application/x-www-form-urlencoded;charset=utf-8'</span>; }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

这个问题只出现在浏览器调试中,实际在手机里运行不需要这个配置。

二、调试篇

1.本地调试

电脑上本地调试,用ionic serve即可在浏览器中调试

2.远程调试

1.在手机上运行Debug版软件,在电脑上调试程序
2.在启动手机上的APP后,在谷歌浏览器(其实360也行)上输入chrome://inspect/#devices,可以进入调试界面(如果出不来,请翻墙)
调试界面
3.单击inspect,可以进入当前显示的页面调试,调试方法和和在浏览器上一致。

远程调试可以快速定位,在浏览器上没有发现的问题,方便调试手机API接口

三.应用开发篇

1.导航置底设置

好不容易按教程一步步建立了tabs样例工程,却发现安卓机上这个tab导航在顶部,浏览器和iOS这个导航在顶部。

解决方法:在app.js里添加以下代码

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">.config(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(<span class="hljs-variable" style="box-sizing: border-box;">$stateProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$urlRouterProvider</span>, <span class="hljs-variable" style="box-sizing: border-box;">$ionicConfigProvider</span>)</span> {</span> <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.tabs.style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'standard'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.tabs.position(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'bottom'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.tabs.style(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'standard'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.tabs.position(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'bottom'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.navBar.alignTitle(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'center'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.navBar.alignTitle(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'center'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.backButton.previousTitleText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>).icon(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ion-ios-arrow-thin-left'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.backButton.previousTitleText(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>).icon(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ion-android-arrow-back'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.ios.views.transition(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ios'</span>); <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$ionicConfigProvider</span>.platform.android.views.transition(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'android'</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

2.百度地图开发

坑1:使用了插件angular-BMap

这个插件功能并不完善,好多功能都没有,如果要使用需要继续开发(如果你有时间,有兴趣,有能力可以fork后继续开发)

坑2:使用了百度地图实例代码,地图不显示

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> BMap<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Map</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"container"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建地图实例 </span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> point <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> BMap<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>Point(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">116.404</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">39.915</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 创建点坐标 </span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">map</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>centerAndZoom(point, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 初始化地图,设置中心点坐标和地图级别 </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

其实只是在模拟手机的浏览器下不显示,在浏览器上不要选择任何手机型号,就能显示,而实际我在自己的手机上build后,也是能正常显示的。具体原因没有深究,如果有知道的朋友欢迎来信。

坑3:GPS位置偏移

使用$cordovaGeolocation.getCurrentPosition()获得的坐标,在百度地图上位置偏移。原因是GPS坐标和百度地图坐标并不是完全对应的,需要使用百度地图提供的GPS坐标转换接口进行转换

<code class="hljs php has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">posToAddrByBaidu</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(lat, long)</span>{</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> Ak = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'yourAK'</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//你应用的AK</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> getUrl = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'http://api.map.baidu.com/geocoder/v2/?'</span>+ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ak='</span> + Ak +<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'&location='</span> +lat+ <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">','</span> + long + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'&output=json&pois=0'</span>; <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$http</span>.get(getUrl) .success(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(data)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (data[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'status'</span>] == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'0'</span>) { <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">$scope</span>.appeal.location = data.result.formatted_address; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'定位失败'</span>; } }).error(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> alert(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"网络问题"</span>); }); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>

坑4 infowindow里面的a链接只能跳转一次

BMap中创建的infowindow,如果里面带有a链接,第一次跳转后,第二次进去就无法跳转了。这个问题目前不知道怎么解决,如果有人知道请告诉我,谢谢。

(不断收集中……)

ionic常用的命令行 - mygrilzhuyulin的专栏 - CSDN博客

mikel阅读(1113)

1、安装cordovasudo npm -g install cordova2、安装ionicsudo npm -g install ionic3、卸载cordovasudo npm -g uinstall cordova4、卸载ionicsudo npm -g uinstall ionic5、安装plat

来源: ionic常用的命令行 – mygrilzhuyulin的专栏 – CSDN博客

1、安装cordova

sudo npm -g install cordova

2、安装ionic

sudo npm -g install ionic

3、卸载cordova

sudo npm -g uinstall cordova

4、卸载ionic

sudo npm -g uinstall ionic

5、安装plateform

ionic add platform ios/android

6、卸载plateform

ionic platform rm ios/android

7、bower[可参考http://www.biaodianfu.com/bower.html]

Bower 是 twitter 推出的一款包管理工具,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系。

一旦你已经安装了上面所说的所有必要文件,键入以下命令安装Bower:

这行命令是Bower的全局安装,-g 操作表示全局。

8、下载angularjs [cd到指定目录]

npm install angular

Ionic CLI 升级到最新版本 - tomKart - 博客园

mikel阅读(1035)

来源: Ionic CLI 升级到最新版本 – tomKart – 博客园

由于Ionic 自身也在不停的更新当中,

所以开发者经常会遇到从官方的CLI 命令,在命令行窗口中执行出错的情况。

就比如我一个月之前安装的ionic 2.2.2版本,已不能使用最新的3.2.0 CLI命令。

(其实困扰也没有那么大,cmd会有提示信息,告诉你command为什么无法执行,选择相应的策略去解决就行了。)

不过这里还是简要介绍一下如何升级Ionic CLI,算是留个小笔记。

npm update -g cordova ionic

执行完成后可以看到cordova和ionic更新后的版本号:

当然最原始的方式 npm uninstall ,然后npm clean,再npm install 也是可以的。

mac终端切换用户

mikel阅读(1245)

mac终端切换用户(做个小笔记)

1、mac终端切换用户到root

sudo -i即可

2、mac终端切换成普通用户

su – test(test为用户名)即可

3、mac可以设置命令别名

如ll,正常情况下,mac终端不识别ll命令,但是alias 命令设置别名后,终端即可以设别ll命令:alias ll=’ls -la’;但是没有修改系统文件,则该命令只能临时生效,下次再打开终端,还是不能识别ll命令,永久生效办法,请修改系统文件,方法有多种,请自行百度(如果不是ll命令,其他命令同理)

深度学习入门篇--手把手教你用 TensorFlow 训练模型 - 腾讯云技术社区 - 博客园

mikel阅读(1509)

来源: 深度学习入门篇–手把手教你用 TensorFlow 训练模型 – 腾讯云技术社区 – 博客园

导语

Tensorflow在更新1.0版本之后多了很多新功能,其中放出了很多用tf框架写的深度网络结构(https://github.com/tensorflow/models ),大大降低了开发难度,利用现成的网络结构,无论fine-tuning还是重新训练方便了不少。最近笔者终于跑通TensorFlow Object Detection API的ssd_mobilenet_v1模型,这里记录下如何完整跑通数据准备到模型使用的整个过程,相信对自己和一些同学能有所帮助。

Object Detection API提供了5种网络结构的预训练的权重,全部是用COCO数据集进行训练,这五种模型分别是SSD+mobilenet、SSD+inception_v2、R-FCN+resnet101、faster RCNN+resnet101、faster RCNN+inception+resnet101。各个模型的精度和计算所需时间如下。下面及介绍下如何使用Object Detection去训练自己的模型。

这里TensorFlow的安装就不再说明了,网上的教程一大把,大家可以找到很详尽的安装TensorFlow的文档。

训练前准备:

使用protobuf来配置模型和训练参数,所以API正常使用必须先编译protobuf库,这里可以下载直接编译好的pb库(https://github.com/google/protobuf/releases ),解压压缩包后,把protoc加入到环境变量中:

$ cd tensorflow/models

$ protoc object_detection/protos/*.proto --python_out=.

 

(我是把protoc加到环境变量中,遇到找不到*.proto文件的报错,后来把protoc.exe放到models/object_detection目录下,重新执行才可以)

然后将models和slim(tf高级框架)加入python环境变量:

PYTHONPATH=$PYTHONPATH:/your/path/to/tensorflow/models:/your/path/to/tensorflow/models/slim

 

数据准备:

数据集需要转化成PASCAL VOC结构,API提供了create_pascal_tf_record.py,把VOC结构数据集转换成.record格式。不过我们发现更简单的方式,Datitran提供一种更简单生产.record格式的方法。

首先需要先要标注图像相应标签,这里可以使用labelImg工具。每标注一张样本,即生成一个xml的标注文件。然后,把这些标注的xml文件,按训练集与验证集分别放置到两个目录下,在Datitran提供了xml_to_csv.py脚本。这里只要指定标注的目录名即可。接下来,然后需要我们把对应的csv格式转换成.record格式。

def main():
    # image_path = os.path.join(os.getcwd(), 'annotations')
    image_path = r'D:\training-sets\object-detection\sunglasses\label\test'
    xml_df = xml_to_csv(image_path)
    xml_df.to_csv('sunglasses_test_labels.csv', index=None)
    print('Successfully converted xml to csv.')

 

调用generate_tfrecord.py,注意要指定–csv_input与–output_path这两个参数。执行下面命令:

python generate_tfrecord.py --csv_input=sunglasses_test_labels.csv --output_path=sunglass_test.record

 

这样就生成了训练及验证用的train.record与test.record。接下来指定标签名称,仿照models/ object_detection/data/ pet_label_map.pbtxt,重新创建一个文件,指定标签名。

item {
  id: 1
  name: 'sunglasses'
}

 

训练:

根据自己的需要,选择一款用coco数据集预训练的模型,把前缀model.ckpt放置在待训练的目录,这里meta文件保存了graph和metadata,ckpt保存了网络的weights,这几个文件表示预训练模型的初始状态。

打开ssd_mobilenet_v1_pets.config文件,并做如下修改:

  1. num_classes:修改为自己的classes num

  1. 将所有PATH_TO_BE_CONFIGURED的地方修改为自己之前设置的路径(共5处)

其他参数均保持默认参数。

准备好上述文件后就可以直接调用train文件进行训练。

python object_detection/train.py \
--logtostderr \
--pipeline_config_path= D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config \
--train_dir=D:/training-sets/data-translate/training

 

TensorBoard监控:

通过tensorboard工具,可以监控训练过程,输入西面指令后,在浏览器输入localhost:6006(默认)即可。

tensorboard --logdir= D:/training-sets/data-translate/training

 

这里面有很多指标曲线,甚至有模型网络架构,笔者对于这里面很多指标含义还没有弄明白,不过感觉出TensorBoard这个工具应该是极其强大。不过我们可以通过Total_Loss来看整体训练的情况。

从整体上看,loss曲线确实是收敛的,整体的训练效果还是满意的。另外,TensorFlow还提供了训练过程中利用验证集验证准确性的能力,但是笔者在调用时,仍有些问题,这里暂时就不详细说明了。

Freeze Model模型导出:

查看模型实际的效果前,我们需要把训练的过程文件导出,生产.pb的模型文件。本来,tensorflow/python/tools/freeze_graph.py提供了freeze model的api,但是需要提供输出的final node names(一般是softmax之类的最后一层的激活函数命名),而object detection api提供提供了预训练好的网络,final node name并不好找,所以object_detection目录下还提供了export_inference_graph.py。

复制代码
python export_inference_graph.py \
--input_type image_tensor
--pipeline_config_path D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config \
--trained_checkpoint_prefix D:/training-sets /data-translate/training/ssd_mobilenet_v1_pets.config /model.ckpt-* \
--output_directory D:/training-sets /data-translate/training/result
复制代码

 

导出完成后,在output_directory下,会生成frozen_inference_graph.pb、model.ckpt.data-00000-of-00001、model.ckpt.meta、model.ckpt.data文件。

调用生成模型:

目录下本身有一个调用的例子,稍微改造如下:

复制代码
import cv2
import numpy as np
import tensorflow as tf
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util


class TOD(object):
    def __init__(self):
        self.PATH_TO_CKPT = r'D:\lib\tf-model\models-master\object_detection\training\frozen_inference_graph.pb'
        self.PATH_TO_LABELS = r'D:\lib\tf-model\models-master\object_detection\training\sunglasses_label_map.pbtxt'
        self.NUM_CLASSES = 1
        self.detection_graph = self._load_model()
        self.category_index = self._load_label_map()

    def _load_model(self):
        detection_graph = tf.Graph()
        with detection_graph.as_default():
            od_graph_def = tf.GraphDef()
            with tf.gfile.GFile(self.PATH_TO_CKPT, 'rb') as fid:
                serialized_graph = fid.read()
                od_graph_def.ParseFromString(serialized_graph)
                tf.import_graph_def(od_graph_def, name='')
        return detection_graph

    def _load_label_map(self):
        label_map = label_map_util.load_labelmap(self.PATH_TO_LABELS)
        categories = label_map_util.convert_label_map_to_categories(label_map,
                                                                    max_num_classes=self.NUM_CLASSES,
                                                                    use_display_name=True)
        category_index = label_map_util.create_category_index(categories)
        return category_index

    def detect(self, image):
        with self.detection_graph.as_default():
            with tf.Session(graph=self.detection_graph) as sess:
                # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
                image_np_expanded = np.expand_dims(image, axis=0)
                image_tensor = self.detection_graph.get_tensor_by_name('image_tensor:0')
                boxes = self.detection_graph.get_tensor_by_name('detection_boxes:0')
                scores = self.detection_graph.get_tensor_by_name('detection_scores:0')
                classes = self.detection_graph.get_tensor_by_name('detection_classes:0')
                num_detections = self.detection_graph.get_tensor_by_name('num_detections:0')
                # Actual detection.
                (boxes, scores, classes, num_detections) = sess.run(
                    [boxes, scores, classes, num_detections],
                    feed_dict={image_tensor: image_np_expanded})
                # Visualization of the results of a detection.
                vis_util.visualize_boxes_and_labels_on_image_array(
                    image,
                    np.squeeze(boxes),
                    np.squeeze(classes).astype(np.int32),
                    np.squeeze(scores),
                    self.category_index,
                    use_normalized_coordinates=True,
                    line_thickness=8)

        cv2.namedWindow("detection", cv2.WINDOW_NORMAL)
        cv2.imshow("detection", image)
        cv2.waitKey(0)

if __name__ == '__main__':
    image = cv2.imread('image.jpg')
    detecotr = TOD()
    detecotr.detect(image)
复制代码

 

下面是一些图片的识别效果:

相关阅读

当强化学习遇见泛函分析

google cloud :穷人也能玩深度学习

[ I am Jarvis ] :聊聊 FaceID 背后的深度学习视觉算法

此文已由作者授权腾讯云技术社区发布,转载请注明文章出处
原文链接:https://cloud.tencent.com/community/article/351424

SSM框架整合项目 :租房管理系统 - 谁将新樽辞旧月,今月曾经照古人 - 博客园

mikel阅读(1767)

来源: SSM框架整合项目 :租房管理系统 – 谁将新樽辞旧月,今月曾经照古人 – 博客园

使用ssm框架整合,oracle数据库

框架:

Spring

SpringMVC

MyBatis

导包:

1, spring

2, MyBatis

3, mybatis-spring

4, fastjson

5, aspectweaver—-AspectJ框架

6, log4j—–打印日志信息

7, ojdbc6.jar

8, jstl.jar, standard.jar—-标准标签库

9, commons-logging-1.2.jar

10,……

项目结构:

配置文件同前面:http://www.cnblogs.com/jiangwz/p/7674275.html

项目代码:

model:

复制代码
 1 package com.hanqi.model;
 2 
 3 public class House {
 4     
 5     private Integer id;
 6     private String keyword;
 7     private String area;
 8     private Integer squaremeter;
 9     private Integer rent;
10     private String renttype;
11     private String housetype;
12 
13     public House(Integer id, String keyword, String area, Integer squaremeter, Integer rent, String renttype,
14             String housetype) {
15         super();
16         this.id = id;
17         this.keyword = keyword;
18         this.area = area;
19         this.squaremeter = squaremeter;
20         this.rent = rent;
21         this.renttype = renttype;
22         this.housetype = housetype;
23     }
24 
25     public House() {
26         super();
27         // TODO Auto-generated constructor stub
28     }
29 
30     public Integer getId() {
31         return id;
32     }
33 
34     public void setId(Integer id) {
35         this.id = id;
36     }
37 
38     public String getKeyword() {
39         return keyword;
40     }
41 
42     public void setKeyword(String keyword) {
43         this.keyword = keyword;
44     }
45 
46     public String getArea() {
47         return area;
48     }
49 
50     public void setArea(String area) {
51         this.area = area;
52     }
53 
54     public Integer getSquaremeter() {
55         return squaremeter;
56     }
57 
58     public void setSquaremeter(Integer squaremeter) {
59         this.squaremeter = squaremeter;
60     }
61 
62     public Integer getRent() {
63         return rent;
64     }
65 
66     public void setRent(Integer rent) {
67         this.rent = rent;
68     }
69 
70     public String getRenttype() {
71         return renttype;
72     }
73 
74     public void setRenttype(String renttype) {
75         this.renttype = renttype;
76     }
77 
78     public String getHousetype() {
79         return housetype;
80     }
81 
82     public void setHousetype(String housetype) {
83         this.housetype = housetype;
84     }
85 
86     @Override
87     public String toString() {
88         return "House [id=" + id + ", keyword=" + keyword + ", area=" + area + ", SQUAREMETER=" + squaremeter
89                 + ", rent=" + rent + ", renttype=" + renttype + ", housetype=" + housetype + "]";
90     }
91 
92 }
复制代码

dao层:

复制代码
 1 package com.hanqi.dao;
 2 
 3 import java.util.List;
 4 
 5 import com.hanqi.model.House;
 6 
 7 public interface HouseDao {
 8 
 9     List<House> selectAll();
10     
11     int inserthouse(House house);
12 
13     int delhouse(Integer id);
14 
15     int updatehouse(House house);
16 
17     List<House> selectinfo(House house);
18 
19 }
复制代码

dao层实现方法:

复制代码
 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper
 3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <mapper namespace="com.hanqi.dao.HouseDao">
 6 
 7     <select id="selectAll" resultType="House">
 8         select t.*from TABLE_HOUSE t
 9     </select>
10     
11     <insert id="inserthouse" parameterType="House" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
12         insert into TABLE_HOUSE values(test1.nextval,#{keyword},#{area},#{squaremeter},#{rent},#{renttype},#{housetype})
13     </insert>
14     
15     <delete id="delhouse" parameterType="Map">
16         delete TABLE_HOUSE t where t.id=#{id}
17     </delete>
18     
19     <update id="updatehouse" parameterType="Map">
20         update TABLE_HOUSE t set t.keyword=#{keyword},t.area=#{area},t.squaremeter=#{squaremeter},t.rent=#{rent},t.renttype=#{renttype},t.housetype=#{housetype} where t.id=#{id}
21     </update>
22     
23     <select id="selectinfo" resultType="House" parameterType="House">
24         select t.* from TABLE_HOUSE t
25         <where>
26             <if test="keyword!=null">
27                 and t.keyword like #{keyword}
28             </if>
29             <if test="area!=null">
30                 and t.area=#{area}
31             </if>
32             <if test="renttype!=null">
33                 and t.renttype in #{renttype}
34             </if>
35             <if test="housetype!=null">
36                 and t.housetype=#{housetype}
37             </if>
38         </where>
39         
40     </select>
41 </mapper>
复制代码

controller控制器:

复制代码
 1 package com.hanqi.controller;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.stereotype.Controller;
 8 import org.springframework.ui.Model;
 9 import org.springframework.web.bind.annotation.RequestMapping;
10 import org.springframework.web.bind.annotation.ResponseBody;
11 import org.springframework.web.bind.annotation.SessionAttributes;
12 import org.springframework.web.servlet.ModelAndView;
13 
14 import com.alibaba.fastjson.JSONObject;
15 import com.hanqi.dao.HouseDao;
16 import com.hanqi.model.House;
17 
18 @Controller
19 @SessionAttributes("currentUser")
20 @RequestMapping("/house")
21 public class HouseController {
22 
23     @Autowired
24     private HouseDao houseDao;
25     
26     @ResponseBody
27     @RequestMapping("/selectAll")
28     public JSONObject selectAll() {
29         JSONObject jo = new JSONObject();
30         List<House> list = houseDao.selectAll();
31         jo.put("total", list.size());
32         jo.put("rows", list);
33         
34         return jo;
35     }
36     
37     @ResponseBody
38     @RequestMapping("/selectinfo")
39     public ModelAndView  selectinfo(House house){
40         
41         house.setKeyword("%"+house.getKeyword()+"%");
42         List<House> list = houseDao.selectinfo(house);
43         ModelAndView modelAndView = new ModelAndView();
44         modelAndView.setViewName("houselook3");
45         modelAndView.addObject("list",list);
46 
47         return modelAndView;
48         
49     }
50     
51     @ResponseBody
52     @RequestMapping("/selectAll1")
53     public ModelAndView selectAll1(Model model) {
54         //List<House> list = houseDao.selectAll();
55         //System.out.println(list);
56         
57         //model.addAttribute("list", list);
58 
59         ModelAndView mv = new ModelAndView("redirect:/houselook.jsp");
60         return mv;
61         
62     }
63 
64     @RequestMapping("/selectAll2")
65     public String selectAll2(Model model) {
66         List<House> list = houseDao.selectAll();
67         System.out.println(list);
68         model.addAttribute("list", list);
69 
70         return "houselook2";
71     }
72     
73     @ResponseBody
74     @RequestMapping("/addhouse")
75     public ModelAndView addhouse(House house) {
76         int i=houseDao.inserthouse(house);
77         
78         ModelAndView mv = new ModelAndView("redirect:/index.jsp");
79         return mv;
80         
81     }
82     
83     @ResponseBody
84     @RequestMapping("/delhouse")
85     public ModelAndView delhouse(Integer id) {
86         int i=houseDao.delhouse(id);
87         ModelAndView mv = new ModelAndView("redirect:/index.jsp");
88         return mv;
89     }
90     
91     @ResponseBody
92     @RequestMapping("/updatehouse")
93     public ModelAndView updatehouse(House house) {
94         int i=houseDao.updatehouse(house);
95         ModelAndView mv = new ModelAndView("redirect:/index.jsp");
96         return mv;
97     }
98     
99 }
复制代码

前台:

复制代码
  1 <%@ page language="java" contentType="text/html; charset=UTF-8"
  2     pageEncoding="UTF-8"
  3     %>
  4 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  5 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  6 <html>
  7 <head>
  8 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  9 <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
 10 <script type="text/javascript"
 11     src="jquery-easyui-1.5.1/jquery.easyui.min.js"></script>
 12     <link rel="shortcut icon" href="img/logo1.jpg"/>
 13 <link type="text/css" rel="stylesheet"
 14     href="jquery-easyui-1.5.1/themes/icon.css"></link>
 15 <link type="text/css" rel="stylesheet"
 16     href="jquery-easyui-1.5.1/themes/default/easyui.css"></link>
 17 <script type="text/javascript"
 18     src="jquery-easyui-1.5.1/locale/easyui-lang-zh_CN.js"></script>
 19 <title>租房管理</title>
 20 <%
 21     String basePath = request.getContextPath();
 22 %>
 23 <!-- <script type="text/javascript" src="js/index.js"></script> -->
 24 <style type="text/css">
 25 .datagrid-btable tr {
 26     height: 30px;
 27 }
 28 </style>
 29 </head>
 30 
 31 <body class="easyui-layout">
 32     <!-- 添加商品 -->
 33     <div data-options="region:'north',split:true"
 34         style="height: 50px; background-color: cornflowerblue">
 35         
 36     </div>
 37     <!-- 对话框开始 -->
 38     <div data-options="region:'center',split:true"
 39         style="padding: 5px; background: #eee">
 40         <div id="tabs" class="easyui-tabs" style="width: 100%; height: 100%;">
 41             <div title="主页" style="">
 42                 <table id="table"></table>
 43                 <!-- 添加的表单 -->
 44                 <div id="zhong" style="display: none">
 45                     <form id="addhouse" method="post"
 46                         style="width: 600px; padding: 20px">
 47                         关键字:<input type="text" name="keyword"><br>
 48                         地区:<input type="text" name="area"><br>
 49                         面积:<input type="text" name="squaremeter"><br>
 50                         租金:<input type="text" name="rent"><br>
 51                         租赁方式:<input type="text" name="renttype"><br>
 52                         房屋类型:<input type="text" name="housetype"><br>
 53                         <input type="submit" name="" id="" value="提交" /><br>
 54                         <input type="reset" value="重置"><br>
 55                     </form>
 56                 </div>
 57                 <!-- 修改的表单 -->
 58                 <div id="gai" style="display: none">
 59                     <form id="gaihouse" action="house/updatehouse.do" method="post"
 60                         style="width: 600px; padding: 20px">
 61                         id:<input type="text" name="id"><br>
 62                         关键字:<input type="text" name="keyword"><br>
 63                         地区:<input type="text" name="area"><br>
 64                         面积:<input type="text" name="squaremeter"><br>
 65                         租金:<input type="text" name="rent"><br>
 66                         租赁方式:<input type="text" name="renttype"><br>
 67                         房屋类型:<input type="text" name="housetype"><br>
 68                         <input type="submit" name="" id="" value="提交" /><br>
 69                         <input type="reset" value="重置"><br>
 70                     </form>
 71                 </div>
 72             </div>
 73 
 74         </div>
 75     </div>
 76     <!-- 对话框结束 -->
 77     <!-- 目录开始 -->
 78     <div data-options="region:'west',split:true" width=210>
 79         <div id="aa" class="easyui-accordion"
 80             style="width: 200px; height: 543px">
 81             
 82             <div title="用户管理" style="overflow: auto; padding: 10px" >
 83                 <ul>
 84                     <li class="lis"><a id="addhouse" class="easyui-linkbutton ab"
 85                         plain="true" >添加房屋信息(先用右边按钮)</a></li>
 86                     <li class="lis"><a href="<%=basePath %>/houselook.jsp" class="easyui-linkbutton ab"
 87                         plain="true">查看租房信息2</a></li>
 88                     <li class="lis"><a href="<%=basePath %>/house/selectAll2.do" class="easyui-linkbutton ab"
 89                         plain="true">查看租房信息3</a></li>
 90                     <li class="lis"><a href="houselook3.jsp" class="easyui-linkbutton ab"
 91                         plain="true">前往租房页面</a></li>
 92                     <li class="lis"><a href="#" class="easyui-linkbutton ab"
 93                         plain="true">修改用户</a></li>
 94                 </ul>
 95             </div>
 96         </div>
 97     </div>
 98     <!-- 底部声明 -->
 99     <div data-options="region:'south',split:true"
100         style="height: 40px; line-height: 40px; vertical-align: center; text-align: center;">
101         玛雅网络版权声明</div>
102     <!-- 目录结束 -->
103 </body>
104 </html>
105 <script type="text/javascript">
106 
107     $(function() {
108         $('#addhouse').form({    
109             url:'house/addhouse.do',
110             onSubmit: function(){
111                 return $('#addhouse').form('validate');//如果有为空则返回false阻止提交
112             },
113             success:function(data){    
114                 if(data=="true"){
115                     alert("添加成功");
116                 }else if(data=="false"){
117                     alert("请检查信息正确!");
118                 }
119             }    
120         });
121         
122         $('#table').datagrid({    
123             url : 'house/selectAll.do',
124             striped:true,//显示斑马线
125             autoRowHeight:false,//定义设置行的高度,根据该行的内容。设置为false可以提高负载性能。这里不设置,css中设置的行高无效
126             singleSelect:true,//只允许选择一行
127             pagination : true,
128             pageNumber : 1,
129             pageSize : 1,
130             pageList : [ 1, 3, 5 ],
131             
132             toolbar : [{
133                 iconCls : 'icon-edit',
134                 text : "添加",
135                 handler : function() {    
136                     var a = $(this).text();
137                     
138                     $('#zhong').dialog({
139                         width : 800,
140                         height : 500,
141                         title : a,
142                         //closed : false,
143                         cache : false,
144                         modal : true
145                     });
146                     
147                     
148                 }
149             },  '-',{
150                 iconCls : 'icon-edit',
151                 text : "修改",
152                 handler : function() {
153                     var a = $(this).text();
154                     $('#gai').dialog({
155                         width : 800,
156                         height : 500,
157                         title : a,
158                         //closed : false,
159                         cache : false,
160                         modal : true
161                     });
162                     $('#gai').dialog("open");
163                     var r = $("#table").datagrid("getSelected");//获取被选中的行,返回对象
164                     $("#gaihouse").form("load", r);//将被选中的信息放到弹出的的表单中,富文本编辑器的内容无法显示
165                 }
166             }, '-',
167             {
168                 iconCls : 'icon-cancel',
169                 text : "删除",
170                 handler : function() {
171                     var id=-1;
172                     id = $('#table').datagrid("getSelected").id;
173                     if(id>-1){
174                         var r1 = confirm("确定删除编号为  "+id+" 的房屋信息吗?");
175                         if(r1) {
176                             window.location.href="house/delhouse.do?id="+id;
177                             alert("删除成功");
178                         }
179                     }else{
180                         alert("请选中需要删除的商品");
181                     }
182                     
183                 }
184             } ],
185 
186              frozenColumns : [ [ {
187                  field : '',
188                 title : '',
189                 width : 20,
190                 checkbox : true
191             } ] ], 
192             columns : [ [ {
193                 field : "id",
194                 title : "信息编号",
195                 width:65
196             },{
197                 field : "keyword",
198                 title : "关键字",
199                 width:180
200             },  
201             {
202                 field : "area",
203                 title : "地区",
204                 width:60
205             }, {
206                 field : "squaremeter",
207                 title : "面积",
208                 width:60
209             }, {
210                 field : "rent",
211                 title : "租金",
212                 width:40
213             } , {
214                 field : "renttype",
215                 title : "租赁方式",
216                 width:60
217             } ,{
218                 field : "housetype",
219                 title : "房屋类型",
220                 width : 60
221             } ] ],
222             
223         }); 
224     });
225 </script>
复制代码
复制代码
 1  <%@ page language="java" contentType="text/html; charset=UTF-8"
 2     pageEncoding="UTF-8" import="java.util.List,com.hanqi.model.House,com.hanqi.controller.HouseController"%>
 3 <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 5 <html>
 6 <head>
 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 8 <title>Insert title here</title>
 9 <script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
10 <script type="text/javascript"
11     src="jquery-easyui-1.5.1/jquery.easyui.min.js"></script>
12     <link rel="shortcut icon" href="img/logo1.jpg"/>
13 <link type="text/css" rel="stylesheet"
14     href="jquery-easyui-1.5.1/themes/icon.css"></link>
15 <link type="text/css" rel="stylesheet"
16     href="jquery-easyui-1.5.1/themes/default/easyui.css"></link>
17 <script type="text/javascript"
18     src="jquery-easyui-1.5.1/locale/easyui-lang-zh_CN.js"></script>
19 </head>
20 <body>
21 <form action="house/selectinfo.do" method="post">
22     区域:<input type="radio" name="area" id="s1" value="张店"/>
23     <label for="s1">张店</label>
24   <input type="radio" name="area" id="s2" value="淄川"/>
25     <label for="s2">淄川</label>
26   <input type="radio" name="area" id="s0" value="周村"/>
27     <label for="s0">周村</label><br>
28     租赁类型:<input type="checkbox" name="renttype" id="s3" value="整租"/>
29     <label for="s3">整租</label>
30   <input type="checkbox" name="renttype" id="s4" value="合租"/>
31     <label for="s4">合租</label>
32   <input type="checkbox" name="renttype" id="s5" value="其他"/>
33     <label for="s5">其他</label><br>
34     房屋类型:<input type="radio" name="housetype" id="s6" value="三室一厅"/>
35     <label for="s6">三室一厅</label>
36   <input type="radio" name="housetype" id="s7" value="自建房"/>
37     <label for="s7">自建房</label>
38   <input type="radio" name="housetype" id="s8" value="其他"/>
39     <label for="s8">其他</label><br>
40     关键字:<input type="text" name="keyword">
41     <input type="submit" value="查询">
42 </form>
43 
44 <%    
45     //HouseController hc=new HouseController();
46     List<House> list=(List<House>)request.getAttribute("list");
47     if(list!=null){
48         out.print("<table border='1'>");
49         for(House h:list){
50             out.print("<tr>");
51             out.print("<td>"+h.getKeyword()+"</td>");
52             out.print("<td>"+h.getArea()+"</td>");
53             out.print("<td>"+h.getSquaremeter()+"</td>");
54             out.print("<td>"+h.getRent()+"</td>");
55             out.print("<td>"+h.getRenttype()+"</td>");
56             out.print("<td>"+h.getHousetype()+"</td>");
57             out.print("</tr>");
58         }
59         out.print("</table>");
60     }
61 %>
62 </body>
63 </html>
复制代码

阿里巴巴 Java 开发规约插件初体验

mikel阅读(1593)

又一次来谈《阿里巴巴 Java 开发手册》,经过这大半年的版本迭代,这本阿里工程师们总结出来避免写出那么多 Bug 的规范,对于 Java 开发者简直就是必备开发利剑了。

针对这个手册,我之前也简单写过两篇简单的解读,手册的确是清晰的说明了日常开发中很容易踩的坑,我不要脸的把链接放一下:

这一次,阿里巴巴于 10 月 14 日在杭州云栖大会上,正式发布众所期待的《阿里巴巴 Java 开发规约》扫描插件!

简单了解一下这插件

该插件由阿里巴巴 P3C 项目组研发。P3C 是世界知名的反潜机,专门对付水下潜水艇,寓意是扫描出所有潜在的代码隐患。

代码已经开源,GitHub:https://github.com/alibaba/p3c
阿里介绍文章:https://mp.weixin.qq.com/s/IbibsXlWHlM59kfXJqRvZA#rd

据说插件支持了IDEA、Eclipse,在扫描代码后,将不符合规约的代码显示出来,甚至在 IDEA 上,我们还基于 Inspection 机制提供了实时检测功能,编写代码的同时也能快速发现问题所在,还实现了批量一键修复的功能。

那我就在 IDEA 下试一下吧。

IDEA 下如何使用?

1.打开 IDEA ,选择 File – Settings – Plugins – Browse repositories
打开 IDEA,选择 File – Settings – Plugins – Browse repositories 后,输入 alibaba 选中 Alibaba Java Coding Guidelines,点击 Install,截至目前已经快有了三千的安装量了。

alibaba guidelines

2.重启IDEA,开始使用
安装后,会提示你重启 IDEA 已启用插件,重启后就可以在你的项目上疯狂点击右键吧,当然菜单栏也会出现俩按钮,它有个快捷键是Ctrl+Shift+Alt+J,你也可以试试看。

checkStart

当然,选中某一个类,或者在这个类里边右键也可以

checkStartClass

3.扫描出坏代码
扫描代码后,将不符合规约的代码按 Blocker/Critical/Major 三个等级显示在下方,双击可以定位至代码处,右侧窗口还有针对代码的批量修复功能,简直不能更 666 了。

bad code

稍微解释下Blocker/Critical/Major三个等级,在 Snoar 中对代码规则有五个级别,这是前三个,翻译下就是:崩溃/严重/重要 ,也就是说前两级别是必须要处理掉的。

Eclipse 如何安装插件?

Eclipse 版插件支持4.2(Juno,JDK1.8+)及以上版本,我们提供自主的Update Site,通过 Help >> Install New Software 然后输入https://p3c.alibaba.com/plugin/eclipse/update
即可看到安装列表。大家可以通过 Help >> Check for Udates 进行插件新版检测

我没有在 Eclipse 上体验,你们有 Eclipse 的可以试试看。

总结一下

这个插件可以说对规范代码有重大意义,可以使我们少写一些 Bug,少抛一些异常,少踩一些坑,但真正要写出健壮代码最重要的还在于我们自己,这个插件还存在很多问题,一些容易产生 NPE 的级联调用、空对象什么的,好像它并不能检查出来,依赖工具永远是不可能解决所有问题的。

当然,它的中文版对我们是无比友好的。