0.目录结构:
1.jar包准备:
2.web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>w-mis</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
<filter>
<display-name>EncodingFilter</display-name>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.jinmayi.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<display-name>TranactionFilter</display-name>
<filter-name>TranactionFilter</filter-name>
<filter-class>com.jinmayi.filter.TranactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TranactionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Log4jInit</servlet-name>
<servlet-class>com.jinmayi.filter.Log4jInit</servlet-class>
<init-param>
<param-name>log4j</param-name><!-- //这个是名字是下边路径配置的标识(好像KEY一样) -->
<param-value>/WEB-INF/classes/log4j.properties</param-value><!-- //这是容器初始化时候加载log4j配置文件的路径(这好像一个value); -->
</init-param>
</servlet>
<filter>
<display-name>Log4jInit</display-name>
<filter-name>Log4jInit</filter-name>
<filter-class>com.jinmayi.filter.Log4jInit</filter-class>
</filter>
<filter-mapping>
<filter-name>Log4jInit</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3.c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="loginpnfy">
<property name="user">root</property>
<property name="password">123</property>
<property name="jdbcUrl">jdbc:mysql:///w-mis</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="acquireIncrement">2</property>
<property name="initialPoolSize">50</property>
<property name="minPoolSize">20</property>
<property name="maxPoolSize">100</property>
<property name="maxStatements">100</property>
<property name="maxStatementsPerConnection">100</property>
</named-config>
</c3p0-config>
4.log4j.properties
log4j.rootLogger = debug,E
log4j.appender.E= org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =${catalina.home}/logs/log_
log4j.appender.E.DatePattern=yyyy-MM-dd'.log'
#log4j.appender.E.Threshold =DEBUG
log4j.appender.E.Threshold =INFO
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern =%-d{yyyy-MM-dd HH\:mm\:ss}[%c] [%t\:%r] - [%p] %m%n
5.Dao.java接口
package com.jinmayi.dao;
import java.util.List;
/**
* Dao 接口, 定义 Dao 的基本操作, 由 BaseDao 提供实现.
*
* @param <T>: Dao 实际操作的泛型类型
*/
public interface Dao<T> {
/**
* 执行 INSERT 操作, 返回插入后的记录的 ID
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
* @return: 插入新记录的 id
*/
int insert(String sql, Object... args);
/**
* 执行 UPDATE 操作, 包括 INSERT(但没有返回值), UPDATE, DELETE
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
*/
void update(String sql, Object... args);
/**
* 执行单条记录的查询操作, 返回与记录对应的类的一个对象
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
* @return: 与记录对应的类的一个对象
*/
T query(String sql, Object... args);
/**
* 执行多条记录的查询操作, 返回与记录对应的类的一个 List
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
* @return: 与记录对应的类的一个 List
*/
List<T> queryForList(String sql, Object... args);
/**
* 执行一个属性或值的查询操作, 例如查询某一条记录的一个字段, 或查询某个统计信息, 返回要查询的值
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
* @return: 执行一个属性或值的查询操作, 例如查询某一条记录的一个字段, 或查询某个统计信息, 返回要查询的值
*/
<V> V getSingleVal(String sql, Object... args);
/**
* 执行批量更新操作
*
* @param sql
* : 待执行的 SQL 语句
* @param args
* : 填充占位符的可变参数
*/
void batch(String sql, Object[]... params);
}
6.BaseDao.java
package com.jinmayi.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.jinmayi.dao.Dao;
import com.jinmayi.db.JDBCUtils;
import com.jinmayi.util.ReflectionUtils;
import com.jinmayi.web.ConnectionContext;
public class BaseDao<T> implements Dao<T> {
private QueryRunner queryRunner = new QueryRunner();
private Class<T> clazz;
public BaseDao() {
clazz = ReflectionUtils.getSuperGenericType(getClass());
}
@Override
public int insert(String sql, Object... args) {
int id = 0;
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = ConnectionContext.getInstance().get();
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
if(args != null){
for(int i = 0; i < args.length; i++){
preparedStatement.setObject(i + 1, args[i]);
}
}
preparedStatement.executeUpdate();
//获取生成的主键值
resultSet = preparedStatement.getGeneratedKeys();
if(resultSet.next()){
id = resultSet.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
JDBCUtils.release(resultSet, preparedStatement);
}
return id;
}
@Override
public void update(String sql, Object... args) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();
queryRunner.update(connection, sql, args);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public T query(String sql, Object... args) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();
return queryRunner.query(connection, sql, new BeanHandler<T>(clazz), args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public List<T> queryForList(String sql, Object... args) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();
return queryRunner.query(connection, sql, new BeanListHandler<T>(clazz), args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public <V> V getSingleVal(String sql, Object... args) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();
return (V)queryRunner.query(connection, sql, new ScalarHandler(), args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public void batch(String sql, Object[]... params) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();
queryRunner.batch(connection, sql, params);
} catch (Exception e) {
e.printStackTrace();
}
}
}
7.JDBCUtils.java
package com.jinmayi.db;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.jinmayi.exception.DBException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
*
* JDBC 的工具类
*
*/
public class JDBCUtils {
private static DataSource dataSource = null;
static{
dataSource = new ComboPooledDataSource("loginpnfy");
}
//获取数据库连接
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new DBException("数据库连接错误!");
}
}
//关闭数据库连接
public static void release(Connection connection) {
try {
if(connection != null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
throw new DBException("数据库连接错误!");
}
}
//关闭数据库连接
public static void release(ResultSet rs, Statement statement) {
try {
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
throw new DBException("数据库连接错误!");
}
try {
if(statement != null){
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
throw new DBException("数据库连接错误!");
}
}
}
8.Page.java
package com.jinmayi.domain;
import java.util.List;
public class Page<T> {
// 当前第几页
private Long pageNow;
// 当前页的 List
private List<T> list;
// 每页显示多少条记录
private long pageSize = 10;
// 共有多少条记录
private long totalItemNumber;
// 构造器中需要对 pageNow 进行初始化
public Page(Long pageNow) {
super();
this.pageNow = pageNow;
}
// 需要校验一下
public long getpageNow() {
if (pageNow <= 0)
pageNow = 1l;
if (getTotalPageNumber() != 0 && pageNow > getTotalPageNumber()) {
pageNow = getTotalPageNumber();
}
return pageNow;
}
public long getPageSize() {
return pageSize;
}
public long setPageSize(long pageSize) {
return this.pageNow = pageSize;
}
public void setList(List<T> list) {
this.list = list;
}
public List<T> getList() {
return list;
}
// 获取总页数
public Long getTotalPageNumber() {
long totalPageNumber = totalItemNumber / pageSize;
if (totalItemNumber % pageSize != 0) {
totalPageNumber++;
}
return totalPageNumber;
}
public void setTotalItemNumber(long totalItemNumber) {
this.totalItemNumber = totalItemNumber;
}
public boolean isHasNext() {
if (getpageNow() < getTotalPageNumber()) {
return true;
}
return false;
}
public boolean isHasPrev() {
if (getpageNow() > 1) {
return true;
}
return false;
}
public long getPrevPage() {
if (isHasPrev()) {
return getpageNow() - 1;
}
return getpageNow();
}
public long getNextPage() {
if (isHasNext()) {
return getpageNow() + 1;
}
return getpageNow();
}
@Override
public String toString() {
return "Page [pageNow=" + pageNow + ", list=" + list + ", pageSize="
+ pageSize + ", totalItemNumber=" + totalItemNumber + "]";
}
}
9.DBException.java
package com.jinmayi.exception;
public class DBException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public DBException() {
// TODO Auto-generated constructor stub
}
public DBException(String msg) {
super(msg);
}
public DBException(String msg, Exception ex) {
super(msg, ex);
}
}
10.EncodingFilter.java
package com.jinmayi.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Servlet Filter implementation class EncodingFilter
*/
public class EncodingFilter implements Filter {
/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String encoding = filterConfig.getServletContext().getInitParameter("encoding");
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
private FilterConfig filterConfig = null;
@Override
public void init(FilterConfig fConfig) throws ServletException {
this.filterConfig = fConfig;
}
}
11.Log4jInit.java
package com.jinmayi.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.PropertyConfigurator;
public class Log4jInit extends HttpServlet implements Filter {
/**
*
*/
private static final long serialVersionUID = 1L;
private Log log = LogFactory.getLog(this.getClass());
private String filterName;
@Override
public void destroy() {
super.destroy();
}
public Log4jInit() {
super();
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occurs
*/
@Override
public void init() throws ServletException {
String file = this.getInitParameter("log4j");// 从web.xml配置读取,名字一定要和web.xml配置一致
if (file != null) {
PropertyConfigurator.configure(file);
}
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
long startTime = System.currentTimeMillis(); //运行前的时间
String requestURI = request.getRequestURI(); //获取访问的URI
requestURI = request.getQueryString() == null ? requestURI //所有的地址栏参数对比
: (requestURI + "?" + request.getQueryString());
chain.doFilter(request, response);
long endTime = System.currentTimeMillis();
//消耗的总时间
log.info(request.getRemoteAddr() + " " + requestURI + " "+ (endTime - startTime) + " " + request.getHeader("user-agent") + " " + response.getStatus());//时间单位:毫秒
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
filterName = filterConfig.getFilterName();//获取 Filter的 name,启动Filter
log.info("启动 Filter: " + filterName);//
log.info("ip, 请求的内容, 响应的时间, 电脑及浏览器的版本, 返回的状态码");
}
}
12.TranactionFilter.java
package com.jinmayi.filter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jinmayi.db.JDBCUtils;
import com.jinmayi.web.ConnectionContext;
/**
* Servlet Filter implementation class TranactionFilter
*/
public class TranactionFilter implements Filter {
/**
* Default constructor.
*/
public TranactionFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Connection connection = null;
try {
// 1. 获取连接
connection = JDBCUtils.getConnection();
// 2. 开启事务
connection.setAutoCommit(false);
// 3. 利用 ThreadLocal 把连接和当前线程绑定
ConnectionContext.getInstance().bind(connection);
// 4. 把请求转给目标 Servlet
chain.doFilter(request, response);
// 5. 提交事务
connection.commit();
} catch (Exception e) {
e.printStackTrace();
// 6. 回滚事务
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
HttpServletResponse resp = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
resp.sendRedirect(req.getContextPath() + "/error-1.jsp");
} finally {
// 7. 解除绑定
ConnectionContext.getInstance().remove();
// 8. 关闭连接
JDBCUtils.release(connection);
}
}
/**
* @see Filter#init(FilterConfig)
*/
@Override
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
13.ReflectionUtils.java
package com.jinmayi.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 反射的 Utils 函数集合 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
*
* @author Administrator
*
*/
public class ReflectionUtils {
/**
* 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型 如: public EmployeeDao extends
* BaseDao<Employee, String>
*
* @param clazz
* @param index
* @return
*/
public static Class<?> getSuperClassGenricType(Class<?> clazz, int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0) {
return Object.class;
}
if (!(params[index] instanceof Class)) {
return Object.class;
}
return (Class<?>) params[index];
}
/**
* 通过反射, 获得 Class 定义中声明的父类的泛型参数类型 如: public EmployeeDao extends
* BaseDao<Employee, String>
*
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getSuperGenericType(Class<?> clazz) {
return (Class<T>) getSuperClassGenricType(clazz, 0);
}
/**
* 循环向上转型, 获取对象的 DeclaredMethod
*
* @param object
* @param methodName
* @param parameterTypes
* @return
*/
public static Method getDeclaredMethod(Object object, String methodName,
Class<?>[] parameterTypes) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
// superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
// Method 不在当前类定义, 继续向上转型
}
// ..
}
return null;
}
/**
* 使 filed 变为可访问
*
* @param field
*/
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers())) {
field.setAccessible(true);
}
}
/**
* 循环向上转型, 获取对象的 DeclaredField
*
* @param object
* @param filedName
* @return
*/
public static Field getDeclaredField(Object object, String filedName) {
for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
// Field 不在当前类定义, 继续向上转型
}
}
return null;
}
/**
* 直接调用对象方法, 而忽略修饰符(private, protected)
*
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
* @return
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static Object invokeMethod(Object object, String methodName,
Class<?>[] parameterTypes, Object[] parameters)
throws InvocationTargetException {
Method method = getDeclaredMethod(object, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("Could not find method ["
+ methodName + "] on target [" + object + "]");
}
method.setAccessible(true);
try {
return method.invoke(object, parameters);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return null;
}
/**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
*
* @param object
* @param fieldName
* @param value
*/
public static void setFieldValue(Object object, String fieldName,
Object value) {
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field ["
+ fieldName + "] on target [" + object + "]");
makeAccessible(field);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
}
/**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
*
* @param object
* @param fieldName
* @return
*/
public static Object getFieldValue(Object object, String fieldName) {
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field ["
+ fieldName + "] on target [" + object + "]");
makeAccessible(field);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return result;
}
}
14.ConnectionContext.java
package com.jinmayi.web;
import java.sql.Connection;
public class ConnectionContext {
private ConnectionContext(){}
private static ConnectionContext instance = new ConnectionContext();
public static ConnectionContext getInstance() {
return instance;
}
private ThreadLocal<Connection> connectionThreadLocal =
new ThreadLocal<Connection>();
public void bind(Connection connection){
connectionThreadLocal.set(connection);
}
public Connection get(){
return connectionThreadLocal.get();
}
public void remove(){
connectionThreadLocal.remove();
}
}