HTML5游戏市场究竟有多大?

编者按:本文编译自SM的“The market for HTML5 gaming”一文,部分内容有删改。

正如我最近在博客中写道的那样,我坚信2012会是HTML5移动游戏大展身手的一年。在创建我自己的游戏开发工作室时,和其他的创业公司一样,我需要做很多功课,以下是我总结的HTML 5游戏创业公司通常会遇到的一些问题,以及我对这些问题的个人理解:  .

虽然我不知道该如何更好地回答这个问题,但过去几年智能手机的销售情况无疑是一个不错的参考。据computing.co.uk报道,2011年第二季度全球的手机销售总量为4.287亿,同比增长16.5%;其中智能手机占销售总量25%,并以74%的增速逐年递增;Google和苹果成为整个智能手机市场的两大主导力量,iOS和Android平台的智能手机共占62%的市场份额,而它们2010年同期的市场份额仅为31%。

更早一些的时候,2009年智能手机全年的销售量为1.724亿,2008年全年的的销售量为1.392亿,略多于2011年一个季度的销售量。

另外,值得一提的是,大屏幕设备正在逐步成为市场主导。

从我自己公司的统计数据来说,2011年11月我们游戏网站的访问量为3.3207万,其中独立访客数为2.4628万,也就是说有8579(约25%)是回头访客。这比我的预期要好。

另据Google的统计数据显示,我们网站平均每个页面浏览2次,这与我的预期大致相符,第一次是浏览游戏列表,第二次是离开页面开始玩选定的游戏。

更深入一些来看,我注意到平均每个访客在网站中的停留时间为2分钟左右,是真正所谓的“来去匆匆”。

从操作系统来看,55%的访问者使用Android系统,16%使用iPhone,15%使用iPad,12%使用iPod,其余的就是使用塞班、三星和诺基亚等等。另一份关于Kimia移动门户网站IOPlay.mobi的统计数据显示,在总量为150万的点击量中,Java 29.5%,Android 22%,Blackberry 21.5%,Symbian 14%,iPhone 13%。在这些数字中,19%的点击量来自HTML 5游戏。

从地理位置上来说,我们网站的大部分访客都是来自欧洲,少量来自美国和亚洲。我相信,一旦iOS 5找到市场立足点,将会有越来越多的iPhone/iPad用户会成为我们网站的访客。而在iOS 5成长起来之前,我将更多地注重Android平台。

自己开发的游戏是什么样的?这些游戏是否真的符合手机游戏玩家的口味?

我们公司开发的游戏大都是传统型的街机游戏,如Hypergunner和Galactians是传统的射击游戏, Danger Ranger是简单的平台游戏,Spy Chase是经典的赛车游戏,从用户反馈来看,我们最受欢迎的游戏是Galactians。我觉得喜欢反复玩我们游戏的人或多或少有一丝怀旧情节,当然,我们也十分注重游戏质量,因此吸引了部分年轻玩家。

目前,已有很多游戏网站陆陆续续高调上线,随着HTML 5的日渐成熟,类似的游戏网站还会越来越多。为了吸引潜在用户,我们首先应清楚玩家需要的是什么。

当前人们喜欢玩的游戏有哪些?玩家的年龄构成是怎样的?以下是来自荷兰知名HTML 5游戏公司Spil的一份统计数据:

Girls (age: 8 to 12)——Dress Up Games、Quizzes、Puzzle Games、Board & Card、Skill GamesTeens (age: 10 to 15)——Action Games、Racing、Sports、Girls Games、AdventureFamily (age: 8 to 88)——Puzzle Games、Girls Games、Skill Games、Racing、Board & Card、Quizzes、Time Management Games

据悉,Spil平均每月的主页访客高达1.4亿,其中8500万为女性。

开放式web技术的移动游戏市场正在以惊人的速度增长,在过去不到半年的时间里,移动游戏网站的数量增加了3倍。当前环境所提供的技术、技能、标准支持,以及各平台不断完善的浏览器功能,为HTML 5游戏开发者创造了前所未有的良机。

