#
1、六顶思考帽的概念:
白帽子:信息(陈述事实,数据。客观情况的陈述)
红帽子:情绪(情感,感受)
黄帽子:利益(逻辑的积极因素)
黑帽子:谨慎(逻辑的消极因素)
绿帽子:创意(思考创新点子)--头脑风暴法,随机词汇法,概念提取法等等
蓝帽子:控制(总恐思考流程)--主持人的角色,要求不带个人意见,针对思考内容,需要合理及时调整思考者讨论问题的方向(所带帽子)
2、六顶思考帽的实质
思维方式的转变
对立--平行
辩论--合作
同时讨论--依次讨论
3、应用场景
a)个人思考问题--可借助freemind工具
b)双人,多人讨论问题
c)团队会议
。。。。。。。
今天在做项目的时候,遇到这样一个需求,这个需求也比较常见:
在显示的一组list版面,当用户鼠标移动到标题的时候,出现tips提示,里面显示当前栏一些详细信息。
难点如下:
1)由于list有多个标题(比如20个),不可能在一个request中,把所有的详细信息取出来put到页面上。所以只能通过ajax异步请求的方式取的数据。
2)取详细信息比较耗性能,需要走一次搜索引擎,走一次数据库多表查询进行结果统计。虽然取的过程比较耗服务器性能,但是取的结果集对象是很小的。
3)单条详细信息load次数只跟个别会员有关,比如,只有a会员的list页面需要load 标题A的详细信息,而且当a用户多次将鼠标移到该标题上,会多次load数据。反观站点整体访问中,其他会员几乎不用load 标题A的信息。所以,把这些详细信息放到全局cache中,比如memcached中,命中率也会很低。不值得。(放session就更别提了,session不是用来放这些数据的:比如某个集群环境中,是使用session复制的机制;比如session过期,短时间内--甚至比较长的时间内,session依旧存在内存中,等等。。。)
那么如何来解决这个问题呢?
正当想说服需求方放弃这个需求时,出现了一个灵感,可以把数据cache在html页面上。思路如下:
1、在html页面上放n个input元素:<input id="list1" type="hidden" value="" />。视为cache对象;
2、首次取详细信息,通过ajax异步访问服务端,将得到的数据存放到相应的input元素中,并且在指定的div上显示详细信息;
3、之后,取同内容的详细信息,只要从相应的input元素中取得即可,并显示在指定的div上。
通过这样处理,可以避免用户多次向服务端取相同的信息。当然这样处理,不能防止恶意用户的访问,但是能满足80%用户的正常流程,还是值得这么做的。
总结一下,符合这种cache的应用场景:
1)全局cache命中率低
2)取数据过程耗性能,取得的结果集本身非常小。
3)在某种场景下,需要多次重复取数据
如果不满足其中一条,那么这种cache思路,将毫无价值。
文中所描述的,仅仅是一种cache的实现思路,并不是一种技术。
jstatd
启动jvm监控服务。它是一个基于rmi的应用,向远程机器提供本机jvm应用程序的信息。默认端口1099。
实例:jstatd -J-Djava.security.policy=my.policy
my.policy文件需要自己建立,内如如下:
grant codebase "file:$JAVA_HOME/lib/tools.jar" {
permission java.security.AllPermission;
};
这是安全策略文件,因为jdk对jvm做了jaas的安全检测,所以我们必须设置一些策略,使得jstatd被允许作网络操作
jps
列出所有的jvm实例
实例:
jps
列出本机所有的jvm实例
jps 192.168.0.77
列出远程服务器192.168.0.77机器所有的jvm实例,采用rmi协议,默认连接端口为1099
(前提是远程服务器提供jstatd服务)
输出内容如下:
jones@jones:~/data/ebook/java/j2se/jdk_gc$ jps
6286 Jps
6174 Jstat
jconsole
一个图形化界面,可以观察到java进程的gc,class,内存等信息。虽然比较直观,但是个人还是比较倾向于使用jstat命令(在最后一部分会对jstat作详细的介绍)。
jinfo(linux下特有)
观察运行中的java程序的运行环境参数:参数包括Java System属性和JVM命令行参数
实例:jinfo 2083
其中2083就是java进程id号,可以用jps得到这个id号。
输出内容太多了,不在这里一一列举,大家可以自己尝试这个命令。
jstack(linux下特有)
可以观察到jvm中当前所有线程的运行情况和线程当前状态
jstack 2083
输出内容如下:
jmap(linux下特有,也是很常用的一个命令)
观察运行中的jvm物理内存的占用情况。
参数如下:
-heap:打印jvm heap的情况
-histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
-histo:live :同上,但是只答应存活对象的情况
-permstat:打印permanent generation heap情况
命令使用:
jmap -heap 2083
可以观察到New Generation(Eden Space,From Space,To Space),tenured generation,Perm Generation的内存使用情况
输出内容:
jmap -histo 2083 | jmap -histo:live 2083
可以观察heap中所有对象的情况(heap中所有生存的对象的情况)。包括对象数量和所占空间大小。
输出内容:
写个脚本,可以很快把占用heap最大的对象找出来,对付内存泄漏特别有效。
jstat
最后要重点介绍下这个命令。
这是jdk命令中比较重要,也是相当实用的一个命令,可以观察到classloader,compiler,gc相关信息
具体参数如下:
-class:统计class loader行为信息
-compile:统计编译行为信息
-gc:统计jdk gc时heap信息
-gccapacity:统计不同的generations(不知道怎么翻译好,包括新生区,老年区,permanent区)相应的heap容量情况
-gccause:统计gc的情况,(同-gcutil)和引起gc的事件
-gcnew:统计gc时,新生代的情况
-gcnewcapacity:统计gc时,新生代heap容量
-gcold:统计gc时,老年区的情况
-gcoldcapacity:统计gc时,老年区heap容量
-gcpermcapacity:统计gc时,permanent区heap容量
-gcutil:统计gc时,heap情况
-printcompilation:不知道干什么的,一直没用过。
一般比较常用的几个参数是:
jstat -class 2083 1000 10 (每隔1秒监控一次,一共做10次)
输出内容含义如下:
Loaded |
Number of classes loaded. |
Bytes |
Number of Kbytes loaded. |
Unloaded |
Number of classes unloaded. |
Bytes |
Number of Kbytes unloaded. |
Time |
Time spent performing class load and unload operations. |
jstat -gc 2083 2000 20(每隔2秒监控一次,共做10)
输出内容含义如下:
S0C
|
Current survivor space 0 capacity (KB). |
EC
|
Current eden space capacity (KB). |
EU
|
Eden space utilization (KB). |
OC
|
Current old space capacity (KB). |
OU
|
Old space utilization (KB). |
PC
|
Current permanent space capacity (KB). |
PU
|
Permanent space utilization (KB). |
YGC
|
Number of young generation GC Events. |
YGCT
|
Young generation garbage collection time. |
FGC
|
Number of full GC events. |
FGCT
|
Full garbage collection time. |
GCT
|
Total garbage collection time. |
输出内容:
如果能熟练运用这些命令,尤其是在linux下,那么完全可以代替jprofile等监控工具了,谁让它收费呢。呵呵。
用命令的好处就是速度快,并且辅助于其他命令,比如grep gawk sed等,可以组装多种符合自己需求的工具。
截图工具不常用,但是真到要用的时候,也还得找一个。scrot口碑不错,网上推荐的文章很多,就选它了。
用了,确实好使,小巧,功能也不弱。
ubuntu下,安然很方便,sudo apt-get install scrot。(当然,我个人还是喜欢编译源码的方式安装。)
介绍下几个常用的参数。(下面的列表就是通过scrot截图出来的)
-b:在选择窗口截图的时候,选中边框截图
-d:延迟n秒后进行截图
-e:截图后,执行某个命令
-q:截图画面质量,1-00,越高质量好,压缩就少。默认是75
-s:通过鼠标选择截图区域
-t:生成缩略图,比如50x60,80x20
整体评价,小巧并且功能不弱,完全胜任普遍的一些截图需求。
effective java中提供了57条建议。针对这些建议,我谈谈自己的理解。
1.考虑用静态工厂方法代替构造函数
静态工厂方式相比于构造函数的两个优点:
1)可以有符合自己身份的方法名,方便客户端代码的阅读
2)调用的时候,不要求创建一个新的实例。可以返回缓存实例,或者singleton实例等
静态工厂方法的最大缺点:
如果类中没有public或者protected的构造函数,使用静态工厂方法的方式得到实例,那么这个类就无法被继承。
比如
public class Demo {
private static Demo demo = new Demo();
public static Demo getInstance() {
return demo;
}
private Demo() {
}
}
那么这个类就无法被继承。
(当然,鼓励使用组合,而不是继承)
在spring没有流行起来的那些日子里,我大量使用工厂方法,但是使用spring等ioc容器后,这一切都是交给容器去处理了。或许,在客户端代码中,工厂模式会因为这些ioc的出>现,而遭受淘汰。
2.使用私有构造函数强化singleton属性
一旦存在public或者protected的构造函数,那么无法保证一个类,一定是sinleton的。因为无法得知客户端代码是使用构造函数,还是同构静态方法去得到类实例。所以对于一个严格要求singleton的类,那么其构造函数必须是私有的。
既然说到singleton了,那么顺便说下几个常见的创建方法
1)
/**
* 优点:简单,而且可以确保一定是singletion实例
* 缺点:类加载时,就会初始化实例,不能做到延迟初始化。
*/
public class Demo {
private static final Demo demo = new Demo();
public static Demo getInstance() {
return demo;
}
private Demo() {
}
}
2)
/**
* 优点:lazy load(延迟初始化实例),提高效率
* 缺点:多线程情况下,可能初始化多份实例
*/
public class Demo {
private static Demo demo = null;
public static Demo getInstance() {
if(demo == null ) {
demo = new Demo();
}
return demo;
}
private Demo() {
}
}
3)
/**
* 优点:lazy load(延迟初始化实例),提高效率
* 采用double check并且同步的方式,理论上确保在多线程的应用场景中,也只创建一份实例
* 备注:(涉及到jvm的实现,在实际应用中,也可能生成多份实例,但是几率是相当地低)
*/
public class Demo {
private static Demo demo = null;
public static Demo getInstance() {
if(demo == null ) {
synchronized(Demo.class) {
if(demo == null) {
demo = new Demo();
}
}
}
return demo;
}
private Demo() {
}
}
3.使用私有构造函数强化不可实例化能力
咋一看这个标题,觉得不可思议,居然让类不具备实例化能力。但是确实也有一些应用场景,比如一些util类,就不需要实例化。但是有很大的副作用,就是类无法被继承。所以换成我,就算是util类,我还是会保留其public的构造函数的。客户端就算要实例化这些util,也无伤大雅。
4.避免创建重复对象
一般情况下,请重复使用同一个对象,而不是每次需要的时候创建一个功能上等价的新对象。这主要是为了性能上的考虑,何况在一般的应用场景下,确实没有必要去重复创建对象。当然有时候为了OO设计考虑,也不特别排斥创建重复的小对象。
需要明确的是,避免创建重复的对象,请不要产生一个误区就是:创建对象的成本非常昂贵。事实上,创建小对象的开销是非常小的,而且现在的jdk gc对于小对象的GC代价也是非常廉价(在之后的日子里,我会针对sun jdk gc,做一次介绍)。比如在做Swing开发的时候,会创建很多EventListener对象,比如在Spring Framework中,就创建很多匿名内隐类对象实现类似ruby等动态语言的Closure(闭包)。
但是也不可否认的是,创建大对象,对大对象的GC 的开销是比较大的。比如初始化一个对象的时候,需要加载10m的文件内容到内存;创建数据库连接对象等等,在这些场景下,创建的开销是相当昂贵了,一定要尽可能避免重复对象的创建(除非特殊需求)。
对于这些大对象,一般采用singleton模式,cache,或者object pool等方式,避免重复的创建。至于采用具体什么方式,需要根据具体的应用场景来决定了。
5.消除过期对象的引用
为什么要这么做?其实只要理解“java内存泄露”这个概念就可以了。java中的内存泄漏不同于C++中的内存泄漏。C++是需要程序员手工管理内存的语言,创建一个对象,用完之后,需要手工删除这个对象。而java不一样,jdk gc替程序员做了这件事情,一旦对象失去了引用之后,jdk gc就会自动回收这个对象。
为了避免java中的内存泄漏,只需要知道一点就可以:对于无用的对象,必须消除对这个对象的引用。
怎么消除对象的引用呢?难道需要手工设置“object=null;”,那么一旦程序中到处充斥着这样的代码,将会是一件非常恶心的事情,严重影响程序的阅读性。
正确的做法是,每个定义的变量给予最紧凑的作用域,一旦对象结束生命周期,自然就消除了对其的引用。
当然在必要的场合,也不反对采用清空对象引用的方法,但是不推荐。
内存泄漏的症状不能在短时间内反应出来,往往是在程序运行一段时间,一天,一周,一个月,甚至一年,才逐渐显现的,一个经验丰富的程序员,也不能确保其代码一定不存在内存泄漏的问题。检查内存泄漏问题,往往需要借助工具,heap profile,比如jprofile等等。在linux下面,可以使用jps jstat jinfo jmap等命令去观察。
最近没有系统学习的计划,看了开源的YOYOPlayer(一个相当强大的播放器软件,基于java编写),心里痒痒,比较肤浅的学习下javasound。
javasound是比较小巧的底层api,引用网上的一幅 javasound体系结构图:
javasound实现: 目前使用最多的是 jdk中javax.sound组件 (包括javax.sound.sampled 和 javax.sound.midi包) 和 开源的 Tritonus(http://www.tritonus.org/)组件
SPI:是Service Provider Interface(服务提供接口),它的作用是以插件的形式提供音频扩展模块。比如,javax.sound组件中,只支持au,mid,wav等少许音频格式,其中不包括mp3。要想支持mp3格式,那么就需要相应的解码器和SPI。所幸的是,已经有相应的开源包。
javazoom(http://www.javazoom.net)下的jlayer,是mp3格式的解码包。
javazoom下的mp3spi就是spi。
只要添加了相应的开源组建包,可以在不修改任何一行代码的情况下,支持其他音频格式。这就是spi的魅力。
简单介绍了javasound的体系结构,下面就介绍一个简易的mp3播放器的实现(所谓简易,就是没有界面,除了能播放mp3等文件外,就啥都不能干了 :) )
几个步骤:
1)得到音频流:
AudioSystem.getAudioInputStream(input)
2)得到音频格式:
audioInputStream.getFormat()
3)初始化数据行信息
数据行信息包括(受数据行支持的音频格式;其内部缓冲区的最小和最大大小
)
DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);
4)从混频器获得源数据行
SourceDataLine
接口提供将音频数据写入数据行的缓冲区中的方法。播放或混合音频的应用程序应该以足够快的速度将数据写入源数据行,以防缓冲区下溢(排空),下溢可能导致单击时音频数据中出现可感知的间断
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
5)将音频数据写入源数据行中
line.start();
int readLenth = 0;
while (readLenth != -1) {
readLenth = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
if (readLenth != -1) {
line.write(AUDIO_BUFER, 0, readLenth);
}
}
line.drain();
line.stop();
line.close();
下面提供完整的简易mp3播放器代码:
其中
AudioPlayer仅仅是一个接口。
/**
* <pre>
* MP3播放器实现
* 线程不安全,没有必要多个线程去启动播放器
* </pre>
*
* @author Lee Jones
*/
public class Mp3Player implements AudioPlayer {
private static final Log log = LogFactory.getLog(Mp3Player.class);
private static final byte[] AUDIO_BUFER = new byte[4096];
private AudioInputStream audioStream;
private AudioFormat decodedFormat;
private AudioInputStream decodedAudioStream;
@Override
public void play(InputStream input) {
if (input == null) {
log.warn("input stream is null");
return;
}
try {
init(input);
play();
} catch (Exception e) {
log.error("play error:", e);
}
}
@Override
public void play(File file) {
if (file == null) {
log.warn("audio file is null");
return;
}
try {
play(new FileInputStream(file));
} catch (FileNotFoundException e) {
log.error("file to inputStream error:", e);
}
}
@Override
public void play(URL url) {
if (url == null) {
log.warn("url is null");
return;
}
try {
play(url.openStream());
} catch (IOException e) {
log.error("url open inputStream error:", e);
}
}
/**
* init
*
* @param input
* @throws UnsupportedAudioFileException
* @throws IOException
*/
protected void init(InputStream input) throws UnsupportedAudioFileException, IOException {
initAudioStream(input);
initDecodedFormat();
initDecodedAudioStream();
}
/**
* init audio input stream
*
* @param input:audio input stream
* @throws IOException
* @throws UnsupportedAudioFileException
*/
protected void initAudioStream(InputStream input) throws UnsupportedAudioFileException, IOException {
audioStream = AudioSystem.getAudioInputStream(input);
}
/**
* init decoded format
*
* @throws UnsupportedAudioFileException
* @throws IOException
*/
protected void initDecodedFormat() throws UnsupportedAudioFileException, IOException {
AudioFormat baseFormat = audioStream.getFormat();
decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
baseFormat.getChannels(), baseFormat.getChannels() * 2,
baseFormat.getSampleRate(), false);
}
/**
* init decoded audio stream
*/
protected void initDecodedAudioStream() {
decodedAudioStream = AudioSystem.getAudioInputStream(decodedFormat, audioStream);
}
/**
* get source data line
*
* @param input audio input stream
* @return
* @throws UnsupportedAudioFileException
* @throws IOException
* @throws LineUnavailableException
*/
protected SourceDataLine getSourceDataLine() throws UnsupportedAudioFileException, IOException,
LineUnavailableException {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);
SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
line.open(decodedFormat);
return line;
}
/**
* play audio
*
* @throws UnsupportedAudioFileException
* @throws IOException
* @throws LineUnavailableException
*/
protected void play() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
SourceDataLine line = getSourceDataLine();
line.start();
int readLenth = 0;
while (readLenth != -1) {
readLenth = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
if (readLenth != -1) {
line.write(AUDIO_BUFER, 0, readLenth);
}
}
line.drain();
line.stop();
line.close();
decodedAudioStream.close();
audioStream.close();
}
}
最后附上简易播放器:
easy mp3 player
启动方式:linux用户使用./mp3player.sh,windows用户使用mp3player.bat启动(需要说明的是,必须设置好JAVA_HOME和PATH,并且使用jdk5以上版本。因为启动脚本中的指定classpath的方法需要jdk5版本以上才支持。如果是jdk1.4下的用户,请修改启动脚本)
lib目录:是简易播放器的lib包支持
log目录:记录log,如果有错误等情况,可查看log。
conf目录:因为没有图形界面,所以需要把播放的mp3文件路径手工写入。支持两种形式,一个是本地mp3文件,另一个是网络mp3资源,分别写入到local.txt和net.txt文件中。
比如
local.txt
/home/jones/data/music/misc/xin_nian_hao.mp3
/home/jones/data/music/misc/guo_ge.mp3
net.txt
http://lubai.com.cn/CGI-BIN/shuanxing.mp3
http://lubai.com.cn/CGI-BIN/shuanxing.mp3
因多媒体方向非自己的工作方向,所以了解的相当肤浅。有兴趣的朋友请多多指教。
春节放假,难得有10天放松的机会,欲把本本从开发机稍稍改装一下,添加上娱乐软件。
装上beep-media-player,mplayer+w32codes,好歹本本可以听听音乐,看看电影了。
唯可惜,本本上没有任何资源。
于是乎,想装上电驴,下载点东东。从网上搜索下,发现linux有几款工具,amule,Azureus,mldonkey。
amule以前用过,感觉一般,没什么特色可言。
Azureus是同事推荐,但没用过,没有发言权。
mldonkey是网上朋友极力推荐的,最终我选择mldonkey,原因如下:
1)速度快,据说可以达到带宽的上限
2)可以同时连接多个server
3)搜索没有限制,不像windows下的emule,屏蔽了大量的敏感词。
。。。
更多优点待挖掘中。
贪图方便的朋友,其实安装这三款软件,都比较方便,在ubuntu7.10源中,都有。
sudo apt-get install amule
sudo apt-get install azureus
sudo apt-get install mldonkey-server mldonkey-gui
我个人是比较倾向于编译源码安装的。
mldonkey下载地址:http://mldonkey.sourceforge.net/Main_Page 截至当前,最新版本是
2.9.3
sancho下载地址:http://sancho-gui.sourceforge.net/download.phtml 最新版本
sancho-0.9.4-58-linux-gtk-java.sh
下载mldonkey,解压,configure(指定安装路径),make ,make install。
下载sancho,添加执行权限,执行脚本。
在mldonkey目录下,执行bin/mlnet
在sancho目录下,执行sancho命令,进行配置,并且选择mlnet的安装路径。此后,只要运行sacho就可以了,不必要再运行mlnet。
需要明确一个概念:mldonkey是核心,支持
ed2k、bittorrent、http、ftp……等协议。而sancho是基于mldonkey的一个图形化界面。所以,只要你愿意使用命令,那么不安装sancho,也无所谓。只不过我也是懒惰的人,所以需要图形界面。
至此,其实软件都安装完成了,只不过还需要一些简单的配置,
在sancho界面进行连接数和下载速度等的配置
编辑~/.mldonkey/downloads.ini文件,进行下载路径的配置
(* The directory where temporary files should be put *)
temp_directory = temp
把temp目录修改成你需要的临时目录
{ dirname = "incoming/files"
strategy = incoming_files
priority = 0
};
把incoming/files修改文件输出路径
我自己是没有作这个修改,只是建立了一个软链接
ln -s
~/.mldonkey/incomfing/files ~/tmp/mldonkey 以后只需要关注这个目录就可以了。
万事大吉,但是发觉下载速度没有想象中那么快,稍有遗憾。不过这个软件还真不错,值得推荐。
在项目中,一直来是使用spring对java mail的封装,来发邮件的。虽然spring的封装已经大大简化了发送邮件的复杂度,但是今天要介绍下apache commons email组件,对java mail进行了更好的封装,对于客户端的调用,已经是相当地方便了。
commons-email maven库地址:
<dependency>
<groupId>commons-email</groupId>
<artifactId>commons-email</artifactId>
<version>1.1</version>
</dependency>
commons-email实现是相当的简单,下面介绍下几个重要的类实现
1)Email
一个抽象类,对java mail进行了封装,提供主要接口如下
setHostName(String):设置smtp服务器地址
setSmtpPort(int):设置smtp服务器端
setAuthenticator(Authenticator):设置授权帐号和密码
setSSL(boolean ssl):是否采用ssl方式连接服务
setMailSession(Session):设置与服务器连接session
setCharset(String):设置邮件主体编码
setFrom(String):设置发件人地址
addTo(String):添加收件人地址
addCc(String):添加抄送人地址
addBcc(String):添加密送人地址
addReplyTo(String):添加回复人地址
setSubject(String):设置邮件标题
setMsg(String):设置邮件主体
send():发送邮件
2)SimpleEmail
继承Email,实现了setMsg(String msg)方法,发送文本格式邮件,调用非常简单
SimpleEmail email = new SimpleEmail();
email.setSSL(true);
email.setSmtpPort(SMTP_PORT);
email.setHostName(SMTP_SERVER);
email.setAuthentication(USER_NAME, PASSWORD);
email.addTo("**@**.com");
email.setFrom("**@**.com");
email.setSubject("subject");
email.setCharset("GBK");
email.setMsg("message");
email.send();
3)MultiPartEmail
继承Email,多了一个添加附件的方法:
attach(URL, String, String)
attach(URL, String, String, String)
attach(DataSource, String, String)
attach(DataSource, String, String, String)
attach(EmailAttachment)
调用方式如下:
MultiPartEmail email = new MultiPartEmail();
email.setSSL(true);
email.setSmtpPort(SMTP_PORT);
email.setHostName(SMTP_SERVER);
email.setAuthentication(USER_NAME, PASSWORD);
email.addTo("**@**.com");
email.setFrom("**@**.com");
email.setSubject("subject");
email.setCharset("GBK");
email.setMsg("message");
email.attach("file:///***.pom.xml", "pom.xml", "pom");
email.send();
4)HtmlEmail
继承MultiPartEmail,与SimpleEmail相比,多了一个setHtmlMsg(String msg)方法,用户设置html格式内容,调用方式同SimpleEmail几乎一致
HtmlEmail email = new HtmlEmail();
email.setSSL(true);
email.setSmtpPort(SMTP_PORT);
email.setHostName(SMTP_SERVER);
email.setAuthentication(USER_NAME, PASSWORD);
email.addTo("**@**.com");
email.setFrom("**@**.com");
email.setSubject("subject");
email.setCharset("GBK");
email.setHtmlMsg("<html><body><b>this is email message!</body></html>");
email.send();
当然,commons email只提供了对smtp协议的封装,不包括对pop协议的封装,所以只能发送邮件,不能接受邮件。
在杭州一直使用无限网络上网,今天回绍兴,只能用adsl上网。
adsl上网是采用pppoe协议上网的,幸好ubuntu默认情况下,已经安装了pppoe程序
如果没有安装的用户,可以使用
sudo apt-get install pppoe pppoeconf
安装pppoe程序和pppoe配置程序
接下来,使用
sudo pppoeconf
进行上网参数配置,主要是配置adsl上网的帐号和密码
最后,使用
sudo pon dsl-provider 联网
sudo poff dsl-provider 断网
整个过程还是比较方便的。
在本本上编程,老是不小心碰到触摸板,导致光标乱飞。
以下是禁用触摸板的方法。
一般情况下,是使用synaptics触摸板驱动。
最直接的方法,就是卸载synaptics驱动。sudo apt-get autoremove synaptics
但是如果一旦需要使用触摸板,还要把驱动装上,太麻烦了。
还有一种比较简单的方法。
编辑xorg.conf文件:sudo vi /etc/X11/xorg.conf
Section "InputDevice"
Identifier "Synaptics Touchpad"
Driver "synaptics"
Option "SendCoreEvents" "true"
Option "Device" "/dev/psaux"
Option "Protocol" "auto-dev"
Option "HorizEdgeScroll" "0"
Option "SHMConfig" "on"
EndSection
添加 Option "SHMConfig" "on" 这行内容
SHMConfig on 表明开启触摸板的参数设置权限
命令:synclient touchpadoff=1 --关闭触摸板
命令:synclient touchpadoff=0 --开启触摸板
自己写一个关闭触摸板命令的sh文件,加入到自启动栏目中,就万事大吉了。