字节流动 2014-10-23
核心Service

源代码文件说明
| 序号 | 文件名 | 说明 | 操作 |
| 1 | readme.md | 说明文档 | 更新 |
| 2 | log4j.properties | 日志属性文件 | 未更新 |
| 3 | BaseMessage.java | 消息基类 | 未更新 |
| 4 | TextMessage.java | 文本消息类 | 未更新 |
| 5 | SignUtil.java | 取Token服务类 | 未更新 |
| 6 | MessageUtil.java | 消息处理工具类 | 未更新 |
| 7 | CoreServlet.java | 核心Servlet,增加doPost()方法 | 未更新 |
| 8 | CoreService.java | 核心服务类,处理前台传过来的请求,并返回响应 | 更新 |
| 9 | web.xml | Web项目配置文件(这里主要配置Servlet的信息) | 未更新 |
| 10 | index.jsp | 首页文件,显示时间信息,主要用来判断工程是否部署成功 | 未更新 |
| 11 | Logging.java | 日志实体类 | 新增 |
| 12 | LoggingDao.java | 日志操作类 | 新增 |
| 13 | LoggingDaoTest.java | 日志测试类 | 新增 |
| 14 | EntitiesHelper.java | 测试辅助类 | 新增 |
| 15 | jdbc.properties | 数据库配置文件 | 新增 |
| 16 | DBUtil.java | 数据库工具类 | 新增 |
| 17 | logging.xml | 测试数据文件 | 新增 |
| 18 | logging_add.xml | 测试数据文件 | 新增 |
日志实体类
Logging.java
package com.coderdream.bean;
public class Logging {
// `id` int(11) NOT NULL AUTO_INCREMENT,
private int id;
// `log_date` datetime DEFAULT NULL,
// private Timestamp logDate; 由于MySQL不能存入带毫米数的Timestamp,这里直接存字符串
private String logDate;
// `log_level` varchar(64) DEFAULT NULL,
private String logLevel;
// `location` varchar(256) DEFAULT NULL,
private String location;
// `message` varchar(1024) DEFAULT NULL,
private String message;
public Logging() {
}
public Logging(int id, String logDate, String logLevel, String location, String message) {
this.id = id;
this.logDate = logDate;
this.logLevel = logLevel;
this.location = location;
this.message = message;
}
public Logging(String logDate, String logLevel, String location, String message) {
this.logDate = logDate;
this.logLevel = logLevel;
this.location = location;
this.message = message;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLogDate() {
return logDate;
}
public void setLogDate(String logDate) {
this.logDate = logDate;
}
public String getLogLevel() {
return logLevel;
}
public void setLogLevel(String logLevel) {
this.logLevel = logLevel;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "Logging [id=" + id + ", logDate=" + logDate + ", logLevel=" + logLevel + ", location=" + location
+ ", message=" + message + "]";
}
}日志操作类
LoggingDao.java
package com.coderdream.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.log4j.Logger;
import com.coderdream.bean.Logging;
import com.coderdream.util.DBUtil;
public class LoggingDao {
private String location;
public static String TAG = "LoggingDao";
private Logger logger = Logger.getLogger(LoggingDao.class);
public LoggingDao() {
}
public LoggingDao(String location) {
this.location = location;
}
public int addLogging(Logging logging) {
logger.debug(TAG + "###0###");
String sql = "INSERT INTO logging (log_date, log_level, location, message) VALUES (?,?,?,?)";
int count = 0;
Connection con = null;
PreparedStatement ps = null;
try {
con = DBUtil.getConnection();
logger.debug(TAG + con);
ps = con.prepareStatement(sql);
ps.setString(1, logging.getLogDate());
ps.setString(2, logging.getLogLevel());
ps.setString(3, logging.getLocation());
ps.setString(4, logging.getMessage());
count = ps.executeUpdate();
logger.debug(TAG + "count: " + count);
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(ps);
DBUtil.close(con);
}
return count;
}
public int debug(String message) {
if (!logger.isDebugEnabled()) {
return 0;
}
logger.debug(TAG + "###0###");
String sql = "INSERT INTO logging (log_date, log_level, location, message) VALUES (?,?,?,?)";
int count = 0;
Connection con = null;
PreparedStatement pre = null;
try {
con = DBUtil.getConnection();
logger.debug(TAG + " ###2### Connection: " + con);
pre = con.prepareStatement(sql);
logger.debug(TAG + " ###3### PreparedStatement: " + pre);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
String logTimestampStr = f_timestamp.format(date);
pre.setString(1, logTimestampStr);
pre.setString(2, "DEBUG");
pre.setString(3, location);
pre.setString(4, message);
count = pre.executeUpdate();
logger.debug(TAG + "###4### count: " + count);
} catch (Exception e) {
logger.debug(TAG + "###5### Exception: " + e.getMessage());
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
return count;
}
public static int debug(String location, String message) {
if (!Logger.getLogger(LoggingDao.class).isDebugEnabled()) {
return 0;
}
String sql = "INSERT INTO logging (log_date, log_level, location, message) VALUES (?,?,?,?)";
int count = 0;
Connection con = null;
PreparedStatement pre = null;
try {
con = DBUtil.getConnection();
pre = con.prepareStatement(sql);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
String logTimestampStr = f_timestamp.format(date);
pre.setString(1, logTimestampStr);
pre.setString(2, "DEBUG");
pre.setString(3, location);
pre.setString(4, message);
count = pre.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
return count;
}
public int error(String message) {
logger.debug(TAG + "###0###");
String sql = "INSERT INTO logging (log_date, log_level, location, message) VALUES (?,?,?,?)";
int count = 0;
Connection con = null;
PreparedStatement pre = null;
try {
con = DBUtil.getConnection();
logger.debug(TAG + con);
pre = con.prepareStatement(sql);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
String logTimestampStr = f_timestamp.format(date);
pre.setString(1, logTimestampStr);
pre.setString(2, "ERROR");
pre.setString(3, location);
pre.setString(4, message);
count = pre.executeUpdate();
logger.debug(TAG + "count: " + count);
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
return count;
}
public static int error(String location, String message) {
String sql = "INSERT INTO logging (log_date, log_level, location, message) VALUES (?,?,?,?)";
int count = 0;
Connection con = null;
PreparedStatement pre = null;
try {
con = DBUtil.getConnection();
pre = con.prepareStatement(sql);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
String logTimestampStr = f_timestamp.format(date);
pre.setString(1, logTimestampStr);
pre.setString(2, "ERROR");
pre.setString(3, location);
pre.setString(4, message);
count = pre.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
return count;
}
PreparedStatement pre;
ResultSet rs;
/**
* @author help
*
* 显示所有记录
* @return
*/
public List<Logging> findLoggings() {
String sql = "select * from logging order by id";
List<Logging> list = new ArrayList<Logging>();
// 获取prepareStatement对象
Connection con = null;
try {
con = DBUtil.getConnection();
pre = con.prepareStatement(sql);
rs = pre.executeQuery();
while (rs.next()) {
Logging logging = new Logging();
logging.setId(rs.getInt("id"));
logging.setLogDate(rs.getString("log_date"));
logging.setLogLevel(rs.getString("log_level"));
logging.setLocation(rs.getString("location"));
logging.setMessage(rs.getString("message"));
list.add(logging);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
return list;
}
/**
* @author help
*
* 显示所有记录
* @return
*/
public Logging findLogging(int id) {
String sql = "select * from logging where id=?";
List<Logging> list = new ArrayList<Logging>();
// 获取prepareStatement对象
Connection con = null;
try {
con = DBUtil.getConnection();
pre = con.prepareStatement(sql);
pre.setInt(1, id);
rs = pre.executeQuery();
while (rs.next()) {
Logging logging = new Logging();
logging.setId(rs.getInt("id"));
logging.setLogDate(rs.getString("log_date"));
logging.setLogLevel(rs.getString("log_level"));
logging.setLocation(rs.getString("location"));
logging.setMessage(rs.getString("message"));
list.add(logging);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(pre);
DBUtil.close(con);
}
if (null != list && 0 < list.size()) {
return list.get(0);
}
return null;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}日志操作测试类
LoggingDaoTest.java
package com.coderdream.dao;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.dbunit.Assertion;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.database.QueryDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.operation.DatabaseOperation;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import com.coderdream.bean.Logging;
import com.coderdream.util.DBUtil;
import com.coderdream.util.EntitiesHelper;
/**
* <pre>
* DBUnit使用步骤
* 1)下载地址为http://sourceforge.net/projects/dbunit/files/
* 2)导入DBUnit所需两个jar文件(dbunit.jar和slf4j-api.jar)
* 3)创建DBUnit用到的xml格式的测试数据,xml文件名建议与表名相同
* 4)创建DBUnit的Connection和DataSet,然后开始进行各项测试工作
*
* 使用注解@BeforeClass,在globalInit()执行打开数据库操作;
* 使用注解@AfterClass,在globalDestroy()执行数据库关闭操作;
*
* 使用注解@Before,每次测试执行之前都先执行init()操作;
* 使用注解@After,每次测试执行之后都会执行destroy()操作;
*
* DBUtil提供数据库操作方法。
* </pre>
*
* @author CoderDream
* @date 2014年10月15日
*
*/
public class LoggingDaoTest {
public static String TAG = "LoggingDaoTest";
private static final Logger logger = LoggerFactory.getLogger(LoggingDaoTest.class);
private static Connection conn;
private static IDatabaseConnection dbUnitConn;
private static String DATA_BACKUP_FILE = "dataBackup_logging.xml";
private static String LOGGING_DATA_FILE = "logging.xml";
@BeforeClass
public static void globalInit() {
conn = DBUtil.getConnection();
System.out.println("DB-Unit Get Connection: " + conn);
try {
// DBUnit中用来操作数据文件的Connection需依赖于数据库连接的Connection
dbUnitConn = new DatabaseConnection(conn);
} catch (DatabaseUnitException e) {
e.printStackTrace();
}
}
@AfterClass
public static void globalDestroy() {
DBUtil.close(conn);
if (null != dbUnitConn) {
try {
dbUnitConn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 备份数据库中某一张或某几张表的数据,同时将xml文件中的数据插入到数据库中
*/
@Before
public void init() throws Exception {
logger.debug("Before #### init");
// 通过QueryDataSet可以有效的选择要处理的表来作为DataSet
QueryDataSet dataSet = new QueryDataSet(dbUnitConn);
// 这里指定只备份t_logging表中的数据,如果想备份多个表,那就再addTable(tableName)即可
dataSet.addTable("logging");
FlatXmlDataSet.write(dataSet, new FileWriter(DATA_BACKUP_FILE));
}
/**
* 还原表数据
*/
@After
public void destroy() throws Exception {
IDataSet dataSet = new FlatXmlDataSet(new FlatXmlProducer(
new InputSource(new FileInputStream(DATA_BACKUP_FILE))));
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConn, dataSet);
}
/**
* <pre>
* 测试查询方法
* DatabaseOperation类的几个常量值
* CLEAN_INSERT----先删除数据库中的所有数据,然后将xml中的数据插入数据库
* DELETE----------如果数据库存在与xml记录的相同的数据,则删除数据库中的该条数据
* DELETE_ALL------删除数据库中的所有数据
* INSERT----------将xml中的数据插入数据库
* NONE------------nothing to do
* REFRESH---------刷新数据库中的数据
* TRUNCATE_TABLE--清空表中的数据
* UPDATE----------将数据库中的那条数据更新为xml中的数据
* </pre>
*/
@Test
public void testFindLogging() throws Exception {
IDataSet dataSet = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(LoggingDaoTest.class.getClassLoader()
.getResourceAsStream(LOGGING_DATA_FILE))));
DatabaseOperation.TRUNCATE_TABLE.execute(dbUnitConn, dataSet);
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConn, dataSet);
// 下面开始数据测试
LoggingDao loggingDao = new LoggingDao();
Logging logging = loggingDao.findLogging(1);
// 预想结果和实际结果的比较
EntitiesHelper.assertLogging(logging);
}
/**
* 更新,添加,删除等方法,可以利用Assertion.assertEquals() 方法,拿表的整体来比较。
*/
@Test
public void testAddLogging() throws Exception {
IDataSet dataSet = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(LoggingDaoTest.class.getClassLoader()
.getResourceAsStream(LOGGING_DATA_FILE))));
DatabaseOperation.TRUNCATE_TABLE.execute(dbUnitConn, dataSet);
DatabaseOperation.CLEAN_INSERT.execute(dbUnitConn, dataSet);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String time = df.format(new Date(1413993830024l));
// Timestamp ts = Timestamp.valueOf(time);
String logStr = "FirstLogging";
// 被追加的记录
Logging newLogging = new Logging(time, "DEBUG", TAG, logStr);
// 执行追加 addLogging 方法
LoggingDao loggingDao = new LoggingDao();
int result = loggingDao.addLogging(newLogging);
Assert.assertEquals(1, result);
// 预期结果取得
IDataSet expectedDataSet = new FlatXmlDataSet(new FlatXmlProducer(new InputSource(LoggingDaoTest.class
.getClassLoader().getResourceAsStream("logging_add.xml"))));
ITable expectedTable = expectedDataSet.getTable("logging");
// 实际结果取得(取此时数据库中的数据)
// Creates a dataset corresponding to the entire database
IDataSet databaseDataSet = dbUnitConn.createDataSet();
ITable actualTable = databaseDataSet.getTable("logging");
// 预想结果和实际结果的比较
Assertion.assertEquals(expectedTable, actualTable);
}
}测试辅助类
EntitiestHelper.java
package com.coderdream.util;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.junit.Assert;
import com.coderdream.bean.Logging;
public class EntitiesHelper {
public static void assertLogging(Logging expected, Logging actual) {
Assert.assertNotNull(expected);
Assert.assertEquals(expected.getId(), actual.getId());
Assert.assertEquals(expected.getLogDate(), actual.getLogDate());
Assert.assertEquals(expected.getLogLevel(), actual.getLogLevel());
Assert.assertEquals(expected.getLocation(), actual.getLocation());
Assert.assertEquals(expected.getMessage(), actual.getMessage());
}
public static void assertLogging(Logging expected) {
String logStr = "InitLogging";
// Timestamp sDate = new Timestamp(1413993830024l);
// 2014-10-23 00:03:50.024
// time: 1413993830024
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String time = df.format(new Date(1413993830024l));
Logging baseLogging = new Logging(1, time, "DEBUG", "LoggingDaoTest", logStr);
assertLogging(expected, baseLogging);
}
}数据库工具类
DBUtil.java
package com.coderdream.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
public class DBUtil {
public static Connection getConnection() {
Connection con = null;
Properties prop = new Properties();// 属性集合对象
InputStream fis;
try {
fis = DBUtil.class.getClassLoader().getResourceAsStream(
"jdbc.properties");
prop.load(fis);// 将属性文件流装载到Properties对象中
String driver = prop.getProperty("driver");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
String url = prop.getProperty("url");// 使用从库的域名
Map<String, String> envMap = System.getenv();
String os = envMap.get("OS");
// local
if (null != os && "Windows_NT".equals(os.trim())) {
username = prop.getProperty("local.username");
password = prop.getProperty("local.password");
url = prop.getProperty("local.url");
}
// SAE
else {
username = prop.getProperty("sae.username");
password = prop.getProperty("sae.password");
url = prop.getProperty("sae.url");
}
Class.forName(driver).newInstance();
con = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
public static void close(Connection con) {
try {
if (null != con) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(PreparedStatement ps) {
try {
if (null != ps) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(ResultSet rs) {
try {
if (null != rs) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}核心服务类
CoreService.java
package com.coderdream.service;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import org.apache.log4j.Logger;
import com.coderdream.bean.Logging;
import com.coderdream.dao.LoggingDao;
import com.coderdream.model.TextMessage;
import com.coderdream.util.MessageUtil;
/**
* 核心服务类
*/
public class CoreService {
public static String TAG = "CoreService";
private Logger logger = Logger.getLogger(CoreService.class);
/**
* 处理微信发来的请求
*
* @param request
* @return xml
*/
public String processRequest(InputStream inputStream) {
logger.debug(TAG + " #1# processRequest");
//Timestamp sDate = new Timestamp(Calendar.getInstance().getTime().getTime());
Date date = Calendar.getInstance().getTime();
SimpleDateFormat f_timestamp = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
String logTimestampStr = f_timestamp.format(date);
Logging logging = new Logging(logTimestampStr, "DEBUG", TAG, "#1# processRequest");
LoggingDao loggingDao = new LoggingDao();
loggingDao.addLogging(logging);
// xml格式的消息数据
String respXml = null;
// 默认返回的文本消息内容
String respContent = "未知的消息类型!";
try {
// 调用parseXml方法解析请求消息
Map<String, String> requestMap = MessageUtil.parseXml(inputStream);
// 发送方帐号
String fromUserName = requestMap.get("FromUserName");
// 开发者微信号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType");
String logStr = "#2# fromUserName: " + fromUserName + ", toUserName: " + toUserName + ", msgType: "
+ msgType;
logger.debug(TAG + logStr);
logging = new Logging(logTimestampStr, "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.MESSAGE_TYPE_TEXT);
logStr = "#3# textMessage: " + textMessage.toString();
logger.debug(TAG + logStr);
logging = new Logging(logTimestampStr, "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 文本消息
if (msgType.equals(MessageUtil.MESSAGE_TYPE_TEXT)) {
respContent = "您发送的是文本消息!";
}
logStr = "#4# respContent: " + respContent;
logger.debug(TAG + logStr);
logging = new Logging(logTimestampStr, "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
// 设置文本消息的内容
textMessage.setContent(respContent);
// 将文本消息对象转换成xml
respXml = MessageUtil.messageToXml(textMessage);
logStr = "#5# respXml: " + respXml;
logger.debug(TAG + logStr);
logging = new Logging(logTimestampStr, "DEBUG", TAG, logStr);
loggingDao.addLogging(logging);
} catch (Exception e) {
e.printStackTrace();
}
return respXml;
}
}Maven工程文件
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.coderdream</groupId>
<artifactId>wxquan</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>wxquan Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<junit.version>4.11</junit.version>
<servlet.api.version>2.5</servlet.api.version>
<jsp.api.version>2.1</jsp.api.version>
<slf4j.version>1.7.5</slf4j.version>
<dom4j.version>1.6.1</dom4j.version>
<xstream.version>1.4.7</xstream.version>
<mysql.version>5.1.17</mysql.version>
<dbunit.version>2.4.9</dbunit.version>
</properties>
<dependencies>
<!-- 测试的时候用到,打包的时候没有 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- 编译的时候用到,打包的时候没有 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.api.version}</version>
<scope>provided</scope>
</dependency>
<!-- 编译的时候用到,打包的时候没有 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.api.version}</version>
<scope>provided</scope>
</dependency>
<!-- 日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- 打包的时候剔除 xml-apis-1.0.b2.jar SAE中不支持 -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
<exclusions>
<exclusion>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 打包的时候剔除 xml-apis-1.0.b2.jar SAE中不支持 -->
<!-- 这个jar必须用1.4.7的高版本,否则SAE不支持 -->
<!-- 详细原因:http://blog.csdn.net/lyq8479/article/details/38878543 -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>${xstream.version}</version>
</dependency>
<!-- 编译的时候用到,打包的时候没有,SAE已包含此jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>${dbunit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>wxquan</finalName>
</build>
</project>将新增和修改过的代码上传到GitHub

将eclipse中的工程导出为wxquan.war档,上传到SAE中,更新已有的版本。
登录微信网页版:https://wx.qq.com/
输入“测试”,返回“您发送的是文本消息”。
查询SAE数据库,发现logging表中已写入相关数据:
完整源代码