1.
简述逻辑操作
(&,|,^)
与条件操作
(&&,||)
的区别。
(15
分
)
2.
下面程序运行会发生什么结果
?
如果有错误,如何改正
? (15
分
)
interface A{
int x = 0;
}
class B{
int x =1;
}
class C
extends B implements A {
public void pX(){
System.out.println(x);
}
public static void main(String[] args) {
new C().pX();
}
}
}
3.
简述
Java Server Page
和
Servlet
的联系和区别。
(20
分
)
4.XML
文档定义有几种形式?它们之间有何本质区别?
解析
XML
文档有哪几种方式?
(20
分
)
5.
简述
synchronized
和
java.util.concurrent.locks.Lock
的异同?
(15
分
)
6.EJB
规范规定
EJB
中禁止的操作有哪些?
(15
分
)
7.
最后还有一题考考你的眼力
:
public String toString(){
return this + "@" + this.hashCode();
}
这个
toString()
方法实现有无不当的地方
?(toString
方法其实可以按你想输出的任何内容输出一些该类的信息
)
答案:
1.
简述逻辑操作
(&,|,^)
与条件操作
(&&,||)
的区别。
(15
分
)
区别主要答两点
:
a.
条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型
,
而且可以操作数值型
b.
逻辑操作不会产生短路
.
如
:
int a = 0;
int b = 0;
if( (a = 3) > 0 || (b = 3) > 0 ) //
操后
a =3,b=0.
if( (a = 3) > 0 | (b = 3) > 0 ) //
操后
a =3,b=3.
答对第一点得
5
分,答对第二点得
10
分
.
本题考察最最基本的知识
,
但仍然有很多大牛级开发人员下马,任何语言在开始的部分
都会详细介绍这些基本知识,但除了学习第一种语言时,没有人在学习新的语言时愿意
花五分钟来复习一下
.
2.
下面程序运行会发生什么结果
?
如果有错误,如何改正
? (15
分
)
interface A{
int x = 0;
}
class B{
int x =1;
}
class C
extends B implements A {
public void pX(){
System.out.println(x);
}
public static void main(String[] args) {
new C().pX();
}
}
}
本题在编译时会发生错误
(
错误描述不同的
JVM
有不同的信息,意思就是未明确的
x
调用,
两个
x
都匹配,就象在同时
import java.util
和
java.sql
两个包时直接声明
Date
一样
)
本题主要考察对接口和类的最最基本的结构的了解
.
对于父类的变量,可以用
super.x
来
明确,而接口的属性默认隐含为
public static final.
所以可以通过
A.x
来明确
.
3.
简述
Java Server Page
和
Servlet
的联系和区别。
(20
分
)
本题不用多说,在答相同点时应该明确知道
jsp
编译后是
"
类
servlet"
而
"
不是
Servlet"
,
答区别时应该回答出
"
侧重于
(
视图
/
控制逻辑
)".
其它可根据情况加减分值
.
知识很简单,
但从面试的角度看,被试者不仅要能知道它们的区别,而且要能比较准确地表达出来
(
以
后写文档要能让别人看得懂,不产生歧义
)
,回答
"jsp
编译后就是
servlet"
视为错误,回答
"jsp
用于视图,
servlet
用于控制逻辑
"
视为错误,应该用侧重于,主要
(
多数
)
用于等词语
表达
.
4.XML
文档定义有几种形式?它们之间有何本质区别?
解析
XML
文档有哪几种方式?
(20
分
)
本题三个答题点
:
a:
两种形式
dtd
,
schema
b:
本质区别
:schema
本身是
xml
的,可以被
XML
解析器解析
(
这也是从
DTD
上发展
schema
的
根本目的
)
c:
两种主要方式
:dom
,
sax.
答出两种得全分,如能答出
saxt
,或其它
(
在答出
dom
,
sax
的基
础上,如果应试者认为其它方式也可以视为对
xml
的解析应该允许
.
但没有答出
dom
,
sax
把
其它方式说成是对
XML
的解析不得分
)
应该加分
.
5.
简述
synchronized
和
java.util.concurrent.locks.Lock
的异同?
(15
分
)
主要相同点
:
Lock
能完成
synchronized
所实现的所有功能
.(
其它不重要
)
主要不同点
:
Lock
有比
synchronized
更精确的线程语义和更好的性能
(
在相同点中回答此点也行
)
synchronized
会自动释放锁
.
而
Lock
一定要求程序员手工释放
.
并且必须在
finally
从句
中释放,如果没有答出在
finally
中释放不得分
.
就如
Connection
没有在
finally
中关闭一
样
.
连最基本的资源释放都做不好,还谈什么多线程编程
.
6.EJB
规范规定
EJB
中禁止的操作有哪些?
(15
分
)
共有
8
点,答出下列
3-4
点得满分
.
·
不能操作线程和线程
API(
线程
API
指非线程对象的方法如
notify
,
wait
等
)
·
不能操作
awt
·
不能实现服务器功能
·
不能对静态属生存取
.
·
不能使用
IO
操作直接存取文件系统
·
不能加载本地库
.
·
不能将
this
作为变量和返回
.
·
不能循环调用
.
7
public String toString(){
return this + "@" + this.hashCode();
}
会变成
public String toString(){
return String.valueOf(this) + "@" + String.valueOf(this.hashCode());
}
而
valueOf
方法又将去调用
toString();
/**
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
*/
这样好像会有问题
原文地址:
Java
本身没有这个能力,不过利用操作系统的命令可以做到。
public static String getMACAddress() {
String address = "";
String os = System.getProperty("os.name");
if ( os != null && os.startsWith("Windows")) {
try {
String command = "cmd.exe /c ipconfig /all";
Process p = Runtime.getRuntime().exec(command);
BufferedReader br =
new BufferedReader(
new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
if (line.indexOf("Physical Address") > 0) {
int index = line.indexOf(":");
index += 2;
address = line.substring(index);
break;
}
}
br.close();
return address.trim();
}
catch (IOException e) { }
}
return address;
}
原文地址:
equals
方法的重要性毋须多言,只要你想比较的两个对象不愿是同一对象,你就应该实现
equals
方法,让对象用你认为相等的条件来进行比较
.
下面的内容只是
API
的规范,没有什么太高深的意义,但我之所以最先把它列在这儿,是因为
这些规范在事实中并不是真正能保证得到实现
.
1.
对于任何引用类型,
o.equals(o) == true
成立
.
2.
如果
o.equals(o1) == true
成立,那么
o1.equals(o)==true
也一定要成立
.
3.
如果
o.equals(o1) == true
成立且
o.equals(o2) == true
成立,那么
o1.equals(o2) == true
也成立
.
4.
如果第一次调用
o.equals(o1) == true
成立再
o
和
o1
没有改变的情况下以后的任何次调用
都成立
.
5.o.equals(null) == true
任何时间都不成立
.
以上几条规则并不是最完整的表述,详细的请参见
API
文档
.
对于
Object
类,它提供了一个最最严密的实现,那就是只有是同一对象是,
equals
方法才返回
true
,也就是人们常说的引用比较而不是值比较
.
这个实现严密得已经没有什么实际的意义,所以在具体子类
(
相对于
Object
来说
)
中,如果我们要进行对象的值比较,就必须实现自己的
equals
方法
.
先来看一下以下这段程序
:
public boolean equals(Object obj)
{
if (obj == null) return false;
if (!(obj instanceof FieldPosition))
return false;
FieldPosition other = (FieldPosition) obj;
if (attribute == null) {
if (other.attribute != null) {
return false;
}
}
else if (!attribute.equals(other.attribute)) {
return false;
}
return (beginIndex == other.beginIndex
&& endIndex == other.endIndex
&& field == other.field);
}
这是
JDK
中
java.text.FieldPosition
的标准实现,似乎没有什么可说的
.
我信相大多数或绝大多数程序员认为,这是正确的合法的
equals
实现
.
毕竟它是
JDK
的
API
实现啊
.
还是让我们以事实来说话吧
:
package debug;
import java.text.*;
public class Test {
public static void main(String[] args) {
FieldPosition fp = new FieldPosition(10);
FieldPosition fp1 = new MyTest(10);
System.out.println(fp.equals(fp1));
System.out.println(fp1.equals(fp));
}
}
class MyTest extends FieldPosition{
int x = 10;
public MyTest(int x){
super(x);
this.x = x;
}
public boolean equals(Object o){
if(o==null) return false;
if(!(o instanceof MyTest )) return false;
return ((MyTest)o).x == this.x;
}
}
运行一下看看会打印出什么
:
System.out.println(fp.equals(fp1));
打印
true
System.out.println(fp1.equals(fp));
打印
flase
两个对象,出现了不对称的
equals
算法
.
问题出在哪里
(
脑筋急转弯:当然出在
JDK
实现的
BUG)?
我相信有太多的程序员
(
除了那些根本不知道实现
equals
方法的程序员外
)
在实现
equals
方法
时都用过
instanceof
运行符来进行短路优化的,实事求是地说很长一段时间我也这么用过。
太多的教程,文档都给了我们这样的误导。而有些稍有了解的程序员可能知道这样的优化可能
有些不对但找不出问题的关键。另外一种极端是知道这个技术缺陷的骨灰级专家就提议不要这
样应用。
我们知道,
"
通常
"
要对两个对象进行比较,那么它们
"
应该
"
是同一类型。所以首先利用
instanceof
运行符进行短路优化,如果被比较的对象不和当前对象是同一类型则不用比较返回
false
,但事实
上,
"
子类是父类的一个实例
"
,所以如果子类
o instanceof
父类,始终返回
true
,这时肯定
不会发生短路优化,下面的比较有可能出现多种情况,一种是不能造型父类而抛出异常,另一种
是父类的
private
成员没有被子类继承而不能进行比较,还有就是形成上面这种不对称比较。可能
会出现太多的情况。
那么,是不是就不能用
instanceof
运行符来进行优化?答案是否定的,
JDK
中仍然有很多实现是正
确的,如果一个
class
是
final
的,明知它不可能有子类,为什么不用
instanceof
来优化呢?
为了维护
SUN
的开发小组的声誉,我不说明哪个类中,但有一个小组成员在用这个方法优化时在后加
加上了加上了这样的注释:
if (this == obj) // quick check
return true;
if (!(obj instanceof XXXXClass)) // (1) same object?
return false;
可能是有些疑问,但不知道如何做(不知道为什么没有打电话给我
......
)
那么对于非
final
类,如何进行类型的
quick check
呢?
if(obj.getClass() != XXXClass.class) return false;
用被比较对象的
class
对象和当前对象的
class
比较,看起来是没有问题,但是,如果这个类的子类
没有重新实现
equals
方法,那么子类在比较的时候,
obj.getClass()
肯定不等于
XXXCalss.class
,
也就是子类的
equals
将无效,所以
if(obj.getClass() != this.getClass()) return false;
才是正
确的比较。
是否
equals
方法一定比较的两个对象就一定是要同一类型?上面我用了
"
通常
"
,这也是绝大多数程序
员的愿望,但是有些特殊的情况,我们可以进行不同类型的比较,这并不违反规范。但这种特殊情况
是非常罕见的,一个不恰当的例子是,
Integer
类的
equals
可以和
Sort
做比较,比较它们的
value
是不
是同一数学值。(事实上
JDK
的
API
中并没有这样做,所以我才说是不恰当的例子)
在完成
quick check
以后,我们就要真正实现你认为的
“
相等
”
。对于如果实现对象相等,没有太高
的要求,比如你自己实现的
“
人
”
类,你可以认为只要
name
相同即认为它们是相等的,其它的
sex
,
ago
都可以不考虑。这是不完全实现,但是如果是完全实现,即要求所有的属性都是相同的,那么如
何实现
equals
方法?
class Human{
private String name;
private int ago;
private String sex;
....................
public boolean equals(Object obj){
quick check.......
Human other = (Human)ojb;
return this.name.equals(other.name)
&& this.ago == ohter.ago
&& this.sex.equals(other.sex);
}
}
这是一个完全实现,但是,有时
equals
实现是在父类中实现,而要求被子类继承后
equals
能正确的工
作,这时你并不事实知道子类到底扩展了哪些属性,所以用上面的方法无法使
equals
得到完全实现。
一个好的方法是利用反射来对
equals
进行完全实现:
public boolean equals(Object obj){
quick check.......
Class c = this.getClass();
Filed[] fds = c.getDeclaredFields();
for(Filed f:fds){
if(!f.get(this).equals(f.get(obj)))
return false;
}
return true;
}
为了说明的方便,上明的实现省略了异常,这样的实现放在父类中,可以保证你的子类的
equals
可以按
你的愿望正确地工作。
关于
equals
方法的最后一点是:如果你要是自己重写(正确说应该是履盖)了
equals
方法,那同时就一
定要重写
hashCode().
为是规范,否则
.............
我们还是看一下这个例子:
public final class PhoneNumber {
private final int areaCode;
private final int exchange;
private final int extension;
public PhoneNumber(int areaCode, int exchange, int extension) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(exchange, 99999999, "exchange");
rangeCheck(extension, 9999, "extension");
this.areaCode = areaCode;
this.exchange = exchange;
this.extension = extension;
}
private static void rangeCheck(int arg, int max, String name) {
if(arg < 0 || arg > max)
throw new IllegalArgumentException(name + ": " + arg);
}
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode;
}
}
注意这个类是
final
的,所以这个
equals
实现没有什么问题。
我们来测试一下
:
public static void main(String[] args) {
Map hm = new HashMap();
PhoneNumber pn = new PhoneNumber(123, 38942, 230);
hm.put(pn, "I love you");
PhoneNumber pn1 = new PhoneNumber(123, 38942, 230);
System.out.println(pn);
System.out.println("pn.equals(pn1) is " + pn.equals(pn1));
System.out.println(hm.get(pn1));
System.out.println(hm.get(pn));
}
既然
pn.equals(pn1)
,那么我
put(pn,"I love you");
后,
get(pn1)
这什么是
null
呢?
答案是因为它们的
hashCode
不一样,而
hashMap
就是以
hashCode
为主键的。
所以规范要求,如果两个对象进行
equals
比较时如果返回
true
,那么它们的
hashcode
要求返回相等的值。
原文地址:
在
JDBC
应用中,如果你已经是稍有水平开发者,你就应该始终以
PreparedStatement
代替
Statement.
也就是说,在任何时候都不要使用
Statement.
基于以下的原因
:
一
.
代码的可读性和可维护性
.
虽然用
PreparedStatement
来代替
Statement
会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说
.
都比直接用
Statement
的代码高很多档次
:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();
不用我多说,对于第一种方法
.
别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心
.
二
.PreparedStatement
尽最大可能提高性能
.
每一种数据库都会尽最大努力对预编译语句提供最大的性能优化
.
因为预编译语句有可能被重复调用
.
所以语句在被
DB
的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中
(
相当于一个涵数
)
就会得到执行
.
这并不是说只有一个
Connection
中多次执行的预编译语句被缓存,而是对于整个
DB
中,只要预编译的语句语法和缓存中匹配
.
那么在任何时候就可以不需要再次编译而可以直接执行
.
而
statement
的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配
.
比如
:
insert into tb_name (col1,col2) values ('11','22');
insert into tb_name (col1,col2) values ('11','23');
即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义
.
事实是没有数据库会对普通语句编译后的执行代码缓存
.
这样每执行一次都要对传入的语句编译一次
.
当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果
.
以保存有更多的空间存储新的预编译语句
.
三
.
最重要的一点是极大地提高了安全性
.
即使到目前为止,仍有一些人连基本的恶义
SQL
语法都不知道
.
String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
如果我们把
[' or '1' = '1]
作为
varpasswd
传入进来
.
用户名随意,看看会成为什么
?
select * from tb_name = '
随意
' and passwd = '' or '1' = '1';
因为
'1'='1'
肯定成立,所以可以任何通过验证
.
更有甚者,把
[';drop table tb_name;]
作为
varpasswd
传入进来,则
select * from tb_name = '
随意
' and passwd = '';drop table tb_name;
有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行
.
而如果你使用预编译语句
.
你传入的任何内容就不会和原来的语句发生任何匹配的关系
.(
前提是数据库本身支持预编译,但上前可能没有什么服务端数据库不支持编译了,只有少数的桌面数据库,就是直接文件访问的那些
)
只要全使用预编译语句,你就用不着对传入的数据做任何过虑
.
而如果使用普通的
statement
,有可能要对
drop
,等做费尽心机的判断和过虑
.
上面的几个原因,还不足让你在任何时候都使用
PreparedStatement
吗
?
原文地址:
一个利己线程调度实例?
所谓利己线程,就是在运行时不考虑其它线程的运行权限和时间分配,一心只顾自己运行完成了事的这种线程,比如
:while(true){............}
但是
,
如果
{..........}
的代码中要调用一些资源,就一定要
sleep
,让资源有空闲的时间来让本线程获取,也许这些资源不是当前线程一方要求调用,但无论如何要空闲一定的时间,即使资源空闲下来时本线程只能调用很少一部份,不然真的就死锁了
.
在图形编程中,加载一个图形是异步的,然后组件会调用观察类
ImageObserver
来不断让图形加载和显示进行更新直到完成
.
因为图形组件的顶级对象
Component
已经实现
ImageObserver
,所以一般来说如果要加载一个
Image
,只要在
drawImage
方法中调用
this(
自己
)
作为观察者就行
.
但是,如果我们要把一个源图象缩放后输出,或把多个源图象合并成一个图象输出
(
图形计数器就是把很多种
0-9
的数字图片合并成一个图片
)
输出,那就是在内存中先生生成一个
BufferedImage
对象,然后把源图象
draw
到
BufferedImage
的一定位置,再把
BufferedImage
编码输出到一个输出流如文件或网页
.
因为
drawImage
是
BufferedImage
的
Graphics
对象调用的,一切都在内存中而根本没有可视组件,所以根本没有观察者对象,而
MediaTracker
对象同样要求一个组件对象构造,在这种时候也没法调用
.
BufferedImage bi = new BufferedImage(
目标宽,目标高,
BufferedImage.TYPE_INT_RGB);
Graphics2D g =(Graphics2D)image.getGraphics();
Image src = Toolkit.getDefaultToolkit().getImage("d:/aaa.jpg");
不管你的
src
原来是多大,只要你
draw
时设定大小,就会以你设定的大小画到目标
bi
上,这就是
缩略图或合成图的方法
.
但在
g.drawImage(src
,坐标
x
,坐标
y
,宽,高,观察者
);
调用时,因为没有一个观察者实例,一次调用
99%
不会成功
.
所以我是这样调用的
:
while (!(flag=g.drawImage(src, 0, 0, 240, 320, null))) ;
大家注意是如果
flag
为
flase
就只有一个
";"
也就是什么也不做直接进入下一次循环
.
我试过一般画一张新图要
10
多秒,如果是生成计数器,这在
servlet
中根本不行
.
没有人愿意用
10
秒的时间等一个计数器出来
.
后来我想让这个
servlet
实现观察者
.
就在
while (!(flag=g.drawImage(src, 0, 0, 240, 320, null))) {
}
中调试它每次
getWidth(null)
的
log
并打印出来,结果发现如果改成
while (!(flag=g.drawImage(src, 0, 0, 240, 320, null))) {
System.out.println(src.getWidth(null));
}
却只要
200MS
,
0.2
秒左右就完成了
.
原来,
System.out
时要调用
BIOS
的资源,这时线程要闲置等待,到反而让
src
资源有了
load
的时间
.
于是改成
:
while (!(flag=g.drawImage(src, 0, 0, 240, 320, null))) {
Thread.currentThread().sleep(1);
}
哈哈
,
成功了
.sleep
时
1,5,10MS
没有多大区别
,
都在
200MS
左右完成
,
一般不要再睡更多的时间
.
所以即使是利己线程的也要看它是否对其它资源的请求
,
真的应了那句话叫
"
予人方便
,
于己方便
!"
原文地址:
有的用户比如叫扬璠,或是李珺。就不能正确显示她的名字,而显示一个扬?
,
李
?
,其他中文没问题,就是这些比较偏怪的中文无法显示。这就是
GBK
和
GB2312
的区别
,
你说的那几个字是
GBK
中的
,GB2312
中根本没有
,
只好
??
了,使用
GBK
就行了。
原文地址:
方法一:
在
JDK CLASSPATH
下命令行打包:
用法:
jar {ctxu}[vfm0M] [jar-
文件
] [manifest-
文件
] [-C
目录
]
文件名
...
选项:
-c
创建新的存档
-t
列出存档内容的列表
-x
展开存档中的命名的(或所有的〕文件
-u
更新已存在的存档
-v
生成详细输出到标准输出上
-f
指定存档文件名
-m
包含来自标明文件的标明信息
-0
仅限存储方式;使用非
ZIP
压缩格式
-M
不生成所有项的清单(
manifest
〕文件
-i
为指定的
jar
文件产生索引信息
-C
改变到指定的目录,并且包含参数
如果指定的文件都是目录,将会使用递归方式加以处理。
必须以指定
'm'
和
'f'
选项的顺序,指定清单
〔
manifest
〕文件名和存档文件名。
示例
1
:将两个
class
文件保存到名称为
'classes.jar'
的存档文件中:
jar cvf classes.jar Foo.class Bar.class
示例
2
:使用现有的清单(
manifest
)文件
'mymanifest'
,将
foo/
目录
下的所有文件保存到名称为
'classes.jar'
的存档文件中:
jar cvfm classes.jar mymanifest -C foo/ .
war
:
jar cvf webapp.war webapp/
ear: jar cvf enapp.ear enapp/
方法二:
在
weblogic classpath
下,
java weblogic.ant.taskdefs.ejb20.DDInit <target directory>
java weblogic.ant.taskdefs.war.DDInit <target directory>
java weblogic.ant.taskdefs.ear.DDInit <target directory>
jar cf jar-file files ...
方法三:
使用打包工具,比如
weblogic builder
。
原文地址:
乱码问题在
JAVA
平台的
jsp/servlet
中可以说是非常令初学者头痛的事
,
甚至很多
"
高手
(
当然只是所谓的
,
如果连乱码都不能解决还叫什么高手
)"
都不知所措
.
我先说明
,
乱码问题绝对没有一种通用的方法来解决绝
,
除非你你都用
i18n
来定义和用
UTF
来传传输
,
显示
,
但这是不可能的
.
我们只有根本不同原因来用不同的解决方案
.
要从底层解决乱码
,
要求程序员要熟悉数据在网络上和内存中的每一个字节是来源和去向
,
这样才能从根本上解决
.
产生的原因
:
1:
数据传输入过程中没有按协议格式化
.
2:
没有根据当前环境决定显示方式
.
下面为了说明
,
我们只讨论汉字乱码产生的原因
:
从客户端提交给服务端
,
对于
POST
传送
,
目前的浏览器都能正确编码
,
但
QueryString
方法是程序员控制的
,
很多程序员根本不对中文的
URL
格式化
,
直接用中文作为参数传送
,
对于
IE6
这样的智能程序高的浏览器可以自动格式化
,
而老版本的浏览器测原方传送
,
则服务器端程序不能正确地从标准输入中取得
.
应该先格式化编码。
如果网络上或内存中原如数据是正确的
,
但要用正确的方式从
byte
转换成系统能显示的字符集
.
假设
"
我
"
的
byte
表示为
78,63(
只是例子
)
,但
78,63
有可能表示日文的ぬ
,
那你就要告诉系统
,
你当前的
byte[] b
表示的是什么字符集
.
而我所见过的
jsp/servlet
容器中除了
resin
在
getParameter()
这个方法实现中都是
return new String(b//byte[]);
而没有指定字集
.WLS
我没的反编译
,
所以不知道它的
HTMLUtil
这个类在实现时是如何指定字符集还是没有。如果各种方法不能解决
,
我们只能对
BEA
不敬了
,
把
ServletRequestWrapper
类
decode
出来
,
在
getParameter()
方法中直接
return new String(b,"GBK")
得了
.
这样省得在
XML
中配置又不起作用。同样从数据库中如果取得的数据乱码
,
我们只要把
JDBC
的
ResultSet
类
decode
出来
,
把其中的
getString(int column)
方法中的
return new String(b)
方法都强行加上
"GBK"
这样取数据保证正确了
,
然后再来解决显示的问题
,
即使你的数据在内存中是正确的
,
你也指定了正确的字符集参数
,
仍然不能保证你看到的是正确的
,
原因是系统知道这个编码是对的
,
但它没有这种字符集来显示
,
或你用来显示的字集不对
.
这就是
JSP
中
<%@page contentType="text/html;charset=xxxx"%>
的作用
,
有人以为光这样就正确了
,
你要知道这句和
response.setContentType("text/html;charset=xxxx");
是一样的
,
只它是告诉浏览器我现在发给你的内容是用
xxxx
字符集来解释的
,
只能在从网络上或内存中取得的数据是正确的前提下才有用
.
现在
servet
也
1.2
也支持设置客户端字符集的方法了
:setCharacterEncoding.
所以乱码问题绝不是一种方法能解决的
,
我们一定要知道它产生的原因
,
从底层来进行原始数据的转换才能解决
.
其实找原因也很简单
,
在
HttpUtil
中加一个直接
getBytes()
方法
,
把得到的原始数据看看是不是你你传过来的
.
比如从
QueryString
传过来
"
我
"aaa.jsp?name=
我
,
那你看看它的
byte
中是不是我的值
,
如果是
,
说明传送没有问题
,
不是就是没有格式化
.
一步步下来
,
总是不难解决的。
原文地址:
如果你只是声明了一个普通
HttpServlet
,那肯定是一个实例多个线程在服务。而如果你声明的同时实现
SingleThreadModel
接口那么
Servlet
是单线程服务,
Servlet
会在一个池里像
EJB
一样在为你服务。
原文地址:
以下措施可以保证这一点,建议在开发过程中使用:
1. startWebLogic.cmd:
set STARTMODE=false
2. web.xml:
<servlet-mapping>
<servlet-name>loginA</servlet-name>
<url-pattern>/servlet/loginCheckA</url-pattern>
<load-on-startup>0</load-on-startup>
</servlet-mapping>
3. weblogic.xml:
<jsp-param>
<param-name>pageCheckSeconds</param-name>
<param-value>0</param-value>
</jsp-param>
4.Make sure that your servlet classes are not in your classpath which can cause this problem.
5.
在
WLS console
中
,
在该
web app
的
Files
页中
,
把
<Reload Period>
设为
1
原文地址:
Tomcat关于UTF-8JSP文件的BUG
刚才
,
我都要睡下了
,
朋友打来电话
,
他们公司新装了
TOMCAT5,
然后在编译
JSP
时
,
被
INCLUDE
的
JSP
都出现了问题
.
就是编译后被
INCLUDE
的地方多了两个
"??"
而其它正常
,
而如果手工把被
INCLUDE
的内容
COPY
上去测没有问题
.
他们的工程师都不知道是什么问题
,
因为周一要发布出去
,
所以非常着急
.
我不知道大家听到这种情况会如何
,
我知道大多数人比我聪明
,
你肯定想到了
,
所以你没有必要再看了
.
我下面的内容只是对没有想到的人而言
.
其实他电话还没打完
,
我就知道问题
99%
是他的
jsp
在编辑的时候是存为
UTF-8
而不是
ANSI
格式
,
否则没有道理出现这种问题
,
事实正是如此
,
我让他用
UE
打开看看果然前面多了几个
UTF
字符
.
重要的是
TOMCAT
这种容器竟然有这样的
BUG,
不能正确读取
UTF-8
格式的文件
,
你总不能强求用户编辑
JSP
文件时一定要存为什么格式吧
?
费话少说
,
下载
tomcat5
的
src,
进入
jakarta-tomcat-jasper/jasper2/src/share/org/apache/jasper/compiler
找到
JspUtil.java
找到
public static InputStream getInputStream(String fname, JarFile jarFile,
JspCompilationContext ctxt,
ErrorDispatcher err)
throws JasperException, IOException {
InputStream in = null;
if (jarFile != null) {
String jarEntryName = fname.substring(1, fname.length());
ZipEntry jarEntry = jarFile.getEntry(jarEntryName);
if (jarEntry == null) {
err.jspError("jsp.error.file.not.found", fname);
}
in = jarFile.getInputStream(jarEntry);
} else {
in = ctxt.getResourceAsStream(fname);
}
if (in == null) {
err.jspError("jsp.error.file.not.found", fname);
}
return in;
}
在return in前加上判断,改成:
public static InputStream getInputStream(String fname, JarFile jarFile,
JspCompilationContext ctxt,
ErrorDispatcher err)
throws JasperException, IOException {
InputStream in = null;
if (jarFile != null) {
String jarEntryName = fname.substring(1, fname.length());
ZipEntry jarEntry = jarFile.getEntry(jarEntryName);
if (jarEntry == null) {
err.jspError("jsp.error.file.not.found", fname);
}
in = jarFile.getInputStream(jarEntry);
} else {
in = ctxt.getResourceAsStream(fname);
}
if (in == null) {
err.jspError("jsp.error.file.not.found", fname);
}
PushbackInputStream testin = new PushbackInputStream(in);
int ch = testin.read();
if (ch != 0xef) {
testin.unread(ch);
}
else if ((ch = testin.read()) != 0xbb) {
testin.unread(ch);
testin.unread(0xef);
}
else if ((ch = testin.read()) != 0xbf) {
throw new IOException("
错误的UTF-8格式文件");
}
else{
//fStream.setEncoding("UTF-8");
testin.read();
}
return testin;
}
编译
,
重新打包
,
替换原来的包
,
运行
TOMCAT,OK!
整个问题解决除了远程登录他的服务器传送文件的时间
,
总共只有
4-5
分钟
.
其实只要问题定位准确
,
就不难解决了
.
我一再强调的是经熟悉底层
,
你如果知道内存中每个
byte
从哪儿来要到哪儿去
,
就可以非常容易地解决问题
.
在此之前我连
TOMCAT5
下载都没有下过
,
更别说试用了
.
但只要你对
JDK
有深入的了解
,
就可以准确地定位问题的所在
.
希望本文能给不是高手的朋友一点帮助和启发
,
对于高手的朋友你可以弃之一笑
.
原文地址:
使用FileUpload组件上传文件?
文件上传在
web
应用中非常普遍,要在
jsp
环境中实现文件上传功能是非常容易的,因为网上有许多用
java
开发的文件上传组件,本文以
commons-fileupload
组件为例,为
jsp
应用添加文件上传功能。
common-fileupload
组件是
apache
的一个开源项目之一,可以从
http://jakarta.apache.org/commons/fileupload/
下载。用该组件可实现一次上传一个或多个文件,并可限制文件大小。
下载后解压
zip
包,将
commons-fileupload-1.0.jar
复制到
tomcat
的
webapps/
你的
webapp/WEB-INF/lib/
下,目录不存在请自建目录。
新建一个
servlet: Upload.java
用于文件上传:
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.*;
public class Upload extends HttpServlet {
private String uploadPath = "C://upload//"; //
上传文件的目录
private String tempPath = "C://upload//tmp//"; //
临时文件目录
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
}
}
在
doPost()
方法中,当
servlet
收到浏览器发出的
Post
请求后,实现文件上传。以下是示例代码:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
try {
DiskFileUpload fu = new DiskFileUpload();
//
设置最大文件尺寸,这里是4MB
fu.setSizeMax(4194304);
//
设置缓冲区大小,这里是4kb
fu.setSizeThreshold(4096);
//
设置临时目录:
fu.setRepositoryPath(tempPath);
//
得到所有的文件:
List fileItems = fu.parseRequest(request);
Iterator i = fileItems.iterator();
//
依次处理每一个文件:
while(i.hasNext()) {
FileItem fi = (FileItem)i.next();
//
获得文件名,这个文件名包括路径:
String fileName = fi.getName();
//
在这里可以记录用户和文件信息
// ...
//
写入文件,暂定文件名为a.txt,可以从fileName中提取文件名:
fi.write(new File(uploadPath + "a.txt"));
}
}
catch(Exception e) {
//
可以跳转出错页面
}
}
如果要在配置文件中读取指定的上传文件夹,可以在init()方法中执行:
public void init() throws ServletException {
uploadPath = ....
tempPath = ....
//
文件夹不存在就自动创建:
if(!new File(uploadPath).isDirectory())
new File(uploadPath).mkdirs();
if(!new File(tempPath).isDirectory())
new File(tempPath).mkdirs();
}
编译该
servlet
,注意要指定
classpath
,确保包含
commons-upload-1.0.jar
和
tomcat/common/lib/servlet-api.jar
。
配置
servlet
,用记事本打开
tomcat/webapps/
你的
webapp/WEB-INF/web.xml
,没有的话新建一个。
典型配置如下:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>Upload</servlet-name>
<servlet-class>Upload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Upload</servlet-name>
<url-pattern>/fileupload</url-pattern>
</servlet-mapping>
</web-app>
配置好servlet后,启动tomcat,写一个简单的html测试:
<form action="fileupload" method="post"
enctype="multipart/form-data" name="form1">
<input type="file" name="file">
<input type="submit" name="Submit" value="upload">
</form>
注意
action="fileupload"
其中
fileupload
是配置
servlet
时指定的
url-pattern
。
原文地址:
我在程序中设置
bea
的
scope="session"
,可是总出以下警告,程序可以正常执行
<2004-6-14 下午 16 时 23 分 55 秒 CST> <Warning> <HTTP Session> <BEA-100061> <Web application: ServletContext(id=8782613,name=DefaultWebApp,context-path=) tried to pl
<2004-6-14 下午 16 时 23 分 55 秒 CST> <Warning> <HTTP Session> <BEA-100061> <Web application: ServletContext(id=8782613,name=DefaultWebApp,context-path=) tried to pl
ace a non-serializable attribute: conn into the session: ANgbIJn2Rb719Kv0AlCpckp
irYkwOSzHw2Ypte1STZ2VH92Nuttb!-2121598438!1087201435515. This attribute will be
lost upon redeployment. This message is logged only once per session.>
这是因为这个
conn
对象不可以串行化,如这样会出现警告信息。
原文地址:
《
J2EE
核心模式》中提到避免重复提交的方法是使用令牌(
token
),在生成修改页面的同时生成一个
token
,把它放在表单(
form
)的一个隐藏域里,并且把它放在
session
属性中。用户提交表单的时候,比较
form
的
token
和
session
中的
token
是否一样,如果一样,修改
session
中的
token
(如果用户刷新,两个
token
就不一样),然后执行操作;如果不一样那就是重复提交的表单,不执行。
原文地址:
这和容器的实现方式有关系,因为在
JSP
中一般不直接操作二进制输出流,一般的容器在解释
JSP
标签时,每一行都加入一个
" ",
如
:
<%OutputStream.write(byte[] b1)%>
<%OutputStream.write(byte[] b2)%>
这样在连续的二进制流中就多了一个空格
,
肯定没有用了
.
当然象
<%@page .....%>
<jsp:useBean ......../>
这类的标签肯定在每一行加了
" ",
也就是调用了
Writer
接口的
println
方法
.
你看连那个老外写的
jspSmartUpload
的例子中
,
他穷极无奈只好把
<%pag....e%>< jsp:useBean../><%%>
写在一行上
,
一旦分开,下载的例子中下载的文件就不对了。
有些容器在实现时如果要输出二进制文件是
,
会自动清空输出流
,
也就是把原来缓冲中
Writer
子类写的文本流清空
,
然后输出二进制流以保证数据的正确性和完整性
,
这是
"
人情
",
因为规范没有要求这么做
,
所以如果不能自动重设你也不能说它不对
,
这叫
"
本份
".
你只有手要调用
,
其实很简单
,
在
response.setContentType ()
前
,
自己把文本流先清空就行了
.
因为容器在解释
JSP
文件前
,
只要看到是这个编译后的
servlet
是实现
HttpJspPage
接口
,
那就肯定先
setContentType
为
("text/html"),
你在调用是
setContentType
为
("image/png")
其实是在改变输出流类型
,
所以应该先空
response
的
buffer,
方法就是一句话
;response.reset();
放在
setContentType ("image/png");
前面啊
.
我这样解释不知道你明白了没有
,
其实在任何调用二进制输出流时都应该调用这一句
,
不管容器有没有先调用
,
你再调用一次也没有关系
.
原文地址:
正常下载完毕可释放资源,可下载中途取消就不行了,我用
finally
也不行,点取消按钮后,
finally
内的代码并没有执行,只有页面时它才认为程序需要关闭而执行
finally
内的代码;
程序如下:
<%
InputStream inStream=null;
try{ inStream=new FileInputStream("/download/"+id);
//
设置输出的格式
response.reset();
response.setContentType("bin");
response.addHeader("Content-Disposition","attachment;filename");
//
循环取出流中的数据
byte[] b = new byte[100];
int len;
while((len=inStream.read(b))>0)
response.getOutputStream().write(b,0,len);
inStream.close();
response.getOutputStream().close();
}catch(IOException e){
System.out.println(e.getMessage());
}finally {
try{
System.out.println("
取消下载");
if(inStream!=null)inStream.close();
response.getOutputStream().close();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
%>
java
有
60
多种
Stream
操作
,
并不是可能拿来互用的
,
要不
SUN
开发小组没事干了啊
,
每一种流在处理不同的数据有不同的效率
,
大家最好把这些基础的东西的实现源码看一看
,
我可以吹一句
,
对我来说
,JAVA
平台上可以解决任何乱码
,
数据混乱
,
因为我清楚每个
byte
的来胧去脉
.
最简单的一个例子
:new PrintWriter(new FileWriter(path,true),true);
大家都清楚这两个
true
有什么作用吗
?
当然第一个简单
,true
表示追加而不是履盖原文件
,
第二个呢
?
大家知道是自动
flush?
那为什么要用参数控制而不在实现时就
flush?
只有
java
是这么实现的
,C/C++
就是自动
flush
的
.
原因何在
?
因为
JAVA
委托系统调用要极度消耗资源的
,
如果每次
println
都真的写文件
,
则用户模式和内核模式之间的切换要消耗极大的资源
,
所以先放在缓冲中
,
当调用
close()
时或
OBU
时一次调用
jini,
请系统写文件
.
但如果
PrintWriter
作为管道流
,
也就是象
Socket
这种通讯时即时性比性能更重要
,
所以要有手工控制的参数
.
这些都是作为网络编程的基础知识
,
我本来不想多说
.
象为什么取消下载资源不能回收这种情况
,
其实你想一想
,
客户端事件是否被服务端接收
?
就是接收了也绝对不会在一个流输出的进程中接收的
,
因为
HTTP
是无状态的
,
除非你的
servlet
就实现这个这种监听
,
不然你在客户端取消
,
只是容器不把
response
对象的
buffer
数据再发给你
,
而
service()
方法本身你不能控制它执行什么
,
要么容器智能一点取消这个方法的执行
(
杀掉线程池中的线程
ID),
而不会让这个方法中的代码产生异常
.
原文地址:
很多第三方的
api
都是这么做的。比如
struts
,就是在
web app
启动的时候,将
struts-config.xml
中的信息写入内存对象。
下面就提供一种其中的时候,读取
web-inf
目录下
test.xml
配置文件内容的代码,异供参考。
web.xml
配置如下:
<servlet>
<servlet-name>ConfigServlet</servlet-name>
<servlet-class>net.test.ConfigServlet</servlet-class>
<init-param>
<param-name>configfile</param-name>
<param-value>/WEB-INF/test.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
代码如下:
public class ConfigServlet extends HttpServlet {
protected final Locale defaultLocale = Locale.getDefault();
public void init() throws ServletException {
try{
initConfigXML();
}catch(Exception e){
System.out.println("ERROR >>>
读取riseconfig.xml文件出现问题");
}
}
protected void initConfigXML() throws IOException, SAXException,ServletException,Exception{
String value = null;
RiseConfig rcObject = null;
value = getServletConfig().getInitParameter("configfile");
InputStream input = getServletContext().getResourceAsStream(value);
//
剩下的就不要写了,自己处理了。
}
}
原文地址:
你的环境变量可能是为
web
应用、
ejb
使用的。
在
WebDescriptor>Web App Descriptor>Parameters
里配置:
<context-param>
<param-name>PATH</param-name>
<param-value>C:/GWSSI/INVOICE/PDF</param-value>
</context-param>
当然只能在
web
应用里才能获得:(
jsp
里的例子)
String strPath=config.getInitParameter("PATH");
在
ejb
里
FPGL_FWSK.jar> EJB Jar> Enterprise Beans> Sessions> InvoiceReturnBean> Environment Entries
里,
Configure a new Environment Entry...
也可以配置供这个
ejb
使用的环境变量:
<env-entry>
<description />
<env-entry-name>DBLanguage</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>American</env-entry-value>
</env-entry>
当然只能在ejb里才能获得:
public String getDbLanguage()
throws NamingException
{
Context initial = new InitialContext();
return (String)initial.lookup("java:comp/env/DBLanguage");
}
至于普通的客户端,怎么得到wls环境变量,那首先应该加载wls变量:
try{
Properties p=System.getProperties();
Enumeration e=p.propertyNames();
String strPropertyName;
while (e.hasMoreElements()) {
strPropertyName=(String)e.nextElement();
out.println(strPropertyName+":"+System.getProperty(strPropertyName));
}
}catch(Exception e){
out.println(e.getMessage());
}
另外可以这样:
web.xml
<context-param>
<param-name>dev2dev.bea.com.cn</param-name>
<param-value>211.157.35.33</param-value>
</context-param>
usage:
Servlet Context ctx=getServletContext();
out.print("dev2dev.bea.com.cn
的Server ip地址是:");
out.print(ctx.getInitParameter("dev2dev.bea.com.cn"));
原文地址:
下面是我的研究成果
.
希望对你有所帮助
:
报表生成一直是企业信息化过程中重要的一环,也是目前比较难于实现的一环,今天作者给大家介绍一种新的报表生成组件
――JFreeReport
。
JFreeReport
是
JFreeReport.Org
基于
LGPL
授权协议提供的一组
java
包,用于生成各类报表,
JFreeReport
的数据继承自
Swing
组件的
TableModel
接口,使用基于
XML
的报表格式定义文件对报表进行格式化。
JFreeReport
生成的报表可以分页预览、打印,而且支持导出为多种格式的文件如
pdf
、
Excel
、
CSV
、
html
等。更重要的是,
JFreeReport
不仅支持基于
C/S
结构的系统,而且支持基于
B/S
结构的系统中的在线报表显示。更详细的关于
JFreeReport
的介绍请大家访问
JFreeReport
的官方网站
JFreeReport.org
。
1
环境准备
1.1 JFreeReport
组件
请大家到
http: //prdownloads.sourceforge.net/jfreereport/jfreereport-0.8.4_7.zip?download
下载
JFreeReport
组件,下载的是一个
ZIP
文件,然后将
ZIP
文件解压缩到
c:/jfreereport
(后面的章节中将使用%
jfreereport_home
%表示这个目录)目录下。
1.2 JFreeReport
扩展组件
请大家到
http: //www.jfree.org/jfreereport/jfreereport-ext-0.8.4_7.zip
下载
JFreeReport
扩展组件,他用于支持
JFreeReport
组件生成的报表的在线显示。请大载后解压缩到
c:/jfreereport-ext
目录下(后面的章节中将使用%
jfreereport_ext_home
%表示这个目录)
1.3 Ant
工具
Apache
公司提供的一个基于
JAVA
的自动化脚本引擎,请大家到
http://ant.apache.org/
下载
ant
的可执行文件,关于如何使用
ant
请大家查看
ant
的帮助文档或者
http://ant.apache.org/
网站上的在线帮助文档。示例中主要是用
ant
来负责编译
java
代码。
1.4
作者提供的代码
为了运行本文中作者提到的例子和相关资源文件,请大家下载作者提供的
vivianjDemo.zip
文件。然后解压缩到%
jfreereport_home
%
/vivianjDemo
(后面的章节中将使用%
demo _home
%表示这个目录)目录下。
2 JFreeReport
生成报表的基本步骤
我们首先演示一个简单的例子,说明使用
JFreeReport
生成报表的一些必要的步骤。
2.1
实例说明
在这个例子中,我们将循环生成
100
条数据放入
TableModel
中,然后使用
JFreeReport
组件提供的预览功能在屏幕上显示生成的报表。
[注]为了简化,这里仅仅是逐条显示数据,不作任何修饰和统计工作,所以也不使用报表格式定义文件。
2.2
代码编制
整个演示实例(
HelloWorld.java
)的代码和相关注释如下,如果你执行了
1.3
中规定的步骤,你可以在%
demo _home
%/
src
/
org/vivianj/jfreereport/
看到这个文件。
/**
* HelloWorld.java
*/
package org.vivianj.jfreereport;
import java.awt.Color;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.jfree.report.Boot;
import org.jfree.report.ElementAlignment;
import org.jfree.report.JFreeReport;
import org.jfree.report.ReportProcessingException;
import org.jfree.report.elementfactory.TextFieldElementFactory;
import org.jfree.report.modules.gui.base.PreviewDialog;
import org.jfree.ui.FloatDimension;
/**
*
使用JFreeReport生成报表的简单例子,用于演示使用JFreeReport生成报表的一些基本步骤
*
*
本例子中,为了简化操作,报表定义是使用java直接编码
*
* @
作者 : bookman
*/
public class HelloWorld
{
/**
*
处理窗口关闭事件
*/
protected static class CloseHandler extends WindowAdapter
{
public void windowClosing(final WindowEvent event)
{
System.exit(0);
}
}
/**
*
创建和显示简单的报表
*/
public HelloWorld()
{
//
获得创建报表需要用到的数据
final TableModel data = createData();
//
获得报表要用到的报表定义内容
final JFreeReport report = createReportDefinition();
//
将报表定义和数据结合
report.setData(data);
try
{
//
将生成的报表放到预览窗口中
final PreviewDialog preview = new PreviewDialog(report);
preview.addWindowListener(new CloseHandler());
preview.pack();
//
显示报表预览窗口
preview.setVisible(true);
}
catch (ReportProcessingException e)
{
System.out.println(e);
}
}
/**
*
创建生成报表需要用到的数据
*
* @
返回一个TableModel实例
*/
private TableModel createData()
{
final Object[] columnNames = new String[]{"Column1", "Column2"};
final DefaultTableModel result = new DefaultTableModel(columnNames, 100);
int rownum = 0;
int colnum = 0;
for (;rownum < 100 ; rownum++)
{
result.setValueAt("say Hello " + rownum + "
次", rownum, 0);
result.setValueAt("say World " + rownum + "
次" , rownum, 1);
}
return result;
}
/**
*
创建一个报表定义
*
* @
返回一个报表定义实例
*/
private JFreeReport createReportDefinition()
{
final JFreeReport report = new JFreeReport();
report.setName("A Very Simple Report");
/**
*
定义要显示报表第一列的样式
*/
TextFieldElementFactory factory = new TextFieldElementFactory();
factory.setName("T1");
factory.setAbsolutePosition(new Point2D.Float(0, 0));
factory.setMinimumSize(new FloatDimension(150, 20));
factory.setColor(Color.black);
factory.setHorizontalAlignment(ElementAlignment.LEFT);
factory.setVerticalAlignment(ElementAlignment.MIDDLE);
factory.setNullString("-");
factory.setFieldname("Column1");
report.getItemBand().addElement(factory.createElement());
/**
*
定义要显示报表第二列的样式
*/
factory = new TextFieldElementFactory();
factory.setName("T2");
factory.setAbsolutePosition(new Point2D.Float(200, 0));
factory.setMinimumSize(new FloatDimension(150, 20));
factory.setColor(Color.black);
factory.setHorizontalAlignment(ElementAlignment.LEFT);
factory.setVerticalAlignment(ElementAlignment.MIDDLE);
factory.setNullString("-");
factory.setFieldname("Column2");
report.getItemBand().addElement(factory.createElement());
/**
*
返回一个报表定义的实例
*/
return report;
}
public static void main(final String[] args)
{
//
初始化JFreeReport
Boot.start();
//
调用演示实例
new HelloWorld();
}
}
2.3
运行例子
如果你执行了
1.3
中规定的步骤,你可以进入命令行界面,然后进入%
demo_home
%目录下,修改
setenv.cmd
中的相关设置,执行
serenv.cmd
设置环境变量。执行
java org.vivianj.jfreereport.HelloWorld
查看运行结果。下面这个图片是作者执行后结果的屏幕截图:
大家可以看到,
JFreeReport
已经自动帮我们实现了分页。上面这个图片显示的是第一页的数据,你可以通过工具栏中的查看其它页面中的内容。
2.4
基本步骤解释
使用
JFreeReport
生成报表通常需要以下三个基本步骤:
1.
生成可通过
TableModel
接口访问的数据,如本例中的
createData
方法完成的功能
2.
生成一个
JFreeReport
实例,他定义了我们如何格式化显示数据,如本例中的
createReportDefinition
方法完成的功能
3.
将数据和
JFreeReport
实例连接起来,并且将该
JFreeReport
实例传给
PreviewDialog
的一个实例显示给用户
3
使用
JFreeReport
生成复杂报表
3.1
报表定义文件
报表定义文件是
JFreeReport
生成复杂报表的重要文件,他就是一个
XML
文档,主要描述如何使用指定的格式生成复杂的报表,同时使用报表定义文件也可以在报表格式需要修改时只需要更新该报表定义文件,而不需要修改应用代码。
3.1.1
报表定义文件分类
JFreeReport
中使用了两种基于
XML
的报表定义文件来保存报表定义信息:简单格式和扩展格式.很明显
,
简单格式不能够完全的描述
JFreeReport
支持的全部报表定义信息
,
但是他更易于上手使用。而扩展格式则能够对
JFreeReport
的报表定义提供完整的支持,但是扩展格式太详细了,不太容易使用。
关于这两种报表定义格式文件所支持的标签内容以及如何编写这两种格式的报表定义文件请大家参考%
jfreereport_home
%下的
jfreereport-0.8.3-A4.pdf
中的相关部分,该文件附录中还包括了这两种格式的报表定义文件的
DTD
文档供大家参考.当然大家也
JFreeReport
的例子中提供了多种形式的报表定义文件,基本上涵盖了常用的报表格式定义,大家可以参考这些例子编写自己的报表定义文件,。
3.2
代码编制
这个例子和
2.2
中的代码基本一致,只是报表定义内容不再由
java
编码实现,而是由报表定义文件提供,所以调用方面稍微有点不同,详细的代码如下,请大家注意其中加粗显示的部分:
/**
* JFreeReport.java
*/
package org.vivianj.jfreereport;
import java.io.File;
import java.text.MessageFormat;
import javax.swing.table.TableModel;
import javax.swing.JFrame;
import org.jfree.ui.RefineryUtilities;
import org.jfree.report.Boot;
import org.jfree.report.modules.gui.base.PreviewFrame;
import org.jfree.report.modules.parser.base.ReportGenerator;
import org.jfree.report.JFreeReport;
import org.vivianj.jfreereport.tablemodel.SampleData;
/**
*
使用JFreeReport生成复杂报表的例子,用于演示使用JFreeReport生成复杂报表的一些基本步骤
*
*
本例子中,报表定义使用了报表定义文件,该文件是保存在c:\下的report3.xml文件
*
本例中使用的报表定义使用了简单报表定义格式
*
* @
作者 : bookman
*/
public class JFreeTest
{
public JFreeTest(final String urlname, final TableModel data)
{
//
创建对报表定义文件的引用
final File in = new File(urlname);;
if (in == null)
{
System.out.print(" in is null");
return;
}
System.out.print("Processing Report: " + in);
final ReportGenerator gen = ReportGenerator.getInstance();
try
{
//
从报表定义文件中获得要用到的报表定义内容
final JFreeReport report1 = gen.parseReport(in);
if (report1 == null)
{
System.out.print(" report1 is null");
return;
}
//
将报表定义和数据结合
report1.setData(data);
//
将生成的报表放到预览窗口中
final PreviewFrame frame1 = new PreviewFrame(report1);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.pack();
RefineryUtilities.positionFrameRandomly(frame1);
frame1.setVisible(true);
frame1.requestFocus();
}
catch (Exception e)
{
System.out.print("report.definitionfailure-----------------------/r/n" + e);
}
}
public static void main(String[] args)
{
Boot.start();
final TableModel data3 = new SampleData();
JFreeTest jft = new JFreeTest("c://report3.xml",data3);
}
}
4
中文乱码问题
大家在参看报表定义文件的时候会发现,里面的报表头定义中有一些显示内容,如果你直接将他修改成中文,显示在报表上就会乱码,这是因为这些报表定义文件都是
XML
文档,他的
encoding
默认设置是
ISO-8859-1
,所以出现了中文乱码的问题,解决办法有两个:
1.
最简单的方法就是将
encoding
的设置修改为
GB2312
2.
还有一个方法就是不修改
encoding
的设置,而是将这些中文内容使用他们的
unicode
码来代替。
[注]作者提供了一个
GUI
的界面提供这种转化功能,你只需要输入中文就可以获得对应的
unicode
码,请大家下载作者提供的
gb2unicode.jar
,设置好
java
运行环境,然后执行
java –jar gb2unicode.jar
就可以了。
原文地址:
POI
介绍
介绍
:
Jakarta_POI
使用
Java
读写
Excel(97-2002)
文件,可以满足大部分的需要。
因为刚好有一个项目使用到了这个工具,花了点时间顺便翻译了一下
POI
本身
带的一个
Guide.
有一些节减和修改,希望给使用这个项目的人一些入门帮助。
POI
下面有几个自项目
:HSSF
用来实现
Excel
的读写
.
以下是
HSSF
的主页
http://jakarta.apache.org/poi/hssf/index.html
下面的介绍是基于以下地址的翻译:
http://jakarta.apache.org/poi/hssf/quick-guide.html
目前的版本为
1.51
应该是很长时间之内的一个稳定版,但
HSSF
提供的
Sample
不是基于
1.51
所写,所以使用的时候需要适当的注意
.
其实
POI
下面的几个子项目侧重不同读写
Word
的
HDF
正在开发当中
.
XML
下的
FOP(http://xml.apache.org/fop/index.html)
可以输出
pdf
文件,也是比较好的一个工具
目录
:
创建一个
workbook
创建一个
sheet
创建
cells
创建日期
cells
设定单元格格式
说明:
以下可能需要使用到如下的类
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
创建
workbook
HSSFWorkbook wb = new HSSFWorkbook();
//
使用默认的构造方法创建
workbook
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
//
指定文件名
wb.write(fileOut);
//
输出到文件
fileOut.close();
创建一个
sheet
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet1 = wb.createSheet("new sheet");
//workbook
创建
sheet
HSSFSheet sheet2 = wb.createSheet("second sheet");
//workbook
创建另外的
sheet
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
创建
cells
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");
//
注意以下的代码很多方法的参数是
short
而不是
int
所以需要做一次类型转换
HSSFRow row = sheet.createRow((short)0);
//sheet
创建一行
HSSFCell cell = row.createCell((short)0);
//
行创建一个单元格
cell.setCellValue(1);
//
设定单元格的值
//
值的类型参数有多中
double ,String ,boolean,
row.createCell((short)1).setCellValue(1.2);
row.createCell((short)2).setCellValue("This is a string");
row.createCell((short)3).setCellValue(true);
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
创建日期
cells
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet sheet = wb.createSheet("new sheet");
HSSFRow row = sheet.createRow((short)0);
HSSFCell cell = row.createCell((short)0);
//
设定值为日期
cell.setCellValue(new Date());
HSSFCellStyle cellStyle = wb.createCellStyle();
//
指定日期显示格式
cellStyle.setDataFormat(HSSFDataFormat.getFormat("m/d/yy h:mm"));
cell = row.createCell((short)1);
cell.setCellValue(new Date());
//
设定单元格日期显示格式
cell.setCellStyle(cellStyle);
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
设定单元格格式
单元格格式的设定有很多形式包括单元格的对齐方式,内容的字体设置,
单元格的背景色等,因为形式比较多,只举一些例子
.
以下的例子在
POI1.5
中可能会有所改变具体查看
API.
..........
// Aqua background
HSSFCellStyle style = wb.createCellStyle();
//
创建一个样式
style.setFillBackgroundColor(HSSFCellStyle.AQUA);
//
设定此样式的的背景颜色填充
style.setFillPattern(HSSFCellStyle.BIG_SPOTS);
//
样式的填充类型。
//
有多种式样如
:
//HSSFCellStyle.BIG_SPOTS
//HSSFCellStyle.FINE_DOTS
//HSSFCellStyle.SPARSE_DOTS
等
style.setAlignment(HSSFCellStyle.ALIGN_CENTER );
//
居中对齐
style.setFillBackgroundColor(HSSFColor.GREEN.index);
//
设定单元个背景颜色
style.setFillForegroundColor(HSSFColor.RED.index);
//
设置单元格显示颜色
HSSFCell cell = row.createCell((short) 1);
cell.setCellValue("X");
cell.setCellStyle(style);
原文地址:
目前为止,在
Java
应用程序中建立一个
Microsoft Excel
文件的最常用的方法是在
JSP
或
Servlet
中创建一个
CSV
(
comma separated values
)文件,并将这个文件以
MIME
,
text/csv
类型返回给浏览器。接着浏览器调用
Excel
并且显示
CSV
文件。
现在有一个提供实用工具给
Java
开发者建立
Excel
文件的项目,该项目是
POI (Poor Obfuscation Implementation )
新
Jakarta
工程中最成熟的一部分。
POI
的
Excel
组件名叫
HSSF (Horrible Spreadsheet format)
。
虽然
HSSF
提供了许多与开发工具交互的不同方法,我们这里只集中讨论简单高级用户
API
。
下面是一个在
Excel
表格中创建矩阵的简单例子:
import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream;
// code run against the jakarta-poi-1.5.0-FINAL-20020506.jar.
public class PoiTest {
static public void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("foo.xls");
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
wb.setSheetName(0, "Matrix");
for(short i=0; i<50; i++) {
HSSFRow row = s.createRow(i);
for(short j=0; j<50; j++) {
HSSFCell cell = row.createCell(j);
cell.setCellvalue(""+i+","+j);
}
}
wb.write(fos);
fos.close();
}
}
这段代码首先创建一个业务手册,从这个业务手册中获取一个表格,给这个表格命名,然后接着在上面写一个
50*50
的矩阵列表。它的输出是一个名为
foo.xls
的
Excel
文件,这个文件即使在
Apple Mac
上也可以打开。
POI
工程是
Java
走出的振奋人心的,全新的一步,它为
Windows
的文件综合开辟了一个新的领域,并且使得
Java
开发者能够改进他们的产品功能。
原文地址:
今天把原来部署在
Tomcat
中的
Web
应用程序迁移到
Weblogic 8.1
中文版上面了
.
基本上没什么大问题
,
就是有几句只适用于
Tomcat
的代码需要修改一下
.
在这里记录下来
,
可能以后还会碰到
.
1
、载入属性文件问题
:
属性文件包括
db.properties
、
mail.properties
等。上述属性文件放在
WEB-INF
目录底下,原来采用
DbContext.class.getClassLoader().getResourceAsStream("../db.properties")
取得输入流
InputStream is
。对
Tomcat
来说,
DbContext.class.getClassLoader()
应该是对应
classes
目录,采用
“../”
回到上层目录,就是
WEB-INF
目录,这个是可行的。而
Weblogic
好象不支持
“../”
,老是提示找不到相应的属性文件。不得已,只好将属性文件放到
classes
目录下。上述代码改为:
DbContext.class.getClassLoader().getResourceAsStream ("db.properties")
。
2
、取得文件绝对路径问题:
在上传下载功能中,经常设计到要取得相应文件或者文件夹的绝对路径问题。这里通常采用
getServletContext().getRealPath("yourFile")
方法。
Tomcat
中可以直接用。而
Weblogic
要采用
getServletConfig().getServletContext().getRealPath ("/upload")
。同事说是两者对
Servlet
的实现不同。
原文地址:
应该采用
listener,
在其中实现一个
Timer
即可,我已经说了实现
listener
啊
,
你可能只想到普通的
listener,servlet
为我们提供了三种模式
,stand,listener,filter,
只要实现一个
listener
就
OK
了啊。
public class MyListener
extends HttpServlet
implements ServletContextListener {
private static Timer timer;
public void contextInitialized(ServletContextEvent sce) {
timer = new Timer(true);
timer.schedule(new TimerTask() {
public void run() {
要定时执的代码
}
}, argslist........);
}
public void contextDestroyed(ServletContextEvent sce) {
timer.cancel();
}
}
你可以完成你想做的任何事。
原文地址:
比如你创建了一个
DataSource
(
MyTestDataSource
),绑定
MyTestConnectionPool
,绑定
MyTestDataSourceJNDI
命名。但是却想在程序中采用
MyDataSource
这个
JNDI
名称。你就需要修改
web.xml
和
weblogic.xml
。
web.xml
修改如下
<resource-ref>
<res-ref-name>MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Application</res-auth>
</resource-ref>
weblogic.xml
修改如下
<reference-descriptor>
<resource-description>
<res-ref-name>MyDataSource</res-ref-name>
<jndi-name>MyTestDataSourceJNDI</jndi-name>
</resource-description>
</reference-descriptor>
原文地址:
把一个
include.jsp
文件放到目录
WEB-INF
里面,然后使用
String url = "/WEB-INF/include.jsp";
String url = "/WEB-INF/include.jsp";
RequestDispatcher rd = pageContext.getRequest().getRequestDispatcher(url);
rd.include(pageContext.getRequest(), pageContext.getResponse());
url));
总是抛出未找到资源异常,这是怎么回事啊。
总是抛出未找到资源异常,这是怎么回事啊。
这好像是
WebLogic
以前的一个问题,由于
WEB-INF
里面的内容对于
WEB
应用而言,都是至关重要的配置文件和类,所以,出于安全考虑,
J2EE
规范对于
WEB-INF
目录是拒绝外部访问的,里面的内容,只允许
Container
访问。
规范原文如下:
No file contained in the WEB-INF directory may be served directly to a client by the container. However, the contents of the WEBINF directory are visible to servlet code using the getResource and getResource-AsStream method calls on the ServletContext, and may be exposed using the RequestDispatcher calls.
原文地址:
在
wls7.0
里部署了一个
web
应用,每次重起
wls
后,
jsp
文件都会被重新编译,如何设置,才能只让编译一次
?
在
wls7.0
里面,再没有特别的指明情况下,自定义的
web
应用会将
web
编译完的
jsp
文件存储在
user_projects/mydomain/applications/.wlnotdelete
目录下。但是
wls7.0
犯了一个错误,在每一次启动的时候,会将
user_projects/mydomain/applications/.wlnotdelete
目录下的文件清空。这就造成了,上次
jsp
编译成的
.class
文件就被删除了。所以,每次重新启动
wls
以后,就造成
jsp
重新编译。
那么如何解决这个问题了。很简单的了。在
weblogic.xml
文件中的
<jsp-descriptor>
元素下,加一个
<jsp-param>
<param-name>workingDir</param-name>
<param-value>workingDir</param-value>
</jsp-param>
这样以后,强迫每次编译后的
jsp
存储在
user_projects/mydomain/workingDir/jsp_servlet
目录下。这样每次重新启动以后,就不需要重新编译了。
原文地址:
如文件为
doc
,在
WEB.XML
文件里加入
<mime-mapping>
<extension>doc</extension>
<mime-type>application/self-define</mime-type>
</mime-mapping>
就可以出现提示下载框了
,application/self-define"
不需要修改
,
因为注册表里没有对应的
application/self-define
内容。
原文地址:
请参考
weblogic doc
中的
webapp
文档。
其中在
weblogic.xml Deployment Descriptor Elements
章节有说明。参考
jsp-descriptor Element
描述说明。其中一个元素
元素:
keepgenerated
默认值:
false
说明:
Saves the Java files that are generated as an intermediary step in. he JSP compilation process.Unless this parameter is set to true,the intermediate Java files are deleted after they are compiled.
原文地址: