#
package com.tianhe.frm.chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
*
*<br>
* 客户端的实现效果 <br>
*<br>
* 1.登录服务器,如果服务器端口号和IP号输入的字符都是"0"则,客户端连接到默认的服务器 <br>
*<br>
* 2.输入聊天昵称 <br>
*<br>
* 3.输入"-quit"会自动退出聊天 <br>
*<br>
* 4.输入"-getList"会得到在线用户的名称 <br>
*<br>
* 5.输入"-to <用户名称> <聊天信息>"会把信息发送到指定的用户处,他人看不到 <br>
*<br>
* 6.输入"-help"会得到客户端相应操作帮助 <br>
*<br>
* 6.直接输入内容则会将内容发送到所有在线的用户处 <br>
*<br>
*<br>
*<br>
*<br>
* 客户端的类与方法 <br>
*<br>
* 1.建立连接方法:connectServer(String ip,int serverPort) <br>
*<br>
* 2.断开连接方法:disconnectServer() <br>
*<br>
* 2.发送消息方法:sendMes(String mes) <br>
*<br>
* 3.接受消息方法:getMes() <br>
*<br>
* 4.接受一次消息:getMesOnce() <br>
*<br>
* 5.获得用户列表:getList(String mes) <br>
*<br>
* 6.测试连接方法:testConnect(String ip,int serverPort) <br>
*<br>
* 7.检查用户名 :checkNickName(String nickName) <br>
*<br>
* 8.获得帮助列表:helpList(); <br>
*<br>
* 9.各项内容的输入在main方法中进行 <br>
*<br>
*<br>
*<br>
*<br>
* 重点注意的地方 <br>
*<br>
* 由于客户端无法知道服务器何时转发数据,所以客户端需要一直不停地监听消息,为了不影响其他的方法,如发送数据,这里用到多线程,即为接受数据单独建立一个线程,以防止影响其他方法的正常工作。
*
*/
public class ChatClient implements Runnable
{
private String serverIp = "localhost";
private int serverPort = 9999;
private InetAddress serverAddr = null;
// 客户端
private DatagramSocket ds = null;
// 发送的数据报
private DatagramPacket dp = null;
// 用来测试是否能够连接成功或者用户名是否正确
// 在testConnect和checkNickName中会用到.
// 并穿插在sendMes方法中
private boolean test = true;
/**
* 建立连接
*
* @param ip 服务器IP号
* @param serverPort 服务器Port
*/
public boolean initServer(InetAddress serverAddr, int serverPort)
{
this.serverAddr = serverAddr;
this.serverPort = serverPort;
try
{
ds = new DatagramSocket();
}
catch (SocketException s)
{
System.out.println("The Connection of server is error.");
return false;
}
return true;
}
/**
* 断开连接
*/
public void disconnectServer()
{
// 当客户端断开连接之前,客户端会向服务器端发送一个信息,
// 以便告诉服务器该客户下线
this.sendMes("-quit");
if (ds != null)
ds.close();
}
/**
* 发送消息
*
* @param mes
*/
public void sendMes(String mes)
{
byte[] buf = mes.getBytes();
dp = new DatagramPacket(buf, buf.length, serverAddr, serverPort);
// 当建立发送时,测试正常
test = true;
try
{
ds.send(dp);
}
catch (NullPointerException n)
{
// 如果无法得到要发送的消息,测试终止
test = false;
System.out.println("The nullity of the address of connection");
}
catch (IOException s)
{
// 如果无法发送消息至服务器,测试终止
test = false;
System.out.println("There is a problem to send message.");
}
finally
{
}
}
/**
* 得到数据
*/
public void getMes()
{
byte[] buf = new byte[1024];
DatagramPacket getDatas = new DatagramPacket(buf, buf.length);
String mes = null;
try
{
while (true)
{
ds.receive(getDatas);
mes = new String(buf, 0, getDatas.getLength());
// 如果服务器发送的消息中的头片段有-getList
// 表明客户端获得在线用户列表,调用getList方法解析
if (mes.indexOf("-getList") == 0)
this.getList(mes);
else
System.out.println(mes);
}
}
catch (IOException i)
{
System.out.println("Fail in receving message");
}
}
/**
* 得到一次数据
*
*/
public String getMesOnce()
{
byte[] buf = new byte[1024];
DatagramPacket getDatas = new DatagramPacket(buf, buf.length);
String mes = null;
try
{
ds.receive(getDatas);
mes = new String(buf, 0, getDatas.getLength());
}
catch (Exception e)
{
System.out.println("!-Can not receive the message!");
}
finally
{
}
return mes;
}
/**
* 显示在线用户列表
*
* @param mes
*/
private void getList(String mes)
{
String[] list = mes.split(",");
System.out.println("在线用户:\n-------------");
for (int i = 1; i < list.length; i++)
{
System.out.println(" * " + list[i]);
}
System.out.println("-------------");
}
/**
* 判断用户名输入是否正确
*/
private boolean checkNickName(String nickName)
{
test = true;
String mes = null;
// 判断昵称是否符合约定
for (int i = 0; i < nickName.length(); i++)
{
char temp = nickName.charAt(i);
// 如果不符合,则终止测试
if (!Character.isLetterOrDigit(temp))
{
test = false;
break;
}
}
// 如果通过约定,则试图向服务器发送昵称,进行判断
if (test)
{
this.sendMes("-nick " + nickName);
mes = this.getMesOnce();
// 如果服务器返回"-nick"标识
// 说明测试昵称失败,终止测试
if (mes.startsWith("-nick"))
{
test = false;
}
}
System.out.println(mes);
return test;
}
/**
* 得到帮助列表
*
*/
public void helpList()
{
System.out.println("重要说明:如果已经成功连接,只要输入内容,所有在线用户都能看到您的发言。" + "\n" + "-help" + " 获取客户端相应操作的帮助" + "\n"
+ "-test" + " 测试与服务器的连接,如果已经服务器连接,请不要选用此项" + "\n" + "-getList" + " 得到在线用户的列表" + "\n"
+ "-to <name> <message>" + "\n" + " 将消息发送到特定的在线用户处" + "\n" + "-quit"
+ " 断开连接,退出聊天室" + "\n");
}
/**
* 线程部分
*/
public void run()
{
getMes();
}
/**
* 各项内容的操作器
*/
public static void main(String[] args)
{
ChatClient cc = new ChatClient();
// serverAddr && serverPort
String serverIp = "localhost";
int serverPort = 9999;
InetAddress serverAddr = null;
if (args != null && args.length > 0)
{
int i = 0;
while (i < args.length)
{
// serverAddr
if (args[i].equalsIgnoreCase("-ServerAddr"))
{
i = i + 1;
serverIp = args[i];
continue;
}
// serverPort
int ti = 9999;
if (args[i].equalsIgnoreCase("-ServerPort"))
{
i = i + 1;
ti = Integer.parseInt(args[i]);
if (ti > 0)
{
serverPort = ti;
}
i = i + 1;
continue;
}
}
}
try
{
serverAddr = InetAddress.getByName(serverIp);
}
catch (UnknownHostException e)
{
e.printStackTrace();
System.exit(-1);
}
System.out.println("欢迎登录Lexiaofei聊天室!");
Scanner input = new Scanner(System.in);
// 连接服务器
cc.initServer(serverAddr, serverPort);
// 输入昵称
boolean goon = true;
while (goon)
{
// 第三步:输入昵称
System.out.println("3.请输入您登录后显示的昵称(只能输入中文、英文字母及数字):");
String nick = input.next();
boolean judge = cc.checkNickName(nick);
// 判断昵称是否输入正确
if (judge)
goon = false;
else
System.out.println("!-您输入的用户名不符合条件,请重新输入!");
}
// 开始运行接收数据
new Thread(cc).start();
// 聊天
String mes = null;
System.out.println("!-您成功进入聊天室!");
while (!(mes = input.nextLine()).equalsIgnoreCase("-quit"))
{
// 如果输入"-test"命令,开始测试
if (mes.trim().equalsIgnoreCase("-getList"))
{
cc.sendMes(mes);
// -nick 设置昵称
}
else if (mes.equalsIgnoreCase("-help"))
{
cc.helpList();
// 如果输入的是空字符,则不发送
}
else
{
if (!mes.equals(""))
{
cc.sendMes(mes);
}
}
}
// 退出
input.close();
cc.disconnectServer();
}
/**
* 错误提示标记
*
* @param str
*/
public static void errorTip(String str)
{
System.out.println("-----------------\n" + str + "\n-----------------");
}
}
package com.tianhe.frm.chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Scanner;
/**
*
*<br>
* 服务器的实现效果: <br>
*<br>
* 1.输入-help得到所有有关服务器操作的命令 <br>
*<br>
* 2.输入-run进入服务器各项内容初始化 <br>
*<br>
* 3.输入-stop断开服务器 <br>
*<br>
* 4.输入-quit断开服务器,并退出操作 <br>
*<br>
* 5.服务器创建成功后,会通过单独的线程运行监听客户端信息(listenLink) <br>
*<br>
* 6.服务器接收到数据后,会将数据移交至数据分析器(analyseMes)处理 <br>
*<br>
* 7.当用户确定连接并确定昵称后,服务器将该用户的地址及姓名存储在infoMemory中。 <br>
*<br>
*<br>
*<br>
*<br>
* 服务器的类与方法: <br>
*<br>
* 1.测试服务器创建:testServer(String ip,int serverPort) <br>
*<br>
* 2.初始化服务器 :initServer(String ip,int serverPort) <br>
*<br>
* 3.确定IP与Port :fixServerLink(String ip,int serverPort) <br>
*<br>
* 4.信息监听器 :listenLink() <br>
*<br>
* 5.数据分析器 :analyseMes(String mes) <br>
*<br>
* 6.获取地址用户名:getConsumerName(SocketAddress sa) <br>
*<br>
* 7.数据转发器 :transforMes(String mes) <br>
*<br>
* 8.数据单项转发器:transforMesSingle(SocketAddress adr,String mes) <br>
*<br>
* 9.停止服务器 :cutServer() <br>
*<br>
* 10.获得帮助列表 :helpList() <br>
*<br>
* 11.错误提示方法 :errorTip(String str) <br>
*<br>
* 12.在主函数中进行相应操作 <br>
*<br>
*<br>
* 重点注意的地方: <br>
*<br>
* 与客户端相仿,为了顺利监听信息,需要另一个线程运行信息监听器
*
*/
public class ChatServer implements Runnable
{
private DatagramSocket ds = null;
private DatagramPacket dp = null;
private String serverIp = "localhost";
private int serverPort = 9999;
private InetAddress serverAddr = null;
// 开始运行监听的变量
private boolean beStart = false;
// 信息存储器
private Hashtable<String, SocketAddress> userCache = new Hashtable<String, SocketAddress>();
/**
* 服务器初始化
*
* @param ip
* @param serverPort
*/
public boolean initServer(InetAddress serverAddr, int serverPort)
{
this.serverAddr = serverAddr;
this.serverPort = serverPort;
try
{
ds = new DatagramSocket(serverPort, serverAddr);
System.out.println("!-The Server Initialization Success!");
// 可以开始运行变量
beStart = true;
}
catch (SocketException s)
{
// 如果出现异常,则服务器测试不通过
errorTip("!-The Server Initialization Fail!--new DatagramSocket(" + serverPort + ", " + serverAddr + ")");
return false;
}
return true;
}
/**
* 监听信息
*
*/
public void listenLink()
{
byte[] buf = new byte[1024];
String mes = null;
try
{
dp = new DatagramPacket(buf, buf.length);
System.out.println("!-The Server starts listenning to message.");
while (beStart)
{
ds.receive(dp);
mes = new String(buf, 0, dp.getLength());
// 将获取的数据传递至数据分析器
this.analyseMes(mes);
}
}
catch (IOException e)
{
errorTip("!-The Server Can not receive message");
}
}
/**
* 数据分析器,给予相应处理
*
* @param mes
*/
private void analyseMes(String mes)
{
// 获取当前客户端的地址:
SocketAddress adr = dp.getSocketAddress();
// -test:进行服务器与客户端的连接测试
// 若成功,则将该客户端发送成功消息
if (mes.trim().equalsIgnoreCase("-test"))
{
transforMesSingle(adr, "-test: !-From Server:Succeed in Testing.");
}
// -quit:接受客户端退出信息
// 将该用户的退出信息转发至所有在线成员
else if (mes.trim().equalsIgnoreCase("-quit"))
{
String name = this.getConsumerName(adr);
System.out.println(name + "//" + adr + " quit! ");
transforMes("* " + name + "退出聊天室");
userCache.remove(name);
}
// -getList:接受客户端获取列表的请求
// 将所有用户连接为字符串的形式,如:"-getList,用户1,用户2...用户n"
else if (mes.trim().equals("-getList"))
{
StringBuffer list = new StringBuffer();
list.append("-getList,");
Enumeration<String> names = userCache.keys();
while (names.hasMoreElements())
{
list.append(names.nextElement() + ",");
}
transforMesSingle(dp.getSocketAddress(), list.toString());
}
// -to:接受客户端请求,将信息转发给相应客户
// 如果目标客户不存在,则向请求客户发送相应消息
else if (mes.indexOf("-to ") != -1 && mes.startsWith("-to "))
{
String main = mes.substring("-to ".length(), mes.length());
String toName = main.substring(0, main.indexOf(" "));
String name = this.getConsumerName(adr);
String con = name + " say to you :" + main.substring(toName.length() + 1, main.length());
if (!userCache.containsKey(toName))
transforMesSingle(adr, "!-The message can not be recevie by whom you send for,please check out.");
else
transforMesSingle(userCache.get(toName), con);
}
// -nick:接受客户端登录请求
// 如果输入的匿名不存在,则登记该用户与infoMemory
// 如果存在则返回相应提示
else if (mes.indexOf("-nick ") != -1 && mes.startsWith("-nick "))
{
String nickName = mes.substring("-nick ".length(), mes.length());
if (userCache.containsKey(nickName))
transforMesSingle(adr, "-nick: !-The nickname you post is already exist,please try others.");
else
{
userCache.put(nickName, adr);
transforMes("Welcome " + nickName + " to Sunspot Chat!");
System.out.println(nickName + "//" + adr.toString() + " succeed in lanuching.");
}
}
// 一般消息将会转发至所有用户
else
{
String name = this.getConsumerName(adr);
transforMes(name + ": " + mes);
}
}
/**
* 通过地址得到用户的昵称 由于Hashtable无法通过Value获取Key,所有专门写该方法
*
* @param sa
* @return
*/
private String getConsumerName(SocketAddress sa)
{
Enumeration<String> names = userCache.keys();
String name = null;
while (names.hasMoreElements())
{
String temp = names.nextElement();
SocketAddress adrs = userCache.get(temp);
// 进行比较
if (sa.equals(adrs))
{
name = temp;
break;
}
}
return name;
}
/**
* 向所有的用户发送数据
*
* @param mes
*/
public void transforMes(String mes)
{
byte[] buf = mes.getBytes();
DatagramPacket sendDatas = null;
Enumeration<SocketAddress> all = userCache.elements();
try
{
while (all.hasMoreElements())
{
sendDatas = new DatagramPacket(buf, buf.length, all.nextElement());
ds.send(sendDatas);
}
}
catch (SocketException s)
{
errorTip("!-The feedback address is error!");
}
catch (IOException i)
{
errorTip("!-Can not send message!");
}
}
/**
* 向单个用户发送数据
*
* @param adr
* @param mes
*/
public void transforMesSingle(SocketAddress adr, String mes)
{
byte[] buf = mes.getBytes();
try
{
DatagramPacket sendDatas = new DatagramPacket(buf, buf.length, adr);
ds.send(sendDatas);
}
catch (SocketException s)
{
errorTip("!-The feedback address is error!");
}
catch (IOException i)
{
errorTip("!-Can not send message!");
}
}
/**
* 断开连接
*
*/
public void cutServer()
{
beStart = false;
if (ds != null)
ds.close();
System.out.println("!-The ds is done.");
}
public void helpList()
{
System.out.println("-help" + " 获取服务器相应操作的帮助" + "\n" + "-run " + " 运行服务器,并同时建立信息监听" + "\n" + "-stop"
+ " 停止服务器" + "\n" + "-quit" + " 停止服务器,并退出命令" + "\n");
}
/**
* 线程
*/
public void run()
{
listenLink();
}
/**
* 主要操作
*
* @param args
*/
public static void main(String[] args)
{
ChatServer cs = new ChatServer();
// serverAddr && serverPort
String serverIp = "localhost";
int serverPort = 9999;
InetAddress serverAddr = null;
if (args != null && args.length > 0)
{
int i = 0;
while (i < args.length)
{
// serverAddr
if (args[i].equalsIgnoreCase("-ServerAddr"))
{
i = i + 1;
serverIp = args[i];
continue;
}
// serverPort
int ti = 9999;
if (args[i].equalsIgnoreCase("-ServerPort"))
{
i = i + 1;
ti = Integer.parseInt(args[i]);
if (ti > 0)
{
serverPort = ti;
}
i = i + 1;
continue;
}
}
}
try
{
serverAddr = InetAddress.getByName(serverIp);
}
catch (UnknownHostException e)
{
e.printStackTrace();
System.exit(-1);
}
// 建立输入
System.out.println("Lexiaofei聊天室创建成功!");
Scanner input = new Scanner(System.in);
System.out.println("!-请输入服务端命令:");
// 开始输入
String command = null;
// 如果输入quit将断开连接,并退出操作
while (!(command = input.next()).equalsIgnoreCase("-quit"))
{
// 获取帮助
if (command.equalsIgnoreCase("-help"))
{
cs.helpList();
}
// 初始化服务器
if (command.equalsIgnoreCase("-run"))
{
boolean goon = true;
while (goon)
{
// 测试服务器创建,如果成功则同时为信息监听器建立线程
System.out.println("!-创建服务器并运行...");
if (cs.initServer(serverAddr, serverPort))
{
new Thread(cs).start();
goon = false;
}
else
System.out.println("!-服务器创建失败,请检查!");
}
}
// 关闭服务器
if (command.equalsIgnoreCase("-stop"))
{
cs.cutServer();
}
}
input.close();
cs.cutServer();
}
/**
* 错误提示
*
* @param str
*/
public static void errorTip(String str)
{
System.out.println("-----------------\n" + str + "\n-----------------");
}
}
<!--weblogic-->
<bean id="jtaTxManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager" />
</bean>
<!--websphere-->
<bean id="jtaTxManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
<tx:advice id="txAdvice" transaction-manager="jtaTxManager">
<tx:attributes>
<tx:method name="select*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="list*" read-only="true" />
<tx:method name="detail*" read-only="true" />
<tx:method name="insert*" />
<tx:method name="update*" />
<tx:method name="delete*" />
<tx:method name="transfer*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(public * com.wbd.ngcrm.example.dictitem.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut" />
</aop:config>
<!-- dataSource begin -->
<bean id="dataSource.yy1a" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/yy1a</value>
</property>
</bean>
<bean id="dataSource.yy1b" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/yy1b</value>
</property>
</bean>
<bean id="dataSource.yy2a" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/yy2a</value>
</property>
</bean>
<bean id="dataSource.yy2b" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>jdbc/yy2b</value>
</property>
</bean>
为了使用WebWork,我们只需要在web.xml配置FilterDispatcher一个过滤器即可,阅读一下FilterDispatcher的JavaDoc和源码,我们可以看到它调用了:
finally
{
ActionContextCleanUp.cleanUp(req);
}
在ActionContextCleanUp中,有这样的代码:
req.setAttribute(CLEANUP_PRESENT, Boolean.TRUE);
如果FilterDispatcher检测到这个属性,就不会清除ActionContext中的内容了,而由ActionContextCleanUp后续的代码来清除,保证了一系列的Filter访问正确的ActionContext.
文档中提到,如果用到SiteMesh的Filter或者其他类似Filter,那么设置顺序是:
ActionContextCleanUp filter
SiteMesh filter
FilterDispatcher
所以最后我们的web.xml应该类似这样:
<filter>
<filter-name>ActionContextCleanUp</filter-name>
<filter-class>com.opensymphony.webwork.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.webwork.sitemesh.FreeMarkerPageFilter</filter-class>
</filter>
<filter>
<filter-name>webwork</filter-name>
<filter-class>com.opensymphony.webwork.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>ActionContextCleanUp</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>webwork</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
问题起因:
今天遇到一个乱码问题,以前已经配置好了的呀。而且是普遍现象,看来是公共的变更引起的问题。
分析过程:
于是开始进行调试,因为是公共问题,所以就对web.xml最近的变更进行增删调试,发现如果使用SecurityFilter就报错,去掉久正常了。
仔细检查,发现如下现象:
1、在设置字符集之前, 提前调用了request.getParameter()方法,就会出现问题。即使后来再设置字符集,随后的action接收的数据也会乱码。
2、对于同一个url,如:*.do,filter-mapping 是有顺序的,按照web.xml中的配置顺序。
从网上查到的结论:
根据servlet2.3规范filter执行是按照web.xml配置的filter-mapping先后顺序进行执行,所以上面的配置会导致遇见*.do的url请求,先进行SecurityFilter的过滤器处理,这时候没有做编码处理,已经是乱码,到下面的filter处理时已经时乱码,再做编码处理已经没有用处。
解决办法:
错误的顺序:
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
正确的顺序:
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
问题起因:
升级spring2.x的dtd声明为xsd声明以后,spring2.x+struts2.x的应用在weblogic81下报错,日志提示建议使用jdk1.5或升级xerces。
解决过程:
自己写了一个spring2.x+struts2.x应用在weblogic81下正常运行。说明问题出在应用上。
拷贝出问题的应用的jar包到成功应用的lib目录,问题仍然存在。说明还有其他隐情。
比对两个应用,发现出问题的应用使用了weblogic.xml, 其中配置了优先加载web-inf\lib的jar包。
此时建立jrokit/jar/lib/endrosed目录,放入最新的xerces包,也不生效。
换一个思路,查询DocumentBuilderFactoryImpl,发现有应用中有4处引用,删除xerces.jar的时候,发布成功。至此问题解决!!!!!!!
问题总结:
1 要注意保留成功的案例,以便比对。
最近碰到两个类似的问题了:一个是websphere下的web-inf\template问题,一个就是由于weblogic.xml干预,造成xerces.jar
的问题。
2 要注意观察实际使用的类的版本
3 升级以后,一定要验证单个平台下是否都能正常使用,并增加评审环节,避免影响他人。
1、gbk -> GBK
2、weblogic.xml中上下文要写为war的应用名字
3、8.1版本中的j2ee组件(filter,listener,servlet)初始化顺序与tomcat,websphere不一样,如果组件之间有依赖,无法实现跨平台相同部署。
在JSP页面中的对象,包括用户创建的对象(例如,JavaBean对象)和JSP的隐含对象,都有一个范围属性。
范围定义了在什么时间内,在哪一个JSP页面中可以访问这些对象。
例如,session对象在会话期间内,可以在多个页面中被访问。application对象在整个Web应用程序的生命周期中都可以被访问。
在JSP中,有4种范围,如下所示。
page范围
具有page范围的对象被绑定到javax.servlet.jsp.PageContext对象中。在这个范围内的对象,只能在创建对象的页面中访问。可以调用pageContext这个隐含对象的getAttribute()方法来访问具有这种范围类型的对象(pageContext对象还提供了访问其他范围对象的getAttribute方法),pageContext对象本身也属于page范围。当Servlet类的_jspService()方法执行完毕,属于page范围的对象的引用将被丢弃。page范围内的对象,在客户端每次请求JSP页面时创建,在页面向客户端发送回响应或请求被转发(forward)到其他的资源后被删除。
request范围
具有request范围的对象被绑定到javax.servlet.ServletRequest对象中,可以调用request这个隐含对象的getAttribute()方法来访问具有这种范围类型的对象。在调用forward()方法转向的页面或者调用include()方法包含的页面中,都可以访问这个范围内的对象。要注意的是,因为请求对象对于每一个客户请求都是不同的,所以对于每一个新的请求,都要重新创建和删除这个范围内的对象。
session范围
具有session范围的对象被绑定到javax.servlet.http.HttpSession对象中,可以调用session这个隐含对象的getAttribute()方法来访问具有这种范围类型的对象。JSP容器为每一次会话,创建一个HttpSession对象,在会话期间,可以访问session范围内的对象。
application范围
具有application范围的对象被绑定到javax.servlet.ServletContext中,可以调用application这个隐含对象的getAttribute()方法来访问具有这种范围类型的对象。在Web应用程序运行期间,所有的页面都可以访问在这个范围内的对象。
访问控件的主要对象是:document对象, 提供几个主要方法来访问对象:
1. document.getElementById
2. document.getElementsByName
3. document.getElementsByTagName
4. document.all
下面谈谈以上几个方法的具体用法:
一.document.getElementById
Var obj=document.getElementById("ID")
根据指定的ID属性值得到对象。返回id属性值等于ID的第一个对象的引用。假如对应的为一组对象,则返回该组对象中的第一个。
<input name="a" type="text" id="b"/>
<input name="b" type="text" id="a"/>
<input type="button" name="submint1" value="text1" onclick=:"alert(document.getElementById("b"))"/>
<input type="button" name="submint2" value="text2" onclick="alert(document.getElementById("a")))"/>
我在IE中测试了上面代码,在第一个文本框中输入1,在第二个文本中输入2,然后点击两个按钮,大吃一惊。
结果两个按钮都返回了第一个文本框的值。
这说明了IE执行document.getElementById(elementName)的时候,返回的是第一个name或者id等于elementName的对象,并不是根据ID来查找的。
相反我在firefox中就不存在这个问题。Firefox执行document.getElementById(elementName)的时候只能查找ID等于elementName对象,如果不存在在返回null.
二.document.getElementsByName
Var obj=document.getElementsByName("Name")
根据Name属性的值获取对象集合。返回name等于指定Name对象的集合。注意这里返回的是一个集合,包括只有一个元素的情况也是一个集合。
document.getElementsByName("name")[0]
这样来获取某一个元素。注意javascript中的集合取一个值可以用[],也可以用()。
如:
<script>
function prop()
{
var objs=document.getElementsByName("a");
alert(objs(0).value);//或者可以alert(objs[0].value)也正确的。
}
</script>
<input type="text" name="a" id="b" value="this is textbox"/>
<input type="button" value="testing" onclick="prop()"/>
三.Document.getElementsByTagName
Var ojbs=document.getElementsByTagName("Tag")
根据基于指定元素名称对象的集合。返回Tag属性等于指定Tag标记的集合。这里也返回的是一个集合。(同上)
四.document.all用法。
document.all是页面内所有元素的一个集合。例如:
document.all(0)表示页面的第一个元素。
Document.all("txt")表示页面上id或name等于txt的所有对象的单个元素和集合元素。
如果页面上的id或name等于txt只有一个元素(包括name和id情况),那么document.all()的结果就只是一个元素,反之就是获取一个集合。
(综合了document.getElementById和document.getElementsByName的各自的特点)。
也可以这样写:document.all.txt也是一样。
例如:
<input name=aaa value=aaa>
<input id=bbb value=bbb>
<script language=Jscript>
alert(document.all.aaa.value) //根据name取value
alert(document.all.bbb.value) //根据id取value
</script>
代码2:
但是常常name可以相同(如:用checkbox取用户的多项爱好的情况)
<input name=aaa value=a1>
<input name=aaa value=a2>
<input id=bbb value=bbb>
<script language=Jscript>
alert(document.all.aaa(0).value)//显示a1
alert(document.all.aaa(1).value)//显示a2
alert(document.all.bbb(0).value)//这行代码会失败
</script>
理论上一个页面中的ID是互不相同的,如果出现不同的tags而有相同的id的话,document.all.id就会失败,就象这样:
<input id=aaa value=a1>
<input id=aaa value=a2>
<script language=Jscript>
alert(document.all.aaa.value)//显示undefined而不是a1或者a2
</script>
所以说遇到了这种情况的话用下面这种写法:
<input id=aaa value=aaa1>
<input id=aaa value=aaa2>
<input name=bbb value=bbb>
<input name=bbb value=bbb2>
<input id=ccc value=ccc>
<input name=ddd value=ddd>
<script language=Jscript>
alert(document.all("aaa",0).value)
alert(document.all("aaa",1).value)
alert(document.all("bbb",0).value)
alert(document.all("bbb",1).value)
alert(document.all("ccc",0).value)
alert(document.all("ddd",0).value)
</script>
另外document.all可以判断浏览器的种类是否是IE,
document.all---------针对IE
document.layers------------针对Netscape
这两个集合.all只在ie里面有效,layers只在nc里面有效
所以就可以通过这个方式来判断不同的浏览器。
最后我来说说getElementById和getElementsByName使用范围:
Id就像身份证号,是唯一的,name就像姓名一样可以同名。
一个元素定义了id,引用该元素时直接用id属性,而name通常用在form中,且必须由document.form.***而来,
也就是说,name 属性定义的元素在脚本中是document 对象的子对象。
1. name用于form内元素,提交需要.id用于form外元素好用因为DOM能直接取得单一元素
2.id 每页只能有一个. name可以有多个 name,有些标签不推荐用它
3. 表单元素(form input textarea select)与框架元素(iframe frame) 用 name这些元素都与表单(框架元素作用于form的target)提交有关,
在表单的接收页面只接收有name的元素 , 赋ID 的元素通过表单是接收不到值的, 你自己可以验证一下有一个例外A 可以赋 name 作为锚点, 也可以赋 ID;只能赋ID不能赋name的元素:(除去与表单相关的元素都只能赋ID)
body li table tr td th p div span pre dl dt dd font b 等等。
这里我引出另一个问题,既然有了ID那为什么还要name呢?
最直接答案:ID就像是一个人身份证号,而 name就像是他的名字,ID虽然是唯一的,但name是可以重复的。
具体来说:对于ID来说,它就是Client端HTML元素的Identity 。而Name 其实要复杂的多,因为 Name 有很多种的用途,所以它并不能完全由ID来代替,从而将其取消掉。
参考网站资料如下:具体用途有:
用途1:作为可与服务器交互数据的HTML元素的服务器端的标示,比如input、select、textarea和button等。我们可以在服务器端根据其Name通过
request.getParameter('name')取得元素提交的值。
用途2:HTML元素Input type="radio" 分组,我们知道radio button控件在同一个分组类,check操作是mutex的,同一时间只能选中一个radio,这个分组就是根据相同的Name属性来实现的。
用途3:建立页面中的锚点,我们知道<a href="URL" >link </a>是获得一个页面超级链接,
如果不用href属性,而改用Name,如:<a name="PageBottom"></a>,我们就获得了一个页面锚点。
用途4:作为对象的 Identity ,如 Applet 、 Object 、 Embed 等元素。比如在 Applet 对象实例中,我们将使用其Name来引用该对象。
用途5:在IMG元素和MAP元素之间关联的时候,如果要定义IMG的热点区域,需要使用其属性usemap,使usemap="#name"(被关联的MAP元素的Name)
用途6:某些特定元素的属性,如attribute,和param。例如为Object定义参数<PARAM NAME = "appletParameter" VALUE = "value" > .
显然这些用途都不是能简单的使用 ID来代替掉的,所以HTML元素的ID和 Name的却别并不是身份证号码和姓名这样的区别,它们更本就是不同作用的东西。
当然HTML元素的Name属性在页面中也可以起那么一点ID的作用,因为在DHTML对象树中,我们可以使用 document.getElementsByName 来
获取一个包含页面中所有指定Name元素的对象数组。
在这里顺便说一下,要是页面中有n(n >1) 个HTML元素的ID都相同了怎么办?在DHTML对象中怎么引用他们呢?
这个时候我们还是可以继续使用document.getElementById获取对象,只不过我们只能获取ID重复的那些对象中在HTML Render时第一个出现的对象。
而这时重复的ID会在引用时自动变成一个数组,ID重复的元素按 Render的顺序依次存在于数组中。
getElementById("xxx")返回第一个id属性为"xxx"或者特定表单元素name为"xxx"的元素
getElementsByName("xxx")返回所有id属性为"xxx"或者特定表单元素name为"xxx"的元素
这里要说明一下其实getElementById和getElementsByName取元素的范围是一样的,区别只是前者只返回第一个元素后者返回所有元素的集合
另外说明一下表单元素 表单元素指的是在<FORM >标签中数据可以被提交给服务器的标签,
主要有 <INPUT > <SELECT > <TEXTAREA >三个标签 这三个标签只有在name属性不为空的时候才能将数据提交给服务器 所以这三种标签多定义了一个name属性
其实这个name属性和id属性是完全一样的都可以定位元素
如果不是表单元素 就算你加了name属性getElementsByName也取不到不信你自己试试
问题起因:
今天两个同事向我反映workspace.jsp页面性能下降了,开始以为他们机器性能差或者jsp没有编译的原因。碍于面子,就坐下来看了一下,这一看不要紧,每次点都比较慢。两个人的机器配置也不差,以前同样的应用速度还是能够忍受的。我立刻感觉到了可能确实存在了问题,一个页面在tomcat单机下要几秒才能出来,肯定是有问题了。我们的系统是企业级别的应用,并发客户量非常的大。要是出了这样的问题,肯定会当场瘫痪的。
问题分析:
我首先通知了负责这个模块的同事,检查最近这个功能的修改纪录。最后发现原来是增加了一个ocx控件的调用。每次访问这个页面都要重新从服务器下载这个控件,导致了页面加载的性能问题。
解决办法:
把控件的加载放到了同一个页面的另一个frame的top.jsp,这样登陆的时候只需要下载一次缓存这个控件,之后workspace.jsp通过top.jsp所在的frame访问到该ocx控件。工作区页面的显示速度又恢复了原来的样子。
问题总结:
1、要相信直觉的力量,发现问题及时定位,不能攒到一起,再排地雷
2、要联系该模块最近的变更,及时找到问题的根源。
3、要注意收集总结这样的案例,以备将来的性能改造。