MyBatis运行时报错“前言中不允许有内容”的解决办法

使用MyBatis写的程序报错:

org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause:
org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 前言中不允许有内容。
at …

看到报错信息中有句中文给高兴得…“前言中不允许有内容”,但是然并卵啊,不明白什么意思…

由于当时没有网,所以没查,不过估计是配置文件的错误(当时使用MyBatis提供的读取文件流的方法Resources.getResourceAsReader()),接着就将配置文件检查了一遍又一遍,还是没有找到错误,就在要放弃的时候,莫名其妙的发现主配置文件的开头有三个问号(“???”),可是Eclipse中却看不到这3个问号!!!

然后突然就想到了UTF-8+BOM,查看文件编码,果然是UTF-8+BOM,我去,怪不得会提示“前言中不允许有内容”…原来就是那个坑爹的BOM!!! 继续阅读

Java缓冲字节流复制文件的代码

对于机械硬盘来说,复制文件时,如果每次复制的数据比较小(比如几个字节),而量又特别大就会是个非常蛋疼的事情,效率非常非常的低,如果能够使用缓存一次性复制较大的数据(8~10K),那么就可以大大提高效率了。

而Java提供了带缓存的读写字节流BufferedInputstream和BufferedOutputsteam,那么通过这两个流复制文件可以提高文件复制的效率,因为通过缓存的方式可以一次性读取更多的字节数,然后再一次性写入更多的字节数,这样可以大大的降低硬盘的IO压力,从而提高复制效率。

Java中BufferedInputstream和BufferedOutputsteam默认的缓冲buff是8K,当然,我们也可以自定义buff,而经过测试(不严谨),发现自定义一个8K的buff比Java使用默认的8K的buff速度要快…而自定义buff的代码也不多,所以建议优先使用自定义buff的代码,那么代码如下: 继续阅读

Java Socket设置连接超时的代码

Java的Socket如果连接不到指定IP和Port的主机,就会抛出IOException异常,而通常情况下,从连接到出现IOException会有一段不定的时长,就是所谓的超时时长,如果超时时长过长,在开发时会影响测试,如果代码成了产品,又会非常的影响用户体验,那么要怎么设置这个时长呢?

Socket的类提供了一个方法:

public void connect(SocketAddress endpoint, int timeout) 
				throws IOException

参数:
endpoint – SocketAddress 提供主机IP和Port
timeout – 要使用的超时值(以毫秒为单位)。

该方法用于将Socket连接到指定的服务器,并设定一个超时值。超时值设定为大于0时,当超时后,就会抛出异常,停止连接,而超时值设为0将无限超时。

因此,使用上述方法就可以设置Socket连接的超时时长了,代码如下: 继续阅读

JSP EL表达式的属性名中不能出现的字符

写Servlet返回JSP的值时,是这样写的:

req.setAttribute("login-error", "登录失败");

JSP中是这样写的:

${login-error}

运行后,页面显示了一个“0”…

这是什么鬼,后台也报错了(我提取出了关键错误信息):

