使用java调用新浪微博开发api进行通信

注:本文代码已失效,请不要模仿之,其他方式请参考 使用scribe方式
最近研究了下新浪微博的开发api,尝试在某些客户端应用中也能够调用相应的api发送新浪微博,经过一番的尝试,最后成功。现将其中的几个关键点,以及相应的demo公示如下,供大家了解。
在本文中,主要演示了如何通过用户名/密码的方式,连接上新浪微博,然后读取最新的微博信息,最后演示如何发送一条简单的微博,其它的都可以通过相应的微博api进行处理,这里就没有仔细深入了。

首先得申请开发者授权,也就是你得在新浪上申请一个应用。直接通过地址为:http://open.weibo.com/,使用你的微博帐号登陆之后,创建一个应用即可。创建应用的目的在于获取相应的app Key和app Secret,在后面的主要api中,均会使用到app key,以便于新浪官方跟踪请求来源。具体流程,请google之。

申请好了之后,我们就开始我们的api之旅了,在本文中,没有使用官方提供的java sdk,因为主是简单的demo,如果是应用开发,还是可以下载相应的java sdk应用的,可以查看其中的example,了解如何进行调用。

本文使用了httpclient,使用maven的话,可以使用groupId为commons-httpclient,artifactId为commons-httpclient将其导入到工程中。其次,为了便于解析返回的数据,使用了JSON组件(fastjson),用于解析json字符串。

继续阅读“使用java调用新浪微博开发api进行通信”

使用监控技术实现tomcat的按需要进行重启

    我们经常需要碰到这种情况,当用户提出一个问题,并且我们已经修改之后,已经由自动更新系统更新到客户方,但这时需要重新启动tomcat才能使新修改的代码工作。这时候,就要想办法来重新启动这个tomcat了。
    有的同学提到一个使用tomcat控制台重新部署项目的想法,但是通过这种方法,有时候并不能有效地进行部署,因为可能存在非守护进程不能完全退出,以及有些资源未能正确回收的问题。相比来说,直接重启tomcat来得更方便一些。

    在前面已经说到,实现项目的自动更新,是利用embeded tomcat来进行重新启动来完成的,这中间实现tomcat在指定时间更新并重启的功能是使用类似监听技术来实现的。即在客户机器上,同时部署了两个组件,一个为运行我们项目的tomcat,另一个则为监控项目代码的java监听器。此监听器用于在指定时间监听项目代码是否有更新,如果有更新,则使用svn进行更新,并重新启动tomcat。相应的代码如下所示:

	private void updateAndRestart() throws Exception {
		logger.log(Level.INFO, "准备执行更新线程......");
		if(hasUpdate(svn)) {
			logger.log(Level.INFO, "发现更新,准备重新启动tomcat......");
			shutdownTomcat();
			logger.log(Level.INFO, "成功关闭tomcat,正在重起");
			startTomcat();
			logger.log(Level.INFO, "重起tomcat成功......");
		} else
			logger.log(Level.INFO, "无有效更新......");
	}

    这样的代码,即实现了tomcat的更新和重启操作,惟一不足的是这段代码并不能接收来自于网页上的命令实现按需要重启,它只能在规定的时间(如每天24点)进行操作。
    有的同学,想到如果将这个监听器做成一个类似项目的服务并启动, 即可以实现效果了。但实际的问题时,对于项目来说,通过路由器打开太多的端口是有害而无利了。我们已经打开了80端口用于项目访问,最好不要再打开其它端口了。

    本文描述了一个在项目代码中增加用于实现重启的功能代码,并通过socket请求访问监听器并通过监听器来重启项目tomcat的实现。

    实现原理如下:

  1.     监听器监听指定端口,进行监听操作
  2.     由项目向外提供重启功能界面,通过功能界面进行操作
  3.     项目的重启功能向监听器指定端口发送重启指令
  4.     监听器接收到相应socket请求,即执行重启操作

继续阅读“使用监控技术实现tomcat的按需要进行重启”

解决使用struts2标签s:url以及s:a时中文产生乱码的问题

    在平常使用web框架进行web开发时,经常讨论的一个问题就是一个中文的乱码问题。一般情况下,包括get乱码和post乱码,都能很好的解决,只需要通过配置tomcat以及增加相应的filter即可。但如果,本身tomcat并不参与解析编码时,即就不能很好地解决了。

    通常在使用一些链接时,我们偶尔会显式地传递一些中文的参数,用于显式查询。如下面的一段url地址(使用源代码查看时的链接地址):

