数据加密算法之MD5和SHA1

这个星期记录一下数据加密算法,记得刚开始学编程的时候就有一个疑问:我们的密码就这么放在数据库里面,多不安全啊,数据库管理员不是拿着数据想干嘛就干嘛吗?但是由于认知有限,一直没有解决这个问题,直到去年实习时,当时的项目经理Zack说,用户密码不能明文存放到数据,必须经过MD5加密,终于解决了这个问题。因为MD5的不可逆性,所以就算知道MD5码,只要你不是一些弱密码,一般情况下发生泄密的可能性是非常非常小的,几乎可以认为是绝对安全的,但MD5实现的实现却很简单,今天就记录一下实习时用到的一个MD5加密算法的一个实现: package cn.bridgeli.demo; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Encryption { public static String MD5(String input) { StringBuffer hexString = null; try { // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(input.getBytes()); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 hexString = new StringBuffer(); // 字节数组转换为 十六进制 数 for (int i = 0; i < md.length; i++) { String shaHex = Integer.toHexString(md[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return hexString.toString(); } public static String SHA1(String decript) { StringBuffer hexString = null; try { MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1"); digest.update(decript.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String hexString = new StringBuffer(); // 字节数组转换为 十六进制 数 for (int i = 0; i < messageDigest.length; i++) { String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); if (shaHex.length() < 2) { hexString.append(0); } hexString.append(shaHex); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return hexString.toString(); } } 这里面还有一个SHA1机密算法的实现,主要是在自学微信开发时,微信在接入验证的数据经过字典排序后SHA1加密,所以就顺便记录了一下,算是两个比较常用的加密算法吧,供大家参考。 ...

December 21, 2014 · 1 min · 159 words · Bridge Li

设计模式综合运用之Excel导入

学以致用,前几篇文章我们学了很多设计模式,今天我们就把这些模式综合运用一下,看看实际应用是怎么导入Excel的,(当然这里面没有用到侦听者模式) 我们先看一下Excel的样子: 因为是Excel的的解析,所以应该是前台上传的,我们应该有一个Servlet来接收前台传过来的数据: package cn.bridgeli.demo.servlet; import java.io.File; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.bridgeli.demo.servce.Container; import cn.bridgeli.demo.servce.ExcelParseStrategy; public class ExcelParseServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //真正的情况下应该由前台传过来的,这里是模拟就写死了 File file = new File("D:/Excel.xls"); String excelType = request.getParameter("excelType"); // 此处是策略模式,至于怎么实现,大家可以参考策略模式 Container container = new Container(); ExcelParseStrategy excelParseStrategy = container.getStrategy(excelType); excelParseStrategy.parse(file); } } 下面看ExcelParseStrategy接口,和具体策略的实现: ...

December 14, 2014 · 3 min · 430 words · Bridge Li

设计模式之模板方法

这一节记录一下模板方法,在学模板方法之前,要先学习一下什么是模板,模板其实就是一个例子,例如我们做市场调研时,调研人员会给我们一个表格,我们只需要回答一些答案即可,映射到我们的代码中就是这个样子: aaaaaaaa bbbbbbbb cccccccc \***\***** dddddddd eeeeeeee ######## ffffffff gggggggg $$$$$$$$ 这是我们第一次写的代码,但是我们在后来的coding中发现,这一段代码我们需要copy一份,只需要该其中的第四行、第七行、第十行就行了,其余的不需要做修改,如果我们copy过去,改一下这么做虽然可以完成,但我们想一想如果我们代码里面一万处这样的代码,难道要copy一万次?这么做是不是很冗余?这时候就需要我们的模板方法上场了,下面看一个我们在实际中的典型应用:JDBC操作数据库,所以我们下面先看一个操作数据库的实际例子: package cn.bridgeli.demo.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import cn.bridgeli.demo.entity.User; import cn.bridgeli.demo.util.DBUtil; public class UserDao { public User getUserById(int userId) { Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; User user = null; String sql = "SELECT * FROM user WHERE id = ?"; try { conn = DBUtil.getConn(); pstmt = DBUtil.getPstmt(conn, sql); pstmt.setInt(1, userId); rs = pstmt.executeQuery(); if (rs.next()) { user = new User(); // } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(rs); DBUtil.close(pstmt); DBUtil.close(conn); } return user; } } 这段代码经过我们分析,很明显就建行不一样:String SQL不一样,pStmt设置参数不一样,if(rs.next())不一样,所以我们可以把它做成模板方法,下面我们就重构着一段代码。在重构这段代码之前有几个问题我们先要明确: ...

December 7, 2014 · 2 min · 294 words · Bridge Li

设计模式之策略模式

今天我们来讨论策略模式,策略模式是一个比较难理解的模式,尤其是和工厂模式相结合时,当时看程杰的《大化设计模式》时,第二个讲的就是这个,那是一个迷迷糊糊啊,其实仔细分析策略模式并没有那么难,在我们学策略模式之前,先搞明白什么是策略呢?策略是:在某一件事上,在一定的情况下,所采取的行动。当然这个“在一定的情况下”一定是某一种情况,也即是可数的。当情况很多的时候,也许我们要用很多烦人if-else去处理,所以策略模式就是解决这类问题的,其一个典型应用就是在电商平台中:不同的用户有不同的等级享有不同的折扣,我想有些人第一想到的处理方式就是: package cn.bridgeli.demo; public class Strategy { public double discount(String grade, double total) { if ("A".equals(grade)) { return total * 0.6; } else if ("B".equals(grade)) { return total * 0.7; } else if ("C".equals(grade)) { return total * 0.8; } else if ("D".equals(grade)) { return total * 0.9; } else { return total; } } } 我相信这么处理只要看过上篇文章的人都会想到,不满足:开闭原则!当我们新增一个策略时,肯定要该这段代码,增加一个if,当我们的策略发生变化时,例如不仅打折而且在过节时发送促销邮件之类的,那么里面的策略也要改,显然这是一个大问题,那么出现这个问题的根源就是不满足:迪米特原则。 ps:就算不用if-else,用switch-case也有同样的问题。那么用策略模式怎么处理呢? 需要我们首先定义一个策略模式的接口: package cn.bridgeli.demo.service; public interface UserGradeStrategyService { public double discount(); } 下面是具体的策略的实现 package cn.bridgeli.demo.service; public class UserGradeAStrategyService implements UserGradeStrategyService { @Override public double discount() { return 0.6; } } package cn.bridgeli.demo.service; public class UserGradeBStrategyService implements UserGradeStrategyService { @Override public double discount() { return 0.7; } } package cn.bridgeli.demo.service; public class UserGradeCStrategyService implements UserGradeStrategyService { @Override public double discount() { return 0.8; } } package cn.bridgeli.demo.service; public class UserGradeDStrategyService implements UserGradeStrategyService { @Override public double discount() { return 0.9; } } package cn.bridgeli.demo.service; public class UserGradeEStrategyService implements UserGradeStrategyService { @Override public double discount() { return 1.0; } } 有一个策略的容器,这个容器知道都有哪些策略,它里面包含所有的策略: ...

November 30, 2014 · 2 min · 246 words · Bridge Li

设计模式之侦听者模式

关于技术,老夫一直认为应该以实用为主,至于那些理论性的东西,用得多了慢慢就理解了,所以为了说明今天这个设计模式,我们先提出一个问题:我们知道很多系统都有注册功能,有些呢,直接返回您已注册成功请直接登录,而有些注册则要求相对比较比较高,例如注册成功之后需要向用户填写的手机发送短信、Email发送邮件之类的,关于这个问题,大家立马想到的也许是这么来实现吧: package cn.bridgeli.regdemo.service; public class UserService { public void register(String username, String password) { // 非空验证 // save到数据库 // 发送短信说,注册成功 // 发送邮件说,注册成功 } } 这是一个很中规中矩的写法,我们都知道面向对象有一个原则是:单一职责原则,也即是最小知识化原则,好像也称迪米特原则和不和陌生人说话,不管怎么说,就是一个类只管一个类型的东西,一个方法只干一件事,例如本例中的注册,那么应该只干注册一件事,至于什么发短信啊,发邮件啊,本质上来说和注册是没有关系的,所以我们可以把发短信,发邮件的方法提取出来,放到其他的地方,例如放到工具类里面,那么提取出来是不是就是最好的了呢?我们应该知道面向对象还有一个原则:开闭原则,这个原则是说,对扩展开放对修改关闭,也就是说,当我们需求发生变化的时候,不应该依赖于去修改源码,而是依赖于对源码的扩展,所以关于我们这个例子:假设有一天我们不需要发送短信了,或者需要有第三种通知用户的方式,您是否能做到不修改源码呢?肯定做不到吧,只有把调用发送短信的代码删了,或者在下面添加第三种通知方式,所以这么做肯定还是不够的,那么为了满足:开闭原则,我们就要引入今天的设计模式:侦听者模式,且看下面的例子: package cn.bridgeli.regdemo.service; import cn.bridgeli.regdemo.listener.EventLinstener; public class UserService { public void register(String username, String password) { // 非空验证 // save到数据库 EventLinstener eventLinstener = new EventLinstener(); String data = "注册成功"; eventLinstener.dispatchEvent("REGSUCESSED", data); } } 核心类EventLinstener package cn.bridgeli.regdemo.listener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class EventLinstener { public static Map<String, List<Observer>> events = new HashMap<String, List<Observer>>(); static { List<Observer> reg = new ArrayList<Observer>(); reg.add(new EmailObserver()); reg.add(new SmsObserver()); events.put("REGSUCESSED", reg); } public void dispatchEvent(String eventName, Object object) { List<Observer> observers = events.get(eventName); if (null != object && !observers.isEmpty()) { for (Observer observer : observers) { observer.execute(object); } } } } 侦听者抽象类Observer ...

November 23, 2014 · 1 min · 173 words · Bridge Li

设计模式之单例模式

在程序设计中,单例模式是非常常用的一个设计模式,至于有点老夫就不用多说了,肯定有一点比较省内存,但什么的类适合于设置成单例呢?一言以蔽之: 在程序设计中,无状态的类都可以设置成单例。 那么问题来了,什么样的类是无状态的,什么样的类是有状态的呢?其实很简单: 没有数据,也就是说这个类只有方法,没有成员变量。 举个例子: User类是否可以设置成单例呢?肯定不行,因为User类每一个对应的Id肯定是不同的人,如果设置成单例,数据就乱了;但一般Service层、DAO层的方法呢?这个一般都是一些业务逻辑,只有一些方法,没有数据,所以肯定可以设置成单例,事实上我们这些类如果有Spring托管,那么自然而然这些类就是单例的。 既然单例使用这么多,有点还这么明显,那么怎么设置一个类是单例的呢?根据老夫第一个项目经理Zack的说法,设置一个类成单例的,有两种方法,首先看第一个,传统意义上的单例: package cn.bridgeli.singleton; public class Singleton { private static volatile Singleton singleton = null; private Singleton() { } public static Singleton getInstance() { if (null == singleton) { synchronized (Singleton.class) { if(null == singleton) { singleton = new Singleton(); } } } return singleton; } } 这个最简单,构造方法设置成私有的,别人就不能new了,想获取实例必须通过getInstance()方法,而这个方法里面是static的,所以这是一个传统意义上的最简单的单例。 除此之外,我们还可以借助于静态内部类的方式实现单利: package cn.bridgeli.demo.singleton; public class Singleton { private Singleton() { } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } } 第二个,管理意义上的单例 我们自己观察可以发现,这个虽然简单,但我们Spring实现的单例,肯定不是这么实现的,那么他是怎么实现的呢?Spring并没有限制我们自己写的类必须要有一个私有的构造方法,所以管理意义上的单例,并不要一个类有一个私有的构造方法,但他会通过一个BeanFactory产生我们想要的实例,参考代码如下: ...

November 16, 2014 · 1 min · 200 words · Bridge Li

Windows下SVN服务器的搭建

作为一个软件开发人员,关于scm的重要性和必要性,相信我不用说了,目前最流行的的两个版本控制工具svn和git,关于这两个区别还是很大的,而git功能更强大,猜测以后会越来流行,在svn作为打败众多SCM工具的一个版本控制系统,他目前的使用还是非常多的,而且操作也非常简单,所以这一节就写一下svn服务器的搭建,有机会将来在写一篇关于git烦人使用的文章。好了,下面进入今天的正题: 首先推荐大家下载Subversion,随便哪个版本都行,安装过程就不说了,可以说是一路next,那么服务器就转好了,下面经过一些设置就可以使用了。 注:可以再cmd中敲一下 svn,看是否安装好了 第一步:在服务器上建立核心仓库,这个很简单,就一个命令 svnadmin create svnrepo 其中svnrepo就是我们的核心仓库,在那个路径下敲,那么这个仓库就会在哪个路径下,那么我们放东西的大仓库就建好了,另外名字我们可以随便写,自己看着什么顺眼就起什么,不过最好做到见名知意 第二步:权限设置,即哪些人可以访问,哪些人不可以访问,这个也很简单,我们进入第一步创建的svnrepo文件下,然后进入conf文件夹,打开svnserve.conf文件,这个文件保存着svn的常见设置, 我们首先找到 \# password-db = passwd 这一行,把前面的注释去掉,也就是把#去掉,最好连空格一块去掉。这个是说明,如果访问我们的服务器,需要在另一个文件中,即passwd文件中配置,同时我们也可以找到这两行: \# anon-access = read \# auth-access = write 也就是匿名访问的权限,匿名访问我们最多给他只读的权限,这个随你的便。 第三步:既然第二步说了我们的密码在passwd文件重配置,那么肯定是打开这个文件,进行配置了,我们可以看到默认有两个人,而且这两个人也是注释掉的,我们可以在下面加自己的用户,前面是用户名和密码,例如: bridgeli = abc123_ 注意两点,1. 这个用户名前面一定不要有空格,否则svn会认为这个用户的名字带空格,很别扭; 2. 你们项目组,有几个人你就填加几个用户名啦,那么这样大家都可以有自己的用户名去提交代码了。 第四步:svn的仓库,我们建好了,配置也做好了,那么现在肯定是把服务器起起来了,起服务器的命令如下: svnserve -d -r svnrepo 其中-d代表后台启动,-r代表root用户,相信知道Linux的对这个用户一定不陌生。svnrepo,就是我们的仓库名。 切记:这个窗口一定不要关,如果关了那么服务器就关了。 那么到此为止,我们svn服务器就建好了,大家就可以往里面提交代码了,但是但是大家有没有发现一个问题,我们很随便就可以提交代码了,大家在提交代码时,有经验的项目经理,一定会要求手下每个提交代码的同学,写上注释,如果不做限制,就这样那么问题就来了,总有人会无意中忘了怎么办?那么我们是不是可以在服务器端限制一下要求所有人必须提交代码呢?答案是肯定可以的。(其实在TortoiseSVN客户端也是可以的,但是但是大家都懂得,在客户端设置这个就太不靠谱了),下面给出在svn服务器端的设置,那么大家就必须在提交时必须写注释了 我们在我们的仓库中的hooks文件夹中,找到pre-commit.tmpl文件,在windows下可以修改这个文件为pre-commit.bat,然后把里面的内容修改为如下: @echo off setlocal set REPOS=%1 set TXN=%2 rem check that logmessage contains at least 10 characters rem &#8230;..代表5个字符 svnlook log "%REPOS%" -t "%TXN%" | findstr "&#8230;&#8230;&#8230;." > nul if %errorlevel% gtr 0 goto err exit 0 :err echo Empty log message not allowed. Commit aborted! 1>&2 exit 1 修改为bat相信大家都知道让Windows知道是可执行文件,据说不加后缀也可以,关于这个我没有测试过,大家可以自己测试,在测试之前呢,为了避免库被破坏,我们可以自己先备份一下。

November 8, 2014 · 1 min · 91 words · Bridge Li

全文检索工具-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 min · 370 words · 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 min · 40 words · 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 min · 179 words · Bridge Li