org.apache.el.parser.ParseException: Encountered ” “error “” at line 1, column, Was expecting one,
“}”, “.”, “[“, “>”, “gt”, “<“, “lt”, “>=”, “ge”, “<=”, “le”, “==”, “eq”, “!=”, “ne”, “&&”, “and”, “||”, “or”, “*”, “+”, “-“, “/”, “div”, “%”, “mod” 继续阅读

Spring报配置文件错误(莫名其妙)

状态

今天用Spring写东西,运行时报配置文件写错了,还是调了一会儿,把报错的地方看了,没找到,又把所有配置都看了一遍,还是没找到……

把所有bean删了,<beans>标签中间就剩下几行空白换行,还是报错……报错的地方都是空白的……无语了,最后突然想到,会不会就是那几行空白出的错……

于是把空白删了,就不报错了……原来是不知道为什么手抖了吧,那几行空白中夹了个全角的空格,这太坑了……

所以,小伙伴们找不到错误可以考虑下这个问题!

 

Java修道之路:WEB应用的四大域笔记

在Servlet和JSP中有用来保存和传递对象参数的对象,这个对象可以看作是个容器,也称为域,程序可以往里面装键值对(绑定对象)。域有4个,分别是:

1、request:请求,所有请求相关的对象参数都被绑定在里面,如果是页面传输的参数通过getParameter方法获取,如果是通过setAttribute方法绑定的参数,通过getAttribute方法获取。该域只能该请求链访问。

2、pageContest:JSP页面上下文,该域只有JSP有,代表整个JSP页面,可以通过该域获得页面的所有属性,当然也可以通过setAttribute和getAttribute方法绑定和获取对象参数。该域在该JSP页面中都能访问。

3、session:会话,当浏览器访问服务器时,服务器会为该浏览器在服务端创建一个session,session可以用来保存数据,当然也是使用setAttribute和getAttribute方法。 继续阅读

tomcat搭建的web项目,网页第二次访问时卡住……

状态

今天用servlet和jsp写了个web小项目,后台查询mysql数据库是使用的dbcp连接池,只开了1个连接。

写完后,启动tomcat访问页面列表时,发现第一次访问没有问题,但是刷新页面或再访问其他列表页面时就一直卡住,服务端不返回任何数据到浏览器……

折腾了很久,各种打桩,发现在重启tomcat的时候,后台可以把第二次访问的页面需要查询的列表打印到控制台,但是不会返回给浏览器(其实,这个时候是没有机会返回了),经过分析,这个很像是后台在等待连接数据库,所以一直无法返回结果。仔细查看程序后,果不其然,后台访问完数据库时,忘了关闭连接,我只开了1个连接,所以第二次访问时后台一直在等待连接数据库……

坑大了,马上加上关闭连接的代码,重新部署后就OK了……所以,连接使用完一定要关闭啊!!!

想起了另一个坑,java操作文件时,没有关闭读写文件的流,文件打死都无法删除……还只有通过任务管理器结束javaw.exe进程后才能删除……所以自己创建的流用完了也要关闭啊!!!

Java修道之路:读取指定路径的文件(如:相对路径,包路径)的方法

写java程序的时候,会用到配置文件,对于配置文件放在哪个目录,怎么读取也算是个麻烦的问题,下面就来说说怎么读取这些文件吧!

1、读取项目根目录的文件:

在Eclipse环境下,“.”(点)代表项目根目录,也就是src目录的父目录,使用时也可以省去“.”,也就是说“./test.txt”或者“test.txt”就代表在项目根目录下的test.txt文件。

下面代码可以用于测试,前提是,项目根目录有“test.txt”文件:

File file = new File("./test.txt");
// File file = new File("test.txt"); // 或者这样写

System.out.println(file.exists()); // true

2、读取相对路径的文件:

相对路径是指相对于该.class文件(在Eclipse中也就是正在编辑的.java文件)的路径,我们知道在html中读取相对文件是使用“文件名“或”文件夹名/文件名”表示与该.html同目录的文件或文件夹下的文件,使用“..”表示父目录文件夹,但是在Java中不全是这样的(我已经悲催的试过了……)。 继续阅读

File对象占多少字节呢?

那天操作File对象的时候,就在想,File对象和其对应的路径字符串哪个更占空间呢?也是突然的好奇心,对象到底占多少个字节呢?

今天就来看看如何得到对象所占的字节数,这里提供两种方法:

1、通过ByteArrayInputStream将对象存入byte数组,然后得出byte数组的大小

2、通过ObjectOutputStream将对象写入txt文件,然后查看txt文件大小

下面来看看代码:

/**
 * 1、通过ByteArrayInputStream写入byte数组实现
 */
@Test
public void test1() throws IOException {
	
	String path = "D:/abc/test.txt";
	File file = new File(path);
	
	// 创建byte数组输出流
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	
	// 创建对象输出流,并套在byte输出流上,这样就可以将对象输出到byte数组中了
	ObjectOutputStream oos = new ObjectOutputStream(baos);
	oos.writeObject(file);
	
	/* 上面两步已经将file对象转成了字节保存在baos的缓冲区了
	 * 通过baos调用toByteArray或者toString就可以查看到缓冲区的内容了 
	 */
	byte[] buf = baos.toByteArray();
	System.out.println("File对象字节数:" + buf.length); // 84
	
	// 将字符串按照默认编码转换为byte数组
	byte[] byteStr = path.getBytes();
	System.out.println("Path字符串字节数:" + byteStr.length); // 15
	
	// 结论:说明File对象中不止存储了Path字符串,还有些其他的东西...
}

说明一下:ByteArrayInputStream是java.io包中的类,可以这么理解,FileOutputStream是把程序中的对象输出到文件中,而这个ByteArrayInputStream是把程序中的对象输出到自带的byte数组缓存中,而读取这个缓存使用方法toByteArray或toString。 继续阅读

PreparedStatement提交null值

Java程序通过JDBC驱动向Oracle数据库的某张表中的age字段(number类型)插入数据,就当这张表只有这一个字段吧。

嗯,上面是前提……

这个时候我使用的是java.sql.PreparedStatment执行带参数的SQL语句,代码如下:

int age = 0;
String sql = "insert into table_name (age) values (?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, age);

这个时候age为0,我就想让插入到数据库的值是null,而不是0,然后我就尝试了这样:

pstmt.setInt(1, null);

当然,是报错了……那么我该怎么办呢?

其实,API还为我们提供了一个方法——setNull,代码改为如下:

if (age == 0) {
    pstmt.setNull(1, java.sql.Types.INTEGER);
} else {
    pstmt.setInt(1, age);
}

来解释一下,setNull的第一个参数和setInt一样,都是“?”的位置号,后面那个Types.INTEGER是SQL类型代码,当插入int时为INTEGER,这个可以查看java.sql.Types的常量,我还不是很明白对应关系……反正这里就是这么用的啦~有兴趣的朋友可以再研究研究~

Java修道之路:学习笔记(1) —— ArrayList集合

ArrayList是List接口的实现类,List是可重复集,也可以叫做有序集。

List的常用实现类还有LinkedList。ArrayList和LinkedList拥有不同的物理存储方式,前者类似于数组,后者称之为链表,即可以通过上一个元素找到下一个元素。

不同的物理方式赋予不同的性质,ArrayList插入元素慢,但是查找元素快,而LinkedList插入元素快,查找元素慢,两者遍历速度相同。

下面以ArrayList为例,列出几个需要注意的点,其他的常用方法查API去~

先给一个ArrayList,并赋值:

List list = new ArrayList();
list.add("One");
list.add("Two");
list.add("Three");

1、打印,List的父类java.util.AbstractCollection重写了toString方法,因此可以将元素直接打印出来。

System.out.println(list.toString());  // [One,Two,Three]
// List的父类java.util.AbstractCollection重写了toString方法,因此可以将元素直接打印出来

继续阅读

约瑟夫问题用面向对象思想来解决的方法

上一篇文章说到了约瑟夫问题,现在再用面向对象的思想来解决。

先建立两个类:Child类和Circle类,分别保存小屁孩儿的信息和圆圈的信息。

约瑟夫问题的面向对象思想解决方法

约瑟夫问题的面向对象思想解决方法

代码如下:

Child类:

/**
 * 用于描述小孩儿的信息,最关键的是该小孩儿前后的两个小孩
 * @author Bigworld
 */
class Child {
	static int count = 1; // 用于生成小孩的编号,每次实例化一个小孩会加1
	
	Child prev, next; // 表示该小孩前后2个小孩
	int id;			// 表示小孩的编号

	public Child() {
		id = count ++; // 给小孩加编号
	}
}

继续阅读

Java修道之路:我也来讲讲约瑟夫问题

“约瑟夫”名字听起来挺B格的,可是不要以为是什么很高深的玩意儿。

举个例子:

有30个小屁孩儿,手拉手的围成一个圈,然后从第一个小屁孩儿开始报数,1,2,3,当报到3时,报3的那个小屁孩儿就退出圈,然后从该报4的那个小 屁孩儿重新开始报1,当又报到3时,报3的那个小屁孩儿退出,这样反复循环,当只剩下最后一个小屁孩儿的时候,问该小屁儿是这个圈中的第几个小屁孩儿。

问题就是这么简单,怎么做呢?

首先想到的就是使用数组模拟这个圈,方法可以,但是程序写起来比较繁琐。

那么面向对象思想呢?也可以,定义一个小孩儿类和一个圈类,然后构建一个双向循环链表,也可以搞定。但是代码量也挺大,而且构建链表的时候会犯晕……

其实,我想说的是一个代码量很少而且也很好理解的算法,就是使用Java提供的“队列(Queue)”,就可以轻松搞定。但是,在这之前必须转换一下思维。 继续阅读

Java修道之路:遍历枚举类以及随机选取枚举值的方法

Java中的Enum是个不错的东西,中文名字叫做“枚举”,怎么用呢?

首先定义一个枚举类,枚举类定义出来就是静态的,里面的值可以自己任意命名,之后Java会自动分配相应的int值,而我们调用枚举类不需要使用int值,而是直接使用枚举的命名,这个用法有点类似于常量。

在枚举类的API中(lang.Enum)还有一些方法,比如ordinal方法就是返回该枚举值对应的int值。

枚举类是定义出来了,但是如果想遍历该枚举类,以及随机选取一个枚举值,该怎么做呢?

经过实验,下面方法可行: 继续阅读

Java修道之路:为 JPanel添加事件监听

使用Java.swing创建窗口的时候一般如下代码:

JFram jf = new JFram();
Jpanel jp = new JPanel;
jf.add(jp);

这样,就创建了一个窗口。

这时如果想要向jp中的对象加入控制事件(如键盘事件),会遇到一个问题:jp无法获得事件……而监听到事件的是jf。

后来查询得知,其实代码很简单,只用给jp添加一段代码即可:

jp.setFocusable(true);

这段代码的意思是重新设置jp的焦点,覆盖其父类 Component的焦点设置,这样jp就可以获得事件了!