/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=销售&startDate=2011-07-01&endDate=2011-07-13

    这个地址在参数中直接带了一个中文的参数"销售",那么这个参数传递在服务器端时,采用的何种编码进行传递的呢。如果使用firefox,我们会看到firefox将其转化为gbk编码进行传输,如下所示:

http://localhost:4444/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=%CF%FA%CA%DB
&startDate=2011-07-01&endDate=2011-07-13

    值得注意的是,这个转换是由firefox在界面上直接进行转换的,即在源代码中查看为"销售"的中文,在界面上转换时就自动转换成了%CF%FA%CA%DB。
    而使用ie时,则不会发生转换,也就是说,ie直接发送中文信息到服务器端,地址信息即会变为:

/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=销售&startDate=2011-07-01&endDate=2011-07-13

    这个和在源代码中看到的是一样的。

    正常情况下,这两种情况都不会有问题,对于firefox,因为已经转换为gbk的url编码格式,在由tomcat进行转码时,会自动转换为CFFA CADB(即销售的gbk编码形式);对于ie,由于是直接发送,传递到tomcat时就是CFFA CADB的编码,经由gbk转换,自然就变成了正确的形式。即在底层发送时,对于"销售"这个中文参数值,firefox发送为%CF%FA%CA%DB,而ie发送为CFFACADB(字节流方式),两者在经由tomcat的gbk编码转换时,都没有问题。

    问题出现在哪儿,当需要在浏览器上,重现当前请求的地址时,即将刚才请求的地址信息,重新显示在界面上(通常这种应用在分页上用得多,即整个请求地址不变,只替换其中的分布参数信息)。这时候,在使用struts2的<s:url/>标签时以及<s:a/>标签时,就会出问题了。
    如在分页应用时,ie在地址栏出现的中文参数,在使用分页重新进行地址引用时,就会出现如下的结果:
    问题就出现在struts2对于url标签,在进行地址重现时的处理手段上,在解析地址信息时(通常是get形式),它并没有使用标签的getParameter形式,而是使用了getQueryString形式。

继续阅读“解决使用struts2标签s:url以及s:a时中文产生乱码的问题”

(转)java编码问题详解

    本文转自:http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/index.html?ca=drs- (原文作者 许令波)

    编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多。本文将向你详细介绍 Java 中编码问题出现的根本原因,你将了解到:Java 中经常遇到的几种编码格式的区别;Java 中经常需要编码的场景;出现中文问题的原因分析;在开发 Java web 程序时可能会存在编码的几个地方,一个 HTTP 请求怎么控制编码格式?如何避免出现中文问题?

    为什么要编码
    不知道大家有没有想过一个问题,那就是为什么要编码?我们能不能不编码?要回答这个问题必须要回到计算机是如何表示我们人类能够理解的符号的,这些符号也就是我们人类使用的语言。由于人类的语言有太多,因而表示这些语言的符号太多,无法用计算机中一个基本的存储单元—— byte 来表示,因而必须要经过拆分或一些翻译工作,才能让计算机能理解。我们可以把计算机能够理解的语言假定为英语,其它语言要能够在计算机中使用必须经过一次翻译,把它翻译成英语。这个翻译的过程就是编码。所以可以想象只要不是说英语的国家要能够使用计算机就必须要经过编码。这看起来有些霸道,但是这就是现状,这也和我们国家现在在大力推广汉语一样,希望其它国家都会说汉语,以后其它的语言都翻译成汉语,我们可以把计算机中存储信息的最小单位改成汉字,这样我们就不存在编码问题了。

    所以总的来说,编码的原因可以总结为:

  1. 计算机中存储信息的最小单元是一个字节即 8 个 bit,所以能表示的字符范围是 0~255 个
  2. 人类要表示的符号太多,无法用一个字节来完全表示
  3. 要解决这个矛盾必须需要一个新的数据结构 char,从 char 到 byte 必须编码

继续阅读“(转)java编码问题详解”

一定要为HttpUrlConnection设置connectTimeout属性以防止连接被阻塞

    我们有一个项目中用到了多个子项目,即将多个子项目的连接地址整合在一起。在客户部署环境中,有一个主终端,负责接受用户登陆,在登陆时,由用户选择最终要登陆的子系统。当输入登陆信息之后,由主终端负责解析用户名和密码,待验证通过之后,再通过主终端负责将用户信息直接发往子系统并通过子系统接口转入到后台操作界面。整个流程就类似于一个统一授权中心,由主终端负责用户授权和访问,在获得授权之后,就可以直接操作子系统了。
    前几天在客户方将数据copy回来并进行分析时,发现在首页显示其它子系统时非常的慢,甚至慢到不能忍受的地步。但这种情况在客户环境中并没有发现。待仔细地查看了数据逻辑处理,发现了后台在列举子系统数据时,首先需要判断当前的子系统是否能够连接,即有一个如下的连接代码:

/** 指定的子系统是否是断开连接的 */
	public static boolean isOffline(SubSystem subSystem) {
		String url = subSystem.getRequestAddress();
		try {
			URL requestURL = new URL(url);
			HttpURLConnection urlConnection = (HttpURLConnection) requestURL.openConnection();
			urlConnection.connect();
			urlConnection.disconnect();
			return false;
		} catch(Exception ignore) {
			return true;
		}
	}

    就是由于这段代码,导致系统长时间停留在这段处理代码中。发现代码在处理connect时,半天无法响应。由于数据是在客户方copy回来了,所要连接的子系统的ip地址为192.168.1.99,而当前在笔者机器的ip为192.168.0.*,即在连接子系统时会无法连接,但这个连接不到所返回的时间也太长了。
    笔者测试了下时间,这段连接不的代码在windows下的异常时间(即开始连接到发生异常的时间)为20秒,而linux下这个时间就长了,达到了180秒,即java要经过180秒才能发现这个连接根本就连接不上。
    笔者又在cmd下通过ping,来测试一下连接时间,也是发现连接时间长时间也没有响应。

继续阅读“一定要为HttpUrlConnection设置connectTimeout属性以防止连接被阻塞”

web应用中服务器端不能终止客户端继续上传的验证

    在查看iteye的时候,发现了这么一个帖子:文件上传:服务器如何终止客户端继续上传。在原文中,提到了这么一个问题:该场景为:当上传文件不满足要求(服务器端检查:如文件超过大小限制,扩展名不正确等),服务器在等待文件上传完成之前立即返回,目的是终止浏览器继续上传。
    这样就不必需要待到客户端在把所有数据都上传到服务器端之后,再给客户端返回一个上传不合法的提示,同时,这也是一个避免大量战胜客户端内存和服务器端内存的一个方法。
    然而实际情况,并非如此,尽管在服务器端已经关闭了接收客户端上传数据的流,并且已经返回了结果,但这并不能阻止客户端继续上传未上传的数据。究其原因,还是因为在服务器端,处理的输入流并不是直接表示当前请求的输入流,关闭一个请求处理的输入流并不代表关闭此次请求的输入流,所以客户端仍然会继续上传剩下的数据。

    笔者做了一个简单的测试,在本机建立一个使用struts2的应用,设定最大上传数据大小为6*1024*1024(即6M)大小。当上传一个大于6M的数据时,服务器端报如一个数据过大的异常。但这并不能演示客户端的情况。于是,将上传数据扩大为600M(即一个oracle的安装文件)。在这次,服务器快速的返回了,然而客户端浏览器确已不再有反应了,进度条还在继续,还在上传中。过了好一会儿,才最终显示由服务器端返回的数据。

    在帖子中,提到一个处理这种问题的方法,即想办法找到表示当前请求的socket,当数据不合法时,直接关掉当前的socket,来关掉此次请求。由于笔者使用的是tomcat作为一个web应用服务器,所以通过反射的方法 找到了当前请求的socket,然后直接关掉此socket,来演示一下直接关掉请求的结果。处理代码如下所示:在JakataMultiPartRequest的parse(HttpServletRequest servletRequest, String saveDir)方法中,通过在catch异常的处理结果中添加以下处理代码:

try {
                Field field = RequestFacade.class.getDeclaredField("request");
                field.setAccessible(true);
                InputStream inputStream = ((InternalInputBuffer)((Request)field.get(( ((RequestFacade)servletRequest))))
            .getCoyoteRequest().getInputBuffer()).getInputStream();
                Field sf = inputStream.getClass().getDeclaredField("socket");
                sf.setAccessible(true);
                Socket socket = (Socket)sf.get(inputStream);
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("too long to upload".getBytes());
                outputStream.flush();
            inputStream.close();
            }catch(Exception ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex);
            }

    即直接关掉在tomcat中表示当前请求处理的socket。有了这个之后,界面上的反应确实有变化了。
   
    在以上代码中,本意是想在数据超过大小的时候,往客户端写一条数据信息,并关掉当前socket(关掉inputStream即可关掉当前socket),并期望浏览器上显示这里回显的数据。然而,结果并不是这样,实际的结果如下:

    因为请求socket被关闭了,所以界面上直接显示以上信息,即连接被关闭了,并没有出现想要的结果。

继续阅读“web应用中服务器端不能终止客户端继续上传的验证”