虽然目前我们还处于HTML5游戏的早期阶段,但随着智能手机的普及,以及技术和标准的逐步成熟,HTML 5游戏的发展空间无疑会越来越大。

英文原文:SM:The market for HTML5 gaming

中文翻译:雷锋网编译。

View the original article here

seo观点,维基百科seo来学习seo

seo背景

为了反对美国反盗版立法,维基百科创始人吉米·威尔士将英文版维基百科关闭24小时,以表达抗议,这种大型网站遇到这种特例情况的操作手法,很值得SEO从业者学习借鉴。

在英文维基百科“关闭”期间,任何用户访问该网站,都无法看到原有的内容,而是显示一个抗议SOPA(反网络盗版法)议案的页面,但实际上我们只要在浏览器中停用Javascript,依旧可以正常访问维基百科。

可以看出,英文维基百科并没有大幅修改原始站点的页面,也没有进行重定向跳转操作,而是通过Javascript脚本语言的方式,修改了原来网页的CSS,对原始内容做了隐藏和遮罩,并显示一段新的内容。

seo操作方式

这种修改seo操作方式,有几个好处:1)实施较为简单,只要所有页面都包含同一个Javascript文件,就只需要修改这个JS文件,即可实现“关闭网站”的操作,而不需要修改网站程序或者重建页面。2)最大的好处是,可以避免seo方面的损失,如果采用修改原始文件,或者301或302的方式跳转,会影响全站的排名,英文维基百科在Google中的排名非常高,很多关键字排名第一,如果大幅做这样的修改,很可能会让Google认为这是作弊,从而降低该网站的排名,而因为Google不抓Javascript,因此使用Javascript进行修改所带来的风险较小。

seo

当然,这也只是适合短时间(一两天)内操作,如果长时间通过Javascript修改网页内容,依旧可能会对网站排名seo造成负面影响。

什么是好的优化呢?

一流的思路+二流的态度=烂

二流的思路+一流的态度=好

一流的思路+一流的态度=成功

 

为何Safari不如Chrome?

Safari是乔布斯在2003年的Macworld大会发布的,9年过去了,08年才发展起来的Chrome用了不到Safari一半的时间远远把Safari甩在了后面,这让Safari情何以堪。Chrome的市场份额从2008年的0%开始,发展到了现在的25%,而苹果的Safari似乎一直徘徊于5%-8%之间。?

两大浏览器都是基于苹果的布局引擎Webkit,按道理Safari是占优势的,因为两者都分别是自己操作系统的默认浏览器,许多人就顺便使用了,懒得去下载别的浏览器。

而且随着OS X Lion的发布,似乎Safari重获新生,Safari是其默认浏览器,而像Chrome这样的第三方软件要开始则比较难,Safari还支持更多功能,如多点触控,Reading List(可在iOS及OS X Lion之间同步),这些都是竞争对手所不具备的,但几个月过去,Safari的增长仍旧缓慢,仅仅随着Mac的售出而增加。

而且移动设备的暴涨也应该让Safari市场份额增加才对,可是事实标明Safari市场份额仍无明显增长,而Chrome,和Android,和移动设备没有任何联系的浏览器却迅猛发展。为什么?

为何Safari不如Chrome?

许多人可能会想,这还不简单,Chrome运行于Windows操作系统,而Safari大部分时候都用于苹果自己的系统,Windows .VS. OS X,哪个使用人群广?很显然是前者,所以Chrome当然比Safari发真快,可是,实际上Safari要比Chrome更早登陆Windows。

在2007年六月,Safari for Windows Beta版就已经发布,正式版于2008年三月发布,而Chrome直到2008年的九月才发布,Chrome只用了一年的时间就超过了Safari。

既然不是Window的原因,那又是什么?

大量Benchmark测试表明Chrome不管在网页打开还是JavaScript表现方面,速度都最快。

