Overview1.问题所在2.解决办法2.1 文件改名(不推荐)2.2 直接指定密钥文件(推荐) Overview 前些天用ssh通过命令行登录我们的bastion4服务器还一切正常，到了昨天已经不能使用，但是用了相同的密钥的FileZilla依然可以登录，这就很奇怪了。 1.问题所在 用FileZilla登录到远程服务器，找到ubuntu用户下面的.ssh文件夹，打开之后可以看到只有一个文件authorized_keys，我把它下载下来。完成之后，我到本机的/home/young/Downloads文件夹里找到它，打开看到我的密钥已经添加进去了，看来是FileZilla可以找到本地/home/young/.ssh/BingjiaoYang_ssh这个文件，但是默认的 ssh ubuntu@bastion4.erc.monash.edu 命令现在已经找不到这个文件了。 经过Jerico和Chris两个人的指点，使用如下命令: ssh -vvv ubuntu@bastion4.erc.monash.edu 显示日志信息如下(只截取最后核心信息)： debug1: Next authentication method: publickey debug1: Trying private key: /home/young/.ssh/id_rsa debug3: no such identity: /home/young/.ssh/id_rsa: No such file or directory debug1: Trying private key: /home/young/.ssh/id_dsa debug3: no such identity: /home/young/.ssh/id_dsa: No such file or directory debug1: Trying private key: /home/young/.ssh/id_ecdsa debug3: no such identity: /home/young/.ssh/id_ecdsa: No such file or directory debug1: Trying private key: /home/young/.ssh/id_ed25519 debug3: no such identity: /home/young/.ssh/id_ed25519: No such file or directory debug2: we did not send a packet, disable method debug1: No more authentication methods to try. Permission denied (publickey). 意思就是找不到/home/young/.ssh/id_rsa这个文件。 2.解决办法 解决办法有如下两个。 2.1 文件改名(不推荐) 把/home/young/.ssh/BingjiaoYang_ssh这个文件改名为id_rsa,同时把/home/young/.ssh/BingjiaoYang_ssh.pub这个文件改名为id_rsa.pub,这时候再用原命令登录就没有问题了。但是这个解决办法明显没有看透本质，所以推荐下一种。 2.2 直接指定密钥文件(推荐) 在命令行中直接输入ssh，可以看到ssh的用法： ➜ ~ ssh usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q cipher | cipher-auth | mac | kex | key] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command] 可以看到，我们可以之间指定文件，来解决找不到文件的问题。所以，正确命令如下： ssh ubuntu@bastion4.erc.monash.edu -i /home/young/.ssh/BingjiaoYang_ssh 以后就没有问题出现了。 还有一个问题有些人可能会困惑：为什么Filezilla仍然可以正常登录？ 原因就在于，我们在首次用Filezilla登录时，会根据密钥文件生成一个BingjiaoYang_bastion4文件，以后Filezilla每次登录都会根据这个文件读取信息，一旦这个文件换了位置或者被删除，FileZilla一样会无法登录。 更多关于远程登录服务器的细节，参考Chris的文章：部署PhosphoPrediction。 最后，感谢Chris和Jerico的热心帮助。
Overview1. 初识Hibernate Overview 这里只是总结一下secretepdb这个项目用到的Hibernate的特性，Hibernate本身细节极其多，不太可能全部记得下来，也没有必要去记，用到的时候去查就可以了，而且Hibernate的设计也都是很符合常理的，所以用正常的思维去想，一般都能理得顺。 1. 初识Hibernate
Overview2.1 需要的jar库2.1.1 Struts2接口包2.1.2 Json需要的包2.2 集成配置2.2.1 前端js请求2.2.2 配置struts.xml2.2.3 StatisticsAction2.2.4 再看前端js2.3 JSON简介 Overview secretepdb这个项目需要展现一些统计图表，我们使用了google的gchart，图表的数据源从数据库异步获取。这里就用到了Struts2和Jquery Ajax的集成。本身都是很规范的东西，应该不会出什么问题，但是特定条件下里面有个坑，在这里梳理一遍。 既然是Struts2跟Ajax集成，肯定也会用到Struts2本身的一些东西，可以先看看我之前写的：Struts2总结 这篇文章，接下来可能就好读一些。 与 Struts2总结 中提到的一样，本文使用的依然是struts-2.3.24.1。 2.1 需要的jar库 2.1.1 Struts2接口包 Struts2内置提供了对各种插件的支持，比如dojo，json，sitemesh等，并在doc文件夹中中提供了帮助文章，doc/struts2-plugins这个文件夹中就是所有支持的插件的帮助文档。 我们跟Ajax通讯所需要的就是就是struts2-json-plugin这个插件，等等...我们是要集成Ajax，可为什么要集成struts2-json-plugin这个看起来毫不相关的插件呢。这是因为，异步传输的通讯方式本身Struts2就支持，配置下struts.xml就可以实现，但是JAVA后台跟前端传输需要使用Json格式传输，而JAVA对象和Json格式的相互转换，就需要用到专有的Json包，所以Struts2提供了下面的插件： struts2-json-plugin-2.3.24.1.jar 这个插件也可以从struts-2.3.24.1的官方下载包的struts-2.3.24.1-all.zip中的lib文件夹中找到。 2.1.2 Json需要的包 处理Json格式需要使用下面的包： json-lib-2.4-jdk15.jar 因为Json包是独立的存在，所以jar的版本号跟Struts2没什么联系。整体来看就是，Struts2和Json都是独立存在的，而Struts2提供了一个插件包，用来将Json集成到Struts2中。 json-lib-2.4-jdk15.jar本身还依赖下面的包： commons-beanutils-1.8.0.jar commons-lang-2.4.jar ezmorph-1.0.6.jar log4j-1.2.15.jar commons-collections-3.2.1.jar commons-logging-1.1.14.jar 跟Struts2所依赖的包情况一样，除了commons-lang-2.4.jar，其他包版本号都没有限制，最简单的方式就是从struts-2.3.24.1-all.zip中的lib文件夹中找，里面都有，实际上因为依赖包跟Struts2有重叠，只需要添加三个包：commons-beanutils-1.8.0.jar、commons-collections-3.2.1.jar和commons-lang-2.4.jar。 特别需要说明的就是commons-lang-2.4.jar，因为commons-lang-2.4.jar和struts-2.3.24.1依赖的commons-lang3-3.2.jar包名都不同了，所以同时引入不会产生冲突，而json-lib-2.4-jdk15.jar依赖的是struts-2.3.24.1（commons-lang 2.0版本的包都可以），而不是commons-lang3-3.2.jar，如果不引入commons-lang-2.4.jar，不会报错，但是就是没办法成功转化数据格式。 2.2 集成配置 2.2.1 前端js请求 $.ajax({ type:"post", url:"ajaxAction/getDataByTypeStatisticsAction",//需要用来处理ajax请求的action,getDataByType为处理的方法名，StatisticsAction为action名，注意这里的ajaxAction/的写法，后面配置struts.xml的时候会提到。 async: true,//通讯是否需要异步执行，默认是true，也就是异步传输，当执行完$.ajax()函数后，js代码继续向下执行，不会等待结果返回。在这里特别的写出来是因为有时候，比如画图，你需要先拿到数据才能画图，因此这里可以设置为false，这样就可以拿到结果，程序才会执行$.ajax()后的代码。 data:{//向后台传递的参数 name:"Chris", age:5, position:"tt"//这里不要加"," 不然会报错，而且根本不会提示错误地方 }, dataType:"json",//设置需要返回的数据类型 success:function(data){//回调函数，通讯成功会调用此函数，参数data用于接收后台的返回值。 var d = eval("("+data+")");//将数据转换成json类型，可以把data用alert()输出出来看看到底是什么样的结构 //得到的d是一个形如{"key":"value","key1":"value1"}的数据类型，然后取值出来 alert(""+d.name+""); alert(""+d.age+""); alert(""+d.position+""); }, error:function(){//回调函数，通讯失败会调用此函数 alert("系统异常，请稍后重试！"); }//这里不要加"," }); 上面的Js脚本，向名为StatisticsAction的action发送异步传输的请求，并传递了三个参数name、gender和position，并指定了StatisticsAction中的getDataByType方法处理该请求。具体解释已经注释在代码中了，很容易明白。 2.2.2 配置struts.xml struts.xml就是前台和后台的连接，我们已经知道了普通的action请求应该怎么配，下面给出Struts2与Ajax通讯的配置方法： <constant name="struts.devMode" value="true" /> <constant name="struts.action.excludePattern" value="/static/.*?" /> /searchResults.jsp /searchNoResults.html result 这里面有两个地方需要注意： 为了防止混淆，我新建了一个name是ajax的 与原来的并列，并将这个 的namespace属性设置为了/ajaxAction，所以前端在请求的时候就不能直接使用action名字了，而是需要使用/ajaxAction/action名字。 中的name属性是包含通配符的，是为了匹配多action请求，上面Js中请求是url:"ajaxAction/getDataByTypeStatisticsAction"，其中，ajaxAction/前缀使得这个请求映射到了name是ajax的 上，而getDataByTypeStatisticsAction与action中的*StatisticsAction匹配，*部分就指代了getDataByType，action的method="{1}"相当于method="第一个通配符配到的字符串"，也就是method="getDataByType"。 这两个设置，就可以将前台的Js请求，映射到了指定的action的指定方法。 2.2.3 StatisticsAction public class StatisticsAction extends ActionSupport{ //用来接收前端Js的参数，名字与Js中的参数名字必须一致。 private String name; private int age; private String position; //省略了name,age,position的get和set方法，这里只是省略不写，程序中必须要有。 ... //用来存储返回给前端页面的值，需要与struts.xml中配置的名字一致，并且必须有get和set方法。 private String result; public String getResult() { return result; } public void setResult(String result) { this.result = result; } //Js请求的action方法 public String getDataByType() { Map<String,Object> map = new HashMap<String,Object>(); //跟传统的action传值一样，这里的name,gender,position由struts接收前端传参后初始化，在action中直接使用就可以了。 map.put("name", name); map.put("gender",gender); map.put("position", position) //将一个JAVA对象（这里是map对象），转化为一个JSON对象。需要import net.sf.json.JSONArray。 JSONObject json = JSONObject.fromObject(map); //注意，这里的result为String类型，内容为： //"{name:"Chris",age:5,position:"tt"}" result = json.toString(); return SUCCESS; } } 2.2.4 再看前端js 我们回过头再看一个js中的细节，回调函数： success:function(data){//回调函数，通讯成功会调用此函数，参数data用于接收后台的返回值。 var d = eval("("+data+")");//将数据转换成json类型，可以把data用alert()输出出来看看到底是什么样的结构 //得到的d是一个形如{"key":"value","key1":"value1"}的数据类型，然后取值出来 alert(""+d.name+""); alert(""+d.age+""); alert(""+d.position+""); } 因为action返回的是一个String类型的值，所以这里回调函数接收到的data，就是一个String类型的值，但是我们需要的是一个js的对象类型，因此使用了eval("("+data+")")将String类型的值变成了一个js对象，这是一个通用的做法，所有通过json格式传送到前端的对象，都需要转化为js对象。 可见，使用JSON是因为js和JAVA两种语言对于对象的定义都有自己的标准，不可能将JAVA中的对象直接传递给js中使用，因此需要使用JSON这种统一规范的形式，在JAVA端，使用了JSON包提供的JSONObject.fromObject方法，将一个JAVA对象转化为JSON格式的字符串，传递给前端的js，js再使用内置的eval()方法将JSON格式的字符串转化为js的对象，从而实现了JAVA与js之间的对象传递。 2.3 JSON简介 直接看阮一峰写的 数据类型和Json格式 吧，对数据类型和JSON格式解释地简洁又足够好，实在没有理由自己再写一段概念上的介绍。 既然提到阮一峰，不得不推荐一下，黑客与画家的译者，中国少有的文采好，能把技术层面的东西讲的深入浅出的软件开发者。他让我想到了台湾的侯捷先生，有涵养，文化底蕴好，文字写得有情感，不生硬，非常值得学习。 My name is Ruan YiFeng(阮一峰). You can call me Frank. I was born in 1970s. I am an IT developer focusing on web technology, and a strong advocate and believer of Free Software. Now I am employed by Alipay.com as an Node/JavaScript engineer. I have an Economics degree, and once worked for a local college in Shanghai as an assistant professor. In spare time, I like reading book, surfing internet, watching movie and taking a leisurely walk outdoors. 好像有点跑题了，下面给出几个不错的JAVA处理JSON的文章： JSON for java入门总结 在 Java 中使用 JSON Java构造和解析Json数据的两种方法详解二 入门之后也可以直接查看JSON in Java的官方API文档： JSON in Java