JSP+SerVlet,对Servlet和Dao层进行优化,抽取出共同代码
只实现了简单的登录和注册,用户名查重、记住用户名和密码、验证码、表单校验并没有实现
GitHub源码地址
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/**
* 对应数据库中的user表
*/
public class User {
private Integer id;
private String username;
private String password;
public User(Integer id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
// 无参构造函数必须得有
public User() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
使用 JDBC + c3p0 获取数据库连接
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
导包并右键 add as library
JDBCUtils
/**
* 获取数据库连接的工具类
*
* @author smallbeef
*
*/
public class JDBCUtils {
// 此处要与c3p0的配置文件中的name一致
private static ComboPooledDataSource dataSource = new ComboPooledDataSource(
"c3p0Config");
private JDBCUtils() {
}
/**
* 获取数据库连接
*
* @return 如果获取连接成功,返回数据的连接对象。
* 如果获取数据库连接失败,则返回null
*/
public static Connection getConnection() {
Connection connection = null;
try {
// 从c3p0中获取数据库连接
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 释放数据库连接
*/
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
getConnection();
}
}
c3p0-config.xml
<c3p0-config>
<named-config name="c3p0Config">
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/userandbookproperty>
<property name="user">rootproperty>
<property name="password">rootproperty>
<property name="maxPoolSize">10property>
<property name="minPoolSize">5property>
<property name="initialPoolSize">3property>
<property name="idleConnectionTestPeriod">3600property>
<property name="acquireIncrement">5property>
<property name="maxIdleTime">50property>
named-config>
c3p0-config>
应当把
c3p0-config.xml
放在src
下,不然new ComboPooledDataSource(“configName");
可能会找不到c3p0-config.xml
文件
数据库连接测试
public class JDBCUtilTest {
@Test
public void testGetConnection() {
Connection conn = JDBCUtils.getConnection();
System.out.println(conn);
JDBCUtils.closeConnection(conn);
}
}
导包:DButils
使用 DBUtils的QueryRunner.update / query
方法实现增删改查
DbUtils是一种 JDBC Utility Component (翻译过来大概就是:JDBC实用部件),故名思意,和数据库操作有关。官网上的简介也称之为 JDBC helper library ,由此可知,DbUtils是一个工具类库,用来进行数据库通信的
【JavaWeb】DbUtils入门之QueryRunner
BaseDao
public class BaseDao<T> {
// 需要获取实际的type
private Class<T> type;
private QueryRunner queryRunner = new QueryRunner();
public BaseDao(){
// 获取父类的类型,父类是带参数的
ParameterizedType superclass = (ParameterizedType) this.getClass().getGenericSuperclass();
System.out.println(superclass.getClass());
// 获取泛型中的具体的类型的class
type = (Class<T>) superclass.getActualTypeArguments()[0];
}
/**
* 获取一个对象
* @param sql sql语句
* @param params 可变参数
* @return
*/
public T getBean(String sql, Object...params){
Connection connection = JDBCUtils.getConnection();
T query = null;
try {
// 查询一个数据,BeanHandler封装一个对象
query = queryRunner.query(connection,sql,new BeanHandler<>(type),params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeConnection(connection);
}
return query;
}
/**
* 获取对象的集合
* @return
*/
public List<T> getBeanList(String sql, Object...params){
Connection connection = JDBCUtils.getConnection();
List<T> query = null;
try {
// 查询一组数据,BeanListHandler封装一组对象
query = queryRunner.query(connection,sql,new BeanListHandler<>(type),params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeConnection(connection);
}
return query;
}
/**
* 执行增删改
*/
public int update(String sql, Object ...params){
int count = 0;
Connection connection = JDBCUtils.getConnection();
try {
count = queryRunner.update(connection, sql, params);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.closeConnection(connection);
}
return count;
}
}
UserDao接口
用 UserDaoImpl
实现/**
* UserDAO具体的实现类
*
* @author smallbeef
*
*/
public class UserDaoImp extends BaseDao<User> implements UserDao {
/**
* 按照用户名和密码查询信息
* @param user
* @return
*/
@Override
public User getUserByUserNameAndPassWord(User user) {
String sql = "select id,username,password from user where username = ? and password = ?";
User bean = this.getBean(sql, user.getUsername(), user.getPassword());
return bean;
}
/**
* 注册 保存用户
* @param user
* @return
*/
@Override
public boolean registUser(User user) {
String sql = "insert into user(`id`,`username`,`password`) values(null, ?, ?)";
int update = this.update(sql, user.getUsername(), user.getPassword());
if(update>0){
return true;
}else
return false;
}
}
public class UserServiceImp implements UserService {
private UserDao ud = new UserDaoImp();
@Override
public User login(User user) {
return ud.getUserByUserNameAndPassWord(user);
}
@Override
public boolean regist(User user) {
return ud.registUser(user);
}
}
一般是建立 LoginServlet
和 RegistServlet
, 注册和登录界面表单分别调用不同的servlet。
此处我们希望一个UserServlet
就能够处理注册和登录请求,让用户的注册和登录请求都经过同一个Userservlet,而不是分别经过loginservlet和registservlet。
实现方法:给form表单带上method参数请求UserServlet,UserServlet通过这个参数判断是注册请求还是登录请求
<form action="/UserServlet?method=login" method="post">
<form action="/UserServlet?method=regist" method="post">
@WebServlet(name = "UserServlet", urlPatterns = "/UserServlet")
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String method = request.getParameter("method");
System.out.println(method);
if("regist".equals(method)){
//注册
regist(request,response);
}
if("login".equals(method)){
//登录
login(request,response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
private UserService us = new UserServiceImp();
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
boolean b = us.regist(new User(null, username, password));
if(b){
//注册成功,返回成功页面,重定向
request.getRequestDispatcher("/pages/regist_success.html").forward(request,response);
}else{
//注册失败,返回失败页面,转发
response.sendRedirect(request.getContextPath()+"/pages/error.jsp");
}
}
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = us.login(new User(null, username, password));
if(user == null){
//登录失败,返回登录页面,转发(换界面)
request.getRequestDispatcher("/pages/error.jsp").forward(request,response);
}else{
//登录成功,返回成功界面 重定向(直接刷新界面)
response.sendRedirect(request.getContextPath() + "/pages/login_success.html");
}
}
}
为了不陷入层层的if判断,我们利用反射来优化此代码
反射:你指定一个方法名,我找到这个方法并直接调用)
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取要调用的方法
String method = request.getParameter("method");
System.out.println(method);
// getDeclaredMethod(方法名,参数列表(传的是各个参数的类))
// 通过反射找到该方法并调用
try {
Method declaredMethod = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
// 把方法权限设大
declaredMethod.setAccessible(true);
// invoke(对象,参数) 执行该方法
declaredMethod.invoke(this,request,response);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// if("regist".equals(method)){
// //注册
// regist(request,response);
// }
// if("login".equals(method)){
// //登录
// login(request,response);
// }
}
所有的servlet都是通过反射来调用相应的方法,所以我们可以抽取出一个BaseServlet
抽取之后Userservlet只需要编写相关逻辑代码就可以了,以后定义的任何方法只需要在form表单上带上方法名即可
BaseServlet
public class BaseServlet extends HttpServlet {
// @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
// @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 解决post乱码问题,设置请求的参数字符集为UTf-8
request.setCharacterEncoding("UTF-8");
// 获取要调用的方法
String method = request.getParameter("method");
System.out.println(method);
// 通过反射找到该方法并调用
// getDeclaredMethod(方法名,参数列表(传的是各个参数的类))
try {
Method declaredMethod = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
// 把方法权限设大
declaredMethod.setAccessible(true);
// invoke(对象,参数) 执行该方法
declaredMethod.invoke(this,request,response);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
UserServlet
@WebServlet(name = "UserServlet" ,urlPatterns = "/UserServlet")
public class UserServlet extends BaseServlet {
private UserService us = new UserServiceImp();
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
boolean b = us.regist(new User(null, username, password));
if(b){
//注册成功,返回成功页面,重定向
request.getRequestDispatcher("/pages/regist_success.html").forward(request,response);
}else{
//注册失败,返回注册页面,转发
response.sendRedirect(request.getContextPath()+"/pages/error.html");
}
}
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = us.login(new User(null, username, password));
if(user == null){
//登录失败,返回登录页面,转发(换界面)
request.getRequestDispatcher("/pages/error.html").forward(request,response);
}else{
//登录成功,返回成功界面 重定向(直接刷新界面)
response.sendRedirect(request.getContextPath() + "/pages/login_success.html");
}
}
}
一连串的request.getParameter
取参过程其实也可以抽取出来,此处就不做了