但是,当Safari发布Windows版的时候,测试结果也是一样的,不管在Mac还是PC上测试,那时候都是最快的,如果仅仅是因为速度,那么Safari在2007年六月的表现就应该和chrome在2008年九月的时候一样。

难道Chrome胜在插件?也许,不过Safari在2010年年中的时候也有了许多插件,当然,Chrome的插件质量更好更丰富,如果这也足够让Safari落后于Chrome,那么开发商们可能早就将游戏植入Chrome,而且,Firefox也先于Chrome和Safari植入插件,现在不也败给了Chrome吗?

很多人抱怨Safari for Windows让人讨厌,自己使用过之后,觉得实际表现介于Firefox及IE之间,尽管测试结果很棒,而苹果最新版本的Safari 5.1仍在继续激怒大家。另外,Safari已经与iTunes绑定在一起有一段时间了,更有理由获得大量市场份额,但似乎很多人下载它但并不是用它。

而另一边,Google对自己的浏览器做了大量宣传,Google.com偶尔会出现Chrome让你下载。

老实说,本人也是Chrome粉丝,Chrome的许多性能是Safari所不具备的。重要的一点就是Chrome全新设计的“新建标签页”,更加可视化,用户可以更方便地管理应用程序、最常访问的网站。页面下方的功能栏上提供了“最常访问的网站”、“应用程序”小标签,点击即可在这两个页面之间进行切换,这是其它浏览器不具备的,也是它的独特之处。

其实具体为什么会这样也没有一个定论,欢迎大家踊跃发言,告诉我们您的观点。

英文原文:TC:Why Has not Safari Skyrocketed Like Chrome Has?

中文翻译:雷锋网编译。

View the original article here

“Java之父”James Gosling

40年前,一个寒冷的冬天,在加拿大一个村庄里,Gosling家的第一个男孩哇哇落地了。家人给他起了名字,叫James。谁也没有想到的是,长大之后,他成为了一个改变计算机语言的天才。

James Gosling从小就喜欢技术,爱鼓捣东西。12岁的时候,他用报废的电话机和电视机中的部件做了一台电子游戏机。附近农民的康拜因(联合收割机)出了问题也常常找他修理。14岁的时候,中学组织到附近大学参观,他记住了大学计算中心的门锁密码,从此开始偷偷地溜进计算中心,学习计算机编程。一年后,大学的天文系招他当了一名临时编程员,编写计算机程序来分析卫星天文数据。

80年代初,James Gosling获得博士学位后到IBM工作,设计IBM第一代工作站。当时,IBM的领导层并不看重工作站项目。失望之余,James Gosling跳槽到了Sun公司。他花了五年功夫领导开发的和OS2很类似的Sun NeWs窗口系统,尽管得到技术界的好评,却未能变成流行的产品。当时他还第一个用C实现的EMACS的所见即所得文本编辑器COSMACS。

在当今这个竞争激烈的软件开发时代,软件设计师一直在试图预测未来软件或者技术的发展趋势。在1990年,Sun公司成立了一个软件设计团队,其中除了James Gosling,还有Patrick Naughton和Mike Sheridan等人,他们合作的项目称为“绿色计划”。他们认为计算机技术发展的一个趋势是数字家电之间的通讯。James开始负责为设备和用户之间的交流创建一种能够实现网络交互的语言。随着大量的时间和金钱投入到“绿色计划”,他们创建了一种语言。这种语言一开始被叫做“Oak”,这个名字得自于Gosling想名字时看到了窗外的一棵橡树。但后来被改为了“Java”。并于1992年9月3日开始应用于Sun工作站的远程遥控。

1994年底,James Gosling参加了在硅谷召开的“技术、教育和设计大会”。他报着试一试的心情向与会者演示了Java的功能。他点击了网页上的一个静止的分子结构图标,一条命令通过互联网送到了几百英里外的网站,下载了一段Java小程序,在本地工作站上开始执行。在几秒钟时间里,原本静止的网页上,一个分子图像以三维动画的方式转了起来。

