目录结构
- 项目结构图
- 增加相关源代码
- 日志实体类
- 日志访问类
- 日志访问测试类
- 测试工具类
- 数据库工具类
-
核心Service
- Maven工程文件
- 上传本地代码到GitHub
- 上传工程WAR档至SAE
- 微信客户端测试
- 查看SAE数据库
- 参考文档
- 完整项目源代码
项目结构图
源代码文件说明
序号 | 文件名 | 说明 | 操作 |
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
将新增和修改过的代码上传到GitHub
上传工程WAR档至SAE
将eclipse中的工程导出为wxquan.war档,上传到SAE中,更新已有的版本。
微信客户端测试
登录微信网页版:https://wx.qq.com/
输入“测试”,返回“您发送的是文本消息”。
查看SAE数据库
查询SAE数据库,发现logging表中已写入相关数据:
参考文档
完整源代码
相关推荐
私信博主免费获取真题解析以及代码
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
23-22.渗透测试-敏感信息收集工具汇总.mp4
ZCANPRO安装包
单片机外文翻译at89s52单片机单片机.doc
基于AT89S52单片机的数字温度计设计.doc
私信博主免费获取真题解析以及代码
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Screenshot_2024-05-10-20-21-01-857_com.chaoxing.mobile.jpg
Android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的移动操作系统,主要应用于移动设备,如智能手机和平板电脑。该系统最初由安迪·鲁宾开发,后被Google公司收购并注资,随后与多家硬件制造商、软件开发商及电信营运商共同研发改良。 Android操作系统的特点包括: 开放源代码:Android系统采用开放源代码模式,允许开发者自由访问、修改和定制操作系统,这促进了技术的创新和发展,使得Android系统具有高度的灵活性和可定制性。 多任务处理:Android允许用户同时运行多个应用程序,并且可以轻松地在不同应用程序之间切换,提高了效率和便利性。 丰富的应用生态系统:Android系统拥有庞大的应用程序生态系统,用户可以从Google Play商店或其他第三方应用市场下载和安装各种各样的应用程序,满足各种需求。 可定制性:Android操作系统可以根据用户的个人喜好进行定制,用户可以更改主题、小部件和图标等,以使其界面更符合个人风格和偏好。 多种设备支持:Android操作系统可以运行在多种不同类型的设备上,包括手机、平板电脑、智能电视、汽车导航系统等。 此外,Android系统还有一些常见的问题,如应用崩溃、电池耗电过快、Wi-Fi连接问题、存储空间不足、更新问题等。针对这些问题,用户可以尝试一些基本的解决方法,如清除应用缓存和数据、降低屏幕亮度、关闭没有使用的连接和传感器、限制后台运行的应用、删除不需要的文件和应用等。 随着Android系统的不断发展,其功能和性能也在不断提升。例如,最新的Android版本引入了更多的安全性和隐私保护功能,以及更流畅的用户界面和更强大的性能。此外,Android系统也在不断探索新的应用场景,如智能家居、虚拟现实、人工智能等领域。 总之,Android系统是一种功能强大、灵活可定制、拥有丰富应用生态系统的移动操作系统,在全球范围内拥有广泛的用户基础。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的移动操作系统,主要应用于移动设备,如智能手机和平板电脑。该系统最初由安迪·鲁宾开发,后被Google公司收购并注资,随后与多家硬件制造商、软件开发商及电信营运商共同研发改良。 Android操作系统的特点包括: 开放源代码:Android系统采用开放源代码模式,允许开发者自由访问、修改和定制操作系统,这促进了技术的创新和发展,使得Android系统具有高度的灵活性和可定制性。 多任务处理:Android允许用户同时运行多个应用程序,并且可以轻松地在不同应用程序之间切换,提高了效率和便利性。 丰富的应用生态系统:Android系统拥有庞大的应用程序生态系统,用户可以从Google Play商店或其他第三方应用市场下载和安装各种各样的应用程序,满足各种需求。 可定制性:Android操作系统可以根据用户的个人喜好进行定制,用户可以更改主题、小部件和图标等,以使其界面更符合个人风格和偏好。 多种设备支持:Android操作系统可以运行在多种不同类型的设备上,包括手机、平板电脑、智能电视、汽车导航系统等。 此外,Android系统还有一些常见的问题,如应用崩溃、电池耗电过快、Wi-Fi连接问题、存储空间不足、更新问题等。针对这些问题,用户可以尝试一些基本的解决方法,如清除应用缓存和数据、降低屏幕亮度、关闭没有使用的连接和传感器、限制后台运行的应用、删除不需要的文件和应用等。 随着Android系统的不断发展,其功能和性能也在不断提升。例如,最新的Android版本引入了更多的安全性和隐私保护功能,以及更流畅的用户界面和更强大的性能。此外,Android系统也在不断探索新的应用场景,如智能家居、虚拟现实、人工智能等领域。 总之,Android系统是一种功能强大、灵活可定制、拥有丰富应用生态系统的移动操作系统,在全球范围内拥有广泛的用户基础。
2024-2030中国防水和修复服务市场现状研究分析与发展前景预测报告
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
37-37.XSS跨站脚本攻击概念介绍.mp4
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
51单片机课程设计-温度传感器
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。