全文检索工具-Lucene(solr)入门

最近闲着没事在写微信公众号,其中一个是聊天机器人,和网上的众多机器人原理一样,但是功能没那么强大(主要是只是库不够强大),但是怎么解决“如何根据用户的问题从回答库中找出最匹配的答案呢?”,大家最先想到的也许是数据库的 LIKE 就好了嘛,但是 LIKE 存在如下问题: 在问答库非常庞大的时候,LIKE 的效率会非常非常的慢; LIKE只适用于关键字匹配,并不适合自然语言匹配。举个例子:用户的问题“河南的省会是哪个城市?”,而数据库的的记录是“河南的省会是哪”,虽然无论是从字面上还是意义上都一样,都 LIKE 却无能为力; LIKE 无法计算相似度。也就是说 LIKE 返回多条记录时,无法确定那个是最佳答案所以此时全文检索引擎的优越性就体现出来了。 全文检索引擎的原理:扫描知识库的每一条记录并分词建立索引,索引记录了词在每一条记录中出现的位置和次数,当收到用户的问题时,也进行分词,然后从索引中找出包含这些词的所有记录,再分别计算相似度,然后可以找出相似度最高的一条记录返回给用户,下面老夫给出一个自己用Lucene(solr)写的例子,这个例子经验证是可以直接跑起来的,至于其众多API,大家可以自己去查官网文档,其实很容易理解。 import java.io.File; import java.io.IOException; import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.Resource; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.IntField; import org.apache.lucene.document.TextField; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.wltea.analyzer.lucene.IKAnalyzer; import cn.bridgeli.livingsmallhelper.entity.Knowledge; import cn.bridgeli.livingsmallhelper.mapper.KnowledgeMapper; import cn.bridgeli.livingsmallhelper.service.ChatService; public class SolrTest { private static final Logger LOG = LoggerFactory.getLogger(DataInit.class); private KnowledgeMapper knowledgeMapper; @Resource private ChatService chatService; public void createIndex() { List<Knowledge> knowledges = knowledgeMapper.query(); Directory directory = null; IndexWriter indexWriter = null; File indexFile = new File(chatService.getIndexDir()); if (!indexFile.exists()) { try { directory = FSDirectory.open(indexFile); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_46, new IKAnalyzer(true)); indexWriter = new IndexWriter(directory, indexWriterConfig); for (Knowledge k : knowledges) { Document document = new Document(); document.add(new TextField("question", k.getQuestion(), Field.Store.YES)); document.add(new IntField("id", k.getId(), Field.Store.YES)); document.add(new TextField("answer", k.getAnswer() == null ? "" : k.getAnswer(), Field.Store.YES)); document.add(new IntField("category", k.getCategory(), Field.Store.YES)); indexWriter.addDocument(document); } indexWriter.commit(); } catch (IOException e) { LOG.error("IOException", e); } finally { try { if (null != indexWriter) { indexWriter.close(); } if (null != directory) { directory.close(); } } catch (IOException e) { LOG.error("IOException", e); } } } } @SuppressWarnings("deprecation") private Knowledge searchIndex(String content) { Knowledge knowledge = null; Directory directory = null; IndexReader reader = null; try { directory = FSDirectory.open(new File(getIndexDir())); reader = IndexReader.open(directory); IndexSearcher searcher = new IndexSearcher(reader); // 这个question 就是以问题为索引去查找,和CreateIndex()中相对应 QueryParser queryParser = new QueryParser(Version.LUCENE_46, "question", new IKAnalyzer(true)); Query query = queryParser.parse(QueryParser.escape(content)); // 这个1 的含义就是找出最相似度最高的一条 TopDocs topDocs = searcher.search(query, 1); if (topDocs.totalHits > 0) { knowledge = new Knowledge(); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); knowledge.setId(doc.getField("id").numericValue().intValue()); knowledge.setQuestion(doc.get("questory")); knowledge.setAnswer(doc.get("answer")); knowledge.setCategory(doc.getField("category").numericValue().intValue()); } } } catch (IOException e) { LOG.error("IOException", e); } catch (ParseException e) { LOG.error("ParseException", e); } finally { try { reader.close(); directory.close(); } catch (IOException e) { LOG.error("IOException", e); } } return knowledge; } @Override public String getIndexDir() { String classpath = SolrTest.class.getResource("/").getPath(); classpath = classpath.replaceAll("%20", " "); LOG.warn("==================" + classpath); return classpath + "index/"; } @Test public void testSolr() throws IOException, ParseException { SolrTest solrTest = new SolrTest(); File indexDir = new File(getIndexDir()); if (!indexDir.exists()) { solrTest.createIndex(indexDir); } solrTest.searchIndex("你好啊"); } } 因为我是用maven写的,所以对应的pom文件,如下: ...

November 2, 2014 · 2 分钟 · Bridge Li

Spring mvc中的forward和redirect以及参数传递

forward和redirect 大家都知道servlet在处理完业务逻辑返回时有两种方法forward和redirect,他们的差异相信不用我再多做解释(如果不知道的请自行谷歌,哪怕是百度也可以),而Spring mvc是对servlet的一种封装,那spring mvc默认采用的是哪一种呢?我们是否可以自己选择采用哪一种方式返回呢?还有我之前在用spring mvc 都是返回到某一个view,它是否可以访问另一个controller呢?针对第一个问题,我们可以看一下spring mvc 的配置文件便知分晓: <property name="viewResolvers"> <list> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </list> </property> 因为WEB-INF是一个受保护的目录,客户端是访问不到的,只能通过服务器端访问,根据forward和redirect的区别,我们很容易看到是forward的方式返回的,针对第二个和第三个问题,其实也很简单,我们只需要让该controller返回String即可,然后在方法的最后 return “redirect:/game”;或者return “forward:/game”;即 redirect或者forward + “:” + “/” + controller的路径或者view的名字即可。 参数传递 因为公司的项目是用Spring mvc开发的,发现参数传递除了通过model,还可以通过 RedirectAttributes,据说参数的传递和跳转的URL后面带的值会有一定的关系,这个我没具体测试,感兴趣的可以自己测测。 总结:这篇文章是近期学到的知识点,以前感觉自己会用Spring mvc了,今天才发现还有好多Spring mvc的特性不知道,值得自己去探索啊!

October 24, 2014 · 1 分钟 · Bridge Li

Java中的split() replace() replaceFirst() replaceAll()四个函数分析

前几天在公司分割一个很简单字符串,结果却怎么测都不对,最后查了一下资料,终于发现了端倪: split(regex); replace(target, replacement); replace(oldChar, newChar); replaceFirst(regex, replacement); replaceAll(regex, replacement) 仔细看一下,你会发现split()、replaceFirst()、replaceAll()的参数都是Regular Expression,也就是正则表达式,只有replace()的参数是字符或者字符串,由于这些参数类型的差异,很有将得不到预期的结果,下面是一些测试代码的例子,大家可以自己测一下 package cn.bridgeli.stringtest; import org.junit.Test; public class StringTest { @Test public void testSplit1() { String str = "111|222|333|444"; String[] result = str.split("|"); for (String string : result) { System.out.println(string); } // String str = "111|222|333|444"; // String[] result = str.split("\|"); // for (String string : result) { // System.out.println(string); // } } @Test public void testSplit2() { String str = "111,222,333,444"; String[] result = str.split("\d"); for (String string : result) { System.out.println(string); } // String str = "111\222\333\444"; // String[] result = str.split("\\"); // for (String string : result) { // System.out.println(string); // } } @Test public void testSplit3() { String str = "111222333444"; String[] result = str.split("\"); for (String string : result) { System.out.println(string); } // String str = "111\222\333\444"; // String[] result = str.split("\\"); // for (String string : result) { // System.out.println(string); // } } @Test public void testReplaceAll() { String str = "111,222,333,444"; String result = str.replaceAll(",", "$"); System.out.println(result); // String str = "111,222,333,444"; // String result = str.replaceAll(",", "\$"); // System.out.println(result); } }

October 20, 2014 · 1 分钟 · Bridge Li

怎么在maven项目中引用本地Java类库

去年实习的时候听说过maven,听说功能特别强大,后来就抽时间自学了一下,尤其感叹于其自动引入jar包的功能,真是太棒了,终于某种程度上把程序猿从classnotfoundexception中解脱出来了,也一定程度上解决了jar包冲突以及版本的问题,但在这几天玩微信开发的时候遇到了一个问题: 我的微信后台是托管到SAE上的,但SAE官方处于安全考虑,把XStream中sun.misc.Unsafe类禁用掉了,这就导致了一个问题XStream不能用了,CSDN知名博主刘峰老师发现了这个问题,于是柳峰老师修改了一下这个类库,其实很简单也即在XStream官方网站http://xstream.codehaus.org/上找到了xstream-1.3.1.jar对应的源码,导入到Eclipse,然后借助Eclipse强大的搜索功能,很快找到了使用sun.misc.Unsafe的类,我尝试将这些类删除或者修改它们的实现,避免使用sun.misc.Unsafe类,最终得到了一个新的jar包,将其命名为xstream-1.3.1-sae-liufeng.jar,用它替换以前项目中使用的xstream-1.3.1.jar,最终项目再次顺利地运行在SAE上,这个方法虽简单粗暴,但确实有效,但是也给我带来了一个问题,我的项目是maven搭建的,那么我怎么把这个jar引入到我的项目中呢? 经过查询资料原来我们可以把本地的jar文件安装到本地repository中,这就完美解决这个问题了,那么怎么把本地的jar文件安装到本地repository中呢?强大的maven当然给我们提供了这个方法: mvn install:install-file -Dfile=xstream-1.3.1-sae-liufeng.jar -DgroupId=cn.bridgeli -DartifactId=xstream-bridgeli -Dversion=1.3.1 -Dpackaging=jar -DgeneratePom=true 相信这条命令不用我解释了,看这篇文章的人一定可以自己看懂的。需要说明的是:执行完这条命令,我们本地的jar就被安装到本地库了文件夹的结构是:cnbridgelixstream-bridgeli1.3.1,即DgroupId + DartifactId + Dversion,文件的名字是:xstream-bridgeli-1.3.1.jar,即:DartifactId + Dversion + . + Dpackaging,然后只需要在我们的项目中引用就可以了,引用的代码: <dependency> <groupId>cn.bridgeli</groupId> <artifactId>xstream-bridgeli</artifactId> <version>1.3.1</version> </dependency> 其中groupId、artifactId、version分别于刚才的命令相对应。 参考:http://blog.csdn.net/youhaodeyi/article/details/1729116 注:我为什么没有采取方法参考资料中的方法二,原因有三: 这个jar并没有加入到本地库中,不利于我们对自己资料的管理 scope被设置成system并不被maven官方所推荐 据有网友说scope被设置成system,那么这个类库并不会被打到war中,这个我没有测试

October 14, 2014 · 1 分钟 · Bridge Li

长链接(URL)转短链接(URL)

现在微博越来越流行,大家有事没事都喜欢在微博上说两句,但由于140字的限制,给我们在分析一些长链接的时候,带来了诸多不便,好在微博有自动缩短URL的功能,那我们是否可以自己缩短一个URL呢?答案是肯定的,下面就给出利用百度的API缩短URL的简单例子 package cn.bridgeli.longurl2short; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; public class LongURL2Short { public static String httpRequest(String outputStr) { StringBuffer buffer = null; try { // 建立连接 URL url = new URL("http://dwz.cn/create.php"); HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection(); httpUrlConn.setDoInput(true); httpUrlConn.setDoOutput(true); httpUrlConn.setUseCaches(false); httpUrlConn.setRequestMethod("POST"); if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStr = "url=" + outputStr; outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 获取输入流 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); // 读取返回结果 buffer = new StringBuffer(); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } // 释放资源 bufferedReader.close(); inputStreamReader.close(); inputStream.close(); httpUrlConn.disconnect(); } catch (Exception e) { e.printStackTrace(); } return buffer.toString(); } } package cn.bridgeli.longurl2short; import org.junit.Test; import com.google.gson.Gson; public class LongUrl2ShortTest { @Test public void testHttpRequest() { String str = LongURL2Short.httpRequest("http://mp.weixin.qq.com/wiki/index.php?title=%E9%95%BF%E9%93%BE%E6%8E%A5%E8%BD%AC%E7%9F%AD%E9%93%BE%E6%8E%A5%E6%8E%A5%E5%8F%A3"); Gson gson = new Gson(); ShortUrl shortUrl = gson.fromJson(str, ShortUrl.class); System.out.println(shortUrl.getTinyurl()); } } package cn.bridgeli.longurl2short; public class ShortUrl { private String tinyurl; public String getTinyurl() { return tinyurl; } public void setTinyurl(String tinyurl) { this.tinyurl = tinyurl; } } 注:httpRequest方法和前一篇文章 如何用https协议发起一个post请求 极其类似,本质是一样的,另外该方法经本人测试会有bug:当长URL是.cn时,转换不成功,目前原因还没找到,猜测是由于转化后的URL的后缀也是.cn的原因,具体在测试。 ...

October 9, 2014 · 1 分钟 · Bridge Li

Jsoup在简单防御XSS攻击和网络爬虫的简单应用

跨站攻击一直是web安全的一大问题,稍有不慎就会中招,各种防不胜防,今天在网上闲逛,发现一个第三方JAR不仅可以简单防御还可以爬取网页,所以写一篇小文以记之,也供有需要的人参考。 预防跨站攻击代码如下: @Test public void testJsoup() { String unsafe = "<p><a href='http://example.com/' onclick='stealCookies()'>Link,<alert>0</alert></a></p>"; String safe = Jsoup.clean(unsafe, Whitelist.basic()); System.out.println(safe); } 其中 unsafe 就是用户提交的数据,其中包含 onclick 和 alert 可能会有害,需要过滤,而 Whitelist.basic() 则是过滤规则,safe 就是过滤后的安全数据。 在网络爬虫方面,曾听北京尚学堂马士兵老师讲过一次正则表达式的简单应用:抓取网页上的邮箱地址,有很多人记不住,但有了这个第三方工具,则轻松很多,他可以根据一个URL直接去抓取,省了不少事,猜测内部也是用正则实现的。 网络爬虫代码如下: @Test public void testSpider() { String url = "http://www.rijiben.com/"; Document doc = null; try { doc = Jsoup.connect(url).get(); } catch (IOException e) { e.printStackTrace(); } if (null != doc) { Elements listrens = doc.getElementsByAttributeValue("class", "listren"); for (Element listren : listrens) { String text = listren.select("li").select("a").html(); System.out.println(text); } } else { System.err.println("网络出异常!"); } } 这是抓取日记本上面,历史上的今日的例子,老夫打算将来用到自己的微信公众号上面,怎么样,是不是很简单? ...

September 30, 2014 · 1 分钟 · Bridge Li

如何用https协议发起一个post请求

这两天研究了微信公众号的开发,发现微信做的太好了,前景太可怕了,如果按照这个趋势,那么将来手机上也许只装一个微信客户端也许就可以做任何事了,其中微信公众号开发自定义菜单时,微信要求用https协议post到微信服务器一个JSON字符串,这里面有两个难点:1. https协议,2. 如何post数据到微信服务器。刚好csdn博主柳峰,有一篇文章是讲解这个的,所以就拿来参考一下,具体代码如下: import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; public class MyX509TrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } 这个是说,相信所有的安全证书,无论是不是安全机构颁发 public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) { httpUrlConn.connect(); } // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.fromObject(buffer.toString()); } catch (ConnectException ce) { log.error("Weixin server connection timed out."); } catch (Exception e) { log.error("https request error:{}", e); } return jsonObject; } 这个就是通过https协议向某一个URL通过post或者get提交一个JSON字符串。另外在编程中还有一个常见的向某一个URL请求数据,代码如下: ...

September 29, 2014 · 2 分钟 · Bridge Li

如何配置一个一键启动的绿色Java web项目

我们知道部署J2EE项目,要首先安装JDK,配环境变量,在安装tomcat,然后MySQL数据库(当然也可以是其他任何你喜欢的数据库),把项目打一个war包放到tomcat的webapps包下面,启动tomcat就可以了,但在某些情况下,例如测试美工等,尤其是美工他们的电脑很多时候没必要安装这些乱七八糟的东西,那么我们是否可以不安装这些东西,而让让美工们的电脑跑项目呢?答案是可以的,我们只需要拷贝一个JDK、MySQL、tomcat到美工的电脑,再把项目拷到tomcat的webapps下,写一个bat的文件,让bat文件设置JDK目录、安装MySQL的服务,调用tomcat启动的命令就可以了,srartup.bat代码如下: @echo off setlocal :: ========================================== :: 1. 环境变量配置 :: ========================================== :: 设置基础目录 (建议根据实际情况修改盘符和路径) set "HOME=C:\Layout\" :: 设置 Java 环境 :: 修正:路径拼接需要加反斜杠 \ set "JAVA_HOME=%HOME%jdk" :: 修正:lib 目录后通常需要加反斜杠,且 CLASSPATH 建议包含当前目录 . set "CLASSPATH=.;%JAVA_HOME%\lib" :: 设置 Tomcat 环境 set "CATALINA_HOME=%HOME%tomcat" set "CATALINA_BASE=%HOME%tomcat" :: 设置 MySQL 环境 set "MYSQL_HOME=%HOME%mysql" :: 更新系统 PATH :: 将新路径添加到 PATH 最前面,确保优先使用 set "PATH=%JAVA_HOME%\bin;%MYSQL_HOME%\bin;%PATH%" :: ========================================== :: 2. 刷新资源管理器 (可选) :: ========================================== :: 注意:这会重启桌面进程,屏幕会闪烁 taskkill /f /im explorer.exe start explorer.exe :: 强制刷新系统环境变量 RunDll32.exe USER32.DLL,UpdatePerUserSystemParameters :: ========================================== :: 3. 启动 MySQL 服务 :: ========================================== echo [INFO] Starting LMS MySQL Service... :: 尝试安装服务 (如果服务已存在可能会报错,可忽略) mysqld -install lms_mysql --defaults-file="%MYSQL_HOME%my.ini" :: 启动服务 net start lms_mysql :: ========================================== :: 4. 启动 Tomcat :: ========================================== echo [INFO] Starting Apache Tomcat... :: 修正:原脚本缺少反斜杠,且 startup.bat 会开启新窗口 :: 建议:使用 catalina.bat run 可以在当前窗口看到日志,方便调试 call "%CATALINA_HOME%\bin\catalina.bat" run shutdown.bat ...

September 20, 2014 · 2 分钟 · Bridge Li

反射的简单应用:解决微信开发中if-else过多的问题

前一段时间,闲着无聊玩微信开发,遇到一个问题:当关注者向公众号发送消息,请求一些服务时,由于是文本消息,所以当公众号拿到消息内容时,必须判断消息以什么打头,即: String content = requestMap.get("Content").trim(); if ("?".equals(content) || "?".equals(content)) { respContent = "您好,我是生活小助手,请根据提示,回复内容选择服务:nn1 回复“天气”获取天气帮助n2 回复“歌曲”获取歌曲帮助n3 回复“公交”获取歌曲帮助n4 回复“火车”获取歌曲帮助"; } else if (content.startsWith("歌曲")) { //TODO } else if (content.startsWith("天气")) { //TODO } else if (content.startsWith("物流")) { //TODO } else if (content.startsWith("公交")) { //TODO } else if (content.startsWith("火车")) { //TODO } else { respContent = "亲,很抱歉,由于功能还不够完善,尚不能处理您回复的信息,请回复“?”显示主菜单,获取帮助,有此给您带来的不便,还请见谅!"; } 来判断何种服务,调用具体的接口来处理,当你的功能越来越完善时,会导致if-else越来越多,多的会自己都搞不清了,另外这个方法也会越来越大,显然不是非常符合面向对象的单一职责原则。那么有没用一个比较好的方法来解决这个问题呢?我曾经的项目经理Zack曾经说过,上天不会这么惩罚一个后期维护代码的人,所以答案是勘定有,今天老夫就给大家带来一个解决方法,需要说明的是:这不是老夫的原创,是老夫研究捷微源码的找到的方法,老夫在捷微方法的基础上做了一些修改,所以先感谢捷微,感谢捷微的开发人员。最后需要说明的是,这个方法也不是很完善,如果有人参考的话,老样子,请做具体修改,但逻辑老夫保证不会有错。 @Override public BaseMessage handleText(String content, String fromUsername, String toUsername) { String respContent = null; BaseMessage baseMessage = null; if ("?".equals(content) || "?".equals(content)) { respContent = "您好,我是生活小助手,请根据提示,回复内容选择服务:nn1 回复“天气”获取天气帮助n2 回复“歌曲”获取歌曲帮助n3 回复“公交”获取公交帮助n4 回复“火车”获取火车帮助"; } else { List<WeixinExpandconfigEntity> weixinExpandconfigEntities = new ArrayList<WeixinExpandconfigEntity>(); boolean isFind = false;// 是否找到关键字信息 for (WeixinExpandconfigEntity weixinExpandconfigEntity : weixinExpandconfigEntities) { // 如果已经找到关键字并处理业务,结束循环。 if (isFind) { break;// 如果找到结束循环 } String[] keys = weixinExpandconfigEntity.getKeyword().split(","); for (String k : keys) { if (content.indexOf(k) != -1) { String className = weixinExpandconfigEntity.getClassname(); String returnType = weixinExpandconfigEntity.getReturnType(); KeyService keyService = null; try { keyService = (KeyService) Class.forName(className).newInstance(); baseMessage = (BaseMessage) Class.forName(returnType).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } keyService.excute(baseMessage, content.substring(2)); isFind = true; break; } } } } if (baseMessage == null) { TextMessage textMessage = new TextMessage(); textMessage.setContent(respContent); baseMessage = textMessage; } baseMessage.setToUserName(fromUsername); baseMessage.setFromUserName(toUsername); baseMessage.setCreateTime(new Date().getTime()); baseMessage.setFuncFlag(0); return baseMessage; }

September 15, 2014 · 1 分钟 · Bridge Li

使用JDK自带的工具解析XML文档

XML和JSON字符串的解析,是Java程序猿的必备技能,关于XML和JSON如何解析,网上的例子可以说是一拉一大把,解析JSON的有什么GSON、json-lib等一大批做得非常好的第三方工具,解析XML的也有什么DOM4J、JDOM、SAX、DOM等等,今天大桥就给大家展示一下如何有JDK自己解析XML,废话不多说,代码如下: package cn.bridgeli.parsexmldemo.parsexml; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class ParseXml { public void parserXml(String fileName) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(fileName); NodeList rootNode = document.getChildNodes(); parseNode(rootNode.item(0)); } catch (FileNotFoundException e) { System.out.println(e.getMessage()); } catch (ParserConfigurationException e) { System.out.println(e.getMessage()); } catch (SAXException e) { System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage()); } } public void parseNode(Node node) { if (node == null) { return; } // if not have child if (!node.hasChildNodes()) { NamedNodeMap attrs = node.getAttributes(); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { Attr attribute = (Attr) attrs.item(i); System.out.print("AttributeName===" + attribute.getName() + " AttributeValue===" + attribute.getValue()); } } String str = node.getTextContent().toString().replaceAll("n", "").replaceAll(" ", ""); if (!str.equals("")) { System.out.println("TextContent ===" + str); } } else { // get attributes NamedNodeMap attrs = node.getAttributes(); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { Attr attribute = (Attr) attrs.item(i); System.out.println("AttributeName===" + attribute.getName() + " AttributeValue===" + attribute.getValue()); } } // get child node NodeList nodes = node.getChildNodes(); for (int j = 0; j < nodes.getLength(); j++) { parseNode(nodes.item(j)); } } } } 具体可以参考: ...

September 14, 2014 · 2 分钟 · Bridge Li