2009年12月2日星期三
[转]application session request page
session:会话作用域,当用户首次访问时,产生一个新的会话,以后服务器就可以记住这个会话状态。生命周期:会话超时,或者服务器端强制使会话失效。
request:请求作用域,就是客户端的一次请求。
page:一个JSP页面。
以上作用范围使越来越小, request和page的生命周期都是短暂的,他们之间的区别就是:一个request可以包含多个page页(include,forward以及filter)。
[转]浅析编写JSP Tag
编写一个JSP Tag涉及三个步骤:
(1)编写JSP
(2)编写JSP Tag的java程序
(3)编写JSP Tag库的描述文件tld(实际是一个XML文件)
这三个步骤之间没有顺序约束,下面是一个简单的例子:
1 编写HelloTag.jsp
- <%@page contentType="text/html"%>
- <html>
- <head><title>Hello Tags Page</title></head>
- <body>
- <%@ taglib uri="/WEB-INF/classes/tags/helloTag.tld" prefix="hello" %>
- <hello:helloTag />
- </body>
- </html>
2 编写JSP Tag
HelloTag.java
- package tags;
- //注意:必须放在一个包中
- import java.io.*;
- import javax.servlet.jsp.*;
- import javax.servlet.jsp.tagext.*;
- public class HelloTag extends TagSupport {
- public int doStartTag() {
- try {
- //使用JspWriter获得JSP的输出对象
- JspWriter jspWriterOutput = pageContext.getOut();
- jspWriterOutput.print("Hello Tag!");
- }
- catch (IOException ioEx) {
- System .out.println("IOException in HelloTag " + ioEx);
- }
- return (SKIP_BODY);
- }
- }
3 编写helloTag.tld
这是Tag库的描述部分:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE taglib
- PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
- "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
- <taglib>
- <tlib-version>1.0</tlib-version>
- <jsp-version>1.2</jsp-version>
- <shorttag -name>helloTag</short -name>
- <uri>/WEB-INFtagshelloTag</uri>
- <display-name>helloTag</display-name>
- <small-icon></small-icon>
- <large-icon></large-icon>
- <description>simple hello tags tag
- </description>
- <tag>
- <name>helloTag</name>
- <tag-class >tags.HelloTag</tag-class >
- <body-content>empty</body-content>
- <small-icon></small-icon>
- <large-icon></large-icon>
- <description></description>
- <example></example>
- </tag>
- </taglib>
4 注意:
通常手工编写XML文件,但是Sun的教程建议使用IDE工具编写自定义tag,比如NetBeans
一般,直接把tld文件放到WEB-INF目录中。
2009年12月1日星期二
[note]URI与URL区别
uri:统一资源标志符
URI是URL的一部分
url定位客户端连接到服务器所需要的信息,如
http://www.csdn.net
http://tcc.com:8080/servlet/logon?name=zhangsan&addr=tttt
完整构成
<protocol>://<servername>[:port]/<url-path>[?query-string]
uri是url组成的一部分,没有域名和查询字符串,
即域名之后查询字符串之前所有的信息,用于制定资源。
例如,对于请求地址
http://java.sun.com/products/servlet/index.html?id=09
url--->http://java.sun.com/products/servlet/index.html?id=09
uri--->/products/servlet/index.html
[转]response.setContentType()的String参数及对应类型
response.setContentType()的String参数及对应类型
<option value="image/bmp">BMP</option>
<option value="image/gif">GIF</option>
<option value="image/jpeg">JPEG</option>
<option value="image/tiff">TIFF</option>
<option value="image/x-dcx">DCX</option>
<option value="image/x-pcx">PCX</option>
<option value="text/html">HTML</option>
<option value="text/plain">TXT</option>
<option value="text/xml">XML</option>
<option value="application/afp">AFP</option>
<option value="application/pdf">PDF</option>
<option value="application/rtf">RTF</option>
<option value="application/msword">MSWORD</option>
<option value="application/vnd.ms-excel">MSEXCEL</option>
<option value="application/vnd.ms-powerpoint">MSPOWERPOINT</option>
<option value="application/wordperfect5.1">WORDPERFECT</option>
<option value="application/vnd.lotus-wordpro">WORDPRO</option>
<option value="application/vnd.visio">VISIO</option>
<option value="application/vnd.framemaker">FRAMEMAKER</option>
<option value="application/vnd.lotus-1-2-3">LOTUS123</option>
2009年11月28日星期六
[原创]Java Web开发参数传输的编码心得
表单的Get或Post方式、AJAX的Get或POST参数传值的情况。使用英文时没什么问题,但是当使用中文时就会出现不同情况。
在此做一个完全的测试。
测试字符为“中文”,“中文”被UTF-8编码一次后为“%E4%B8%AD%E6%96%87”,两次为“%25E4%25B8%25AD%25E6%2596%2587”。
客户端Html编码为UTF-8,服务器端setCharaterEncoding("utf-8");并且不设置server.xml中connector元素的URIEncoding属性。
测试浏览器为Firefox 3.5 和IE 8.服务器为Tomcat 6.
客户端提交时使用的jquery的get和post方法提交的参数。
表单Get方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 乱码 乱码 乱码
表单Post方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 中文 中文 中文
AJAX的Get方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 乱码 乱码 乱码
客户端encodeURIComponent加密一次 编码一次后结果 中文 中文
客户端encodeURIComponent加密两次 编码两次后结果 编码一次后结果 中文
AJAX的Post方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 中文 中文 中文
客户端encodeURIComponent加密一次 编码一次后结果 中文 中文
客户端encodeURIComponent加密两次 编码两次后结果 编码一次后结果 中文
客户端Html编码为UTF-8,服务器端不设置setCharaterEncoding("utf-8");并且不设置server.xml中connector元素的URIEncoding属性。
测试浏览器为Firefox 3.5 和IE 8.服务器为Tomcat 6.
客户端提交时使用的jquery的get和post方法提交的参数。
表单Get方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客 户端不加密 乱码 乱码 乱码
表单Post方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 乱码 乱码 乱码
AJAX的Get方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 乱码 乱码 乱码
客户端encodeURIComponent加密一次 编码一次后结果 中文 中文
客户端encodeURIComponent加密两次 编码两次后结果 编码一次后结果 中文
AJAX的Post方式
服务器端不解码 服务器端UTF-8解码一次 服务器端UTF-8解码两次
客户端不加密 乱码 乱码 乱码
客户端encodeURIComponent加密一次 编码一次后结果 中文 中文
客户端encodeURIComponent加密两次 编码两次后结果 编码一次后结果 中文
- 对比两次实验,setCharaterEncoding("utf-8");只有在表单的Post方式和AJAX的post方式时会起作用。post方式会对参数进行utf-8编码(取决于html的编码),而服务器端得默认解码是iso-8859-1,不设置编码的类型所以会产生乱码。
- Get方式时,始终使用默认的编码类型“iso-8895-1”进行解码,除非设置server.xml的配置文件。所以也可以在客户端不编码的情况下,在服务器端用iso-8859-1编码,再用utf-8解码。(如:new String(old.getBytes("iso-8859-1"),"utf-8"));)。之所以要用utf-8编码是为了保持一致性,.java文件都是utf-8编码存储的。
- 客户端在参数的传输时,都是先根据网页的编码,对参数编码,此处的情况就是utf-8。
- 中文时,用utf-8编码,再用iso-8859-1解码就会出现乱码,但是英文则不会。因为UTF-8和iso-8859-1对非中文字符的编码是一样的。
- 为了同时照顾到get和post的两种情况,以及表单提交的情况。
- 首先编码需一致采用utf-8(自定),使用setCharaterEncoding("utf-8");
- 表单方式提交数据时不使用get,既不安全又有乱码问题。实在需要就是用new String(old.getBytes("iso-8859-1"),"utf-8"));的方法。
- AJAX的get方式时,可以在客户端编码一次(或两次),在服务器端对应的解码一次(两次)。
- 在客户端进行一次(两次)编码,在服务器端手动配置了一次(两次)解码。但是服务器默认的getParameter也会进行解码!那不就多解码了一次?
- 原因是这里使用了jquery,它的ajax方法会自动对参数进行编码
function add( key, value ){
s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
};- 如果您是手动添加参数到url上的,那么客户端必须还要encodeURIComponent(value)一次。
2009年11月27日星期五
[转]java类初始化顺序
- public class InitialOrderTest {
- // 静态变量
- public static String staticField = "静态变量";
- // 变量
- public String field = "变量";
- // 静态初始化块
- static {
- System.out.println(staticField);
- System.out.println("静态初始化块");
- }
- // 初始化块
- {
- System.out.println(field);
- System.out.println("初始化块");
- }
- // 构造器
- public InitialOrderTest() {
- System.out.println("构造器");
- }
- public static void main(String[] args) {
- new InitialOrderTest();
- }
- }
public class InitialOrderTest { // 静态变量 public static String staticField = "静态变量"; // 变量 public String field = "变量"; // 静态初始化块 static { System.out.println(staticField); System.out.println("静态初始化块"); } // 初始化块 { System.out.println(field); System.out.println("初始化块"); } // 构造器 public InitialOrderTest() { System.out.println("构造器"); } public static void main(String[] args) { new InitialOrderTest(); } }
运行以上代码,我们会得到如下的输出结果:
- 静态变量
- 静态初始化块
- 变量
- 初始化块
- 构造器
这与上文中说的完全符合。那么对于继承情况下又会怎样呢?我们仍然以一段测试代码来获取最终结果:
- class Parent {
- // 静态变量
- public static String p_StaticField = "父类--静态变量";
- // 变量
- public String p_Field = "父类--变量";
- // 静态初始化块
- static {
- System.out.println(p_StaticField);
- System.out.println("父类--静态初始化块");
- }
- // 初始化块
- {
- System.out.println(p_Field);
- System.out.println("父类--初始化块");
- }
- // 构造器
- public Parent() {
- System.out.println("父类--构造器");
- }
- }
- public class SubClass extends Parent {
- // 静态变量
- public static String s_StaticField = "子类--静态变量";
- // 变量
- public String s_Field = "子类--变量";
- // 静态初始化块
- static {
- System.out.println(s_StaticField);
- System.out.println("子类--静态初始化块");
- }
- // 初始化块
- {
- System.out.println(s_Field);
- System.out.println("子类--初始化块");
- }
- // 构造器
- public SubClass() {
- System.out.println("子类--构造器");
- }
- // 程序入口
- public static void main(String[] args) {
- new SubClass();
- }
- }
class Parent { // 静态变量 public static String p_StaticField = "父类--静态变量"; // 变量 public String p_Field = "父类--变量"; // 静态初始化块 static { System.out.println(p_StaticField); System.out.println("父类--静态初始化块"); } // 初始化块 { System.out.println(p_Field); System.out.println("父类--初始化块"); } // 构造器 public Parent() { System.out.println("父类--构造器"); } } public class SubClass extends Parent { // 静态变量 public static String s_StaticField = "子类--静态变量"; // 变量 public String s_Field = "子类--变量"; // 静态初始化块 static { System.out.println(s_StaticField); System.out.println("子类--静态初始化块"); } // 初始化块 { System.out.println(s_Field); System.out.println("子类--初始化块"); } // 构造器 public SubClass() { System.out.println("子类--构造器"); } // 程序入口 public static void main(String[] args) { new SubClass(); } }
运行一下上面的代码,结果马上呈现在我们的眼前:
- 父类--静态变量
- 父类--静态初始化块
- 子类--静态变量
- 子类--静态初始化块
- 父类--变量
- 父类--初始化块
- 父类--构造器
- 子类--变量
- 子类--初始化块
- 子类--构造器
现在,结果已经不言自明了。大家可能会注意到一点,那就是,并不是父类完全初始化完毕后才进行子类的初始化,实际上子类的静态变量和静态初始化块的初始化是在父类的变量、初始化块和构造器初始化之前就完成了。
那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?实际上这取决于它们在类中出现的先后顺序。我们以静态变量和静态初始化块为例来进行说明。
同样,我们还是写一个类来进行测试:
- public class TestOrder {
- // 静态变量
- public static TestA a = new TestA();
- // 静态初始化块
- static {
- System.out.println("静态初始化块");
- }
- // 静态变量
- public static TestB b = new TestB();
- public static void main(String[] args) {
- new TestOrder();
- }
- }
- class TestA {
- public TestA() {
- System.out.println("Test--A");
- }
- }
- class TestB {
- public TestB() {
- System.out.println("Test--B");
- }
- }
public class TestOrder { // 静态变量 public static TestA a = new TestA(); // 静态初始化块 static { System.out.println("静态初始化块"); } // 静态变量 public static TestB b = new TestB(); public static void main(String[] args) { new TestOrder(); } } class TestA { public TestA() { System.out.println("Test--A"); } } class TestB { public TestB() { System.out.println("Test--B"); } }
运行上面的代码,会得到如下的结果:
- Test--A
- 静态初始化块
- Test--B
[原创][精品]一道Java题
代码如下:
* 父类
* @author rongxinhua
*
*/
public class Father{
private String name="FATHER";
public Father(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Father says, I am " + name);
}
public void tellName(String name){
System.out.println("Father's name is " + name);
}
}
* 子类
* @author rongxinhua
*
*/
public class Son extends Father{
private String name="SON";
public Son(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Son says, I am " + name);
}
public void tellName(String name){
System.out.println("Son's name is " + name);
}
}
结果为:
Son says, I am null
Son's name is FATHER
Son says, I am SON
Son's name is SON
下面两个打印结果很容易想到。但是前面两个就有点摸不着头脑。我一开始也难以理解,主要是考虑的方向错误,误以为是与初始化顺序有关的题目。但其实是一道关于”重写“的题目。
解答:
Son的两个方法whoAmI和tellName重写了父类的方法,这一点是毋庸置疑的。这里有一点:重写是静态的,重写的过程在编译时就完成了,而重载则是动态的(延迟绑定)。所以当执行 Father who = new Son(); 时,实际的执行顺序如下
1. Son的whoAmI()方法:System.out.println("Father says, I am " + name);看起来有点奇怪,这不都一样吗?的确差不多。但是name不同!3与4的name是Son德name属性(这很容易理解)。
2. Son的tellName(String name)方法:System.out.println("Son's name is " + name);
3. Son的whoAmI()方法:System.out.println("Father says, I am " + name);
4. Son的tellName(String name)方法:System.out.println("Son's name is " + name);
2的name是方法参数传过来的,而且是在父类的构造函数中执行的,那么name的值应该是父类的name属性。可能有点不理解,那么在父类的构造函数中加上一句
System.out.println("Father says, I am " + name);
得到的结果是”Father says, I am FATHER“。所以name属性在父类的构造方法中的确为”Father“且传给了被重写的tellName方法。
1的name值又为什么为null呢?因为whoAmI方法中的name值直接来自类的实例变量。或许你认为Father的name值应该传给它,不就打印出Son's name is FATHER吗?其实不是。虽然变量名都是name,但是这两个变量是不同的。在编译成字节码的时候这两个变量就区分出来了。Java中方法可以重写,但类的属性不行。对此你可以把name的访问权限都改成public结果仍旧不变。还不理解,那就把Father的name属性名改为name_f,并且在子类的whoAmI方法中加入如下代码:
super.whoAmI();
得到的结果为:
Son says, I am null可见父类的whoAmI方法仍旧可以正常打印结果。这样理解就方便多了!
Son's name is FATHER
Father says, I am FATHER
Son says, I am SON
Son's name is SON
结论:从这到题可以知道几点:
Java的重写是在编译成字节码时执行的。
Java的方法可以重写但是变量不行。
父类的变量会被保留,如果此变量的权限不为private,则可以通过super来访问。
被重写的方法中引用的实例变量是子类的变量,即使与父类变量名重复,也不会在父类的执行环境中(如构造函数)使用父类变量。
被重写的父类方法可以用super访问。