留着点吧,万一还有用呢~
command+shift+f 格式化
command+option+left 上一个文件
command+/注释
command+shift+r 查找资源
command+1 重命名
command+q 关闭eclipse
search 菜单查找
右键-refactor-rename
右键-refactor-move
alt + h 文件搜索
command+option+t 重命名
command+shift+m 引入包 import
你若盛开,蝴蝶自来
留着点吧,万一还有用呢~
command+shift+f 格式化
command+option+left 上一个文件
command+/注释
command+shift+r 查找资源
command+1 重命名
command+q 关闭eclipse
search 菜单查找
右键-refactor-rename
右键-refactor-move
alt + h 文件搜索
command+option+t 重命名
command+shift+m 引入包 import
最近的视频项目遇到了内存泄漏,找问题真是蛋疼的事。
主要就是context没有释放,handler的不合理使用,bitmap没有回收,connection没有close等
首先纪录一下sdk官方写handler的方式
1 | public abstract class WeakHandler<T> extends Handler { |
activity中
1 | public abstract class BaseActivity extends AppCompatActivity { |
最后积累一个内存泄露监测工具,square公司的LeakCanary,square确实开源了些好用的东西。
LeakCanary作为一个简单粗暴的工具,用法也相当简单
在build.gradle中引入LeakCanary
1 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' |
一个是debug包,一个是release包的,从引入包的结构也能看出端倪
由于LeakCanary是测试整个app的内存泄露情况,所以你需要在你的application中启动它
1 | package com.zimo.guo; |
这么有逼格的工具,赶紧来试试吧,要想使你的app的内存泄露灰飞烟灭,try it
1 | $ adb devices |
1 | adb start-server |
1 | adb shell pm list packages |
1 | adb install APK的路径 |
1 | adb shell pm clear 包名 |
1 | adb shell dumpsys activity activities | grep mFocusedActivity |
1 | adb shell am start -n com.tencent.mm/.ui.LauncherUI |
1 | adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n com.lee.test/.CompleteReceiver |
1 | adb shell am force-stop -n 包名 |
1 | adb pull 手机文件路径 电脑上目录 |
1 | adb shell input keyevent 具体数值 |
1 | adb logcat [<option>] ... [<filter-spec>] ... |
1 | adb shell |
1 | adb shell cat /system/build.prop |
1 | adb shell screencap -p /sdcard/hello.png |
1 | adb shell screenrecord /sdcard/lee.mp4 |
1 | adb reboot |
1 | adb shell monkey -p 包名 -v 500 |
1 | adb shell ps |
1 | adb shell screenrecord /sdcard/demo.mp4 |
限制录制时间:
参数: –time-limit
1 | adb shell screenrecord --time-limit 10 /sdcard/demo.mp4 |
说明:限制视频录制时间为10s,如果不限制,默认180s
指定视频分辨率大小:
1 | adb shell screenrecord --size 1280*720 /sdcard/demo.mp4 |
指定视频的比特率:
参数: –bit-rate
1 | adb shell screenrecord --bit-rate 6000000 /sdcard/demo.mp4 |
直接把文件放在 tomcat6/webapps/ROOT 目录下,
然后在网址中访问: http://192.168.2.31:8080/download.zip 便可下载。
在tomcat安装目录\conf\Catalina\localhost下建立任意文件名xml文件,比如:download.xml,内容如下:
1 | <?xml version="1.0" encoding="UTF-8"?> |
修改tomcat配置文件,文件目录\conf\web.xml,要将红色的false改为true。
1 | <servlet> |
重启tomcat,访问http://127.0.0.1:8080/download
在使用过程中似乎配到某些格式的文件下载不稳定,出现下载到一半便中断的现象。
前段时间去天房科技面试,面试的哥们人不错,提到了百分比布局,这几天顺便看了看。
原项目代码
https://github.com/JulienGenoud/android-percent-support-lib-sample
张鸿洋大神做了些修改,看下,学习。。
http://blog.csdn.net/lmj623565791/article/details/46767825
有两个gradle
./app/build.gradle
./build.gradle
项目根目录下的build.gradle只做了比较commen的配置,app下的build.gradle是针对此app更细致的配置
1 | apply plugin: 'com.android.application' |
AS中的 gradle在android-studio3/gradle/gradle-2.2.1/bin目录下,可以将其加入到环境变量中
打印hello world,新建一个build.gradle文件
1 | task helloworld << { |
1 | $ gradle -q helloworld |
参数-q只是打印log,这个task也就是此功能而已。
使用Android Studio新建一个工程之后,其目录结构是这样的:
1 | ├── app #Android App目录 |
settings.gradle用于配置project,标明其下有几个module,比如这里包含一个:app module
1 | include ':app' |
和settings.gradle在同一目录下的build.gradle是一个顶级的build配置文件,在这里可以为所有project以及module配置一些常用的配置.
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. |
以初始化好的build.gradle为例
1 | apply plugin: 'com.android.application' |
开头第一行apply plugin: ‘com.android.application’,这表示该module是一个app module,应用了com.android.application插件,如果是一个android library,那么这里的是apply plugin: ‘com.android.library’。
其次是基于哪个SDK编译,这里是API LEVEL,是21,buildToolsVersion是基于哪个构建工具版本进行构建的。defaultConfig是默认配置,如果没有其他的配置覆盖,就会使用这里的。看其属性的名字就可以知道其作用,比如applicationId是配置包名的,versionCode是版本号,versionName是版本名称等。
buildTypes是构建类型,常用的有release和debug两种,可以在这里面启用混淆,启用zipAlign以及配置签名信息等。
dependencies就不属于Android专有的配置了,它定义了该module需要依赖的jar,aar,jcenter库信息。
在android.signingConfigs{}下定义一个或者多个签名信息,然后在buildTypes{}配置使用即可。比如这里
1 | android { |
我们可以为不同的buildTypes选择是否启用混淆,一般release发布版本是需要启用混淆的,这样别人反编译之后就很难分析你的代码,而我们自己开发调试的时候是不需要混淆的,所以debug不启用混淆。对release启用混淆的配置如下:
1 | android { |
minifyEnabled为true表示启用混淆,proguardFile是混淆使用的配置文件,这里是module根目录下的proguard.cfg文件
Android Gradle给我们提供了productFlavors,让我们可以对生成的APK包进行定制,所以就有了多渠道。
1 | android { |
这样当我们运行assembleRelease的时候就会生成3个release包,分别是dev、google以及baidu的。目前看这三个包除了文件名没有什么不一样,因为我们还没有定制,使用的都是defaultConfig配置。这里的flavor和defaultConfig是一样的,可以自定义其applicationId、versionCode以及versionName等信息,比如区分不同包名:
1 | android { |
在我们打包发版的时候,一次性打几十个包,这时候我们就想让生成的apk文件名有区分,比如一眼就能看出这个apk是哪个版本的,哪个渠道的,是哪天打的包等等,这就需要我们在生成apk文件的时候动态修改生成的apk文件名达到这一目的。
1 | def buildTime() { |
以baidu渠道为例,以上的代码会生成一个名字为Mymoney_baidu_v9.5.2.6_20150330.apk安装包。下面我们分析一下,Android Gradle任务比较复杂,它的很多任务都是自动生成的,为了可以更灵活的控制,Android Gradle提供了applicationVariants、libraryVariants以及testVariants,他们分别适用于app、 library、app和library都适用。
这里是循环处理每个applicationVariant,当他们的输出文件名以apk结尾并且buildType是release时,重新设置新的输出文件名,这样就达到了我们批量修改生成的文件名的目的。
AndroidManifest.xml这是一个很重要的文件,我们的很多配置都在这里定义。有时候我们的一些配置信息,比如一个第三方应用的 key,第三方统计分析的渠道号等也要在这里进行配置。这里以友盟统计分析平台为例,演示这一功能的使用。在友盟统计分析中,我们需要根据渠道进行统计,比如google,百度,应用宝等渠道的活跃新增等,友盟的SDK是在AndroidManifest里配置一个name为UMENG_CHANNEL的 meta-data,这样这个meta-data的值就表示这个apk是哪个渠道,我们版本发布有几十个渠道,以前ant打包的时候是采用文字替换的办法,现在Gradle有更好的处理办法,那就是manifestPlaceholders,它允许我们动态替换我们在AndroidManifest文件里定义的占位符。
1 | <meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/> |
如上${UMENG_CHANNEL_VALUE}就是一个占位符,然后我们在gradle的defaultConfig;里这样定义脚本:
1 | android { |
以前的意思就是我们的默认配置里AndroidManifest的${UMENG_CHANNEL_VALUE}占位符会被dev这个字符串所替换,也就说默认运行的版本是一个开发板。以此类推,我们其他渠道的版本就可以这样定义:1
2
3
4
5
6
7
8
9
10
11
12android {
productFlavors {
google{
applicationId "org.flysnow.demo.google"
manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'google')
}
baidu{
applicationId "org.flysnow.demo.baidu"
manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'baidu')
}
}
}
这样有多少个渠道就做多少次这样的定义,即可完成分渠道统计。但是如果上百个渠道,这样一个个写的确太累,很麻烦,我们继续研究,同学们有没有发现,我们的渠道名字和我们的flavorName一样,我们用这个flavorName作为UMENG_CHANNEL_VALUE不就好了吗,可以批量的替换吗?当然可以,这又体现了我们Gradle的强大和灵活之处。
1 | productFlavors.all { flavor -> |
循环每个flavor,并把他们的UMENG_CHANNEL_VALUE设置为他们自己的name名字,ok,搞定。
BuildConfig.java是Android Gradle自动生成的一个java类文件,无法手动编译,但是可以通过Gradle控制,也就是说他是动态可配置的,有了这个功能就很好玩了,这里以生产环境和测试环境为例来说明该功能的使用。
我们在开发App的时候免不了要和服务器进行通信,我们的服务器一般都有生产和测试环境,当我们处理开发和测试的时候使用测试环境进行调试,正式发布的时候使用生成环境。以前的时候我们通过把不同的配置文件打包进APK中来控制,现在不一样了,我们有更简便的方法,这就是 buildConfigField。
1 | android { |
buildConfigField 一共有3个参数,第一个是数据类型,就是你定义的常量值是一个什么类型,和Java的类型是对等的,这里是String。第二个参数是常量名,这里是 API_SERVER_URL。第三个参数是常量值。如此定义之后,就会在BuildConfig.java中生成一个常量名为 API_SERVER_URL的常量定义。默认配置的生成是:
1 | public final static String API_SERVER_URL = "http://test.flysnow.org/" |
当是baidu和google渠道的时候生成的就是http://www.flysnow.org/了。这个常量可以在我们编码中引用。在我们进行打包的时候会根据Gradle配置动态替换。
我们发现一般渠道版本都是用来发布的,肯定用的是生产服务器,所以我们可以使用批处理来搞定这个事情,而不用在一个个渠道里写这些配置。
1 | productFlavors.all { flavor -> buildConfigField 'String','API_SERVER_URL','"http://www.flysnow.org/"' } |
此外,比如Gradle的resValue,也是和buildConfigField,只不过它控制生成的是资源,比如我们在android的 values.xml定义生成的字符串。可以用它来动态生成我们想要的字符串,比如应用的名字,可能一些渠道会不一样,这样就可以很灵活的控制自动生成,关于resValue详细介绍请参考相关文档,这里不再举例说明。
代码覆盖率现在已经成为检验单元测试是否覆盖到的一种手段,Android Gradle提供了原生的用于单元测试的代码覆盖率,这个就是jacoco。今天我们不谈这个,我想要的是在我们生成的APK包中已经包含了检测代码覆盖率的代码,这样当我们安装APK后运行进行一些测试的时候,这些检测代码覆盖率的代码就会被执行到,这样最后我们导出一份代码测试覆盖率的文件,然后生成查看测试覆盖率报告看哪些覆盖到,哪些没有覆盖到。这种场景在检测测试工程师测试功能以及Android UI自动化测试是否完全覆盖尤为有效。这里代码覆盖率框架我选择的是emma,一来这个在Ant打包的时候一直在用,二来它具有很方便的插装功能。
emma插装的是class文件,所以我们只能在编译完java文件生成class文件后进行插装,这是我们进行覆盖率代码插装的最好时机。找到了时机,那么具体对应在Gradle脚本上是哪呢?还记不记得我们上面讲的applicationVariants,每一个 applicationVariant都有一个javaCompile属性,javaCompile是一个JavaCompile类型的Task,这个就是负责编译java代码的。是Task就有doLast方法,就是在这个任务本身完成之后要做的事情,我们就是在这个方法里进行我们的代码覆盖率的安装。一般我们这个插装只是在特性情况下,那么我们新增一个特殊的flavor好了,专门做这个使用,这里我姑且叫feature。
1 | applicationVariants.all { variant -> |
非常简单,我们使用javaexec命令执行java应用程序进程插装,插装模式使用的是overwrite,就是插装后覆盖源文件。 getSdkDirectory()函数获取你电脑上的Android SDK目录,这里我们使用SDK自带的emma,保持每个人的统一。另外注意进行代码覆盖率插装的APK不能进行代码混淆,这个很简单,为feature flavor指定不混淆的proguardFile覆盖默认的proguardFile即可。最后该APK需要emma的框架代码,所以要配置 feature flavor的特殊依赖信息。
1 | dependencies { |
在Gradle 进行dex的可能会遇到内存不够用的情况,错误信息大概是java.lang.OutOfMemoryError: GC overhead limit exceeded。这个时候只需要配置dexOptions的javaMaxHeapSize大小即可,我这里配置4g:
1 | dexOptions { javaMaxHeapSize "4g" } |
1 | https://github.com/rujews/android-tech-docs/blob/master/new-build-system/user-guide/README.md |
gradle
// 移除lint检查的错误 lintOptions { abortOnError true }
之前写信乎的时候,需求用jenkins进行版本构建,当时照着师傅的构建脚本修改写了写,是用ant跑的,现在as的版本构建工具都使用gradle了,回顾一下吧。
打包需要借助JDK和Android SDK中的工具,这些工具的路径在不同的开发人员和系统中可能会不同,所以,我们将这些需要修改的地方,放在build.properties配置文件中,如下:
1 | os.home=/home/leleliu008 jdk.home=${os.home}/bin/jdk1.7.0_67 jarsigner=${jdk.home}/bin/jarsigner android.sdk.home=${os.home}/bin/adt-bundle-linux-x86_64-20140702/sdk android.sdk.platform=${android.sdk.home}/platforms/android-19 aapt=${android.sdk.home}/build-tools/17.0.0/aapt aidl=${android.sdk.home}/build-tools/17.0.0/aidl dx=${android.sdk.home}/build-tools/17.0.0/dx apk-builder=${android.sdk.home}/tools/apkbuilder zipalign=${android.sdk.home}/tools/zipalign proguard.home=${android.sdk.home}/tools/proguard/lib proguard.config=proguard.cfg keystore.path=debug.keystore keystore.password=android keystore.key=androiddebugkey |
Ant和命令行使用android SDK提供的aapt程序生成R.java。
Ant脚本如下:
<target name="gen-R-java" depends="make-dirs">
<echo>Generating R.java / Manifest.java from the resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg value="${gen.dir}" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${res.dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
</target>
1
2
3
### 2,使用aidl工具将.aidl文件转换成.java文件
使用了aidl进程通信机制的时候,需要将.aidl文件转换成Java类,使用aidl工具可以完成此工作,如下:
```
<target name="aidl" depends="make-dirs">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failonerror="true">
<arg value="-p${android.sdk.platform}/framework.aidl" />
<arg value="-I${src.dir}" />
<arg value="-o${gen.dir}" />
<fileset dir="src">
<include name="**/*.aidl" />
</fileset>
</apply>
</target>
### 3,使用javac工具将.java文件编译成.class文件
Ant已经内置了javac任务,可以直接使用该任务完成Java的编译,如下:
1 | ### 4,使用proground对.class文件进行混淆 |
Android的dalvik虚拟机不同于JVM,他不能直接执行.class文件,必须将这些.class文件经过优化打包到一个.dex文件中,以提升执行效率,如下:
1 | <target name="dex"> <echo>Converting compiled files and external libraries into ${dex-file}...</echo> <apply executable="${dx}" failonerror="true" parallel="true"> <arg value="--dex" /> <arg value="--output=${dex-file}" /> <arg path="${classes.dir}" /> <fileset dir="${libs.dir}" includes="*.jar" /> </apply> </target> |
1 | <target name="package-res-and-assets"> <echo>Packaging resources and assets...</echo> <exec executable="${aapt}" failonerror="true"> <arg value="package" /> <arg value="-f" /> <arg value="-M" /> <arg value="AndroidManifest.xml" /> <arg value="-S" /> <arg value="${res.dir}" /> <arg value="-A" /> <arg value="${assets.dir}" /> <arg value="-I" /> <arg value="${android-jar}" /> <arg value="-F" /> <arg value="${resources-file}" /> </exec> </target> |
对照R.java文件的生成,可以看到参数发生了变化,少了-m 和 -J,如果看aapt用法中的描述就知道,-m和-J是结对出现的,用以指明R.java文件的生成路径。-M、-S、-I之前都有提到,这里不再介绍。 -F的作用是指明打包后的资源文件的路径,在最后一定要加上文件名,最好加上扩展名。这里参考Eclipse中自动编译时制定的.ap_后缀名。
需要注意的是apkbuilder这个工具从API 17开始,不再提供了,所以,我们只能找到之前这个工具,放入对应的位置,即可使用。
1 | <target name="gen-unsigned-apk" depends="dex, package-res-and-assets"> <echo>Packaging ${unsigned-out-file} for release...</echo> <exec executable="${apk-builder}" failonerror="true"> <arg value="${unsigned-out-file}" /> <arg value="-u" /> <arg value="-z" /> <arg value="${resources-file}" /> <arg value="-f" /> <arg value="${dex-file}" /> <arg value="-rf" /> <arg value="${src.dir}" /> <arg value="-rj" /> <arg value="${libs.dir}" /> <arg value="-nf" /> <arg value="${libs.dir}" /> </exec> <echo>It will need to be signed with jarsigner before being published.</echo> </target> |
Android应用程序必须进行签名,否则无法安装。同时,我们也可以进行签名验证,以防二次打包。
Ant脚本:
<target name="sign-apk" depends="gen-unsigned-apk">
<exec executable="${jarsigner}" failonerror="true">
<arg value="-verbose" />
<arg value="-storepass" />
<arg value="${keystore.password}" />
<arg value="-keystore" />
<arg value="${keystore.path}" />
<arg value="-digestalg" />
<arg value="SHA1" />
<arg value="-sigalg" />
<arg value="MD5withRSA" />
<arg value="-sigfile" />
<arg value="CERT" />
<arg value="-signedjar" />
<arg value="${signed-out-file}" />
<arg value="${unsigned-out-file}" />
<arg value="${keystore.key}" />
</exec>
</target>
1
2
### 9,使用zipalign对签名后的apk文件进行字节对齐优化
Android SDK中包含一个“zipalign”的工具,它能够对打包的应用程序进行优化,使得在运行时Android与应用程序间的交互更加有效率。因此,这种方式能够让应用程序和整个系统运行得更快。
Ant脚本:
```
<target name="zipalign" depends="sign-apk">
<exec executable="${zipalign}" failonerror="true">
<arg value="-v" />
<arg value="-f" />
<arg value="4" />
<arg value="${signed-out-file}" />
<arg value="${zipalign-out-file}" />
</exec>
</target>
### 10,Debug和release版本
一般Debug版本,打开Log开关,不进行混淆,这样便于排查问题,而release版本用于真实情况,所以会把Log开关关闭,并且进行混淆,所以,我们一般会提供两个版本,两个版本的流程基本上一样,只是个别地方不同。
Debug版本的打包:
1
<target name="debug">
<echo>Packaging debug package...</echo>
<replaceregexp byline="true">
<regexp pattern="false"/>
<substitution expression="true"/>
<fileset dir="${basedir}/src/com/datatang/client/base/" includes="DebugLog.java"/>
</replaceregexp>
<antcall target="compile" />
<antcall target="zipalign" />
</target>
release版本的打包:
1
<target name="release">
<echo>Packaging release package...</echo>
<replaceregexp byline="true">
<regexp pattern="true"/>
<substitution expression="false"/>
<fileset dir="${basedir}/src/com/datatang/client/base/" includes="DebugLog.java"/>
</replaceregexp>
<antcall target="obfuscate" />
<antcall target="zipalign" />
</target>
由于代码的版本控制工具使用的是SVN,所以,我们需要将SVN上指定的SVN提交号或者是最新的代码先导出到本地,然后根据Debug和release版本依次进行上面的流程,即可完成打包工具了。
这个工作使用了Shell脚本完成,这里使用Shell脚本的原因是:
1,一般的服务器是GNU/Linux系统,可以方便的执行Shell脚本,我们可以将这个脚本部署在服务器上。
2,SVN客户端工具在Windows上没有命令行工具,只有GUI工具,如果要使用Ant还需要依赖其他的Jar包,也不方便。
3,我们鼓励开发人员使用GNU/Linux系统进行开发Android程序。
打包完成后,需要将apk上传到SVN的指定目录,如果打包成功,还需要在SVN上创建一个该版本对应的Tag,脚本如下:
projectDir=http://192.168.1.24/pro/department/factory/project/DataTang_for_Android;
tagsDir=$projectDir/02.%E5%BC%80%E5%8F%91/source/tags;
apkDir=$projectDir/01.%E4%BA%A7%E5%93%81/%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%89%88%E6%9C%AC;
repositoryUrl=$projectDir/02.%E5%BC%80%E5%8F%91/source/trunk/DatatangForAndroid;
repositoryUserName=liufupin@datatang.com;
repositoryPassword=shujutang1508
1 | 先删除存放源码的目录: |
导出源码到本地:
1 | echo Check out begain, please wait patiently! svn export -r HEAD --username $repositoryUserName --password $repositoryPassword $repositoryUrl project echo Check out over! |
切换到存放源码的目录:
cd project
1
2
3
获取AndroidManifest.xml中的版本号:
```
versionName=`cat AndroidManifest.xml | grep 'versionName="[^"]*"' | sed 's/.*versionName="\([^"]*\)".*/\1/'`;
echo $versionName;
获取build.properties配置的os.home变量的值,因为不同系统的不同用户,这个值可能不同:
oldHome=/home/leleliu008
newHome=$HOME
sed -i “s#${oldHome}#${newHome}#g” build.properties1
2
打release包
ant release1
将release包上传到SVN指定目录中:
svn import –username $repositoryUserName –password $repositoryPassword bin/DataTang_for_android.apk $apkDir/DataTang_forandroid$versionName(obfuscate).apk -m “import $versionName obfuscate apk”1
打debug包:
ant debug1
2
将release包上传到SVN指定目录中:
svn import –username $repositoryUserName –password $repositoryPassword bin/DataTang_for_android.apk $apkDir/DataTang_forandroid$versionName.apk -m “import $versionName unobfuscate apk”1
2
构建完成后,先删除bin目录和gen目录,因为这些目录是构建过程中生成的,不需要提交到SVN中:
rm -rf bin
rm -rf gen1
2
在SVN上创建该版本的tag:
svn import –username $repositoryUserName –password $repositoryPassword project $tagsDir/DatatangForAndroid_$versionName -m “create tag $versionName” –no-ignore1
2
3
### 11,渠道包
在Android项目的根目录下面有一个channel文件夹,里面有一个渠道号的配置文件channels.txt,如下:
100000
100001
100002
100003
100004
100005
100005
100006
100007
100008
100009
1 | 打渠道包的shell脚本: |
操作系统:CentOS 7 x86_64
主机地址:192.168.1.48
主机用户名:root
主机密码:Simple1921
打包需要使用Android SDK中的工具,所以,必须安装Android SDK。
需要使用SVN进行管理源代码,所以必须安装SVN客户端。
跨页面传值
内置对象:为了跨页面传值和状态保持。→HTTP的无状态性
Session:每一台电脑访问服务器,都会是独立的一套session,key值都一样,但是内容都是不一样的
不一样:
session 保存在服务器内存中,由用户第一次访问服务器时创建,需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session,可调用request.getSession(true)强制生成Session。
Session什么时候失效?
session 需要客户端浏览器的支持,因为Session需要使用Cookie作为识别标志。http协议是无状态的,session不能依据http连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。
该Cookie为服务器自动生成的,它的maxAge属性一般为-1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是由浏览器窗口内的链接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择”在新窗口中打开”时,子窗口便可以访问父窗口的Session。
如果客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另一种解决方案:URL地址重写。
URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(String url)实现URL地址重写,该方法会自动判断客户端是否支持Cookie。如果客户端支持Cookie,会将URL原封不动地输出来。如果客户端不支持Cookie,则会将用户Session的id重写到URL中。
注意:TOMCAT判断客户端浏览器是否支持Cookie的依据是请求中是否含有Cookie。尽管客户端可能会支持Cookie,但是由于第一次请求时不会携带任何Cookie(因为并无任何Cookie可以携带),URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,因此URL地址重写后的地址中就不会带有jsessionid了。
在AJAX浏览器来进行发送数据时,一般它所默认的都是UTF-8的编码.
1 | function verify() { |
这里要做两次encodeURI的原因以及说明:
1 | 其中具体的原理分析如下,假设页面端输入的中文是一个“中”,按照下面步骤进行解码 |
http://jenkins-ci.org/content/thank-you-downloading-os-x-installer
1 | <?xml version='1.0' encoding='UTF-8'?> |
如果要修改端口,比如7070,可在第8步重启jenkins前执行以下命令修改端口参数:
1 | sudo defaults write /Library/Preferences/org.jenkins-ci httpPort 7070 |