2008年8月13日
#
linux-geum:/etc/init.d # more start_oracle.sh #this script is used to start the oracle
su - oracle -c "/opt/oracle/product/10g/bin/dbstart"
su - oracle -c "/opt/oracle/product/10g/bin/lsnrctl start" ln -s /etc/init.d/start_oracle.sh /etc/rc.d/rc2.d/S16start_oracle ln -s /etc/init.d/start_oracle.sh /etc/rc.d/rc3.d/S16start_oracle ln -s /etc/init.d/start_oracle.sh /etc/rc.d/rc5.d/S16start_oracle
linux-geum:/etc/init.d # more stop_oracle.sh #this script is used to stop the oracle
su - oracle -c "/opt/oracle/product/10g/bin/lsnrctl stop"
su - oracle -c "/opt/oracle/product/10g/bin/bin/dbshut" ln -s /etc/init.d/stop_oracle.sh /etc/rc.d/rc2.d/S16stop_oracle ln -s /etc/init.d/stop_oracle.sh /etc/rc.d/rc3.d/S16stop_oracle ln -s /etc/init.d/stop_oracle.sh /etc/rc.d/rc5.d/S16stop_oracle
在/etc/init.d 下新建after.local或者编辑after.local文件,
文件内容 /usr/local/bin/memcached -d -m 512 -u root -l 192.168.1.106 -p 11211 -c 1024 -P /tmp/memcached.pid
1、主要实现用户在进行某项操作时,多数据库的更新、插入和删除详细信息。记录操作时的请求信息。 2、在进入Controller时,生成一个事物ID,在这个Controller中进行的所有DAO操作都绑定该事物ID。并进行记录日志信息。
package com.centralsoft.filter;
import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Date; import java.util.HashMap; import java.util.regex.Pattern;
import net.sf.json.JSONObject;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component;
import com.centralsoft.cache.CacheService; import com.centralsoft.cache.annotations.Cache; import com.centralsoft.cache.entity.MemCacheKey; import com.centralsoft.entity.SysLogDetail; import com.centralsoft.manager.pub.ThreadBean; import com.centralsoft.manager.pub.ThreadId; import com.centralsoft.pub.dao.SysLogDAO; import com.centralsoft.webservice.pub.DateSHA;
/** * DAO层AOP拦截器,实现记录用户操作过的所有方法和参数,并实现DAO层缓存 * * @author Administrator * */ @Aspect @Component public class AspectAutoDAOBean {
@Autowired @Qualifier("CacheService") private CacheService memcache;
@Autowired @Qualifier("SysLogDAO") private SysLogDAO SysLogDAO;
@Around("execution(* com.centralsoft.*.dao.Zr*DAO.*(..))") public Object before(ProceedingJoinPoint joinPoint) throws Throwable { // 获取请求事务ID信息 ThreadId threadId = new ThreadBean().getThreadId(); // 调用方法名称 String methodName = joinPoint.getSignature().getName(); // 调用参数 Object[] args = joinPoint.getArgs(); Object object = null;
// 数据库更新操作日志 if (Pattern.matches("(save|insert|add|delete|remove|del|update)[\\S]*", methodName)) { if (threadId != null && threadId.getTransactionalId() != null) { // 获取执行请求事务ID String transactionalId = threadId.getTransactionalId(); // 获取执行请求用户ID String userId = threadId.getUserId(); SysLogDetail sysLogDetail = new SysLogDetail(); sysLogDetail.setXh(transactionalId); sysLogDetail.setUserId(userId); sysLogDetail.setMethod(methodName); JSONObject msg = new JSONObject(); // 处理参数 for (Object temp : args) { // 获取参数类型,不同参数类型数据处理不一样 Class<? extends Object> paramClazz = temp.getClass(); String classType = paramClazz.getName(); if (classType.equals("java.lang.String")) { msg.put("key", temp); } else if (classType.equals("java.util.HashMap")) { msg.putAll((HashMap<?, ?>) temp); } else if (classType.startsWith("com.")) { try { Field[] f = paramClazz.getDeclaredFields(); for (Field field : f) { String fieldName = field.getName(); field.setAccessible(true); msg.put(fieldName, field.get(temp)); } } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } } } sysLogDetail.setMsg(msg.toString()); // 记录DAO数据库操作日志 SysLogDAO.insertSysLogDetail(sysLogDetail); } // 执行数据库操作 object = joinPoint.proceed();
// 数据库查询缓存 } else if (Pattern.matches("(query|load|get|select|read)[\\S]*", methodName)) { // DAO层缓存注解 MemCacheKey cacheKey = new MemCacheKey(); // 获取cache注解属性 Cache cache = null; // 获取请求方法 Class<?> cls = joinPoint.getTarget().getClass(); // 获取class中的所有方法 Method[] methods = cls.getMethods(); for (Method m : methods) { // 获取执行方法前的注解信息。 if (m.getName().equals(methodName)) { cache = m.getAnnotation(Cache.class); break; } }
if (cache != null) { // 获取memcacheKey,并进行MD5加密 cacheKey = memcacheKey(cache, args); // 判断缓存服务器是否存在该可以值 if (memcache.exist(cacheKey.getMemcacheKey())) { object = memcache.get(cacheKey.getMemcacheKey()); } else { // 执行数据库操作 object = joinPoint.proceed(); // 将数据存放进缓存 if (cacheKey.getMemcacheKey() != null) { memcache.put(cacheKey.getMemcacheKey(), object == null ? "" : object, new Date(cacheKey .getTime())); } } } else { // 执行数据库操作 object = joinPoint.proceed(); } } else { // 执行数据库操作 object = joinPoint.proceed(); }
return object;
}
/** * 获取根据注解中的key获取memcache的含参数key值 * * @param cache * @param parameterObject * @return * @author fei.zhao 2011-10-10 */ @SuppressWarnings("unchecked") private static MemCacheKey memcacheKey(Cache cache, Object[] args) { MemCacheKey tempKey = new MemCacheKey(); String key = ""; boolean flag = true; StringBuilder keyBuilder = new StringBuilder(32); // 获取注解中的key值 String cacheKey = cache.key(); Object[] cacheArgs = cacheKey.split("\\.");
// 设置请求参数在args[]中的序号 // key参数进行循环遍历 for (Object s : cacheArgs) { // 判断是否是格式$,$... if (s.toString().startsWith("$")) { // 获取参数名称 String type = s.toString().substring(1); // 获取参数值 Object temp = args[0]; // 获取参数类型,不同参数类型数据处理不一样 Class<? extends Object> paramClazz = temp.getClass(); String classType = paramClazz.getName(); if (classType.equals("java.lang.String")) { keyBuilder.append(temp); } else if (classType.equals("java.util.HashMap")) { keyBuilder.append(((HashMap) temp).get(type)); } else if (classType.startsWith("com.")) { try { Field f = paramClazz.getDeclaredField(type);// 实体中字段 f.setAccessible(true);// 允许访问私有字段 keyBuilder.append(f.get(temp)); } catch (SecurityException e) { flag = false; e.printStackTrace(); } catch (NoSuchFieldException e) { flag = false; e.printStackTrace(); } catch (IllegalArgumentException e) { flag = false; e.printStackTrace(); } catch (IllegalAccessException e) { flag = false; e.printStackTrace(); } } } else { keyBuilder.append(s); } // 每个参数后面添加 “.”号分隔 keyBuilder.append("."); } if (args.length == 3) { keyBuilder.append(args[1] + ".").append(args[2]); } if (flag == true) { key = keyBuilder.toString(); tempKey.setMemcacheKey(DateSHA.shaEncrypt(key)); tempKey.setTime(cache.time()); } return tempKey; } }
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉及到COOKIE问题的处理。我们知道目前流行的***页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用java.net.HttpURLConnection来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的“顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!
我们不可能列举所有可能的顽固,我们会针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http服务器的访问绝非易事。
Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所形侍狻?/font>
1. 读取网页(HTTP/HTTPS)内容
下面是我们给出的一个简单的例子用来访问某个页面
/*
* Created on 2003-12-14 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面
* @author Liudong
*/
public class SimpleClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
//设置代理服务器地址和端口
//client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);
//使用GET方法,如果服务器需要通过HTTPS连接,那只需要将下面URL中的http换成https
HttpMethod method = new GetMethod("http://java.sun.com");
//使用POST方法
//HttpMethod method = new PostMethod("http://java.sun.com");
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印返回的信息
System.out.println(method.getResponseBodyAsString());
//释放连接
method.releaseConnection();
}
}
在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请求的过程,非常的简单!
2. 以GET或者POST方式向网页提交参数
其实前面一个最简单的示例中我们已经介绍了如何使用GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:
/*
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/**
* 提交参数演示
* 该程序连接到一个用于查询手机号码所属地的页面
* 以便查询号码段1330227所在的省份以及城市
* @author Liudong
*/
public class SimpleHttpClient {
public static void main(String[] args) throws IOException
{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost("www.imobile.com.cn", 80, "http");
HttpMethod method = getPostMethod();//使用POST方式提交数据
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印结果页面
String response =
new String(method.getResponseBodyAsString().getBytes("8859_1"));
//打印返回的信息
System.out.println(response);
method.releaseConnection();
}
/**
* 使用GET方式提交数据
* @return
*/
private static HttpMethod getGetMethod(){
return new GetMethod("/simcard.php?simcard=1330227");
}
/**
* 使用POST方式提交数据
* @return
*/
private static HttpMethod getPostMethod(){
PostMethod post = new PostMethod("/simcard.php");
NameValuePair simcard = new NameValuePair("simcard","1330227");
post.setRequestBody(new NameValuePair[] { simcard});
return post;
}
}
在上面的例子中页面http://www.imobile.com.cn/simcard.php需要一个参数是simcard,这个参数值为手机号码段,即手机号码的前七位,服务器会返回提交的手机号码对应的省份、城市以及其他详细信息。GET的提交方法只需要在URL后加入参数信息,而POST则需要通过NameValuePair类来设置参数名称和它所对应的值
3. 处理页面重定向
在JSP/Servlet编程中response.sendRedirect方法就是使用HTTP协议中的重定向机制。它与JSP中的<jsp:forward …>的区别在于后者是在服务器中实现页面的跳转,也就是说应用容器加载了所要跳转的页面的内容并返回给客户端;而前者是返回一个状态码,这些状态码的可能值见下表,然后客户端读取需要跳转到的页面的URL并重新加载新的页面。就是这样一个过程,所以我们编程的时候就要通过HttpMethod.getStatusCode()方法判断返回值是否为下表中的某个值来判断是否需要跳转。如果已经确认需要进行页面跳转了,那么可以通过读取HTTP头中的location属性来获取新的地址。
状态码
对应HttpServletResponse的常量
详细描述
301
SC_MOVED_PERMANENTLY
页面已经永久移到另外一个新地址
302
SC_MOVED_TEMPORARILY
页面暂时移动到另外一个新的地址
303
SC_SEE_OTHER
客户端请求的地址必须通过另外的URL来访问
307
SC_TEMPORARY_REDIRECT
同SC_MOVED_TEMPORARILY
下面的代码片段演示如何处理页面的重定向
client.executeMethod(post);
System.out.println(post.getStatusLine().toString());
post.releaseConnection();
//检查是否重定向
int statuscode = post.getStatusCode();
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY) ||
(statuscode == HttpStatus.SC_MOVED_PERMANENTLY) ||
(statuscode == HttpStatus.SC_SEE_OTHER) ||
(statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
//读取新的URL地址
Header header = post.getResponseHeader("location");
if (header != null) {
String newuri = header.getValue();
if ((newuri == null) || (newuri.equals("")))
newuri = "/";
GetMethod redirect = new GetMethod(newuri);
client.executeMethod(redirect);
System.out.println("Redirect:"+ redirect.getStatusLine().toString());
redirect.releaseConnection();
} else
System.out.println("Invalid redirect");
}
我们可以自行编写两个JSP页面,其中一个页面用response.sendRedirect方法重定向到另外一个页面用来测试上面的例子。
4. 模拟输入用户名和口令进行登录
本小节应该说是HTTP客户端编程中最常碰见的问题,很多网站的内容都只是对注册用户可见的,这种情况下就必须要求使用正确的用户名和口令登录成功后,方可浏览到想要的页面。因为HTTP协议是无状态的,也就是连接的有效期只限于当前请求,请求内容结束后连接就关闭了。在这种情况下为了保存用户的登录信息必须使用到Cookie机制。以JSP/Servlet为例,当浏览器请求一个JSP或者是Servlet的页面时,应用服务器会返回一个参数,名为jsessionid(因不同应用服务器而异),值是一个较长的唯一字符串的Cookie,这个字符串值也就是当前访问该站点的会话标识。浏览器在每访问该站点的其他页面时候都要带上jsessionid这样的Cookie信息,应用服务器根据读取这个会话标识来获取对应的会话信息。
对于需要用户登录的网站,一般在用户登录成功后会将用户资料保存在服务器的会话中,这样当访问到其他的页面时候,应用服务器根据浏览器送上的Cookie中读取当前请求对应的会话标识以获得对应的会话信息,然后就可以判断用户资料是否存在于会话信息中,如果存在则允许访问页面,否则跳转到登录页面中要求用户输入帐号和口令进行登录。这就是一般使用JSP开发网站在处理用户登录的比较通用的方法。
这样一来,对于HTTP的客户端来讲,如果要访问一个受保护的页面时就必须模拟浏览器所做的工作,首先就是请求登录页面,然后读取Cookie值;再次请求登录页面并加入登录页所需的每个参数;最后就是请求最终所需的页面。当然在除第一次请求外其他的请求都需要附带上Cookie信息以便服务器能判断当前请求是否已经通过验证。说了这么多,可是如果你使用httpclient的话,你甚至连一行代码都无需增加,你只需要先传递登录信息执行登录过程,然后直接访问想要的页面,跟访问一个普通的页面没有任何区别,因为类HttpClient已经帮你做了所有该做的事情了,太棒了!下面的例子实现了这样一个访问的过程。
/*
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.*;
import org.apache.commons.httpclient.methods.*;
/**
* 用来演示登录表单的示例
* @author Liudong
*/
public class FormLoginDemo {
static final String LOGON_SITE = "localhost";
static final int LOGON_PORT = 8080;
public static void main(String[] args) throws Exception{
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT);
//模拟登录页面login.jsp->main.jsp
PostMethod post = new PostMethod("/main.jsp");
NameValuePair name = new NameValuePair("name", "ld");
NameValuePair pass = new NameValuePair("password", "ld");
post.setRequestBody(new NameValuePair[]{name,pass});
int status = client.executeMethod(post);
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
//查看cookie信息
CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
Cookie[] cookies = cookiespec.match(LOGON_SITE, LOGON_PORT, "/", false, client.getState().getCookies());
if (cookies.length == 0) {
System.out.println("None");
} else {
for (int i = 0; i < cookies.length; i++) {
System.out.println(cookies[i].toString());
}
}
//访问所需的页面main2.jsp
GetMethod get = new GetMethod("/main2.jsp");
client.executeMethod(get);
System.out.println(get.getResponseBodyAsString());
get.releaseConnection();
}
}
5. 提交XML格式参数
提交XML格式的参数很简单,仅仅是一个提交时候的ContentType问题,下面的例子演示从文件文件中读取XML信息并提交给服务器的过程,该过程可以用来测试Web服务。
import java.io.File;
import java.io.FileInputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PostMethod;
/**
* 用来演示提交XML格式数据的例子
*/
public class PostXMLClient {
public static void main(String[] args) throws Exception {
File input = new File(“test.xml”);
PostMethod post = new PostMethod(“http://localhost:8080/httpclient/xml.jsp”);
// 设置请求的内容直接从文件中读取
post.setRequestBody(new FileInputStream(input));
if (input.length() < Integer.MAX_VALUE)
post.setRequestContentLength(input.length());
else post.setRequestContentLength(EntityEnclosingMethod.CONTENT_LENGTH_CHUNKED);
// 指定请求内容的类型
post.setRequestHeader("Content-type", "text/xml; charset=GBK");
HttpClient httpclient = new HttpClient();
int result = httpclient.executeMethod(post);
System.out.println("Response status code: " + result);
System.out.println("Response body: ");
System.out.println(post.getResponseBodyAsString());
post.releaseConnection();
}
}
6. 通过HTTP上传文件
httpclient使用了单独的一个HttpMethod子类来处理文件的上传,这个类就是MultipartPostMethod,该类已经封装了文件上传的细节,我们要做的仅仅是告诉它我们要上传文件的全路径即可,下面的代码片段演示如何使用这个类。
MultipartPostMethod filePost = new MultipartPostMethod(targetURL);
filePost.addParameter("fileName", targetFilePath);
HttpClient client = new HttpClient();
//由于要上传的文件可能比较大,因此在此设置最大的连接超时时间
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
int status = client.executeMethod(filePost);
上面代码中,targetFilePath即为要上传的文件所在的路径。
7. 访问启用认证的页面
我们经常会碰到这样的页面,当访问它的时候会弹出一个浏览器的对话框要求输入用户名和密码后方可,这种用户认证的方式不同于我们在前面介绍的基于表单的用户身份验证。这是HTTP的认证策略,httpclient支持三种认证方式包括:基本、摘要以及NTLM认证。其中基本认证最简单、通用但也最不安全;摘要认证是在HTTP 1.1中加入的认证方式,而NTLM则是微软公司定义的而不是通用的规范,最新版本的NTLM是比摘要认证还要安全的一种方式。
下面例子是从httpclient的CVS服务器中下载的,它简单演示如何访问一个认证保护的页面:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
public class BasicAuthenticationExample {
public BasicAuthenticationExample() {
}
public static void main(String[] args) throws Exception {
HttpClient client = new HttpClient();
client.getState().setCredentials(
"www.verisign.com",
"realm",
new UsernamePasswordCredentials("username", "password")
);
GetMethod get = new GetMethod("https://www.verisign.com/products/index.html");
get.setDoAuthentication( true );
int status = client.executeMethod( get );
System.out.println(status+""+ get.getResponseBodyAsString());
get.releaseConnection();
}
}
8. 多线程模式下使用httpclient
多线程同时访问httpclient,例如同时从一个站点上下载多个文件。对于同一个HttpConnection同一个时间只能有一个线程访问,为了保证多线程工作环境下不产生冲突,httpclient使用了一个多线程连接管理器的类:MultiThreadedHttpConnectionManager,要使用这个类很简单,只需要在构造HttpClient实例的时候传入即可,代码如下:
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
以后尽管访问client实例即可。
import org.apache.commons.httpclient.methods.PostMethod;
public class UTF8PostMethod extends PostMethod
{
public static final String ENCODE_UTF8 = "UTF-8";
/**
* 默认构造函数
* @param url 地址
*/
public UTF8PostMethod(String url)
{
super(url);
}
/* (non-Javadoc)
* @see org.apache.commons.httpclient.methods.EntityEnclosingMethod#getRequestCharSet()
*/
@Override
public String getRequestCharSet()
{
return ENCODE_UTF8;
}
/* (non-Javadoc)
* @see org.apache.commons.httpclient.HttpMethodBase#getResponseCharSet()
*/
@Override
public String getResponseCharSet()
{
return ENCODE_UTF8;
}
}
package com.org.softwore;
import org.apache.commons.httpclient.methods.GetMethod;
public class UTF8GetMethod extends GetMethod {
public static final String ENCODE_UTF8 = "UTF-8";
/**
* 默认构造函数
*
* @param url
* 地址
*/
public UTF8GetMethod(String url) {
super(url);
}
/*
* (non-Javadoc)
*
* @see
* org.apache.commons.httpclient.methods.EntityEnclosingMethod#getRequestCharSet
* ()
*/
@Override
public String getRequestCharSet() {
return ENCODE_UTF8;
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.httpclient.HttpMethodBase#getResponseCharSet()
*/
@Override
public String getResponseCharSet() {
return ENCODE_UTF8;
}
}
测试使用!
HttpMethod method = null;
try {
HttpClient client = new HttpClient();
method = new UTF8PostMethod(
"http://.........");
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
String response = method.getResponseBodyAsString();
System.out.println(response);
}
} catch (HttpException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (method != null) {
method.releaseConnection();
}
}
鼎鼎大名的Spring框架3.0版在12月5日由其作者之一——Juergen Hoeller先生在博客里宣告问世,并命为里程碑版,给Spring粉丝们带来了震撼的快感。笔者即开“快车”拉了两个包回来,遗憾的是参考文档至今还没有出来(仅有API文档),这为学习Spring 3.0带来了非常大的困难,但没有阻挡笔者对新产品的兴趣。
Spring之父Rod Johnson先生早在2003年就预言EJB将死(观点颇具争议),攻击EJB之臃肿是在虐待程序员。然而EJB 3.0出来后几乎宣判Spring死刑,但自2.0版以后Spring火爆程度已经超过EJB,两者的争斗至今仍不停息,这也是Spring 3.0连文档还没有整理出来就匆匆推出的原因。当然,Spring与EJB有很多各自独特优势之处,例如EJB的分布式运算、标准规范,Spring的IoC、AOP切面编程、偶合集成、MVC等等,取各自之长在企业中应用如虎添翼。Spring目前已经加入了J2EE规范,J2EE世界将更加精彩......
或许是用腻了Struts1那死板的WEB框架,才对Spring MVC爱不释手,尤其是2.5版本以后,支持全注解配置方式,已经使很久没有再写过xml文件了。
3.0版是完全兼容2.5,因此了解2.5版的@MVC则更容易接受。正如Arjen Poutsma小伙子在他的博客里说的那样,3.0时代将集中致力于表述性状态转移(REST,希望我没有翻译错,金山词霸翻译为“休息”)的网络服务和更容易的网络编程。的确增加了更多的控制器类型,并增强了SOAP/WSDL/WS这些基于分布式体系结构。
先回忆下2.5注解方式的@MVC,来一个示例:
@Controller
public class ArticleController{
@RequestMapping("/articleView")
public String getArticle(@RequestParam("id") String id, HttpServletRequest request){
request.setAttribute("article", service.find(Article.class, id));
return "articleView";
}
}
ArticleController没有实现任何接口,是一个最普通不过的pojo,如果浏览器来了articleView.do?id=xxx这个请求,Spring会找到getArticle()这个方法,该方法第一个参数绑定到了URL上的请求参数,第二个是J2EE标准的request对象(可见Spring MVC是非侵入式的,不像变态的Struts2),事实上还可以给定HttpServletResponse,ModelMap,甚至自己的类型,Spring都会为你将值传入进来。通过一个逻辑层service组件根据id参数值去底层查找Article对象,并放入request作用域中,最后返回的是面页视图名,这个例子中是返回到articleView.jsp中。
上例再变通下:
@Controller
public class ArticleController{
@RequestMapping("/articleView_*")
public String getArticle(HttpServletRequest request){
String id = StringUtil.getParam(request.getRequestURI(),"articleView_*");
request.setAttribute("article", service.find(Article.class, id));
return "articleView";
}
}
对于articleView_aaa.do,articleView_bbbb.do,articleView_c5h8j2.do,articleView_xxx.do,这样的请求都会由getArticle()这个方法来应付,是不是很有意思?
Spring 3.0增加了一个@ PathVariable注解来支持可变的请求路径,将上面的代码在3.0版中再变通下:
@Controller
public class ArticleController{
@RequestMapping("/articleView/${id}") //可以接受articleView/aaa.do,articleView/xxx.do...
public String getArticle(@PathVariable String id, HttpServletRequest request){
request.setAttribute("article", service.find(Article.class, id));
return "articleView";
}
}
再变得复杂些:
@Controller
public class ArticleController{
@RequestMapping("/articleList/${pageSize}/channel/*/category/${id}")
public String getArticles((@PathVariable Integer pageSize, @PathVariable int id, HttpServletRequest request){
Integer channelId = StringUtil.getParam(request.getRequestURI(),"channel/*/");
request.setAttribute("articles", service.findScroll(Article.class, pageSize,50,"channel=? and category=?",new Object[]{channelId,id}));
return "articleList";
}
}
它已经灵活到URL地址完全可以自己随意编制。
根据内容协商制的视图解析机制:
2.5版是由@MVC控制器来决定视图解析器,3.0版将变得更加灵活,似乎可以通过扩展名来转到不同的解析器中,例如请求一个.pdf文件将是如何效果呢?3.0版都会带来不可思议的模式。
HTTP方法的转换:
先看前台页面一段Html代码
<form:form method="delete">
<p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>
HTTP规范中form表单只有两种方法——POST和GET,而3.0做了一个过滤器,可以转换这些方法至四种——GET, PUT, POST, 和 DELETE。控制器接受请求:
@Controller("/deleteArticle")
public class ArticleController{
de style="line-height: 28px; ">@RequestMappingde>de style="line-height: 28px; ">(method = RequestMethod.DELETE)
de> public String deleteArticle(@PathVariable String id, HttpServletRequest request){
service.delete(Article.class, id);
return "message";
}
}
3.0版仅在MVC子集中就增加了很多新特性,如果在IoC、AOP等等其它子集所有的变革,绝对可以称得上Srping创始人所述的里程碑版本。3.0版使用的注解列表如下:
? @Autowired
? @Component
? @Controller
? @InitBinder
? @ManagedAttribute
? @ManagedOperation
? @ManagedOperationParameters
? @ManagedOperationParameter
? @ManagedResource
? @PathVariable
? @PostConstruct
? @PreDestroy
? @Repository
? @RequestMapping
? @Required
? @Resource
? @Service
? @Transactional
目前Spring 3版本已经到了M2,应该是M3完成后将推出最终正式版本,我想很快会来临,按照Spring的创始人罗德.约翰逊的预言,未来J2EE应用中Spring+Tomcat将占主导地位,是否引起争议,笔者不敢点评,不过Oracle收购Sun后,Java社区将是如何,还无从知晓,似乎罗德.约翰逊对这宗收购案也有些紧张,因为Oracle不像Sun的第一个谈判者IBM那样有过开放技术的先例(可以回忆下IBM早期的主板总线开放掀起的兼容机潮至今波涛不熄)。目前国内对新东西消化尚慢,我到图书城看了下,Spring 2.5的资料都很难找到。且很多企业都是抱着Struts1.x在做开发,尽管笔者这样说会引来很多争议,但Struts1时代的灭亡只是时间问题。Struts2虽然改进了很多,依笔者看,与Spring MVC相比仍有诸多的不足,尤其看不惯那种变态的侵入模式,看看它把HttpServletRequest、HttpSession、HttpServletResponse等servlet标准组件干成什么样?开源时代,至少我不愿意接受那种变态的潜规则。
笔者早先常用Struts1.x框架,它搭配了一套自己的ActionForm,使得编程工作量增加,虽然可以变通使用自己的Pojo,但对于没有掌握J2EE底层工具类(BeanUtil)的开发人员来说,其类型匹配是非常复杂的事。事实上Spring MVC早在1.x版本就完全使用自己的pojo来对应表单的填充,配上属性编辑器,可以解决类型转换问题,完全实现领域模型驱动的设计模式。由于MVC层的控制器也是Spring容器的Bean而已,因此对整个项目的控制、扩展变得非常容易。同时上文也顺便点评了Struts2,可见Spring MVC在各类MVC框架的优势所在。本身罗德.约翰逊先生是设计模式高手,一个优秀的框架给我们带来的远远不只是开发效率,还有更先进的开发模式和理念...
笔者对Spring框架研究肤浅,待日后了解掌握更多时会常在博客中述之。
Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。
1. 配置文件
Log4J配置文件的基本格式如下:
#配置根Logger
log4j.rootLogger = [ level ] , appenderName1 , appenderName2 , …
#配置日志信息输出目的地Appender
log4j.appender.appenderName = fully.qualified.name.of.appender.class
log4j.appender.appenderName.option1 = value1
…
log4j.appender.appenderName.optionN = valueN
#配置日志信息的格式(布局)
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
…
log4j.appender.appenderName.layout.optionN = valueN
其中 [level] 是日志输出级别,共有5级:
FATAL 0
ERROR 3
WARN 4
INFO 6
DEBUG 7
Appender 为日志输出目的地,Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
Layout:日志输出格式,Log4j提供的layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下:
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss , SSS},输出类似:2002年10月18日 22 : 10 : 28 , 921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java: 10 )
2. 在代码中初始化Logger:
1)在程序中调用BasicConfigurator.configure()方法:给根记录器增加一个ConsoleAppender,输出格式通过PatternLayout设为"%-4r [%t] %-5p %c %x - %m%n",还有根记录器的默认级别是Level.DEBUG.
2)配置放在文件里,通过命令行参数传递文件名字,通过PropertyConfigurator.configure(args[x])解析并配置;
3)配置放在文件里,通过环境变量传递文件名等信息,利用log4j默认的初始化过程解析并配置;
4)配置放在文件里,通过应用服务器配置传递文件名等信息,利用一个特殊的servlet来完成配置。
3. 为不同的 Appender 设置日志输出级别:
当调试系统时,我们往往注意的只是异常级别的日志输出,但是通常所有级别的输出都是放在一个文件里的,如果日志输出的级别是BUG!?那就慢慢去找吧。
这时我们也许会想要是能把异常信息单独输出到一个文件里该多好啊。当然可以,Log4j已经提供了这样的功能,我们只需要在配置中修改Appender的Threshold 就能实现,比如下面的例子:
[配置文件]
### set log levels ###
log4j.rootLogger = debug , stdout , D , E
### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n
### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 保存异常信息到单独文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/error.log ## 异常日志文件名
log4j.appender.D.Append = true
log4j.appender.D.Threshold = ERROR ## 只输出ERROR级别以上的日志!!!
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
[代码中使用]
public class TestLog4j {
public static void main(String[] args) {
PropertyConfigurator.configure( " D:/Code/conf/log4j.properties " );
Logger logger = Logger.getLogger(TestLog4j. class );
logger.debug( " debug " );
logger.error( " error " );
}
}
运行一下,看看异常信息是不是保存在了一个单独的文件error.log中
log4j.properties 使用
一.参数意义说明
输出级别的种类
ERROR、WARN、INFO、DEBUG
ERROR 为严重错误 主要是程序的错误
WARN 为一般警告,比如session丢失
INFO 为一般要显示的信息,比如登录登出
DEBUG 为程序的调试信息
配置日志信息输出目的地
log4j.appender.appenderName = fully.qualified.name.of.appender.class
1.org.apache.log4j.ConsoleAppender(控制台)
2.org.apache.log4j.FileAppender(文件)
3.org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
4.org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
5.org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
配置日志信息的格式
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
1.org.apache.log4j.HTMLLayout(以HTML表格形式布局),
2.org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
3.org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
4.org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
控制台选项
Threshold=DEBUG:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
Target=System.err:默认情况下是:System.out,指定输出控制台
FileAppender 选项
Threshold=DEBUF:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
File=mylog.txt:指定消息输出到mylog.txt文件。
Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
RollingFileAppender 选项
Threshold=DEBUG:指定日志消息的输出最低层次。
ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。
File=mylog.txt:指定消息输出到mylog.txt文件。
Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。
MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。
MaxBackupIndex=2:指定可以产生的滚动文件的最大数。
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
日志信息格式中几个符号所代表的含义:
-X号: X信息输出时左对齐;
%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%r: 输出自应用启动到输出该log信息耗费的毫秒数
%c: 输出日志信息所属的类目,通常就是所在类的全名
%t: 输出产生该日志事件的线程名
%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main (TestLog4.java:10)
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%: 输出一个"%"字符
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
%m: 输出代码中指定的消息,产生的日志具体信息
%n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行
可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边较远输出的字符截掉。
二.文件配置Sample1
log4j.rootLogger=DEBUG,A1,R
#log4j.rootLogger=INFO,A1,R
# ConsoleAppender 输出
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
# File 输出 一天一个文件,输出路径可以定制,一般在根路径下
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=blog_log.txt
log4j.appender.R.MaxFileSize=500KB
log4j.appender.R.MaxBackupIndex=10
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n
文件配置Sample2
下面给出的Log4J配置文件实现了输出到控制台,文件,回滚文件,发送日志邮件,输出到数据库日志表,自定义标签等全套功能。
log4j.rootLogger=DEBUG,CONSOLE,A1,im
#DEBUG,CONSOLE,FILE,ROLLING_FILE,MAIL,DATABASE
log4j.addivity.org.apache=true
###################
# Console Appender
###################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
#####################
# File Appender
#####################
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
# Use this layout for LogFactor 5 analysis
########################
# Rolling File
########################
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
log4j.appender.ROLLING_FILE.Threshold=ERROR
log4j.appender.ROLLING_FILE.File=rolling.log
log4j.appender.ROLLING_FILE.Append=true
log4j.appender.ROLLING_FILE.MaxFileSize=10KB
log4j.appender.ROLLING_FILE.MaxBackupIndex=1
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
####################
# Socket Appender
####################
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
log4j.appender.SOCKET.RemoteHost=localhost
log4j.appender.SOCKET.Port=5001
log4j.appender.SOCKET.LocationInfo=true
# Set up for Log Facter 5
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n
########################
# Log Factor 5 Appender
########################
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
########################
# SMTP Appender
#######################
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
log4j.appender.MAIL.Threshold=FATAL
log4j.appender.MAIL.BufferSize=10
log4j.appender.MAIL.From=chenyl@yeqiangwei.com
log4j.appender.MAIL.SMTPHost=mail.hollycrm.com
log4j.appender.MAIL.Subject=Log4J Message
log4j.appender.MAIL.To=chenyl@yeqiangwei.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
########################
# JDBC Appender
#######################
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
log4j.appender.DATABASE.user=root
log4j.appender.DATABASE.password=
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=SampleMessages.log4j
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
###################
#自定义Appender
###################
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
log4j.appender.im.host = mail.cybercorlin.net
log4j.appender.im.username = username
log4j.appender.im.password = password
log4j.appender.im.recipient = corlin@yeqiangwei.com
log4j.appender.im.layout=org.apache.log4j.PatternLayout
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
三.高级使用
实验目的:
1.把FATAL级错误写入2000NT日志
2. WARN,ERROR,FATAL级错误发送email通知管理员
3.其他级别的错误直接在后台输出
实验步骤:
输出到2000NT日志
1.把Log4j压缩包里的NTEventLogAppender.dll拷到WINNT\SYSTEM32目录下
2.写配置文件log4j.properties
# 在2000系统日志输出
log4j.logger.NTlog=FATAL, A8
# APPENDER A8
log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
log4j.appender.A8.Source=JavaTest
log4j.appender.A8.layout=org.apache.log4j.PatternLayout
log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
3.调用代码:
Logger logger2 = Logger.getLogger("NTlog"); //要和配置文件中设置的名字相同
logger2.debug("debug!!!");
logger2.info("info!!!");
logger2.warn("warn!!!");
logger2.error("error!!!");
//只有这个错误才会写入2000日志
logger2.fatal("fatal!!!");
发送email通知管理员:
1. 首先下载JavaMail和JAF,
http://java.sun.com/j2ee/ja/javamail/index.html
http://java.sun.com/beans/glasgow/jaf.html
在项目中引用mail.jar和activation.jar。
2. 写配置文件
# 将日志发送到email
log4j.logger.MailLog=WARN,A5
# APPENDER A5
log4j.appender.A5=org.apache.log4j.net.SMTPAppender
log4j.appender.A5.BufferSize=5
log4j.appender.A5.To=chunjie@yeqiangwei.com
log4j.appender.A5.From=error@yeqiangwei.com
log4j.appender.A5.Subject=ErrorLog
log4j.appender.A5.SMTPHost=smtp.263.net
log4j.appender.A5.layout=org.apache.log4j.PatternLayout
log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
3.调用代码:
//把日志发送到mail
Logger logger3 = Logger.getLogger("MailLog");
logger3.warn("warn!!!");
logger3.error("error!!!");
logger3.fatal("fatal!!!");
在后台输出所有类别的错误:
1. 写配置文件
# 在后台输出
log4j.logger.console=DEBUG, A1
# APPENDER A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
2.调用代码
Logger logger1 = Logger.getLogger("console");
logger1.debug("debug!!!");
logger1.info("info!!!");
logger1.warn("warn!!!");
logger1.error("error!!!");
logger1.fatal("fatal!!!");
--------------------------------------------------------------------
全部配置文件:log4j.properties
# 在后台输出
log4j.logger.console=DEBUG, A1
# APPENDER A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 在2000系统日志输出
log4j.logger.NTlog=FATAL, A8
# APPENDER A8
log4j.appender.A8=org.apache.log4j.nt.NTEventLogAppender
log4j.appender.A8.Source=JavaTest
log4j.appender.A8.layout=org.apache.log4j.PatternLayout
log4j.appender.A8.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
# 将日志发送到email
log4j.logger.MailLog=WARN,A5
# APPENDER A5
log4j.appender.A5=org.apache.log4j.net.SMTPAppender
log4j.appender.A5.BufferSize=5
log4j.appender.A5.To=chunjie@yeqiangwei.com
log4j.appender.A5.From=error@yeqiangwei.com
log4j.appender.A5.Subject=ErrorLog
log4j.appender.A5.SMTPHost=smtp.263.net
log4j.appender.A5.layout=org.apache.log4j.PatternLayout
log4j.appender.A5.layout.ConversionPattern=%-4r %-5p [%t] %37c %3x - %m%n
全部代码:Log4jTest.java
/*
* 创建日期 2003-11-13
*/
package edu.bcu.Bean;
import org.apache.log4j.*;
//import org.apache.log4j.nt.*;
//import org.apache.log4j.net.*;
/**
* @author yanxu
*/
public class Log4jTest
{
public static void main(String args[])
{
PropertyConfigurator.configure("log4j.properties");
//在后台输出
Logger logger1 = Logger.getLogger("console");
logger1.debug("debug!!!");
logger1.info("info!!!");
logger1.warn("warn!!!");
logger1.error("error!!!");
logger1.fatal("fatal!!!");
//在NT系统日志输出
Logger logger2 = Logger.getLogger("NTlog");
//NTEventLogAppender nla = new NTEventLogAppender();
logger2.debug("debug!!!");
logger2.info("info!!!");
logger2.warn("warn!!!");
logger2.error("error!!!");
//只有这个错误才会写入2000日志
logger2.fatal("fatal!!!");
//把日志发送到mail
Logger logger3 = Logger.getLogger("MailLog");
//SMTPAppender sa = new SMTPAppender();
logger3.warn("warn!!!");
logger3.error("error!!!");
logger3.fatal("fatal!!!");
}
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/azheng270/archive/2008/03/12/2173430.aspx
查看进行命令: |
ps -ef | grep tomcat |
查看日志 |
tail -f logs/catalina.out |
74文件传送跳转文件夹 |
/opt/transport/ |
复制文件命令 |
scp UserOperateServiceImpl.class 118.123.253.71:/opt/transport/ |
远程连接 |
ssh 118.123.253.71 |
结束进程命令 |
kill -9 31454 |
启动tomcat |
sh bin/startup.sh |
搜索日志中的内容 |
grep '18923858130' interfaceLog.log* |
本地复制文件 |
cp -r appMarketWebApi appMarketWebApi2000000 |
删除文件命令 |
rm appMarketWebApi.zip |
压缩文件命令 |
zip -r AppStoreBak1108.zip AppStore |
复制文件清除.svn文件夹 |
xcopy appMarketWebApi1.3 11111111111 /s /i |
从现网复制文件命令 |
scp 10.128.100.115:/opt/transport/appMarketWebApi_1111_115.zip /opt/transport/ |
查看文件占用量大命令 |
du -k|sort -t " " +0 -n -r|more |
查看当前目录文件大小 |
du -sh . |
tar包解压命令 |
tar -xvf |
抓内存包命令 |
jmap -dump:format=b,file=heap20101216.bin |
useradd -d /home -s /bin/sh liyanhong |
passwd liyanhong |
package com.org.softwore.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.SocketException;
import org.apache.commons.net.telnet.TelnetClient;
import com.org.softwore.domain.TelnetInfo;
public class TelnetUtil {
private TelnetClient telnet = new TelnetClient("VT220");
private InputStream in;
private PrintStream out;
private String prompt = ">";
String s;
public void TelnetCmd(TelnetInfo telnetInfo) throws SocketException,
IOException, InterruptedException {
// 防火墙中高级的网络连接设置的本地连接取消选择
// Connect to the specified server
telnet.connect(telnetInfo.getServerIp(), telnetInfo.getServerPort());
// Get input and output stream references
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
// Login telnet
readUntil("login: ");
write(telnetInfo.getServerUser());
readUntil("password: ");
write(telnetInfo.getServerPwd());
readUntil(prompt);
// 执行命令
if (telnetInfo.getMap() != null) {
int a = 0;
for (Integer id : telnetInfo.getMap().keySet()) {
String temp = telnetInfo.getMap().get(id);
write(temp);
// 处理ftp登录,不需要执行readUntil(prompt)
if (temp.startsWith("ftp")) {
a = 2;
}
if (a > 0) {
a = a - 1;
continue;
} else {
readUntil(prompt);
}
}
}
System.out.println("\n");
}
public String readUntil(String pattern) throws IOException {
char lastChar = pattern.charAt(pattern.length() - 1);
StringBuffer sb = new StringBuffer();
// boolean found = false;
char ch = (char) in.read();
while (true) {
sb.append(ch);
if (ch == lastChar) {
if (sb.toString().endsWith(pattern)) {
// 处理编码,界面显示乱码问题
byte[] temp = sb.toString().getBytes("iso8859-1");
System.out.print(new String(temp, "GBK"));
return new String(temp, "GBK");
}
}
ch = (char) in.read();
}
}
public void write(String value) throws InterruptedException {
out.println(value);
out.flush();
Thread.sleep(1000);
}
public void disconnect() throws IOException {
telnet.disconnect();
}
}
package com.org.softwore.domain;
import java.io.Serializable;
import java.util.TreeMap;
public class TelnetInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6592407260449335815L;
private String serverIp;
private String serverUser;
private String serverPwd;
private int serverPort;
private String ftpIp;
private String ftpUser;
private String ftpPwd;
private String ftpPort;
private TreeMap<Integer, String> map;
public TreeMap<Integer, String> getMap() {
return map;
}
public void setMap(TreeMap<Integer, String> map) {
this.map = map;
}
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
}
public String getServerUser() {
return serverUser;
}
public void setServerUser(String serverUser) {
this.serverUser = serverUser;
}
public String getServerPwd() {
return serverPwd;
}
public void setServerPwd(String serverPwd) {
this.serverPwd = serverPwd;
}
public int getServerPort() {
return serverPort;
}
public void setServerPort(int serverPort) {
this.serverPort = serverPort;
}
public String getFtpIp() {
return ftpIp;
}
public void setFtpIp(String ftpIp) {
this.ftpIp = "ftp " + ftpIp;
}
public String getFtpUser() {
return ftpUser;
}
public void setFtpUser(String ftpUser) {
this.ftpUser = ftpUser;
}
public String getFtpPwd() {
return ftpPwd;
}
public void setFtpPwd(String ftpPwd) {
this.ftpPwd = ftpPwd;
}
public String getFtpPort() {
return ftpPort;
}
public void setFtpPort(String ftpPort) {
this.ftpPort = ftpPort;
}
}
package com.org.softwore.service;
public interface TelnetService {
public boolean windowsTelnetDownLoad();
public boolean windowsTelnetUpLoad();
public boolean windowsTelnetUpGrade();
public boolean windowsTelnetTomcat(String stats);
public boolean windowsTelnetBackUpSoftware();
}
package com.org.softwore.service.impl;
import java.io.IOException;
import java.net.SocketException;
import java.util.TreeMap;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.org.softwore.domain.TelnetInfo;
import com.org.softwore.service.TelnetService;
import com.org.softwore.util.TelnetUtil;
@Transactional
@Service("telnetService")
public class TelnetServiceImpl implements TelnetService {
/**
* 上传升级问价到ftp服务器
*/
@Override
public boolean windowsTelnetUpLoad() {
boolean reslut = false;
TelnetInfo telnetInfo = new TelnetInfo();
telnetInfo.setServerIp("127.0.0.1");
telnetInfo.setServerUser("administrator");
telnetInfo.setServerPwd("123456");
telnetInfo.setServerPort(23);
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "ftp 10.39.62.45");
map.put(2, "admin");
map.put(3, "admintianyi");
map.put(4, "bin");
map.put(5, "mkdir test1");
map.put(6, "cd /test1");
map.put(7, "put c:\\upgrade\\appMarketWebApi.zip");
map.put(8, "put c:\\upgrade\\T_RANKSWITCHTEMP.sql");
map.put(9, "bye");
telnetInfo.setMap(map);
TelnetCmd(telnetInfo);
return reslut;
}
/**
* 下载升级程序和文件
*/
@Override
public boolean windowsTelnetDownLoad() {
boolean reslut = false;
TelnetInfo telnetInfo = new TelnetInfo();
//telnet
telnetInfo.setServerIp("127.0.0.1");
telnetInfo.setServerUser("administrator");
telnetInfo.setServerPwd("123456");
telnetInfo.setServerPort(23);
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1, "cd c:\\");
map.put(2, "rd test /s /q");
map.put(3, "mkdir test");
map.put(4, "ftp 10.39.62.45");
map.put(5, "admin");
map.put(6, "admintianyi");
map.put(7, "bin");
map.put(8, "lcd c:\\test");
map.put(9, "cd test1");
map.put(10, "get appMarketWebApi.zip");
map.put(11, "get T_RANKSWITCHTEMP.sql");
map.put(12, "bye");
telnetInfo.setMap(map);
TelnetCmd(telnetInfo);
return reslut;
}
/**
* 服务器开启和关闭
*/
@Override
public boolean windowsTelnetTomcat(String stats) {
//安装tomcat7,使用服务来进行启动和停止
boolean reslut = false;
TelnetInfo telnetInfo = new TelnetInfo();
telnetInfo.setServerIp("127.0.0.1");
telnetInfo.setServerUser("administrator");
telnetInfo.setServerPwd("123456");
telnetInfo.setServerPort(23);
// 需要执行的sql语句
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
if(stats.equals("start")){
map.put(1, "net start Tomcat7");
}
if(stats.equals("stop")){
map.put(1, "net stop Tomcat7");
}
telnetInfo.setMap(map);
TelnetCmd(telnetInfo);
return reslut;
}
/**
* 备份软件程序
*/
@Override
public boolean windowsTelnetBackUpSoftware(){
boolean reslut = false;
TelnetInfo telnetInfo = new TelnetInfo();
telnetInfo.setServerIp("127.0.0.1");
telnetInfo.setServerUser("administrator");
telnetInfo.setServerPwd("123456");
telnetInfo.setServerPort(23);
// 需要执行的sql语句
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
//执行sql脚本
map.put(1, "cd c:\\");
map.put(2, "rd testback /s /q");
map.put(3, "mkdir testback");
map.put(4, "cd c:\\testback");
map.put(5, "mkdir appMarketWebApi");
map.put(6, "xcopy \"c:\\Tomcat 7.0\\webapps\\appMarketWebApi\" appMarketWebApi /s /y");
telnetInfo.setMap(map);
TelnetCmd(telnetInfo);
return reslut;
}
/**
* 执行sql脚本和升级程序
*/
@Override
public boolean windowsTelnetUpGrade() {
boolean reslut = false;
TelnetInfo telnetInfo = new TelnetInfo();
telnetInfo.setServerIp("127.0.0.1");
telnetInfo.setServerUser("administrator");
telnetInfo.setServerPwd("123456");
telnetInfo.setServerPort(23);
// 需要执行的sql语句
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
//执行sql脚本
map.put(1, "sqlplus appstore/appstore@appstore226");
map.put(2, "@c:\\test\\T_RANKSWITCHTEMP.sql");
map.put(3, "exit");
//执行升级程序
map.put(5, "cd c:\\test");
map.put(6, "unzip appMarketWebApi.zip");
map.put(7, "xcopy appMarketWebApi \"c:\\Tomcat 7.0\\webapps\\appMarketWebApi\" /s /y");
telnetInfo.setMap(map);
TelnetCmd(telnetInfo);
return reslut;
}
/**
* 公共的调用执行telnet命令
* @param telnetInfo
* @return
*/
public boolean TelnetCmd(TelnetInfo telnetInfo) {
boolean reslut = false;
if (telnetInfo != null) {
TelnetUtil telnet = new TelnetUtil();
try {
telnet.TelnetCmd(telnetInfo);
telnet.disconnect();
reslut = true;
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return reslut;
}
}
package com.org.softwore.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import com.org.softwore.service.TelnetService;
@Controller("telnetController")
public class TelnetController {
@Autowired
@Qualifier("telnetService")
private TelnetService telnetService;
/**
* 上传升级问价到ftp服务器
*/
public void windowsTelnetUpLoad() {
telnetService.windowsTelnetUpLoad();
}
/**
* 下载升级程序和文件
*/
public void windowsTelnetDownLoad() {
telnetService.windowsTelnetDownLoad();
}
/**
* 备份软件程序
*/
public void windowsTelnetBackUpSoftware() {
telnetService.windowsTelnetBackUpSoftware();
}
/**
* 服务关闭
*/
public void windowsTelnetStopTomcat() {
String stats = "stop";
telnetService.windowsTelnetTomcat(stats);
}
/**
* 执行sql脚本和升级程序
*/
public void windowsTelnetUpGrade() {
telnetService.windowsTelnetUpGrade();
}
/**
* 服务开启
*/
public void windowsTelnetStartTomcat() {
String stats = "start";
telnetService.windowsTelnetTomcat(stats);
}
}
package com.org.softwore.service;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.org.softwore.controller.TelnetController;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "/applicationContext.xml" })
public class TelnetUtilTest {
@Autowired
@Qualifier("telnetController")
private TelnetController telnetController;
/**
* 上传升级问价到ftp服务器
*/
@Test
public void windowsTelnetUpLoad() {
telnetController.windowsTelnetUpLoad();
}
/**
* 下载升级程序和文件
*/
@Test
public void windowsTelnetDownLoad() {
telnetController.windowsTelnetDownLoad();
}
/**
* 备份软件程序
*/
@Test
public void windowsTelnetBackUpSoftware() {
telnetController.windowsTelnetBackUpSoftware();
}
/**
* 关闭服务
*/
@Test
public void windowsTelnetStopTomcat() {
telnetController.windowsTelnetStopTomcat();
}
/**
* 执行sql脚本和升级程序
*/
@Test
public void windowsTelnetUpGrade() {
telnetController.windowsTelnetUpGrade();
}
/**
* 启动服务
*/
@Test
public void windowsTelnetStartTomcat() {
telnetController.windowsTelnetStartTomcat();
}
}
为了进行系统维护操作,有时需要再windows和linux或Unix系统之间互传文件,虽然有很多工具可以实现该功能,但我还是觉得命令行来的方便快捷,起初使用linux的scp命令,总是不成功,网上也没有相关介绍,经过几次努力之后,终于成功的摸索出了scp命令在写windows的路径时的写法,于是马上下了出来,与大家分享:
从linux系统复制文件到windows系统:scp /oracle/a.txt administrator@192.168.3.181:/d:/
在linux环境下,将windows下的文件复制到linux系统中:scp administrator@192.168.3.181:/d:/test/config.ips /oracle
请注意:因为windows系统本身不支持ssh协议,所以,要想上面的命令成功执行,必须在windows客户端安装ssh for windows的客户端软件,比如winsshd,使windows系统支持ssh协议才行。
commons-net-2.0.jar
log4j-1.2.15.jar
package com;
import java.io.InputStream;
import java.io.PrintStream;
import org.apache.commons.net.telnet.TelnetClient;
import org.apache.log4j.Logger;
public class TelnetHandler {
private static final Logger logger = Logger.getLogger(TelnetHandler.class);
private TelnetClient telnet = new TelnetClient("VT220");
private InputStream in;
private PrintStream out;
private String prompt=" ";
String s;
public void TelnetCmd(String server, String user, String password) {
try {
// Connect to the specified server
telnet.connect(server, 23);
logger.info("Login............................");
// Get input and output stream references
in = telnet.getInputStream();
out = new PrintStream(telnet.getOutputStream());
// Login
readUntil("login: ");
write(user);
readUntil("password: ");
write(password);
// Advance to a prompt
readUntil(prompt);
} catch (Exception e) {
e.printStackTrace();
logger.info("logon failed", e);
}
}
public String readUntil(String pattern) {
try {
char lastChar = pattern.charAt(pattern.length() - 1);
StringBuffer sb = new StringBuffer();
// boolean found = false;
char ch = (char) in.read();
while (true) {
System.setProperty("GBK", "iso8859-1");
System.out.print(ch);
sb.append(ch);
if (ch == lastChar) {
if (sb.toString().endsWith(pattern)) {
// System.out.print( sb.toString());
return sb.toString();
}
}
ch = (char) in.read();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void write(String value) {
try {
out.println(value);
out.flush();
// System.out.println(value);
} catch (Exception e) {
e.printStackTrace();
}
}
public String sendCmd(String command) {
try {
write(command);
return readUntil(s + prompt);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void disconnect() {
try {
telnet.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
logger.info("发送命令开始");
TelnetHandler telnet1 = new TelnetHandler();
telnet1.TelnetCmd("127.0.0.1", "administrator", "123456");
// Exec Cmd
// telnet1.sendCmd("dir");
telnet1.sendCmd("cd c:\\test");
telnet1.disconnect();
// telnet1.sendCmd("xcopy c:\\httpdownload.txt c:\\test");
logger.info("发送命令结束");
} catch (Exception e) {
e.printStackTrace();
}
}
}
1、建一个Project取名为SOAP
2、将axis-1_4\webapps\axis\WEB-INF\lib下的所有文件拷贝到你的SOAP工程文件下
3、新建一个HelloWord.java
package com;
public class HelloWord {
public String getHelloWord(userInfo userInfo) {
return "hi!:" + userInfo.getName() + "| " + userInfo.getPassword()
+ " | " + userInfo.getArea();
}
}
4、新建一个userInfo.java 对象
package com;
public class userInfo implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = -1536718814867769008L;
String name;
String password;
String area;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
}
5、在WEB-INF\server-config.wsdd 文件添加以下内容(注意颜色标记的地方时跟soap相关的地方)
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<handler type="java:org.apache.axis.handlers.http.URLMapper"
name="URLMapper" />
<service name="HelloWord" provider="java:RPC">
<parameter name="className" value="com.HelloWord" />
<parameter name="allowedMethods" value="getHelloWord" />
<beanMapping languageSpecificType="java:com.userInfo" qname="ns:userInfo" xmlns:ns="urn:BeanService"/>
</service>
<transport name="http">
<requestFlow>
<handler type="URLMapper" />
</requestFlow>
</transport>
</deployment>
6、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>
<display-name>Apache-Axis</display-name>
<servlet>
<servlet-name>AxisServlet</servlet-name>
<display-name>Apache-Axis Servlet</display-name>
<servlet-class>
org.apache.axis.transport.http.AxisServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jws</welcome-file>
</welcome-file-list>
</web-app>
7、访问路径 http://localhost:8080/SOAP/services/HelloWord?wsdl
8、使用soapUI 3.6.1 生成客户端JUNIT测试代码.进行单元测试!设置soapui的axis参数
9、生成客户端JUNIT测试代码
10、将生成的代码放到SOAP工程下。修改测试用例。
11、执行测试,查看结果:
Nginx作为一个后起之秀,他的迷人之处已经让很多人都投入了他的怀抱。配置简单,实现原理简单。做一个负载平衡的再好不过了。
其原理:
简单介绍一下他的安装及配置过程
官方网站
http://wiki.codemongers.com/Main
一、依赖的程序
1. gzip module requires zlib library
2. rewrite module requires pcre library
3. ssl support requires openssl library
二、安装
./configure
make
make install
默认安装的路径是/usr/local/nginx
更多的安装配置
./configure --prefix=/usr/local/nginx
--with-openssl=/usr/include (启用ssl)
--with-pcre=/usr/include/pcre/ (启用正规表达式)
--with-http_stub_status_module (安装可以查看nginx状态的程序)
--with-http_memcached_module (启用memcache缓存)
--with-http_rewrite_module (启用支持url重写)
三、启动及重启
启动:nginx
重启:kill -HUP `cat /usr/local/nginx/logs/nginx.pid`
测试配置文件:nginx -t
简单吧,安装,启动都比较方便。
四、配置文件
http://wiki.codemongers.com/NginxFullExample
#运行用户
user nobody nobody;
#启动进程
worker_processes 5;
#全局错误日志及PID文件
error_log logs/error.log notice;
pid logs/nginx.pid;
#工作模式及连接数上限
events {
#工作模式有:select(标准模式),poll(标准模式),kqueue(高效模式,适用FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 and MacOS X),
#epoll(高效模式,本例用的。适用Linux 2.6+,SuSE 8.2,),/dev/poll(高效模式,适用Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+)
use epoll;
worker_connections 1024;
}
#设定http服务器,利用它的反向代理功能提供负载均衡支持
http {
#设定mime类型
include conf/mime.types;
default_type application/octet-stream;
#设定日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
#设定请求缓冲
client_header_buffer_size 10k;
large_client_header_buffers 4 4k;
#开启gzip模块,要求安装gzip 在运行./config时要指定
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
#设定访问日志
access_log logs/access.log main;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
#设定负载均衡的服务器列表
upstream backserver {
#weigth参数表示权值,权值越高被分配到的几率越大
#本例是指在同一台服务器,多台服务器改变ip即可
server 127.0.0.1:8081 weight=5;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
#设定虚拟主机,默认为监听80端口,改成其他端口会出现问题
server {
listen 80;
server_name test.com www.test.com;
charset utf8;
#设定本虚拟主机的访问日志
access_log logs/test.com.log main;
#如果访问 /images/*, /js/*, /css/* 资源,则直接取本地文件,不用转发。但如果文件较多效果不是太好。
location ~ ^/(images|js|css)/ {
root /usr/local/testweb;
expires 30m;
}
#对 "/" 启用负载均衡
location / {
proxy_pass http://backserver;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
#设定查看Nginx状态的地址,在运行./config 要指定,默认是不安装的。
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
#是否要通过用户名和密码访问,测试时可以不加上。conf/htpasswd 文件的内容用 apache 提供的 htpasswd 工具来产生即可
#auth_basic_user_file conf/htpasswd;
}
}
ATI Installer HOWTO for SUSE/Novell users
openSUSE 10.2
If you want or need to use the latest and greatest ATI driver, continue here .
Use YaST -> Software -> Change installation Source -> Add Protocol: http Server Name: : www2.ati.com Directory on Server: suse/10.2to add the ATI http server as additional installation source.Now use YaST -> Software -> Install and Delete Softwareto install the ATI/fglrx driver. Select the following packages: x11-video-fglrxG01 ati-fglrxG01-kmp-<kernel-flavor><kernel-flavor> depends on your installed kernel. Check with"uname -r" for installed default/smp/bigsmp kernel. Use "sax2 -r"for X.Org configuration.SUSE LINUX 10.1 / SLES10 / SLED10
If you want or need to use the latest and greatest ATI driver, continue here .
Update your Kernel via YOU (YaST Online Update). Use YaST -> Software -> Change installation Source -> Add Protocol: http Server Name: : www2.ati.com Directory on Server: suse/sle10to add the ATI http server as additional installation source.Now use YaST -> Software -> Install and Delete Softwareto install the ATI/fglrx driver. Select the following packages: x11-video-fglrx ati-fglrx-kmp-<kernel-flavor><kernel-flavor> depends on your installed kernel. Check with "uname -r" for installed default/smp/bigsmp kernel. Use "sax2 -r"for X.Org configuration.Manual driver installation for SUSE LINUX 10.0, SLES9, NLD9 and earlier
Since ATI driver release 8.16.20 the ATI installer needs to be usedto create SUSE/Novell RPMs. Download the ATI installer from the ATI website. http://www.ati.com --> Drivers & Software --> LinuxIt is possible to create RPMs for the following SUSE/Novell distros.This information has been retrieved by using the installer itself: ati-driver-installer-8.35.5-x86.x86_64.run --listpkg[...]SuSE Packages: SuSE/NLD9-IA32 NLD9 SuSE/SLES9-IA32 SLES9 SuSE/SUSE91-IA32 SUSE 9.1 SuSE/NLD9-AMD64 NLD9 (x86_64) SuSE/SLES9-AMD64 SLES9 (x86_64) SuSE/SUSE91-AMD64 SUSE 9.1 (x86_64) SuSE/SUSE100-IA32 SUSE 10.0 SuSE/SUSE92-IA32 SUSE 9.2 SuSE/SUSE93-IA32 SUSE 9.3 SuSE/SUSE100-AMD64 SUSE 10.0 (x86_64) SuSE/SUSE92-AMD64 SUSE 9.2 (x86_64) SuSE/SUSE93-AMD64 SUSE 9.3 (x86_64) SuSE/SLED10-IA32 SLED10 SuSE/SLES10-IA32 SLES10 SuSE/SUSE101-IA32 SUSE 10.1 SuSE/SLED10-AMD64 SLED10 (x86_64) SuSE/SLES10-AMD64 SLES10 (x86_64) SuSE/SUSE101-AMD64 SUSE 10.1 (x86_64) SuSE/SUSE102-IA32 openSUSE 10.2 SuSE/SUSE102-AMD64 openSUSE 10.2 (x86_64) Example:--------Create a RPM for SUSE 10.0 (i386) by using the installer. ./ati-driver-installer-8.35.5-x86.x86_64.run --buildpkg SuSE/SUSE100-IA32Afterwards install the created RPM by using the rpm command. In thementioned example above this would be: rpm -Uhv fglrx_6_8_0_SUSE100-8.35.5-1.i386.rpmThe postinstall script of this RPM will try to compile the requiredkernel module. If this fails, you'll get a message how to proceed.You still need to configure the driver with SaX2. Details can be foundin /usr/share/doc/packages/fglrx/README.SuSE.Unfortunately you need to recompile the "fglrx" kernel module rightafter any kernel (security) update. Use "fglrx-kernel-build.sh" for this.
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mtnk/archive/2007/03/31/1547912.aspx
摘要: Suse Linux Enterprise Server 11.0
安装、配置与管理手册
Version 1.0
1. 安装准备
l x86计算机,20G以上硬盘,100M以太网卡,2G以上内存;
l 安装介质:SuseLinux DVD 2-1... 阅读全文
String attachmentFile = "XXXXXXXX";
attachmentFile = MimeUtility.decodeText(attachmentFile);
attachmentPart.setFileName(MimeUtility.encodeText(fds.getName()));
使用java mail 包收发中文邮件的编码,解码问题以及解决方法
JSP教程-邮件相关
编码
邮件头(参见RFC822,RFC2047)只能包含US-ASCII字符。邮件头中任何包含非US-ASCII字符的部分必须进行编码,使其只 包含US-ASCII字符。所以使用java mail发送中文邮件必须经过编码,否则别人收到你的邮件只能是乱码一堆。不过使用java mail 包的解决方法很简单,用它自带的MimeUtility工具中encode开头的方法(如encodeText)对中文信息进行编码就可以了。
例子:
MimeMessage mimeMsg = new MimeMessage(mailSession);
//让javamail决定用什么方式来编码 ,编码内容的字符集是系统字符集mimeMsg.setSubject( MimeUtility.encodeText( Subject) );
//使用指定的base64方式编码,并指定编码内容的字符集是gb2312
mimeMsg.setSubject( MimeUtility.encodeText( Subject,”gb2312”,”B”));
通常对邮件头的编码方式有2种,一种是base64方式编码,一种是QP(quoted-printable)方式编码,javamail根据具体情况来选择编码方式。
如“txt测试”编码后内容如下:
=?GBK?Q?Txt=B2=E2=CA=D4
里面有个=?GBK?Q?,GBK表示的是内容的字符集,?Q?表示的是以QP方式编码的,后面紧跟的才是编码后的中文字符。所以用MimeUtility工具编码后的信息里包含了编码方式的信息。
邮件的正文也要进行编码,但它不能用MimeUtility里的方法来编码。邮件正文的编码方式的信息是要放在Content- Transfer-Encoding这个邮件头参数中的,而MimeUtility里面的方法是将编码方式的信息放在编码后的正文内容中。所以如果你对正 文也用MimeUtility进行处理,那么其他邮件程序就不会正常显示你编码的邮件,因为其他邮件软件如outlook,foxmail只会根据 Content-Transfer-Encoding这个里面的信息来对邮件正文进行解码。
其实,邮件正文部分的编码javamail已经自动帮你做了,当你发送邮件的时候,它会自己决定编码方式,并把编码方式的信息放入 Content-Transfer-Encoding这个邮件头参数中,然后再发送。所以你所要做的就是直接把邮件正文的内容放入邮件中就可以了。
对邮件正文的编码方式比较多,包括了base64和QP方式,还有一些如7bit,8bit等等,因为javamail自动为邮件正文编码,所以我就不一一祥叙了。
例子:
//处理邮件正文
MimeBodyPart mbp=new MimeBodyPart();
if ( ContentType() == null || ContentType.equals(""))
mbp.setText( Content );
else
mbp.setContent( Content, Content );
解码
javamail包中的MimeUtility工具中也提供了对邮件信息解码的方法,都是以decode开头的一些方法(如decodeText)
例子:
String Subject = mimemsg.getSubject();
String ChSubject = MimeUtility.decodeText(Subject);
对于base64和QP编码后信息,decode* 方法能将他们正确的解码,但是,如果指定的字符集不对,那么javamail就会出现错误,不能正确地将其解码。
如有的邮件系统将”txt测试”编码后如下:
=?x-unkown?Q?Txt=B2=E2=CA=D4
这里指定的字符集是x-unknown,是非明确的字符集,javamail就不能正确的处理了,但是”测试”这两个中文字还是按照gbk字符集编码的,所以你可以手工的将编码方式信息改正确,再用decode*方法来解码。
例子:
if ( str.indexOf("=?x-unknown?") >=0 ){
str = str.replaceAll("x-unknown","gbk" ); // 将编码方式的信息由x-unkown改为gbk
try{
str = MimeUtility.decodeText( str ); //再重新解码
}catch( Exception e1){
return str ;
}
decode*方法都是根据在编码信息中包含的编码方式的信息来解码,所以decode*方法对邮件正文解码是无效的,因为邮件正文中不包含编码方式的信息。
同编码一样,邮件正文的解码也是由javamail做了。Javamail根据Content-Transfer-Encoding里的信息,来对邮件的正文解码。
客户程序从javamail取得的正文内容字符集为iso-8859-1,所以还要将字符集转换一下,例:
String CorrectContent = new String( Content.getbytes(“iso-8859-1”),”gb2312”);
CorrentContent为正确的邮件正文了
摘要: A概念
最常用的概念
1、 scalars:存储单值
字符串:简单文本由单或双引号括起来。
数字:直接使用数值。
日期:通常从数据模型获得
布尔值:true或false,通常在<#if …>标记中使用
2、 hashes:充当其它对象的容器,每个都关联一个唯一的查询名字
具有一个唯一的查询名字和他包含的每个变量... 阅读全文
借windows7系统的风光。我这几天也开始玩win7,笔记本系统我都重装了5-6次了,考虑到win7还不成熟、我又比较喜欢win7,所以考虑使用装双系统XP+WIN7,花了2个小时将XP、WIN7重新全部安装,打好补丁,升级,将自己常用的软件都安装上
工作原因需要安装ORACLE,考虑双系统中都安装ORACLE,系统切换之间数据的使用也需要一起切换,考虑XP和WIN7都安装ORACLE软件,公用一个数据库文件。经过几个小时的奋战,终于完成预期的目标。
首先是双系统的安装中需要注意的,2个系统的机器名必须一样。否则再同步的时候会出现错误,这种错误也都是能再装完之后解决,所以,机器名不一样也可以,就是后面麻烦下而已。
系统硬盘规划如下:(硬盘320G分区买来就是分的4个区,本人懒惰,也就懒得再去分小了、因安装的是双系统的原因,C盘和D盘再显示上会根据登陆的系统而变化、最后2个分区则不变化,所以将公用数据文件安装再DISK1盘)
首先我在XP系统的系统盘上只安装10.2.0.1.0数据库软件。
然后再单独创建数据库(单独创建的数据库文件位置存放再DISK1中如:oradb)。
建立监听、配置本地NET服务名。
一切完好之后再使用升级补丁,将Oracle升级至10.2.0.3.0,升级时间大约30分钟,根据电脑性能时间会有变化。
然后再切换至WIN7系统中同样的方法安装Oracle,因为WIN7系统的oracle版本使用的是for vista 版本。版本号为10.2.0.3.0,无需升级。
WIN7系统的系统盘上只安装10.2.0.3.0数据库软件。。
然后再单独创建数据库(单独创建的数据库文件位置同样存放再DISK1中如:oradb,覆盖掉再XP系统中ORACLE创建的数据库文件)。
然后回到切换至XP系统,将WIN7系统中ORACLE目录oracle"product"10.2.0"db_1"database下的SPFILEORCL.ORA复制到XP系统中oracle同级
目录下SPFILEORCL.ORA覆盖掉。启动数据库会出现ORA-00201 ,ORA-00202错误,解决方法如下:
进入cmd运行界面。用sysdba账号登陆。然后运行以下命令:
create pfile from spfile;
shutdown immediate
startup mount pfile='d:"oracle"product"10.1.0"Db_2"database"initorcl.ora'
show parameter compatible
shutdown immediate
startup
检查运行,完成后创建表空间等信息、完成后返回WIN7系统,即可同步操作数据。此方法是双击冷备的思想。
在pl/sql里怎样进行半,全角转换?
To_Multi_Byte(str)
To_Single_Byte(str)
转http://www.gzit.org/27/viewspace-3306.html
package com;
import java.util.ArrayList;关注ITz]'p6g5n-KlX
import java.util.List;
public class SimpleTest{关注IT1rq3XJw8K.uk&fK$w
关注IT IQvF'S3U
/**
ZyJ9l2@9@K0 *关注IT)~d3X(v*^ \jn3M
* @return 所有公司
t8~)^.L.kq9Y0 */关注IT_ s9A?i:^Z
public List<Company> getAllCompany(){
`Gq(c rzCG0 List<Company> list = new ArrayList<Company>();关注ITyc?n#P3H
Company company = null;关注ITm n"o@a%vF#p8O
company = new Company(1,"广西博联信息通信技术有限责任公司");关注IT7p9wloKHs
list.add(company);
\t%? EgoZ/Jl3FI6r0 company = new Company(2,"能创信息科技有限责任公司");关注IT:kA E+Kh#UI
list.add(company);
@"E}.U0t,V1I0 return list;关注IT9l#W*{"s&m
}
!l0{"PF/z&y R9a.o/y0
Ue3t N0^q%v.E0 /**
)^ D*FpTn+a5I!e0 *关注IT[1r^3g"Q,Ih
* @param companyId 公司编号
-aWE)@QP&?}0 * @return 公司下所有部门
@4M,|PVgn!H L0 */关注IT0ZGrm:b'?
public List<Department> getDepartment(int companyId){
W(o&TK Is0hC0 List<Department> list = new ArrayList<Department>();关注IT4V0v(t)v1J.TM,m.y
Department department = null;
Wvc(d"g4D eV2A0 if(companyId==1){关注IT]$Z$X*W*mv8`%qQ
department = new Department(1,1,"软件事业部");关注IT]!A F)AV\$I5J
list.add(department);关注ITIYRRcSj
department = new Department(2,1,"工程部");关注ITU rCpeq8M
list.add(department);
5O#{ `8v8Ta)}B$L0 }else{关注IT ug,L?5[:y@k C:]
department = new Department(1,2,"企管部");关注ITk/BY3iM/X,`%e
list.add(department);关注IT&I7Z9{5`kV/l Avj |5L
department = new Department(2,2,"财务部");
b'jm;yVa'Ww;Ea0 list.add(department);
z W Pp$yx3M0 }关注ITG gA3V5t0^ xM
return list;
4O v#k$x:P3n0 }关注IT$tV5JN8sF u:FJ
y'b-^Bma0 /**关注IT/A(^g]jU P*u-\,H
*关注IT:m'| NmVWtX/Y
* @param departmentId 部门编号关注IT} l)^8GbA
* @return 部门下所有员工关注IT.^VB |7V;b D'J'eH+n
*/
2gkge \x/ip-c4tW0 public List<Person> getPerson(int departmentId){关注ITFR*B5bnj_2[&Q
List<Person> list = new ArrayList<Person>();
A@T5y8M]:H5h/c0 Person person = null;关注ITK Z-M ~MF
if(departmentId==1){关注IT\t.T\3Mx
person = new Person(1,1,"张三");关注ITe)_3a4xcw
list.add(person);
wkw2P)G u7G(Z0 person = new Person(2,1,"李四");
{ uhJ;y9V&C` H0 list.add(person);
%q(xK1? VR0 }else{
s|] l)J:@o,p@y0 person = new Person(1,2,"王五");关注ITi'j*FST I
list.add(person);关注IT^@j { x US i
person = new Person(2,2,"赵六");关注IT ux#kse o;W
list.add(person);
4B/cP*v5z [P0 }关注IT g Bc!D)p*jB)X
return list;关注IT'X:[] lH
}
}
d z-]6Gn/T9f1OR0
|
package com;
public class Company {
private int id;关注IT|:NQQ,|8W,D!QV
private String companyName;
$ffG s&X1|I0 关注ITy*eK ~4xog
public Company(int id,String companyName){
.q;k2a&}j*LL0 this.id = id;
'\ u:Jpv)j0 this.companyName = companyName;关注ITV[,Ty8Fu
}
public int getId() {关注IT:F| |n-n!w$sX5PL
return id;
NPPJ,?0 }
public void setId(int id) {关注ITh2emjTe il+[D
this.id = id;
W@b ` L4i0 }
public String getCompanyName() {关注IT$wP8oO%} ?xe4k
return companyName;
S0Kz%GX$?auN W0 }
public void setCompanyName(String companyName) {
zMv*g ic8S&YqcN0 this.companyName = companyName;
v\'x-pT0 }
}
*mHu$CU~wb9x x0
|
package com;
public class Department {
private int id;关注IT [n0zYU
private int companyId;关注IT$S __L'FDvy2WD
private String departmentName;
public Department(int id, int companyId, String departmentName) {
,ni)o5G$yL'[o(}Q0 this.id = id;
q3Gzw"E6v8?o.MT0 this.companyId = companyId;关注IT+r"mo:pO$L![4U
this.departmentName = departmentName;
/q\6Aj5]0m3G#l-P9a0 }
public int getId() {
w"j`I` J0 return id;
x(P!d6tu v a"T0 }
public void setId(int id) {关注ITlQ1r8wS5_'hb
this.id = id;关注IT pGy3Jl{0tkW
}
public int getCompanyId() {
@!PpRi0 return companyId;关注ITs c!i"DQ5_D
}
public void setCompanyId(int companyId) {关注ITrp` i5D/_L
this.companyId = companyId;关注ITYT+Y6CkJ t2x
}
public String getDepartmentName() {
fSa p.@9e&L0 return departmentName;关注IT!Pe L6m D7n wM
}
public void setDepartmentName(String departmentName) {关注IT/bD(o/RPq
this.departmentName = departmentName;
'|S4q p4]0 }
}关注IT){0[0DsY:te9V A r$T
|
package com;
public class Person {
private int id;
U{*D:dw+i6W0 private int departmentId;
q6a e ?5u5\ b|0?]KI0 private String userName;
public Person(int id,int departmentId, String userName) {关注IT#c%qN s2Xup kIc
this.id = id;关注ITs%z&uZ2T Bbj
this.departmentId = departmentId;
|5nI&y.LO y)Cx(C.r b"x0 this.userName = userName;关注IT_,ep*n(H
}
public int getDepartmentId() {关注IT&ue1rG X%WJN[
return departmentId;
"qn%DVY2mGh0 }
public void setDepartmentId(int departmentId) {关注ITa? d(_7s
this.departmentId = departmentId;关注IT+`vt Pb4oS
}
public String getUserName() {
]etq"Seza0 return userName;
3fZn} j-z(V+ir,a0 }
public void setUserName(String userName) {
9pWKaR|0 this.userName = userName;
~FT_7a/l6lD$}V0 }
public int getId() {
*i:k5KIZyr'o0 return id;
g+j[M(o`0 }
public void setId(int id) {
vBj&P/` DUqB0 this.id = id;
:x:d5MOwo0 }
}
-KIsR)D9j7a+VDr rE3Ve0
|
<?xml version="1.0" encoding="UTF-8"?>关注ITWF0A~V
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "dwr10.dtd" >关注IT GszT,f+Fc:RT
<dwr>
P/QC qq)cf0 <allow>关注IT.M%D9A4u{A&^`
<!-- 声明哪个类可以提供JS直接调用 -->
Nf9r/PN%N-Du)D0 <create javascript="SimpleTest" creator="new">关注IT'T G m*[5A\#|1~;`%Y
<param name="class" value="com.SimpleTest"></param>
\u)NR5z5QSP7t&@0 <!-- 该类里公开出来给JS调用的方法 -->
sh+c`K#sL'T#l0 <include method="getAllCompany" />关注IT$|i'^(lf$`y[2x I
<include method="getDepartment" />
cP(^2LF5c:K$s*ce0 <include method="getPerson" />
_/J0?wiqL%w0 </create>
/zms8Vonw0 <!-- 类型转换 -->关注IT N*a#}ip*^H
<convert match="com.Person" converter="bean">
.pV*p:QtOB0 <param name="include" value="id,departmentId,userName"></param>
5v8V6|3`U-WPya)nS0 </convert>
vu| ow4J b ^)@0 <convert match="com.Department" converter="bean">关注IT.g SgkS'u S]`
<param name="include" value="id,companyId,departmentName"></param>关注ITX~_L nT
</convert>
p3G!a/V;|y0 <convert match="com.Company" converter="bean">关注IT W6L q.dtp%Qv\
<param name="include" value="id,companyName"></param>
z+sas-D)C"PS,|0 </convert>关注ITD/g|U2c:Y
</allow>关注IT"['f&XZ`~
</dwr>关注IT,FruT'[ m%A1M
|
<%@ page language="java" pageEncoding="GB18030"%>关注IT*B&kW!{i
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
lgX^J G0<html>关注ITi'l*l#zG(q
<head>
uLA#O!~1s:c@0 <title>My JSP 'simpleTest.jsp' starting page</title>
eI-k1b-TDW w0 关注IT7g h.ICd(r
<meta. http-equiv="pragma" content="no-cache">关注ITQ _-x5Mm
<meta. http-equiv="cache-control" content="no-cache">关注ITe}yN |"S
<meta. http-equiv="expires" content="0"> 关注ITax(bO%Odh
<meta. http-equiv="keywords" content="keyword1,keyword2,keyword3">
t%X$Wjx&VH.`0 <meta. http-equiv="description" content="This is my page">
/[Y7V5~PEWQ p0
5b Z{3V!q O V5x1u!e0 </head>
)gD&OE\0 <script. type="text/javascript" src="dwr/engine.js"></script>关注IT1r"V3R{cP/~3Jc7Q
<script. type="text/javascript" src="dwr/util.js"></script>关注IT#bM"@K,O@ X
<script. type="text/javascript" src="dwr/interface/SimpleTest.js"></script>关注ITi(V6w \6~!l/a A#s [
6_*@k$wN0 <body nload="initial()">关注IT!nt9lT`1e/M%h
<script. type="text/javascript">
y]#zLJE0 /*页面初始加载公司栏目*/关注IT?%]%wR7ICTg0_
function initial(){
'h&BHt iEU0 SimpleTest.getAllCompany(function(data){dealSelect("i",data)});关注ITjty,Fwrb
}关注IT&I!\_N d4xYHd
/*获取下拉菜单的值并填充下一栏目*/
w)UR!qK$ma0 function show(flag){关注IT(y4Ff L4U5i
if(flag=="c"){关注ITI$o+U{]r+k[Y
var companyId = $("company").value;
_$|"Q7s)K-m"[/z*[)n0 SimpleTest.getDepartment(companyId,function(data){dealSelect(flag,data)});
cAj9K(u/g] E)I v6Iw0 }else if(flag=="d"){
J$L&o2}pD6kw0 var departmentId = $("department").value;
u}u'`\6~d*^0 SimpleTest.getPerson(departmentId,function(data){dealSelect(flag,data)});
0@Vy ~cZF |0 }
'X#Wc ?'| nW0 }关注ITk @#n[[&L&_OP5]4_o
/*填充select的内容*/
NgcV,[0X0 function dealSelect(flag,data){
G YKF-I6HRfu)d0 clearSelect(flag);
1tC0BTVC?r3F0 if(flag=="c"){
*Td\#}%kT(|0 DWRUtil.addOptions("department",data,"id","departmentName");
9N#R2Pt4B0 }else if(flag=="d"){
Oj"@2V$l,{6L:K0 DWRUtil.addOptions("person",data,"id","userName");关注IT(I'Syg7[g[ l+R5r"l
}else if(flag=="i"){
d'X'Fj5JJQ!Z8~0 DWRUtil.addOptions("company",data,"id","companyName");关注IT R W8[| x9a1QFq
}
~m+hRysQ P T,c)?a0@0 }关注IT!e6B&wgK6a6W4f
/*清除下拉表单的内容*/
6n`%~ j,_RU0 function clearSelect(flag){关注ITC1z#B-a6g3f/u*_
if(flag=="c"){
I5c'e3n(|b0 var tmp = $("department");
)P$oa7G0AQ/o$cb0 while(tmp.childNodes.length>1){关注ITP(vJsB?XE"@
tmp.removeChild(tmp.lastChild);
ew)j^q0 }
0H+J,D R8i0 }else if(flag="d"){关注ITl UJS P)e _-W
var tmp = $("person");关注ITb-j-[&d&S }`[
while(tmp.childNodes.length>1){
h8iOK4e0 tmp.removeChild(tmp.lastChild);
qTBv)hZ#v:X{+n0 }关注ITJZ,P0_C
}关注IT`Tt5D({7P
}
y1ipi*J0 /*清空select里的内容*/
})uTT-t"Y0 </script>关注ITc ^2Wf ]p%g
公司:<select id='company' nchange="show('c')"><option value="">======</option></select>关注ITLAD"Ei f8zo2uO
部门:<select id='department' nchange="show('d')"><option value="">======</option></select>
z/VjF&{({0 成员:<select id='person'><option value="">======</option></select>
j!IJ$dQ0 </body>
;R$n'W7L){ n*^P IE.tr0</html>关注ITT[$[*l;x9I] N
|
12:52:31,162 INFO Logger:51 - Logging using commons-logging.
12:52:31,287 INFO DWRServlet:51 - retrieved system configuration file: weblogic.utils.zip.SafeZipFileInputStream@2453319
12:52:31,334 INFO DefaultConfiguration:51 - Creator 'jsf' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: javax/faces/el/ValueBinding (jsf-api.jar)
12:52:31,349 INFO DefaultConfiguration:51 - Creator 'pageflow' not loaded due to ClassNotFoundException. This is only an problem if you wanted to use it. Cause: Beehive/Weblogic Creator not available. (可以不用理会)
12:52:31,349 INFO DefaultConfiguration:51 - Creator 'script' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: org/apache/bsf/BSFException (bsf-2.3.0.jar)
12:52:31,412 INFO DefaultConfiguration:51 - Converter 'jdom' not loaded due to NoClassDefFoundError. This is only an problem if you wanted to use it. Cause: org/jdom/Document (jdom-1.0.jar)
12:52:31,443 INFO DefaultConfiguration:51 - Converter 'hibernate' not loaded due to ClassNotFoundException. This is only an problem if you wanted to use it. Cause: Failed to find either org.hibernate.Hibernate or net.sf.hibernate.Hibernate (hibernate-3.0.1.jar ).
12:52:31,459 INFO DefaultConverterManager:51 - Type 'org.jdom.Document' is not convertable due to missing converter 'jdom'. This is only an problem if you wanted to use it.
12:52:31,459 INFO DefaultConverterManager:51 - Type 'org.jdom.Element' is not convertable due to missing converter 'jdom'. This is only an problem if you wanted to use it.
添加相应的包,
http://www.findjar.com/jar/jdom/jars/jdom-1.0.jar.html
http://www.java2s.com/Code/Jar/Spring-Related/Downloadjsfapijar.htm
查找相应的CLASS,下载包
13:20:43,131 WARN DefaultConverterManager:59 - Missing type info for save_yhsj(0<0>). Assuming this is a map with String keys. Please add to <signatures> in dwr.xml
13:20:43,131 WARN DefaultConverterManager:59 - Missing type info for save_yhsj(0<1>). Assuming this is a map with String keys. Please add to <signatures> in dwr.xml
13:20:43,146 INFO ExecuteQuery:51 - Exec[0]: FyglImpl.save_yhsj()
在页面中:
function saveSjjl(){
var param=new Object();
param["S_nbxh"]=document.form1.S_nbxh.value;
param["S_yhmc"]=document.form2.S_yhmc.value;
param["D_cbsj"]=document.form2.D_cbsj.value;
param["S_rqsj"]=document.form2.S_rqsj.value;
param["S_cbry"]=document.form2.S_cbry.value;
FyglImpl.save_yhsj(param,{
callback:function(str) {
$('saveSjjl').disabled = true;
alert("保存成功!");
},
timeout:5000,
errorHandler:function(message) { alert("Oops: " + message); }
});
}
CLASS中:
public void save_yhsj(Map param) {}
解决方法:
<signatures>
<![CDATA[
import java.util.Map;
import com.fygl.implement.FyglImpl;
FyglImpl.save_yhsj(Map<String,String> param);
]]>
</signatures>
replace(replace(str,chr(13),''),chr(10),'')
update hz_qyfddbr h set jl=(select replace(replace(jl,chr(13),''),chr(10),'') from hz_qyfddbr r where r.nbxh=h.nbxh )
今天需要使用个本地化的问题,努力看了点资料,终于解决
COPE点资料来保存
用户定义指令-使用@符合来调用
有两种不同的类型:Macro(宏)和transform(传递器),Macro是在模板中使用macro指令定义,而transform是在模板外由程序定义(基本上都是基于Java的),这里通过Macro来介绍自定义指令。
例一:
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
使用:<@greet></@greet> 或 <@greet/>
结果:<font size="+2">Hello Joe!</font>
参数-在macro指令中可以在宏变量之后定义参数
例二:
<#macro greet person>
<font size="+2">Hello ${person}!</font>
</#macro>
使用:<@greet person="Fred"/> and <@greet person="Batman"/>
结果: <font size="+2">Hello Fred!</font> and <font size="+2">Hello Batman!</font>
macro可以有多个参数,参数的次序是无关的,在macro指令中只能使用定义的参数,并且必须对所有参数赋值,可以在定义参数时指定缺省值:
<#macro greet person color="black">
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
在自定义指令嵌套内容:模板片断中使用<#nested>指令
<#macro border>
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</tr></td></table>
</#macro>
使用:<@border>The bordered text</@border>
结果:
<table border=4 cellspacing=0 cellpadding=4>
<tr><td>The bordered text
</tr></td></table>
<#nested>指令可以被多次调用:
<#macro do_thrice>
<#nested>
<#nested>
<#nested>
</#macro>
使用:
<@do_thrice>Anything.</@do_thrice>
结果:
Anything.
Anything.
Anything.
注意:嵌套内容是无法访问到macro中的局部变量的。
例如:
<#macro repeat count>
<#local y = "test">
<#list 1..count as x>
${y} ${count}/${x}: <#nested>
</#list>
</#macro>
<@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat>
结果:
test 3/1: ? ? ?
test 3/2: ? ? ?
test 3/3: ? ? ?
下面是一个嵌套使用自定义指令的例子:
<@border>
<ul>
<@do_thrice>
<li><@greet person="Joe"/>
</@do_thrice>
</ul>
</@border>
结果:
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<ul>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
</ul>
</tr></td></table>
在macro中使用循环变量-作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字:
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
/@repeat
结果:
1. 0.5
2. 1
3. 1.5
4. 2 Last!
注意:循环变量和用户定义指令开始标记指定的数目可以不同,调用时少指定循环变量,则多指定的值不可见,调用时多指定循环变量,多余的循环变量不会被创建。
模板中的变量,有三种类型:
1.) plain(全局)变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换
2.) 局部变量:在macro中有效,使用local指令创建和替换
3.) 循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建;宏的参数是局部变量,而不是循环变量
用assign指令创建和替换的例子:
<#assign x = 1> <#-- create variable x -->
${x}
<#assign x = x + 3> <#-- replace variable x -->
${x}
结果:
1
4
局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子:
<#assign x = "plain">
1. ${x} <#-- we see the plain var. here -->
<@test/>
6. ${x} <#-- the value of plain var. was not changed -->
<#list ["loop"] as x>
7. ${x} <#-- now the loop var. hides the plain var. -->
<#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
8. ${x} <#-- it still hides the plain var. -->
</#list>
9. ${x} <#-- the new value of plain var. -->
<#macro test>
2. ${x} <#-- we still see the plain var. here -->
<#local x = "local">
3. ${x} <#-- now the local var. hides it -->
<#list ["loop"] as x>
4. ${x} <#-- now the loop var. hides the local var. -->
</#list>
5. ${x} <#-- now we see the local var. again -->
</#macro>
结果:
1. plain
2. plain
3. local
4. loop
5. local
6. plain
7. loop
8. loop
9. plain2
内部循环变量隐藏同名的外部循环变量,例如:
<#list ["loop 1"] as x>
${x}
<#list ["loop 2"] as x>
${x}
<#list ["loop 3"] as x>
${x}
</#list>
${x}
</#list>
${x}
</#list>
结果:
loop 1
loop 2
loop 3
loop 2
loop 1
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe:
<#assign user = "Joe Hider">
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->
命名(namespaces)空间-通常情况,只使用一个命名空间,称为主命名空间(main namespace),但你是不会意识到这些的;为了创建可重用的macro、transforms或其它变量的集合(通常称库),必须使用多命名空间,为了防止同名冲突。
首先创建一个库(假设保存在lib/my_test.ftl中):
<#macro copyright date>
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "jsmith@acme.com">
使用import指令导入库到模板中,Freemarker会为导入的库创建新的命名空间,并可以通过import指令中指定的hash(散列)变量访问库中的变量:
<#import "/lib/my_test.ftl" as my>
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
结果:
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
<br>Email: jsmith@acme.com</p>
jsmith@acme.com
fred@acme.com
上面的例子中使用的两个同名变量并没有冲突,因为它们位于不同的命名空间
可以使用assign指令在导入的命名空间中创建或替代变量:
<#import "/lib/my_test.ftl" as my>
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}
结果:
jsmith@acme.com
jsmith@other.com
数据模型中的变量任何地方都可见,也包括不同的命名空间,下面修改了刚才创建的库:
<#macro copyright date>
<p>Copyright (C) ${date} ${user}. All rights reserved.</p>
</#macro>
<#assign mail = "${user}@acme.com">
假设数据模型中的user变量的值是Fred:
<#import "/lib/my_test.ftl" as my>
<@my.copyright date="1999-2002"/>
${my.mail}
结果:
<p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
Fred@acme.com
最后用macro指令解决问题,
<#macro zch code text="dd">
<#include "/view/xtgl/xtsjwh/zchsz${ThemeHelpersMap[code]?default(text)}.js">
</#macro>
<@zch code="jc"/>
10:05:05,937 INFO QyFunctionImpl:16 - Update xhgl set xh=69 where table_name='sl_yhzcnr'
10:05:05,984 INFO XmlBeanDefinitionReader:158 - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
10:05:06,000 INFO SQLErrorCodesFactory:120 - SQLErrorCodes loaded: [DB2, HSQL, MS-SQL, MySQL, Oracle, Informix, PostgreSQL, Sybase]
10:05:06,046 ERROR DispatcherServlet:412 - Could not complete request
org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ Update xhgl set xh=69 where table_name='sl_yhzcnr' ]; SQL state [S1009]; error code [0]; Connection is read-only. Queries leading to data modification are not allowed.; nested exception is java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
at com.mysql.jdbc.SQLError.createSQLException(Ljava.lang.String;Ljava.lang.String;)Ljava.sql.SQLException;(SQLError.java:910)
at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;Z)I(Statement.java:1265)
at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:1235)
at weblogic.jdbc.wrapper.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:360)
at org.springframework.jdbc.core.JdbcTemplate$1UpdateStatementCallback.doInStatement(Ljava.sql.Statement;)Ljava.lang.Object;(JdbcTemplate.java:381)
at org.springframework.jdbc.core.JdbcTemplate.execute(Lorg.springframework.jdbc.core.StatementCallback;)Ljava.lang.Object;(JdbcTemplate.java:254)
at org.springframework.jdbc.core.JdbcTemplate.update(Ljava.lang.String;)I(JdbcTemplate.java:391)
at com.yhgl.implement.QyFunctionImpl.getXh(Ljava.lang.String;)Ljava.lang.String;(QyFunctionImpl.java:17)
at com.yhgl.implement.QyFunctionImpl$$FastClassByCGLIB$$86b27578.invoke(ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(<generated>:0)
at net.sf.cglib.proxy.MethodProxy.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()Ljava.lang.Object;(Cglib2AopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:122)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Lorg.aopalliance.intercept.MethodInvocation;)Ljava.lang.Object;(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;Lnet.sf.cglib.proxy.MethodProxy;)Ljava.lang.Object;(Cglib2AopProxy.java:643)
at com.yhgl.implement.QyFunctionImpl$$EnhancerByCGLIB$$abfcb417.getXh(Ljava.lang.String;)Ljava.lang.String;(<generated>:0)
at com.contorller.Yhdjcontroller.save_nr(Ljavax.servlet.http.HttpServletRequest;Lorg.springframework.web.servlet.ModelAndView;)Ljava.lang.String;(Yhdjcontroller.java:79)
at com.contorller.Yhdjcontroller.save(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(Yhdjcontroller.java:51)
at jrockit.reflect.NativeMethodInvoker.invoke0(Ljava.lang.Object;ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at jrockit.reflect.NativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(Ljava.lang.String;Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:403)
at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:358)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(AbstractController.java:139)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;Ljava.lang.Object;)Lorg.springframework.web.servlet.ModelAndView;(SimpleControllerHandlerAdapter.java:44)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:684)
at org.springframework.web.servlet.DispatcherServlet.doService(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:625)
at org.springframework.web.servlet.FrameworkServlet.processRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:392)
at org.springframework.web.servlet.FrameworkServlet.doPost(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:357)
at javax.servlet.http.HttpServlet.service(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(HttpServlet.java:853)
<2008-8-21 上午10时05分06秒 CST> <Error> <HTTP> <BEA-101020> <[ServletContext(id=36466092,name=SpringMVC,context-path=/SpringMVC)] Servlet failed with Exception
org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ Update xhgl set xh=69 where table_name='sl_yhzcnr' ]; SQL state [S1009]; error code [0]; Connection is read-only. Queries leading to data modification are not allowed.; nested exception is java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed.
at com.mysql.jdbc.SQLError.createSQLException(Ljava.lang.String;Ljava.lang.String;)Ljava.sql.SQLException;(SQLError.java:910)
at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;Z)I(Statement.java:1265)
at com.mysql.jdbc.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:1235)
at weblogic.jdbc.wrapper.Statement.executeUpdate(Ljava.lang.String;)I(Statement.java:360)
at org.springframework.jdbc.core.JdbcTemplate$1UpdateStatementCallback.doInStatement(Ljava.sql.Statement;)Ljava.lang.Object;(JdbcTemplate.java:381)
at org.springframework.jdbc.core.JdbcTemplate.execute(Lorg.springframework.jdbc.core.StatementCallback;)Ljava.lang.Object;(JdbcTemplate.java:254)
at org.springframework.jdbc.core.JdbcTemplate.update(Ljava.lang.String;)I(JdbcTemplate.java:391)
at com.yhgl.implement.QyFunctionImpl.getXh(Ljava.lang.String;)Ljava.lang.String;(QyFunctionImpl.java:17)
at com.yhgl.implement.QyFunctionImpl$$FastClassByCGLIB$$86b27578.invoke(ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(<generated>:0)
at net.sf.cglib.proxy.MethodProxy.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(MethodProxy.java:149)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint()Ljava.lang.Object;(Cglib2AopProxy.java:698)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:122)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Lorg.aopalliance.intercept.MethodInvocation;)Ljava.lang.Object;(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()Ljava.lang.Object;(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Ljava.lang.Object;Ljava.lang.reflect.Method;[Ljava.lang.Object;Lnet.sf.cglib.proxy.MethodProxy;)Ljava.lang.Object;(Cglib2AopProxy.java:643)
at com.yhgl.implement.QyFunctionImpl$$EnhancerByCGLIB$$abfcb417.getXh(Ljava.lang.String;)Ljava.lang.String;(<generated>:0)
at com.contorller.Yhdjcontroller.save_nr(Ljavax.servlet.http.HttpServletRequest;Lorg.springframework.web.servlet.ModelAndView;)Ljava.lang.String;(Yhdjcontroller.java:79)
at com.contorller.Yhdjcontroller.save(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(Yhdjcontroller.java:51)
at jrockit.reflect.NativeMethodInvoker.invoke0(Ljava.lang.Object;ILjava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at jrockit.reflect.NativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at jrockit.reflect.VirtualNativeMethodInvoker.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;(Unknown Source)
at java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;I)Ljava.lang.Object;(Unknown Source)
at org.springframework.web.servlet.mvc.multiaction.MultiActionController.invokeNamedMethod(Ljava.lang.String;Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:403)
at org.springframework.web.servlet.mvc.multiaction.MultiActionController.handleRequestInternal(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(MultiActionController.java:358)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)Lorg.springframework.web.servlet.ModelAndView;(AbstractController.java:139)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;Ljava.lang.Object;)Lorg.springframework.web.servlet.ModelAndView;(SimpleControllerHandlerAdapter.java:44)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:684)
at org.springframework.web.servlet.DispatcherServlet.doService(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(DispatcherServlet.java:625)
at org.springframework.web.servlet.FrameworkServlet.processRequest(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:392)
at org.springframework.web.servlet.FrameworkServlet.doPost(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(FrameworkServlet.java:357)
at javax.servlet.http.HttpServlet.service(Ljavax.servlet.http.HttpServletRequest;Ljavax.servlet.http.HttpServletResponse;)V(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(Ljavax.servlet.ServletRequest;Ljavax.servlet.ServletResponse;)V(HttpServlet.java:853)
>
<bean id="baseTxService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="proxyTargetClass" value="true" />
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间类型。
这里是一个使用日期函数的例子。下面的查询选择了所有记录,其date_col的值是在最后30天以内:
mysql> SELECT something FROM table
WHERE TO_DAYS(NOW()) - TO_DAYS(date_col) select DAYOFWEEK('1998-02-03');
-> 3
WEEKDAY(date)
返回date的星期索引(0=星期一,1=星期二, ……6= 星期天)。
mysql> select WEEKDAY('1997-10-04 22:23:00');
-> 5
mysql> select WEEKDAY('1997-11-05');
-> 2
DAYOFMONTH(date)
返回date的月份中日期,在1到31范围内。
mysql> select DAYOFMONTH('1998-02-03');
-> 3
DAYOFYEAR(date)
返回date在一年中的日数, 在1到366范围内。
mysql> select DAYOFYEAR('1998-02-03');
-> 34
MONTH(date)
返回date的月份,范围1到12。
mysql> select MONTH('1998-02-03');
-> 2
DAYNAME(date)
返回date的星期名字。
mysql> select DAYNAME("1998-02-05");
-> 'Thursday'
MONTHNAME(date)
返回date的月份名字。
mysql> select MONTHNAME("1998-02-05");
-> 'February'
QUARTER(date)
返回date一年中的季度,范围1到4。
mysql> select QUARTER('98-04-01');
-> 2
WEEK(date)
WEEK(date,first)
对于星期天是一周的第一天的地方,有一个单个参数,返回date的周数,范围在0到52。2个参数形式WEEK()允许
你指定星期是否开始于星期天或星期一。如果第二个参数是0,星期从星期天开始,如果第二个参数是1,
从星期一开始。
mysql> select WEEK('1998-02-20');
-> 7
mysql> select WEEK('1998-02-20',0);
-> 7
mysql> select WEEK('1998-02-20',1);
-> 8
YEAR(date)
返回date的年份,范围在1000到9999。
mysql> select YEAR('98-02-03');
-> 1998
HOUR(time)
返回time的小时,范围是0到23。
mysql> select HOUR('10:05:03');
-> 10
MINUTE(time)
返回time的分钟,范围是0到59。
mysql> select MINUTE('98-02-03 10:05:03');
-> 5
SECOND(time)
回来time的秒数,范围是0到59。
mysql> select SECOND('10:05:03');
-> 3
PERIOD_ADD(P,N)
增加N个月到阶段P(以格式YYMM或YYYYMM)。以格式YYYYMM返回值。注意阶段参数P不是日期值。
mysql> select PERIOD_ADD(9801,2);
-> 199803
PERIOD_DIFF(P1,P2)
返回在时期P1和P2之间月数,P1和P2应该以格式YYMM或YYYYMM。注意,时期参数P1和P2不是日期值。
mysql> select PERIOD_DIFF(9802,199703);
-> 11
DATE_ADD(date,INTERVAL expr type)
DATE_SUB(date,INTERVAL expr type)
ADDDATE(date,INTERVAL expr type)
SUBDATE(date,INTERVAL expr type)
这些功能执行日期运算。对于MySQL 3.22,他们是新的。ADDDATE()和SUBDATE()是DATE_ADD()和DATE_SUB()的同义词。
在MySQL 3.23中,你可以使用+和-而不是DATE_ADD()和DATE_SUB()。(见例子)date是一个指定开始日期的
DATETIME或DATE值,expr是指定加到开始日期或从开始日期减去的间隔值一个表达式,expr是一个字符串;它可以以
一个“-”开始表示负间隔。type是一个关键词,指明表达式应该如何被解释。EXTRACT(type FROM date)函数从日期
中返回“type”间隔。下表显示了type和expr参数怎样被关联: type值 含义 期望的expr格式
SECOND 秒 SECONDS
MINUTE 分钟 MINUTES
HOUR 时间 HOURS
DAY 天 DAYS
MONTH 月 MONTHS
YEAR 年 YEARS
MINUTE_SECOND 分钟和秒 "MINUTES:SECONDS"
HOUR_MINUTE 小时和分钟 "HOURS:MINUTES"
DAY_HOUR 天和小时 "DAYS HOURS"
YEAR_MONTH 年和月 "YEARS-MONTHS"
HOUR_SECOND 小时, 分钟, "HOURS:MINUTES:SECONDS"
DAY_MINUTE 天, 小时, 分钟 "DAYS HOURS:MINUTES"
DAY_SECOND 天, 小时, 分钟, 秒 "DAYS HOURS:MINUTES:SECONDS"
MySQL在expr格式中允许任何标点分隔符。表示显示的是建议的分隔符。如果date参数是一个DATE值并且你的计算仅仅
包含YEAR、MONTH和DAY部分(即,没有时间部分),结果是一个DATE值。否则结果是一个DATETIME值。
mysql> SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
-> 1998-01-01 00:00:00
mysql> SELECT INTERVAL 1 DAY + "1997-12-31";
-> 1998-01-01
mysql> SELECT "1998-01-01" - INTERVAL 1 SECOND;
-> 1997-12-31 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
INTERVAL 1 SECOND);
-> 1998-01-01 00:00:00
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
INTERVAL 1 DAY);
-> 1998-01-01 23:59:59
mysql> SELECT DATE_ADD("1997-12-31 23:59:59",
INTERVAL "1:1" MINUTE_SECOND);
-> 1998-01-01 00:01:00
mysql> SELECT DATE_SUB("1998-01-01 00:00:00",
INTERVAL "1 1:1:1" DAY_SECOND);
-> 1997-12-30 22:58:59
mysql> SELECT DATE_ADD("1998-01-01 00:00:00",
INTERVAL "-1 10" DAY_HOUR);
-> 1997-12-30 14:00:00
mysql> SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
-> 1997-12-02
mysql> SELECT EXTRACT(YEAR FROM "1999-07-02");
-> 1999
mysql> SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");
-> 199907
mysql> SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");
-> 20102
如果你指定太短的间隔值(不包括type关键词期望的间隔部分),MySQL假设你省掉了间隔值的最左面部分。例如,
如果你指定一个type是DAY_SECOND,值expr被希望有天、小时、分钟和秒部分。如果你象"1:10"这样指定值,
MySQL假设日子和小时部分是丢失的并且值代表分钟和秒。换句话说,"1:10" DAY_SECOND以它等价于"1:10" MINUTE_SECOND
的方式解释,这对那MySQL解释TIME值表示经过的时间而非作为一天的时间的方式有二义性。如果你使用确实不正确的日期,
结果是NULL。如果你增加MONTH、YEAR_MONTH或YEAR并且结果日期大于新月份的最大值天数,日子在新月用最大的天调整。
mysql> select DATE_ADD('1998-01-30', Interval 1 month);
-> 1998-02-28
注意,从前面的例子中词INTERVAL和type关键词不是区分大小写的。
TO_DAYS(date)
给出一个日期date,返回一个天数(从0年的天数)。
mysql> select TO_DAYS(950501);
-> 728779
mysql> select TO_DAYS('1997-10-07');
-> 729669
TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。
FROM_DAYS(N)
给出一个天数N,返回一个DATE值。
mysql> select FROM_DAYS(729669);
-> '1997-10-07'
TO_DAYS()不打算用于使用格列高里历(1582)出现前的值。
DATE_FORMAT(date,format)
根据format字符串格式化date值。下列修饰符可以被用在format字符串中: %M 月名字(January……December)
%W 星期名字(Sunday……Saturday)
%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
%Y 年, 数字, 4 位
%y 年, 数字, 2 位
%a 缩写的星期名字(Sun……Sat)
%d 月份中的天数, 数字(00……31)
%e 月份中的天数, 数字(0……31)
%m 月, 数字(01……12)
%c 月, 数字(1……12)
%b 缩写的月份名字(Jan……Dec)
%j 一年中的天数(001……366)
%H 小时(00……23)
%k 小时(0……23)
%h 小时(01……12)
%I 小时(01……12)
%l 小时(1……12)
%i 分钟, 数字(00……59)
%r 时间,12 小时(hh:mm:ss [AP]M)
%T 时间,24 小时(hh:mm:ss)
%S 秒(00……59)
%s 秒(00……59)
%p AM或PM
%w 一个星期中的天数(0=Sunday ……6=Saturday )
%U 星期(0……52), 这里星期天是星期的第一天
%u 星期(0……52), 这里星期一是星期的第一天
%% 一个文字“%”。
所有的其他字符不做解释被复制到结果中。
mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
-> 'Saturday October 1997'
mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
'%D %y %a %d %m %b %j');
-> '4th 97 Sat 04 10 Oct 277'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
'%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
MySQL3.23中,在格式修饰符字符前需要%。在MySQL更早的版本中,%是可选的。
TIME_FORMAT(time,format)
这象上面的DATE_FORMAT()函数一样使用,但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。
其他修饰符产生一个NULL值或0。
CURDATE()
CURRENT_DATE
以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值,取决于函数是在一个字符串还是数字上下文被使用。
mysql> select CURDATE();
-> '1997-12-15'
mysql> select CURDATE() + 0;
-> 19971215
CURTIME()
CURRENT_TIME
以'HH:MM:SS'或HHMMSS格式返回当前时间值,取决于函数是在一个字符串还是在数字的上下文被使用。
mysql> select CURTIME();
-> '23:50:26'
mysql> select CURTIME() + 0;
-> 235026
NOW()
SYSDATE()
CURRENT_TIMESTAMP
以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回当前的日期和时间,取决于函数是在一个字符串还是在数字的
上下文被使用。
mysql> select NOW();
-> '1997-12-15 23:50:26'
mysql> select NOW() + 0;
-> 19971215235026
UNIX_TIMESTAMP()
UNIX_TIMESTAMP(date)
如果没有参数调用,返回一个Unix时间戳记(从'1970-01-01 00:00:00'GMT开始的秒数)。如果UNIX_TIMESTAMP()用一
个date参数被调用,它返回从'1970-01-01 00:00:00' GMT开始的秒数值。date可以是一个DATE字符串、一个DATETIME
字符串、一个TIMESTAMP或以YYMMDD或YYYYMMDD格式的本地时间的一个数字。
mysql> select UNIX_TIMESTAMP();
-> 882226357
mysql> select UNIX_TIMESTAMP('1997-10-04 22:23:00');
-> 875996580
当UNIX_TIMESTAMP被用于一个TIMESTAMP列,函数将直接接受值,没有隐含的“string-to-unix-timestamp”变换。
FROM_UNIXTIME(unix_timestamp)
以'YYYY-MM-DD HH:MM:SS'或YYYYMMDDHHMMSS格式返回unix_timestamp参数所表示的值,取决于函数是在一个字符串
还是或数字上下文中被使用。
mysql> select FROM_UNIXTIME(875996580);
-> '1997-10-04 22:23:00'
mysql> select FROM_UNIXTIME(875996580) + 0;
-> 19971004222300
FROM_UNIXTIME(unix_timestamp,format)
返回表示 Unix 时间标记的一个字符串,根据format字符串格式化。format可以包含与DATE_FORMAT()函数列出的条
目同样的修饰符。
mysql> select FROM_UNIXTIME(UNIX_TIMESTAMP(),
'%Y %D %M %h:%i:%s %x');
-> '1997 23rd December 03:43:30 x'
SEC_TO_TIME(seconds)
返回seconds参数,变换成小时、分钟和秒,值以'HH:MM:SS'或HHMMSS格式化,取决于函数是在一个字符串还是在数字
上下文中被使用。
mysql> select SEC_TO_TIME(2378);
-> '00:39:38'
mysql> select SEC_TO_TIME(2378) + 0;
-> 3938
TIME_TO_SEC(time)
返回time参数,转换成秒。
mysql> select TIME_TO_SEC('22:23:00');
-> 80580
mysql> select TIME_TO_SEC('00:39:38');
-> 2378
---------------------------------------------------------------------------------------------------------------------------
mysql日期处理函数
mysql日期处理函数
mysql自己有格式化日期格式的函数,可以在查询语句中使用
DATE_FORMAT(date,format)
根据format字符串格式化date值。下列修饰符可以被用在format字符串中: %M 月名字(January……December)
%W 星期名字(Sunday……Saturday)
%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
%Y 年, 数字, 4 位
%y 年, 数字, 2 位
%a 缩写的星期名字(Sun……Sat)
%d 月份中的天数, 数字(00……31)
%e 月份中的天数, 数字(0……31)
%m 月, 数字(01……12)
%c 月, 数字(1……12)
%b 缩写的月份名字(Jan……Dec)
%j 一年中的天数(001……366)
%H 小时(00……23)
%k 小时(0……23)
%h 小时(01……12)
%I 小时(01……12)
%l 小时(1……12)
%i 分钟, 数字(00……59)
%r 时间,12 小时(hh:mm:ss [AP]M)
%T 时间,24 小时(hh:mm:ss)
%S 秒(00……59)
%s 秒(00……59)
%p AM或PM
%w 一个星期中的天数(0=Sunday ……6=Saturday )
%U 星期(0……52), 这里星期天是星期的第一天
%u 星期(0……52), 这里星期一是星期的第一天
%% 一个文字“%”。
如需要用php处理,可先用strtotime函数将日期转换为unix时间戳,再用date函数格式化
对于Weblogic8.1可直接修改eauser_projectsdomainsmydomain下的startweblogic.cmd
找到 “Set classpath=”,加入mysql.jar的路径,如:
set CLASSPATH=C:mysql.jar;%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%jrelib t.jar;%WL_HOME%serverlibwebservices.jar;%CLASSPATH%
mysql.jar的路径最好放在最前面。
当weblogic合成在myeclipse中的时候,在myeclipse的weblogic的classpath中设置驱动的路径
1)控制台报The WebLogic Server did not start up properly.
java.io.InvalidClassException: javax.management.MBeanAttributeInfo; local class incompatible: stream classdesc serialVersionUID = 7043855487133450673, local class serialVersionUID = 8644704819898565848
错误原因及解决办法:MBeanAttributeInfo的serialVersionUID的版本控制id不一样,说明是使用这个被使用的bean被修改过了,很显然是版本不对;修改startWebLogic.cmd文件,设置set JAVA_HOME=D:\bea\jdk141_05,使其指向weblogic自带的jdk;重启startWebLogic.cmd问题消失。
2)错误报Deployment descriptor "web.xml" is malform
ed. Check against the DTD: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find
错误原因及解决办法:解析web.xml出现问题,修改OPEN_CMS\webapp\WEB-INF\web.xml文件;在该文件的 最上面添加如下内容:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
重新启动错误消失。
3)错误为Deployment descriptor "/WEB-INF/
web.xml" is malformed. Check against the DTD: The content of element type "t
ag" must match "(name,tag-class,tei-class?,body-content?,display-name?,small-ico
n?,large-icon?,description?,variable*,attribute*,example?)". (line 40, column 11
).>
错误原因及解决办法:由于weblogic8在解析xml文件时,对xml文件的内容格式要求特别严格;必须按照xml格式的要求
及排列顺序,所以必须重新组织其内容,一定严格要注意顺序,如 <servlet>就不能放在<servlet-mapping>后面。
4)错误java.lang.SecurityException: Prohibited package name: java.lang
错误原因及解决办法:访问包可视的方法或变量错误;这个错误恨少见,一直没有想明白其中缘由;后来只能采用直接引用jar文件的法子解决该问题;
i)利用opencms自带的build.xml文件,运行ant jar命令;生成opencms.jar和webdav.jar两个文件
ii)在startWebLogic.cmd添加如下内容,引进上面的2个jar文件
set CLASSPATH=%CLASSPATH%;%OPEN_CMS%\build\opencms.jar
set CLASSPATH=%CLASSPATH%;%OPEN_CMS%\build\webdav.jar
大家有兴趣的可以参考《透视JAVA——反编译、修补和逆向工程技术》这本书的$4.2章的内容,如果找到更好的解决方法也请来信告知,谢谢~_~
5)其它注意事项,在eclipse下最好采用和运行weblogic一样的jdk版本进行编译,否则会出现文件访问版本不一致的bug
2.调用有简单返回值的java方法
2.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod2"/>
</create>
</allow>
</dwr>
2.2、javascript中调用
首先,引入javascript脚本
其次,编写调用java方法的javascript函数和接收返回值的回调函数
Function callTestMethod2(){
testClass.testMethod2(callBackFortestMethod2);
}
Function callBackFortestMethod2(data){
//其中date接收方法的返回值
//可以在这里对返回值进行处理和显示等等
alert("the return value is " + data);
}
其中callBackFortestMethod2是接收返回值的回调函数
3、调用有简单参数的java方法
3.1、dwr.xml的配置
配置同1.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod3"/>
</create>
</allow>
</dwr>
3.2、javascript中调用
首先,引入javascript脚本
其次,编写调用java方法的javascript函数
Function callTestMethod3(){
//定义要传到java方法中的参数
var data;
//构造参数
data = “test String”;
testClass.testMethod3(data);
}
4、调用返回JavaBean的java方法
4.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod4"/>
</create>
<convert converter="bean" match=""com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
<creator>标签负责公开用于Web远程的类和类的方法,<convertor>标签则负责这些方法的参数和返回类型。convert元素的作用是告诉DWR在服务器端Java 对象表示和序列化的JavaScript之间如何转换数据类型。DWR自动地在Java和JavaScript表示之间调整简单数据类型。这些类型包括Java原生类型和它们各自的封装类表示,还有String、Date、数组和集合类型。DWR也能把JavaBean转换成JavaScript 表示,但是出于安全性的原因,要求显式的配置,<convertor>标签就是完成此功能的。converter="bean"属性指定转换的方式采用JavaBean命名规范,match=""com.dwr.TestBean"属性指定要转换的javabean名称,<param>标签指定要转换的JavaBean属性。
4.2、javascript中调用
首先,引入javascript脚本
其次,编写调用java方法的javascript函数和接收返回值的回调函数
Function callTestMethod4(){
testClass.testMethod4(callBackFortestMethod4);
}
Function callBackFortestMethod4(data){
//其中date接收方法的返回值
//对于JavaBean返回值,有两种方式处理
//不知道属性名称时,使用如下方法
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
//知道属性名称时,使用如下方法
alert(data.username);
alert(data.password);
}
其中callBackFortestMethod4是接收返回值的回调函数
5、调用有JavaBean参数的java方法
5.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod5"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
5.2、javascript中调用
首先,引入javascript脚本
其次,编写调用java方法的javascript函数
Function callTestMethod5(){
//定义要传到java方法中的参数
var data;
//构造参数,date实际上是一个object
data = { username:"user", password:"password" }
testClass.testMethod5(data);
}
6、调用返回List、Set或者Map的java方法
6.1、dwr.xml的配置
配置同4.1
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod6"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
</dwr>
注意:如果List、Set或者Map中的元素均为简单类型(包括其封装类)或String、Date、数组和集合类型,则不需要<convert>标签。
6.2、javascript中调用(以返回List为例,List的元素为TestBean)
首先,引入javascript脚本
其次,编写调用java方法的javascript函数和接收返回值的回调函数
Function callTestMethod6(){
testClass.testMethod6(callBackFortestMethod6);
}
Function callBackFortestMethod6(data){
//其中date接收方法的返回值
//对于JavaBean返回值,有两种方式处理
//不知道属性名称时,使用如下方法
for(var i=0;i<data.length;i++){
for(var property in data){
alert("property:"+property);
alert(property+":"+data[property]);
}
}
//知道属性名称时,使用如下方法
for(var i=0;i<data.length;i++){
alert(data[i].username);
alert(data[i].password);
}
}
7、调用有List、Set或者Map参数的java方法
7.1、dwr.xml的配置
<dwr>
<allow>
<create creator="new" javascript="testClass" >
<param name="class" value="com.dwr.TestClass" />
<include method="testMethod7"/>
</create>
<convert converter="bean" match="com.dwr.TestBean">
<param name="include" value="username,password" />
</convert>
</allow>
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(List<TestBean>);
]]>
</signatures>
</dwr>
<signatures>标签是用来声明java方法中List、Set或者Map参数所包含的确切类,以便java代码作出判断。
7.2、javascript中调用(以返回List为例,List的元素为TestBean)
首先,引入javascript脚本
其次,编写调用java方法的javascript函数
Function callTestMethod7(){
//定义要传到java方法中的参数
var data;
//构造参数,date实际上是一个object数组,即数组的每个元素均为object
data = [
{
username:"user1",
password:"password2"
},
{
username:"user2",
password:" password2"
}
];
testClass.testMethod7(data);
}
注意:
1、对于第6种情况,如果java方法的返回值为Map,则在接收该返回值的javascript回调函数中如下处理:
function callBackFortestMethod(data){
//其中date接收方法的返回值
for(var property in data){
var bean = data[property];
alert(bean.username);
alert(bean.password);
}
}
2、对于第7种情况,如果java的方法的参数为Map(假设其key为String,value为TestBean),则在调用该方法的javascript函数中用如下方法构造要传递的参数:
function callTestMethod (){
//定义要传到java方法中的参数
var data;
//构造参数,date实际上是一个object,其属性名为Map的key,属性值为Map的value
data = {
"key1":{
username:"user1",
password:"password2"
},
"key2":{
username:"user2",
password:" password2"
}
};
testClass.testMethod(data);
}
并且在dwr.xml中增加如下的配置段
<signatures>
<![CDATA[
import java.util.List;
import com.dwr.TestClass;
import com.dwr.TestBean;
TestClass.testMethod7(Map<String,TestBean>);
]]>
</signatures>
3、由以上可以发现,对于java方法的返回值为List(Set)的情况,DWR将其转化为Object数组,传递个javascript;对于java方法的返回值为Map的情况,DWR将其转化为一个Object,其中Object的属性为原Map的key值,属性值为原Map相应的value值。
4、如果java方法的参数为List(Set)和Map的情况,javascript中也要根据3种所说,构造相应的javascript数据来传递到java中。
FreeMarker的指令的文件就称为模板(Template)。
模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。
数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。
数据类型:
一、基本:
1、scalars:存储单值
字符串:简单文本由单或双引号括起来。
数字:直接使用数值。
日期:通常从数据模型获得
布尔值:true或false,通常在<#if …>标记中使用
2、hashes:充当其它对象的容器,每个都关联一个唯一的查询名字
具有一个唯一的查询名字和他包含的每个变量相关联。
3、sequences:充当其它对象的容器,按次序访问
使用数字和他包含的每个变量相关联。索引值从0开始。
4、集合变量:
除了无法访问它的大小和不能使用索引来获得它的子变量:集合可以看作只能由<#list...>指令使用的受限sequences。
5、方法:通过传递的参数进行计算,以新对象返回结果
方法变量通常是基于给出的参数计算值在数据模型中定义。
6、用户自定义FTL指令:宏和变换器
7、节点
节点变量表示为树型结构中的一个节点,通常在XML处理中使用。
模板:
使用FTL(freeMarker模板语言)编写
组成部分
一、整体结构
1、注释:<#--注释内容-->,不会输出。
2、文本:直接输出。
3、interpolation:由 ${var} 或 #{var} 限定,由计算值代替输出。
4、FTL标记
二、指令:
freemarker指令有两种:
1、预定义指令:引用方式为<#指令名称>
2、用户定义指令:引用方式为<@指令名称>,引用用户定义指令时须将#换为@。
注意:如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。
freemarker指令由FTL标记来引用,FTL标记和HTML标记类似,名字前加#来加以区分。如HTML标记的形式为<h1></h1>则FTL标记的形式是<#list></#list>(此处h1标记和list指令没有任何功能上的对应关系,只是做为说明使用一下)。
有三种FTL标记:
1)、开始标记:<#指令名称>
2)、结束标记:</#指令名称>
3)、空标记:<#指令名称/>
注意:
1) FTL会忽略标记之中的空格,但是,<#和指令 与 </#和指令 之间不能有空格。
2) FTL标记不能够交叉,必须合理嵌套。每个开始标记对应一个结束标记,层层嵌套。 如:
<#list>
<li>
${数据}
<#if 变量>
<p>game over!</p>
</#if>
</li>
</#list>
注意事项:
1)、FTL对大小写敏感。所以使用的标记及interpolation要注意大小写。name与NAME就是不同的对象。<#list>是正确的标记,而<#List>则不是。
2)、interpolation只能在文本部分使用,不能位于FTL标记内。如<#if ${var}>是错误的,正确的方法是:<#if var>,而且此处var必须为布尔值。
3)、FTL标记不能位于另一个FTL标记内部,注释例外。注释可以位于标记及interpolation内部。
三、表达式
1、直接指定值:
1-1、字符串:
由双引号或单引号括起来的字符串,其中的特殊字符(如' " \等)需要转义。
1-2、raw字符串:
有一种特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:
${r"/${data}"year""}屏幕输出结果为:/${data}"year"
转义 含义
序列
\" 双引号(u0022)
\' 单引号(u0027)
\\ 反斜杠(u005C)
\n 换行(u000A)
\r Return (u000D)
\t Tab (u0009)
\b Backspace (u0008)
\f Form feed (u000C)
\l <
\g >
\a &
\{ {
\xCode 4位16进制Unicode代码
1-3、数字:直接输入,不需要引号
1)、精度数字使用“.”分隔,不能使用分组符号
2)、目前版本不支持科学计数法,所以“1E3”是错误的
3)、不能省略小数点前面的0,所以“.5”是错误的
4)、数字8、+8、08和8.00都是相同的
1-4、布尔值:true和false,不使用引号
1-5、序列:由逗号分隔的子变量列表,由[]方括号限定。
1)、子变量列表可以是表达式
2)、可以使用数字范围定义数字序列,<b>不需要方括号限定</b>,例如2..5等同于[2, 3, 4, 5],但是更有效率,可以定义反递增范围如:5..2。
1-6、散列(hash)
1)、由逗号分隔的键/值列表,由{}大括号限定,键和值之间用冒号分隔,如:{"key1":valu1,"key2":"character string"....}
2)、键和值都是表达式,但是键必须是字符串。
2、获取变量:
2-1、顶层变量:${变量名}
变量名只能是字母、数字、下划线、$、#、@ 的组合,且不能以数字开头。
2-2、散列:有两种方法
1)、点语法:变量名字和顶层变量的名字受同样的限制
2)、方括号语法:变量名字无限制,可以是任意的表达式的结果
book.author.name
book.author.["name"]
book["author"].name
book["author"]["name"]
以上是等价的。
2-3、序列:使用散列的方括号语法获取变量,方括号中的表达式结果必须为数字。注意:第一个项目的索引为0。可以使用
[startindex..endindex]语法获取序列片段。
2-4、特殊变量:FreeMarker内定义变量,使用.variablename语法访问。
3、字符串操作
3-1、interpolation:使用${}或#{}在文本部分插入表达式的值,例如:
${"hello${username}!"}
${"${username}${username}${username}"}
也可以使用+来获得同样的结果:
${"hello"+username+"!"}
${username+username+username}
注意:${}只能用于文本部分而不能出现于标记内。
<#if ${user.login}>或<#if "${user.login}">都是错误的;
<#if user.login>是正确的。
本例中user.login的值必须是布尔类型。
3-2、子串:
举例说明:假如user的值为"Big Joe"
${user[0]}${user[4]}结果是:BJ
${user[1..4]}结果是:ig J
4、序列操作
4-1、连接操作:可以使用+来操作,例如:
["title","author"]+["month","day"]
5、散列操作
5-1、连接操作:可以使用+来操作,如果有相同的KEY,则右边的值会替代左边的值,例如:
{"title":散列,"author":"emma"}+{"month":5,"day":5}+{"month":6}结果month的值就是6。
6、算术运算
6-1、操作符:+、-、*、/、%
除+号以外的其他操作符两边的数据,必须都是数字类型。
如果+号操作符一边有一个字符型数据,会自动将另一边的数据转换为字符型数据,运算结果为字符型数据。
6-2、比较操作符:
1)、=
2)、==
3)、!=
4)、<
5)、<=
6)、>
7)、>=
1-3的操作符,两边的数据类型必须相同,否则会产生错误
4-7的操作符,对于日期和数字可以使用,字符串不可以使用。
注意:
1)、FreeMarker是精确比较,所以"x" "x " "X"是不等的。
2)、因为<和>对FTL来说是开始和结束标记,所以,可以用两种方法来避免这种情况:
一种是使用括号<#if (a<b)>
另一是使用替代输出,对应如下:
< lt
<= lte
> gt
>= gte
6-3、逻辑操作符:只能用于布尔值,否则会出现错误。
&&(and)与运算
||(or)或运算
!(not)非运算
6-4、内建函数:使用方法类似于访问散列的子变量,只是使用?代替.例如:${test?upper_case?html}
常用的内建函数列举如下:
1)、字符串使用:
html:对字符串进行HTML编码
cap_first:字符串第一个字母大写
lower_first:字符串第一个字母小写
upper_case:将字符串转换成大写
trim:去年字符前后的空白字符
2)、序列使用:
size:获得序列中元素的数目
3)、数字使用:
int:取得数字的整数部分
7、操作符的优先顺序:
后缀:[subbarName][subStringRange].(mathodParams)
一元:+expr、-expr、! (not)
内建:?
乘法:*、/、%
加法:+、-
关系:<、<=、>、>= (lt、lte、gt、gte)
相等:=、==、!=
逻辑与:&& (and)
逻辑或:|| (or)
数字范围:..
四、interpolation
inperpolation只能用于文本,有两种类型:通用interpolation及数字interpolation
1、通用interpolation
如${expr}
1-1、插入字符串值:直接输出表达式结果。
1-2、插入数字值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation
如:
<#setting number_format="currency" />
<#assign answer=42 />
${answer} <#-- ¥42.00 -->
${answer?string} <#-- ¥42.00 -->
${answer?string.number} <#-- 42 -->
${answer?string.currency} <#-- ¥42.00 -->
${answer?string.percent} <#-- 42,00% -->
1-3、插入日期值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation
如:
${lastupdata?string("yyyy-MM-dd HH:mm:ss zzzz")} <#-- 2003-04-08 21:24:44 Pacific Daylight Time -->
${lastupdata?string("EEE,MMM d, ''yy")} <#-- tue,Apr 8, '03 -->
${lastupdata?string("EEEE,MMMM dd, yyyy,hh:mm:ss a '('zzz')'")} <#-- Tuesday,April 08, 2003, 09:24:44 PM (PDT)-->
1-4、插入布尔值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation
如:
<#assign foo=ture />
${foo?string("yes","no")} <#-- yes -->
2、数字interpolation:
有两种形式:
1)、#{expr}
2)、#{expr;format}:format可以用来格式化数字,format可以是如下:
mX:小数部分最小X位
MX:小数部分最大X位
例如:
<#assign x=2.582 />
<#assign y=4 />
#{x;M2} <#-- 2.58 -->
#{y;M2} <#-- 4 -->
#{x;m1} <#-- 2.582 -->
#{y;m1} <#-- 4.0 -->
#{x;m1M2} <#-- 2.58 -->
#{y;m1M2} <#-- 4.0 -->
杂项
一、用户定义指令
宏和变换器变量是两种不同类型的用户自定义指令,他们的区别是:
宏可以在模板中用macro指令来定义
变换器是在模板外由程序定义
1、宏:和某个变量关联的模板片段,以便在模板中通过用户自定义指令使用该变量
1-1、基本用法:
例如:
<#macro greet>
<font size="+2"> Hello JOE!</font>
</#macro>
使用时:
<@greet></@greet>
如果没有体内容也可以用
<@greet />
1-2、变量:
1)、可以在宏定义之后定义参数,宏参数是局部变量,只在宏定义中有效。如:
<#macro greet person>
<font size="+2"> Hello ${person}!</font>
</#macro>
使用时:
<@greet person="emma"> and <@greet person="LEO">
输出为:
<font size="+2"> Hello emma!</font>
<font size="+2"> Hello LEO!</font>
注意:宏的参数是FTL表达式,所以,person=emma和上面的例子中具有不同的意义,这意味着将变量emma的值传给person,这个值可能是任意一种数据类型,甚至是一个复杂的表达式。
宏可以有多个参数,使用时参数的次序是无关的,但是只能使用宏中定义的参数,并且对所有参数赋值。如:
<#macro greet person color>
<font size="+2" color="${color}"> Hello ${person}!</font>
</#macro>
使用时:
<@greet color="black" person="emma" />正确
<@greet person="emma" />错误,color没有赋值,此时,如果在定义宏时为color定义缺省值<#macro greet person color="black">这样的话,这个使用方法就是正确的。
<@greet color="black" person="emma" bgcolor="yellow" />错误,宏greet定义中未指定bgcolor这个参数
2、嵌套内容:
2-1、自定义指令可以有嵌套内容,使用<#nested>指令,执行自定义指令开始和结束标记之间的模板片段。例如:
<#macro greet>
<p>
<#nested>
</p>
</#macro>
<@greet>hello Emma!</@greet>
输出为
<p>hello Emma!</p>
2-2、<#nested>指令可以被多次调用,例如
<#macro greet>
<p>
<#nested>
<#nested>
<#nested>
<#nested>
</p>
</#macro>
<@greet>hello Emma!</@greet>
输出为
<p>
hello Emma!
hello Emma!
hello Emma!
hello Emma!
</p>
2-3、嵌套的内容可以是有效的FTL,例如:
<#macro welcome>
<p>
<#nested>
</p>
</#macro>
<#macro greet person color="black">
<font size="+2" color="${color}"> Hello ${person}!</font>
</#macro>
<@welcome>
<@greet person="Emma" color="red" />
<@greet person="Andrew" />
<@greet person="Peter" />
</@welcome>
输出为:
<p>
<font size="+2" color="red"> Hello Emma!</font>
<font size="+2" color="black"> Hello Andrew!</font>
<font size="+2" color="black"> Hello Peter!</font>
</p>
2-4、宏定义中的局部变量对嵌套内容是不可见的,例如:
<#macro repeat count>
<#local y="test" />
<#list 1..count as x>
${y}${count}/${x}:<#nested />
</#list>
</#macro>
<@repeat count=3>
${y?default("?")}
${x?default("?")}
${count?default("?")}
</@repeat>
输出结果为
test 3/1:???
test 3/2:???
test 3/3:???
2-5、在宏定义中使用循环变量,通常用来重复嵌套内容,基本用法为:作为nested指令的参数,传递循环变量的实际值,而在调用自定义指令时,在标记的参数后面指定循环变量的名字。
例如:
<#macro repeat count>
<#list 1..count as x>
<#nested x,x/2,x==count />
</#list>
</#macro>
<@repeat count=4;c,halfc,last>
${c}. ${halfc}
<#if last>
last!
</#if>
</@repeat>
输出结果是
1. 0.5
2. 1
3. 1.5
4. 2last!
注意:指定循环变量的数目和用户定义指令开始标记指定的不同不会有问题
调用时,少指定循环变量,多指定的值会不见
调用时,多指定循环变量,多余的循环变量不会被创建
二、在模板中定义变量
1、在模板中定义的变量有三种类型
1-1、plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换。
1-2、局部变量:在宏定义体中有效,使用local指令创建和替换。
1-3、循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建。
注意:
1)、宏的参数是局部变量,不是循环变量。
2)、局部变量隐藏同名的plain变量
3)、循环变量隐藏同名的plain变量和局部变量。
例如:
<#assign x="plain">
1. ${x} <#-- plain -->
<@test />
6. ${x}
<#list ["loop"] as x>
7. ${x} <#-- loop -->
<#assign x="plain2">
8. ${x} <#-- loop -->
</#list>
9. ${x} <#-- plain2 -->
<#macro test>
2. ${x} <#-- plain -->
<#local x="local">
3. ${x} <#-- local -->
<#list ["loop"] as x>
4. ${x} <#-- loop -->
</#list>
5. ${x} <#-- local -->
</#macro>
4)、内部循环变量隐藏同名的外部循环变量
<#list ["loop1"] as x>
${x} <#-- loop1 -->
<#list ["loop2"] as x>
${x} <#-- loop2 -->
<#list ["loop3"] as x>
${x} <#-- loop3 -->
</#list>
${x} <#-- loop2 -->
</#list>
${x} <#-- loop1 -->
</#list>
5)、模板中的变量会隐藏数据模型中的同名变量,如果需访问数据模型中的变量,使用特殊变量global。
例如:
假设数据模型中的user值为Emma
<#assign user="Man">
${user} <#-- Man -->
${.global.user} <#-- Emma -->
一:
myeclipse 傻瓜式的完成spring和hibernate的载入;
注意需要把lib里面的 asm-XX和 commons-collections-XX 低版本的删除掉,因为载入spring和hibernate的时候会装在2个不一样的版本,包冲突.
记得把dwr的包放进去
数据库用mysql.
CREATE TABLE `book` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(11) default NULL,
`isbm` varchar(11) default NULL,
`author` varchar(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=gbk;
id为自动增长
二:
完成上步后用hibernate的反向机制,完成数据库表的映射
如下:
AbstractBook.java
package com;
/**
* AbstractBook generated by MyEclipse Persistence Tools
*/
public abstract class AbstractBook implements java.io.Serializable {
// Fields
private Integer id;
private String name;
private String isbm;
private String author;
// Constructors
/** default constructor */
public AbstractBook() {
}
/** full constructor */
public AbstractBook(String name, String isbm, String author) {
this.name = name;
this.isbm = isbm;
this.author = author;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getIsbm() {
return this.isbm;
}
public void setIsbm(String isbm) {
this.isbm = isbm;
}
public String getAuthor() {
return this.author;
}
public void setAuthor(String author) {
this.author = author;
}
}
Book.java
package com;
// Generated by MyEclipse Persistence Tools
/**
* Book generated by MyEclipse Persistence Tools
*/
public class Book extends AbstractBook implements java.io.Serializable {
// Constructors
/** default constructor */
public Book() {
}
/** full constructor */
public Book(String name, String isbm, String author) {
super(name, isbm, author);
}
}
BookDAO.java
package com;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* Data access object (DAO) for domain model class Book.
*
* @see com.Book
* @author MyEclipse Persistence Tools
*/
public class BookDAO extends HibernateDaoSupport {
private static final Log log = LogFactory.getLog(BookDAO.class);
protected void initDao() {
// do nothing
}
public void save(Book transientInstance) {
log.debug("saving Book instance");
try {
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
}
public void delete(Book persistentInstance) {
log.debug("deleting Book instance");
try {
getHibernateTemplate().delete(persistentInstance);
log.debug("delete successful");
} catch (RuntimeException re) {
log.error("delete failed", re);
throw re;
}
}
public Book findById(java.lang.Integer id) {
log.debug("getting Book instance with id: " + id);
try {
Book instance = (Book) getHibernateTemplate().get("com.Book", id);
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
public List findByExample(Book instance) {
log.debug("finding Book instance by example");
try {
List results = getHibernateTemplate().findByExample(instance);
log.debug("find by example successful, result size: "
+ results.size());
return results;
} catch (RuntimeException re) {
log.error("find by example failed", re);
throw re;
}
}
public List findByProperty(String propertyName, Object value) {
log.debug("finding Book instance with property: " + propertyName
+ ", value: " + value);
try {
String queryString = "from Book as model where model."
+ propertyName + "= ?";
return getHibernateTemplate().find(queryString, value);
} catch (RuntimeException re) {
log.error("find by property name failed", re);
throw re;
}
}
public List findAll() {
log.debug("finding all Book instances");
try {
String queryString = "from Book";
return getHibernateTemplate().find(queryString);
} catch (RuntimeException re) {
log.error("find all failed", re);
throw re;
}
}
public Book merge(Book detachedInstance) {
log.debug("merging Book instance");
try {
Book result = (Book) getHibernateTemplate().merge(detachedInstance);
log.debug("merge successful");
return result;
} catch (RuntimeException re) {
log.error("merge failed", re);
throw re;
}
}
public void attachDirty(Book instance) {
log.debug("attaching dirty Book instance");
try {
getHibernateTemplate().saveOrUpdate(instance);
log.debug("attach successful");
} catch (RuntimeException re) {
log.error("attach failed", re);
throw re;
}
}
public void attachClean(Book instance) {
log.debug("attaching clean Book instance");
try {
getHibernateTemplate().lock(instance, LockMode.NONE);
log.debug("attach successful");
} catch (RuntimeException re) {
log.error("attach failed", re);
throw re;
}
}
public static BookDAO getFromApplicationContext(ApplicationContext ctx) {
return (BookDAO) ctx.getBean("BookDAO");
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Book.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.Book" table="book" catalog="test">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="name" length="11" />
</property>
<property name="isbm" type="java.lang.String">
<column name="isbm" length="11" />
</property>
<property name="author" type="java.lang.String">
<column name="author" length="11" />
</property>
</class>
</hibernate-mapping>
BookManageService.java 暴露给dwr使用的接口
package com;
import java.util.List;
public interface BookManageService {
public List<Book> getAllBooks();
public List<Book> getBookByName(String name);
public void updateBook(Book book);
public void addBook(Book book);
public void deleteBook(Integer id);
}
BookManageServiceImpl.java 接口的实现类
package com;
import java.util.List;
public class BookManageServiceImpl implements BookManageService {
private BookDAO bookDAO;
public BookDAO getBookDAO() {
return bookDAO;
}
public void setBookDAO(BookDAO bookDAO) {
this.bookDAO = bookDAO;
}
public void addBook(Book book) {
System.out.println("impl:"+book);
bookDAO.save(book);
}
public void deleteBook(Integer id) {
Book book = bookDAO.findById(id);
bookDAO.delete(book);
}
@SuppressWarnings("unchecked")
public List<Book> getAllBooks() {
return bookDAO.findAll();
}
@SuppressWarnings("unchecked")
public List<Book> getBookByName(String name) {
return bookDAO.findByProperty(name, name);
}
public void updateBook(Book book) {
bookDAO.attachDirty(book);
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/Book.hbm.xml</value>
</list>
</property>
</bean>
<bean id="BookDAO" class="com.BookDAO">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="bookManageServiceTarget"
class="com.BookManageServiceImpl">
<property name="bookDAO">
<ref bean="BookDAO" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="bookManageService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="bookManageServiceTarget" />
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
</beans>
dwr.xml
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">
<dwr>
<allow>
<convert converter="bean" match="com.Book" />
<create creator="spring" javascript="BookManageService">
<param name="beanName" value="bookManageService" />
<include method="getAllBooks" />
<include method="getBookByName" />
<include method="updateBook" />
<include method="addBook" />
<include method="deleteBook" />
</create>
</allow>
</dwr>
index.jsp
<html>
<head>
<title>DWR test</title>
<script type='text/javascript' src='/shdwr/dwr/interface/BookManageService.js'></script>
<script type='text/javascript' src='/shdwr/dwr/engine.js'></script>
<script type='text/javascript' src='/shdwr/dwr/util.js'></script>
<script type="text/javascript">
var bookCache ={};
var currentBook = null;
function loadAllBooks(){
BookManageService.getAllBooks(handleGetAllBooks,handleGetAllBooksError);
}
function handleGetAllBooks(books){
dwr.util.removeAllRows("booksBody",{ filter:function(tr){
return (tr.id != "pattern");
}});
var book,id;
for(var i = 0; i < books.length; i++){
book = books[i];
id = book.id;
dwr.util.cloneNode("pattern", { idSuffix:id });
dwr.util.setValue("t_name" + id, book.name);
dwr.util.setValue("t_isbm" + id, book.isbm);
dwr.util.setValue("t_author" + id,book.author);
$("pattern" + id).style.display = "block";
bookCache[id] = book;
}
}
function handleGetAllBooksError(msg){
alert("Error: " + msg);
}
function addBook(){
var book ={name:null,isbm:null,author:null};
dwr.util.getValues(book);
dwr.engine.beginBatch();
BookManageService.addBook(book);
loadAllBooks();
dwr.engine.endBatch();
}
function editBook(btId){
currentBook = bookCache[btId.substring(4)];
dwr.util.setValues(currentBook);
}
function updateBook(){
var book = {id:null,name:null,isbm:null,author:null};
dwr.util.getValues(book);
book.id = currentBook.id;
BookManageService.updateBook(book,handleUpdateBook,handleUpdateBookError);
}
function handleUpdateBook(){
alert("Update book successfully!");
loadAllBooks();
}
function handleUpdateBookError(msg){
alert("Error: " + msg);
}
function deleteBook(btId){
var i = confirm("Are you sure to delete the book?");
if(i == true)
BookManageService.deleteBook(btId.substring(6),handleDeleteBook,handleDeleteBookError);
}
function handleDeleteBook(){
alert("The book has been delete successfully!");
loadAllBooks();
}
function handleDeleteBookError(msg){
alert("Error: " + msg);
}
function reset(){
dwr.util.setValue("name", "");
dwr.util.setValue("isbm", "");
dwr.util.setValue("author", "");
}
</script>
</head>
<body onload="loadAllBooks()">
<div>
<h2>
Add book
</h2>
<table>
<tr>
<td>
Name:
</td>
<td>
<input type="text" id="name">
</td>
</tr>
<tr>
<td>
ISBN:
</td>
<td>
<input type="text" id="isbm">
</td>
</tr>
<tr>
<td>
Author:
</td>
<td>
<input type="text" id="author">
</td>
</tr>
<tr>
<td colspan="2">
<input type="button" id="add" value="Add" onclick="addBook()">
<input type="reset" id="reset" value="reset" onclick="reset()">
<input type="button" id="update" value="Update"
onclick="updateBook()">
</td>
</tr>
</table>
</div>
<hr>
<div id="list">
<table border="1">
<thead>
<tr>
<th>
Name
</th>
<th>
ISBN
</th>
<th>
Author
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody id="booksBody">
<tr id="pattern" style="display: none;">
<td>
<span id="t_name"></span>
</td>
<td>
<span id="t_isbm"></span>
</td>
<td>
<span id="t_author"></span>
</td>
<td>
<span id="action"> <input id="edit" type="button"
value="Edit" onclick="editBook(this.id)" /> <input id="delete"
type="button" value="Delete" onclick="deleteBook(this.id)" />
</span>
</td>
</tr>
</tbody>
</table>
</div>
</body>
1、addRows 增添数据行到指定的table
方法基本语法:dwr.util.addRows(id, array, cellfuncs, [options]);
* id:table 的 id (最好是一个tbody的id)
* array: 需要被填充到table里的数据对象,可以是数组,集合等对象,每一个数组元素对应table的一行
* cellfuncs: function数组 每个元素对应table某一列数据的取得方式
* options: 包含几个属性的对象(可选)
options:(来源:www.iocblog.net)
# 属性rowCreator: 一个function,默认返回document.createElement("tr"),可以编辑返回自定义的tr(比如不同的样式)
# 属性cellCreator: 一个function,默认返回document.createElement("td"),可以编辑返回自定义的tr(比如不同的样式)
# 属性escapeHtml: 是否转义<,>,&,",'
当所有call back function 都需要转义,则可以使用dwr.util.setEscapeHtml(false)
2、removeAllRows 把指定table的所有行都移除
方法基本语法:dwr.util.removeAllRows(id);
* id:table 的 id (最好是一个tbody的id)
3、byId
你可以把它看成是document.getElementById()的替代版,如果指定的id有多个匹配项,就会返回一个element数组
方法基本语法:dwr.util.byId(id)
另:在引入util.js的环境下,你还可以使用$(id)代替document.getElementById(),但是为了不和Prototype相冲突,还是建议各位使用 byId。
4、getValue 取得html 页面元素的value
方法基本语法:dwr.util.getValue(id);
5、getText
用法和getValue方法相同,唯一的不同在于getText是用来取得下拉框列表的Text值,而非Value
6、getValues
方法基本语法:dwr.util.getValues(object) ;
参数是一个拥有多个属性的javascript object,属性名称是html页面元素的id,属性value为html页面元素的value,该方法不返回任何东西,而是改变了object的属性值。
7、setValue 设置html 页面元素的value
方法基本语法:dwr.util.setValue(id, value [, options]) ;
如果id参数指定的页面元素是select列表,该列表与value参数值相匹配的option选项会处于选中状态。
8、setValues
方法基本语法:dwr.util.setValues(object) ;
参数是一个拥有多个属性的javascript object,属性名称是html页面元素的id,属性value为html页面元素的value
9、addOptions
方法基本语法:dwr.util.addOptions(...); 有多种调用方式:
# dwr.util.addOptions(id,["first","second","third"]) id参数指定的页面元素可以是ol、ul或select,String数组将被set到id指定的页面元素
# dwr.util.addOptions(id,[{name:"first",value:"1"},{name:"second",value:"2"},{name:"third",value:"3"}],"value","name")
这种方式只对应select的情形,如上所述,Object数组里每个元素的value属性值将被set到option的value里,name属性将被set到option的text里。
如果没有第四个参数,将会把value属性值同时set到option的value和text里。
# dwr.util.addOptions(id,{first:"1",second:"1",third:"3"})
这种方式也只对应select的情形,第二个参数是一个Object,属性名set到option的value里,属性值set到option的text里
10、removeAllOptions
方法基本语法:dwr.util.removeAllOptions(id);
除去所有动态加载的Options或列表项,与addOptions配合使用
11、onReturn
方法基本语法:dwr.util.onReturn(event, func)
当输入回车时,调用func名指定的方法
12、useLoadingMessage
方法基本语法:dwr.util.useLoadingMessage();
显示一个正在加载的图片。必须在页面loaded以后调用
一:
用myeclipse中的傻瓜式添加spring组件。
修改web.xml文件内容,如下:(红色标记处)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-dwr.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
二:
将文件交给spring来管理
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">
<dwr>
<allow>
<create creator="spring" javascript="DWRUserAccess">
<param name="beanName" value="dwrUserAccess"/>
</create>
<convert match="com.dwr.User" converter="bean"></convert>
</allow>
</dwr>
三:
在web-inf下新建applicationContext-dwr.xml文件,内容如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-autowire="byName">
<bean name="dwrUserAccess" class="com.dwr.DWRUserAccess"></bean>
</beans>
OK。
DWR(Direct Web Remoting)是一个WEB远程调用框架.利用这个框架可以让AJAX开发变得很简单.利用DWR可以在客户端利用JavaScript直接调用服务端的Java方法并返回值给JavaScript就好像直接本地客户端调用一样(DWR根据Java类来动态生成JavaScrip代码).它的最新版本DWR0.6添加许多特性如:支持Dom Trees的自动配置,支持Spring(JavaScript远程调用spring bean),更好浏览器支持,还支持一个可选的commons-logging日记操作.
以上摘自open-open,它通过反射,将java翻译成javascript,然后利用回调机制,轻松实现了javascript调用Java代码。
其大概开发过程如下:
1.编写业务代码,该代码是和dwr无关的。
2.确认业务代码中哪些类、哪些方法是要由javascript直接访问的。
3.编写dwr组件,对步骤2的方法进行封装。
4.配置dwr组件到dwr.xml文件中,如果有必要,配置convert,进行java和javascript类型互转。
5.通过反射机制,dwr将步骤4的类转换成javascript代码,提供给前台页面调用。
5.编写网页,调用步骤5的javascript中的相关方法(间接调用服务器端的相关类的方法),执行业务逻辑,将执行结果利用回调函数返回。
6.在回调函数中,得到执行结果后,可以继续编写业务逻辑的相关javascript代码。
下面以用户注册的例子,来说明其使用。(注意,本次例子只是用于演示,说明DWR的使用,类设计并不是最优的)。
1.先介绍下相关的Java类
User: 用户类,
public class User {
//登陆ID,主键唯一
private String id;
//姓名
private String name;
//口令
private String password;
//电子邮件
private String email;
//以下包含getXXX和setXXX方法
.......
}
UserDAO:实现User的数据库访问,这里作为一个演示,编写测试代码
public class UserDAO {
//存放保存的数据
private static Map dataMap = new HashMap();
//持久用户
public boolean save(User user) {
if (dataMap.containsKey(user.getId()))
return false;
System.out.println("下面开始保存用户");
System.out.println("id:"+user.getId());
System.out.println("password:"+user.getPassword());
System.out.println("name:"+user.getName());
System.out.println("email:"+user.getEmail());
dataMap.put(user.getId(), user);
System.out.println("用户保存结束");
return true;
}
//查找用户
public User find(String id) {
return (User)dataMap.get(id);
}
}
DWRUserAccess:DWR组件,提供给javascript访问的。
public class DWRUserAccess {
UserDAO userDAO = new UserDAO();
public boolean save(User user) {
return userDAO.save(user);
}
public User find(String id) {
return userDAO.find(id);
}
}
下面说明下程序执行的流程
1.用户在页面上输入相关注册信息,id、name、password、email,点击“提交”按钮
2.javascript代码开始执行,根据用户填写相关信息,通过dwr提供的DWRUserAccess.js里save的方法,调用服务器端的DWRUserAccess类save方法,将注册信息保存。
3.通过DWRUserAccess.jsp里的find方法,调用服务器端DWRUserAccess类里的find方法,执行用户信息查找。
注意,在以上的执行过程中,DWRUserAccess是供DWR调用的,是DWR组件,因此需要将DWRUserAccess类配置到dwr中。
接下来讲解本次dwr测试环境的配置。
1.新建一个webapp,命名为testApp
2.将dwr.jar拷贝到testApp的WEB-INF的lib目录下
3.编译上面的User,UserDAO,DWRUserAccess类,放到classes目录下
4.在web.xml中配置servlet,适配路径到dwr目录下,如下所示
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<description>Direct Web Remoter Servlet</description>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>scriptCompressed</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
以上的配置可以拦截testApp下所有指向dwr的请求,关于这个拦截器,我们会在后面介绍。
5.WEB-INF下新建一个dwr.xml文件,内容如下:
< xml version="1.0" encoding="UTF-8" >
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd">
<dwr>
<allow>
<create creator="new" javascript="DWRUserAccess">
<param name="class" value="test.DWRUserAccess"/>
</create>
<convert converter="bean" match="test.User"/>
</allow>
</dwr>
这里我们把DWRUserAccess配置到了dwr中,create元素中,creater="new"表示每调用一次DWRUserAccess时,需要new一个这样的类;javascript="DWRUserAccess",表示提供给前台页面调用的javascirpt文件是DWRUserAccess.js。
convert元素用于数据类型转换,即java类和javascript之间相互转换,因为和前台交换的是User对象,因此需要对此使用bean转换,我们将在后面介绍这个类。
4.编写测试的HTML页面 test.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>DWR测试</TITLE>
<meta http-equiv=Content-Type content="text/html; charset=gb2312">
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
</HEAD>
<BODY>
<B>用户注册</B><br>
------------------------------------------------
<Br>
<form name="regForm">
登陆ID:<input type="text" name="id"><br>
口 令:<input type="password" name="password"><br>
姓 名:<input type="text" name="name"><br>
电子邮件:<input type="text" name="email"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnSave()"><br>
</form>
<br>
<br><B>用户查询</B><br>
------------------------------------------------
<Br>
<form name="queryForm">
登陆ID:<input type="text" name="id"><br>
<input type="button" name="submitBtn" value="提交" onclick="OnFind()"><br>
</form>
<br>
</BODY>
</HTML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注册成功!");
} else {
alert("登陆ID已经存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("无法找到用户:"+queryForm.id.value);
return;
}
alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
以下对页面的javascript进行解释
<script src="/oblog312/dwr/engine.js"></script>
<script src="/oblog312/dwr/util.js"></script>
这两个是dwr提供的,用户可以不必关心,只需要导入即可
<script src="/oblog312/dwr/interface/DWRUserAccess.js"></script>
是我们编写的DWRUserAccess类,经dwr反射后,生成的javascript代码,它和DWRUserAccess.java是对应的,供用户调用,实际上我们就是通过这个js文件去调用服务器端的DWRUserAccess类的。
<SCRIPT LANGUAGE="JavaScript">
<!--
function saveFun(data) {
if (data) {
alert("注册成功!");
} else {
alert("用户名已经存在!");
}
}
function OnSave() {
var userMap = {};
userMap.id = regForm.id.value;
userMap.password = regForm.password.value;
userMap.name = regForm.name.value;
userMap.email = regForm.email.value;
DWRUserAccess.save(userMap, saveFun);
}
function findFun(data) {
if (data == null) {
alert("无法找到用户:"+queryForm.id.value);
return;
}
alert("找到用户,nid:"+data.id+",npassword:"+data.password+",nname:"+data.name+",nemail:"+data.email);
}
function OnFind() {
DWRUserAccess.find(queryForm.id.value, findFun);
}
//-->
</SCRIPT>
这段javascirpt代码,我们来看下OnSave函数,首先它构造一个map,将表单数据都设置到map中,然后调用DWRUserAccess.save(userMap, saveFun),执行save操作。大家可以注意到,服务器端的DWRUserAccess中的save方法是这样的:boolean save(User user),其参数是一个User对象,返回一个boolean值;而客户端的方法是这样的:save(userMap,saveFun),第一个参数userMap是javascirpt中的map对象,在这里相当于服务器端的User对象(在服务器端执行时,会通过convert转换成User对象),前面我们提到dwr是利用回调函数来返回执行结果的,第二个参数saveFun即是一个回调函数。在函数function saveFun(data)中,data是执行结果,这里是一个bool值,非常简单的,我们通过判断data是否为真,可以知道用户名是否重复,用户是否注册成功。
看一下OnFind查找函数,执行结果在回调函数findFun(data)中,因为服务器端返回的是一个User对象,通过convert,将会转换成javascript的一个map对象,
于是在findFun中,通过data.id、data.name、data.password、data.email我们可以轻松的访问到这个User对象。
好了配置完毕,启动服务器,在目录中打入localhost/testApp/test.html。
1.在“用户注册”表单中,id框中输入admin,password中输入123456,name中输入chenbug,email中输入chenbug@zj.com,点击提交按钮,弹出对话框:“注册成功”,在服务器后台可以看到信息如下:
下面开始保存用户
id:admin
password:123456
name:chenbug
email:chenbug@zj.com
用户保存结束
再次点击提交按钮,弹出对话框“登陆ID已经存在”。
2.在“用户查询”对话框中,输入登陆ID为admin,点击提交按钮,提示找到用户,并显示相关信息,输入admin123,点击提交按钮,提示无法找到用户。
至此,测试结束。
后续:
1。拦截器 uk.ltd.getahead.dwr.DWRServlet
该类拦截所有指向dwr目录下的请求,并调用Processor的handler方法进行处理,在uk.ltd.getahead.dwr.impl.DefaultProcessor下,我们可以看到详细的处理过程。
if (pathInfo.length() == 0 ||
pathInfo.equals(HtmlConstants.PATH_ROOT) ||
pathInfo.equals(req.getContextPath()))
{
resp.sendRedirect(req.getContextPath() + servletPath + HtmlConstants.FILE_INDEX);
}
else if (pathInfo.startsWith(HtmlConstants.FILE_INDEX))
{
index.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_TEST))
{
test.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_INTERFACE))
{
iface.handle(req, resp);
}
else if (pathInfo.startsWith(HtmlConstants.PATH_EXEC))
{
exec.handle(req, resp);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_ENGINE))
{
file.doFile(req, resp, HtmlConstants.FILE_ENGINE, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_UTIL))
{
file.doFile(req, resp, HtmlConstants.FILE_UTIL, HtmlConstants.MIME_JS);
}
else if (pathInfo.equalsIgnoreCase(HtmlConstants.FILE_DEPRECATED))
{
file.doFile(req, resp, HtmlConstants.FILE_DEPRECATED, HtmlConstants.MIME_JS);
}
else
{
log.warn("Page not found (" + pathInfo + "). In debug/test mode try viewing /[WEB-APP]/dwr/"); //$NON-NLS-1$ //$NON-NLS-2$
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
通过判断request请求的servlet路径,进行处理,大家可以自己去参看,这里不详细讨论。
2.bean转换器,<convert converter="bean" match="test.User"/>
将dwr.jar解压缩,在路径ukltdgetaheaddwr下可以看到dwr.xml,这里配置了系统默认的一些转换器,
<converter id="bean" class="uk.ltd.getahead.dwr.convert.BeanConverter"/>即是刚才用到User类的转换器,进入代码我们来看看它是如何在javascript和java间进行转换的。
打开BeanConverter代码,定位到函数
public Object convertInbound(Class paramType, InboundVariable iv, InboundContext inctx) throws ConversionException
即是将javascript对象转换成java对象的,其中
paramType即Class类型,在上面的例子中是test.User,
InboundVariable iv,是传入的值,通过iv.getValue可以得到传入的javascript值串
InboundContext inctx,是入口参数上下文,用于保存转换的后java对象。
因为前台传入的是一个javascript的map类型,而map肯定是以{开始和以}结束的,于是在这个函数一开始进行了判断
if (!value.startsWith(ConversionConstants.INBOUND_MAP_START))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingOpener", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
if (!value.endsWith(ConversionConstants.INBOUND_MAP_END))
{
throw new IllegalArgumentException(Messages.getString("BeanConverter.MissingCloser", ConversionConstants.INBOUND_MAP_START)); //$NON-NLS-1$
}
javascript中,map里各个项是用逗号连接的,如var userMap = {id:'admin',password:'123456',name:'chenbug',email:'chenbug@zj.com'};而每个项的键值对是用冒号连接的,
在convertInbound函数的接下来的处理中,即是通过分析map字串,通过paramType构造java实例(即User类),然后通过反射,将这些键值对设置到java实例中,并返回。
这样就完成了javascript到java的转换。
另一个函数
public String convertOutbound(Object data, String varname, OutboundContext outctx) throws ConversionException
即是将java对象转换为javascript对象(其实是声明和赋值语句)。
Object data ,是待转换的java对象
String varname,是javascript中的该对象的变量名
OutboundContext outctx,传出参数上下文,用于保存转换后的javascript值
StringBuffer buffer = new StringBuffer();
buffer.append("var "); //$NON-NLS-1$
buffer.append(varname);
buffer.append("={};"); //$NON-NLS-1$
这里声明了map类型的变量。
即下来来的代码即是通过反射进行变量赋值,如下
buffer.append(varname);
buffer.append('.');
buffer.append(name);
buffer.append('=');
buffer.append(nested.getAssignCode());
buffer.append(';');
大家可以自己去参看更多的代码。
3.dwr本身提供了一个测试环境,大家在配置完后,可以在IE中输入地址http://localhost/testApp/dwr/index.html,看到配置的各DWR组件,并进行相关测试。
|