“哇!”James Gosling听到了全场观众的赞叹声。

不久后,硅谷最大的报纸《圣荷西信使报》在头版刊登了一篇专文,“为什么Sun认为一杯热咖啡能让你鼓足精神”。从文章见报开始,负责Java市场人员的电话响个不停。不久,全美的主要报刊杂志都刊登了Java的报道。

Java出名了!

到了2000年,Java已经成为世界上最流行的电脑语言。绿色小组当初设计Java是为了面向数字家庭,支持各种家电设备。他们没有想到的是,Java支持的计算模式,实际上就是互联网的模式。

对于Java语言的巨大成功,没有人比James Gosling 更加谦逊:“我从来没有想到Java技术将会这么火。当我的老板问我它将达到多少次下载时,我说 10,000 次。而他认为我太过乐观了。”

java udp广播代码示例

应用场景: 一个学校,每当下课时间到了提供提示下课功能。

分析:用UDP实现广播向同网段电脑发送数据,客户端接受接受到数据后,弹出提示对话框。服务端需要一个循环来判断时间是否到下课时间,这里如果用死循环,很占系统资源,我测试CUP在100%,用java的Timer类可以很好的解决这个问题,既能保证程序始终运行,又不怎么占系统资源,具体什么原理,没有仔细研究过。下面来看代码具体实现

服务段代码:

import java.io.IOException;  
import java.net.DatagramPacket;  
import java.net.DatagramSocket;  
import java.net.InetAddress;  
import java.net.SocketException;  
import java.net.UnknownHostException;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.Timer;  
public class UdpSend {  
    public void sendData()throws SocketException,  
    UnknownHostException{  
        DatagramSocket ds = new DatagramSocket();// 创建用来发送数据报包的套接字  
        String str = "1";  
        DatagramPacket dp = new DatagramPacket(str.getBytes(),  
                str.getBytes().length,  
                InetAddress.getByName("255.255.255.255"), 3001);  
        // 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号  
        try {  
            ds.send(dp);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        ds.close();  

    }  
    public static void main(String[] args) {  
        Timer timer = new Timer();  
        timer.schedule(new MyTask(), 1000, 1000);  
    }  
    static class MyTask extends java.util.TimerTask{   
        @Override  
        public void run() {   
            UdpSend tt = new UdpSend();  
            Date d = new Date();  
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");  
            String strdate = sdf.format(d);  
            String[] classTime = {"17:18:00","17:19:00","17:20:00"};  
            for(int i = 0;i<classTime.length;i++){  
                 if(classTime[i].equals(strdate)){  
                     try {  
                        tt.sendData();  
                    } catch (SocketException e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    } catch (UnknownHostException e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    }  
                 }  
            }     
        }  
    }  
}

客户单简单代码示例,没有做循环

package udp;  
import java.net.DatagramPacket;  
import java.net.DatagramSocket;  
public class UdpRecv {  
    public static void main(String[] args) throws Exception {  
        DatagramSocket ds = new DatagramSocket(3001);// 创建接收数据报套接字并将其绑定到本地主机上的指定端口  
        byte[] buf = new byte[1024];  
        DatagramPacket dp = new DatagramPacket(buf, 1024);  
        ds.receive(dp);  
        String strRecv = new String(dp.getData(), 0, dp.getLength()) + " from "  
                + dp.getAddress().getHostAddress() + ":" + dp.getPort();  
        System.out.println(strRecv);  
        ds.close();  
    }  
}

 

Java开发WebService实例–计数器

如果使用GOOGLE、BAIDU等搜索工具,搜索WebService的相关知识,可以查到N多的网页,我就是通过这些网页的学习,逐渐掌握了些WebService的相关知识。这里对那些无私奉献知识的人一并表示感谢。

网上关于WebService的例子,多是一些简单得不能再简单的hello world的例子,简单得以至于你对WebService没有什么感觉。有了WebService的基本知识后,我一直再想,可以把什么样的即简单又实用 的东东做成WebService,开展示一下其功能特点。今天终于想到一个:计数器,计数器用得比较多,功能比较独立,做成WebService可以一劳 永逸为不同系统(不管是JSP还ASP,这是WebService的突出优点)、不同应用节省此类编码工作,可以说以后再也不用写计数器了。只要用就行 了。

说了这么多废话,下面我们开始。本教程介绍一下WebService环境搭建、服务部署的相关知识,然后介绍一个计数器的开发。

运行图:

二、基础工作

1.开发环境
我使用axis做为Web Service引擎,它是Apache的一个开源web service引擎。它目前最为成熟的开源web service引擎之一。下面我主要介绍一下如何使用Axis搭建web service 服务的环境。
①安装tomcat5.0应用服务器(也可以装5.5,不过我一直在用5.0);
②解压下载( http://ws.apache.org/Axis)后的axis包,将包中axis目录复制到tomcat目录下的webapps目录下;
③将axis/WEB-INF/lib目录下类文件复制到tomcat目录下的common/lib目录下;
④重新启动tomcat,访问http://localhost:8080/axis/happyaxis.jsp,如果能访问,表示安装成功;
注意,axis有几个可选的包,如email.jar….,你可以找来放到tomcat目录下的common/lib目录下,如果不使用相关的功能也可以不用。
这样,开发环境就搭建好了。

2.如何部署Web Service
部署有三种方式:Dynamic Invocation Interface(DII)、Stubs方式、Dynamic Proxy方式;这里就介绍一下简单,也是我使用的方式:DII。
DII方式中,先写好服务的JAVA文件(假设名字为helloworld.java),然后把它(注意是源文件)拷贝到webapps/axis目录 中,后缀改成jws(此时文件名为:helloworld.jws),然后访问连接http://localhost: 8080/Axis/helloworld.jws?wsdl,页面显示Axis自动生成的wsdl,这样一个Web Service就部署好了。怎么样,是不是很简。
我的计数器服务就是以这种方式部署的,下文中我会只说将计数器服务部署好,你可不要说:怎么部署,我不会呀。那在古代就要被打手板了。所以我想,古代只学四书五经也是件好事呀。现在要学这么多东西,半天学不会,手要被打烂了。

三、计数器服务的编写
计数器大家都知道了,比较简单。我的计数器也同样简单,有以下功能及特点:提供四种计数器(总数器、月计数器、周计数器及日计数器);考虑到Web Service要服务于多种应用,这个计数器还支持多个用户;使用XML文件来记录数据。
记录文件名为:d:”counter.xml。注意,此文件在服务里是硬编码,如果修改名字,请在服务程序中也进行相应的修改。文件内容格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<counter>
<item>
<name>wallimn</name>
<password>123</password>
<dc>59</dc>
<wc>59</wc>
<mc>59</mc>
<tc>59</tc>
<rt>2007-4-16 16:01:29</rt>
</item>
<counter>

说是计数器服务,其实跟编写普通的JAVA应用没有什么两样。我的计数器代码比较简单,我就不做过多的介绍了,把它贴在下面,源码中有少量注释,相信大家不看注释也看得懂。服务有只有一个接口:Counter(String name, String password),以后在客户端拿来用就可以了。还多说一句,我和程序使用到了dom4j解析xml包,要调试的请自行准备好jar包。部署方法请参照上文。

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
/**
*功能:提供计数器服务的WebService,可以为多用户提供服务。<br/>
* @version : V1.0
* @author : 王力猛(Email: wallimn@sohu.com QQ: 54871876)
* @date : 2007-4-16 下午04:32:45
*/
public class WsCounterByWallimn {
//计数器文档,注意名字名路径。
private final String FileN = "d:/counter.xml";
private final static DateFormat DATEFORMATER = DateFormat.getDateTimeInstance();
//出错的情况下返回的值
private final static String ERRORINFO="-1;-1;-1;-1";
public WsCounterByWallimn(){ }

/**
*功能:打开计数器文档<br/>
*编码:王力猛 时间:2007-4-16 下午04:44:29<br/>
*/
private Document openDocument(){
Document doc=null;
SAXReader reader = new SAXReader();
try {
File xmlfile = new File(FileN);
doc = reader.read(xmlfile);
xmlfile=null;
} 
catch (DocumentException e) {
e.printStackTrace();
}
return doc;
}

/**
*功能:取指定名称计数器的详细信息,并设置计数器加1。<br/>
*编码:王力猛 时间:2007-4-16 下午04:49:57<br/>
*/
private synchronized String countertick( String name, String password){
Document doc = openDocument();
Date currdt = new java.util.Date();
//mc:month counter(月计数器); dc: day counter(日计数器); 
//tc: total counter(总计数器); wc: week counter(周计数器);
//rt: registe time登记时间
String mc="-1",dc="-1",tc="-1",wc="-1",rt="-1";
Element root = doc.getRootElement();
Element selitem=null,item=null;
for(Iterator it = root.elementIterator("item"); it.hasNext();){
item = (Element)it.next();
if(name.equals(item.element("name").getText())){ 
selitem=item;
String pwd = item.elementText("password");
if(!password.equals(pwd)){
return ERRORINFO;//密码不对,直接返回
}
mc=item.element("mc").getText();
dc=item.element("dc").getText();
tc=item.element("tc").getText();
wc=item.element("wc").getText();
rt=item.element("rt").getText();
break;
}
}

//如果selitem为空,说明没有个名字的计数器。则添加一个。
if(selitem==null){
//System.out.println("没有找到这个名字的计数器:"+name);
rt=DATEFORMATER.format(currdt);
selitem = doc.getRootElement().addElement("item");
selitem.addElement("name").setText(name);
selitem.addElement("tc").setText("0");
selitem.addElement("mc").setText("0");
selitem.addElement("wc").setText("0");
selitem.addElement("dc").setText("0");
selitem.addElement("rt").setText(rt);
selitem.addElement("password").setText(password);
mc="0";
wc="0";
dc="0";
tc="0";
}

//处理计数器加一操作。
Calendar currcr=Calendar.getInstance();
//总数器总是加1。
tc =String.valueOf(Integer.parseInt(tc)+1);
selitem.element("tc").setText(tc);
Date lastdt = null;
try {
lastdt = DATEFORMATER.parse(rt);
} 
catch (ParseException e) {
lastdt = new java.util.Date();
}
Calendar lastcr = Calendar.getInstance();
lastcr.setTime(lastdt);
currcr.setTime(currdt);
//System.out.println("上次登记时间:"+DATEFORMATER.format(lastdt));
//System.out.println("本次登记时间:"+DATEFORMATER.format(currdt));
if(lastcr.get(Calendar.YEAR)==currcr.get(Calendar.YEAR)){
//月相同,月计数加1
if(lastcr.get(Calendar.MONTH)==currcr.get(Calendar.MONTH)){
mc = String.valueOf(Integer.parseInt(mc)+1);
}
else{
mc="1";
}
//日相同,日计数加1
if(lastcr.get(Calendar.DAY_OF_YEAR)==currcr.get(Calendar.DAY_OF_YEAR))
dc = String.valueOf(Integer.parseInt(dc)+1);
else
dc = "1";

if(lastcr.get(Calendar.WEEK_OF_YEAR)==currcr.get(Calendar.WEEK_OF_YEAR))
wc = String.valueOf(Integer.parseInt(wc)+1);
else
wc = "1";
} 
else{//年不一样,则月计数器、周计数器日计数器肯定也不一样。
mc="1"; dc="1"; wc="1"; 
}
selitem.element("mc").setText(mc);
selitem.element("wc").setText(wc);
selitem.element("dc").setText(dc);
//登记记录时间
selitem.element("rt").setText(DATEFORMATER.format(currdt));

try {
XMLWriter xw = new XMLWriter(new FileWriter(FileN));
xw.write(doc);
xw.close();
} 
catch (IOException e) {
e.printStackTrace();
} 
return tc+";"+mc+";"+wc+";"+dc;
}
/**
*功能:服务暴露的接口,也就是指定名称、密码,返回指定的计数,并将计数器加1。<br/>
*编码:王力猛 时间:2007-4-17 上午10:05:22<br/>
*/
public String Counter(String name, String password){
if(password==null ¦¦ name==null)return ERRORINFO;
return countertick(name, password);
}
}

四、客户端编写
客户端是个页面,为了条理清晰,我先写个调用Web Service的类,其内容如下:

package com.wallimn.WebService;//调试请注意包名

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

public class CounterServiceClient {
private String counterarr[];

public boolean getCounter(String CounterName, String password) {
boolean res = false;
try {
String endpoint = "http://localhost:8080/axis/WsCounterByWallimn.jws";//此处注意,请与你的开发环境匹配
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("Counter");
// 填写你要调用的方法名称
String counter = (String) call.invoke(new Object[] { CounterName, password });
counterarr = counter.split(";");
res = (counterarr != null && counterarr.length == 4);
} 
catch (Exception e) {
}
return res;
}

public String getDc() {
return counterarr[3];
}

public String getMc() {
return counterarr[1];
}

public String getTc() {
return counterarr[0];
}

public String getWc() {
return counterarr[2];
}
}

到页面(test.jsp)上就简单了,我也把它贴在下面:

<%@ page language="java" import="com.wallimn.WebService.CounterServiceClient" pageEncoding="GB18030"%>
<%
CounterServiceClient client = new CounterServiceClient();
client.getCounter("hello","123");
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>计数器测试页面</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0"> 
<meta http-equiv="keywords" content="wallimn,计数器,WebService">
<meta http-equiv="description" content="计数器使用示例">
</head>

<body>
<h2 align="center">计数器详情</h2>
<hr/> 
总访问量:<%=client.getTc()%> <br/>
今天访问量:<%=client.getDc()%> <br/>
本周访问量:<%=client.getWc()%> <br/>
本月访问量:<%=client.getMc()%> <br/> 
<hr/> 
<p>欢迎交流<br/>博客:http://blog.csdn.net/wallimn<br/>电邮:wallimn@sohu.com</p>
</body>
</html>

 

五、结束语

至此一个完整计数器的Web Service开发、使用的程序的全部完成了。将上面的类、及页面部署到任意的一个上下文中,通过浏览器打开test.jsp,就可以看了结果了。
欢迎访问我的博客(http://blob.csdn.net/wallimn)留言或发邮件(wallimn@sohu.com)交流。

java面试之i++

i++ 和++i使用的不同点是i++是程序完毕后自增,++i是程序开始前自增。++i好理解,但i++我还理解不好,程序完毕后自增,怎么算是程序执行完呢?

  int l = 0;     
      l = l++;
      System.out.println(l);

这样l会不会自增呢? 答案不会。l为0

  int l = 0;
      l = l++ + 8;
      System.out.println(l);

这样呢? 答案也不会自增,l为8

那么什么情况下l会自增呢?什么情况下叫做程序完毕后自增呢?

int l = 0;
      l = l++ + l;
      System.out.println(l);

这样才会自增,l为1。
总结:只有i++之后遇到含有i的表达式时才会自增。

看几个示例:

package plusplus;
public class Test {
    public static void main(String[] args) {
      int i = 0;
      i = i++ + ++i;
      System.out.println(i);
      int j = 0;
      j = ++j + j++ + j++ + j++;
      System.out.println(j);
      int k = 0;
      k = k++ + k++ + k++ + ++k;
      System.out.println(k);
    }
}

分析i=i++ + ++i;
先执行i++,i为0,再执行++i,i为1,所以i=0+1=1,但i++操作还要自增,所在最后i=2;

分析j = ++j + j++ + j++ + j++;
j =   1 + 1   + 2   + 3 = 7

分析k = k++ + k++ + k++ + ++k;
k = 0   + 1   + 2   +  4  = 7

java笔试:记录自己的java笔试题目java written examination

java笔试是初级开发人员必过的一道门槛。这一段找工作,参加了很多java笔试,顺便把面试的题目记录下来。

一.java笔试之读txt文件

1.java笔试读txt文件方法一

import java.io.File;
import java.io.FileReader;
public class ReadTxt {
    public static void main(String[] args) {
        File f = new File("D:/sql.txt");
        try {
            FileReader fr = new FileReader(f);
            char[] temp= new char[(int)f.length()];
            fr.read(temp);
            StringBuffer sb = new StringBuffer();
            for(int i=0;i<temp.length;i++){
                sb.append(temp[i]);
            }
            System.out.println(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.java笔试读txt文件方法2

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class ReadTxt1 {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("D:/sql.txt");
            BufferedReader br = new BufferedReader(new InputStreamReader(fis));
            String s;
            StringBuffer sb = new StringBuffer();
            while((s = br.readLine())!=null){
                sb.append(s + " /n");
            }
            System.out.println(sb.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

对于java笔试,一定要端正态度,这些都是基本功,不要像我当时,碰了很多钉子,才知道回头抓基本功。

如何防止同一个用户在不同机子上登陆

用户在主机a上登陆后在表log中存记录userId,sessionIda
同时
用户在主机b上登陆后在表log中更新记录userId,sessionIdb
这样使log表中总是保存最新的userId和sessionId,

然后,可一个拦截器,拦截用户的请求,对比log表中的session,
如果sessionId不一致,就把这个用户的session废掉validate.
这样,就会踢掉先前登陆的用户。

不知道还有没有更好的方法。

BaseDAO

package com.daacc.dao;

import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class BaseDAO extends HibernateDaoSupport {

    /**
     * 使用hql 语句进行分页查询操作
     * 
     * @param hql
     *            需要查询的hql语句
     * @param offset
     *            第一条记录索引
     * @param pageSize
     *            每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql, final int offset,
            final int pageSize) {

        List list = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                List result = session.createQuery(hql).setFirstResult(offset)
                        .setMaxResults(pageSize).list();
                return result;
            }
        });
        return list;
    }

    /**
     * 使用hql 语句进行分页查询操作
     * 
     * @param hql
     *            需要查询的hql语句
     * @param value
     *            如果hql有一个参数需要传入,value就是传入的参数
     * @param offset
     *            第一条记录索引
     * @param pageSize
     *            每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql, final Object value,
            final int offset, final int pageSize) {

        List list = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                List result = session.createQuery(hql).setParameter(0, value)
                        .setFirstResult(offset).setMaxResults(pageSize).list();
                return result;
            }
        });
        return list;
    }

    /**
     * 使用hql 语句进行分页查询操作
     * 
     * @param hql
     *            需要查询的hql语句
     * @param values
     *            如果hql有多个个参数需要传入,values就是传入的参数数组
     * @param offset
     *            第一条记录索引
     * @param pageSize
     *            每页需要显示的记录数
     * @return 当前页的所有记录
     */
    public List findByPage(final String hql, final Object[] values,
            final int offset, final int pageSize) {

        List list = getHibernateTemplate().executeFind(new HibernateCallback() {
            public Object doInHibernate(Session session)
                    throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                for (int i = 0; i < values.length; i++) {
                    System.out.println("in BaseDAO:values[" + i + "]:"
                            + values[i]);
                    query.setParameter(i, values[i]);

                }
                List result = query.setFirstResult(offset).setMaxResults(
                        pageSize).list();
                return result;
            }
        });
        return list;
    }

    public int findMaxIdFromObj(String obj) {

        String hql = "select max(id) from " + obj;
        System.out.println("hql:" + hql);
        List maxlist = (List) getHibernateTemplate().find(hql);
        System.out.print(maxlist.get(0).toString());
        return Integer.parseInt(maxlist.get(0).toString());
    }

}