分析:
我们要分析这个程序需要什么样的架构
无论干什么我们都需要于数据库进行交互,所以第一步就是建立这个项目的数据库以及表
注:下面的页面全部都是jsp页面
目的:
完成登录以及注册功能
登录 :当用户点击登录跳转到另外一个页面,如图
对应的前端代码为:
用户输入用户名以及密码
在前端,这是一个表单,所以我们点击登录时,需要把数据提交到一个userServlet程序中,在userServlet程序中进行数据判断分析是否存在,在写这个servlet程序之前,我们还需要一些东西,什么东西呢?
准备:
- 用户的 数据模型 User
- 把数据库的连接以及数据库的操作封装到一个类中JdbcUtils
- 编写BaseDao程序(数据的增删改查)
- 编写UserDao程序(l对User进行的数据库操作(在BaseDao程序上进行操作))
- 编写UserService这类作用为了完成在Servlet程序中的方法Service层其实就是业务层,这里要完成的操作就是注册(Register)和登录(Login)
- 编写Servlet程序对前台的要实现的功能直接对接
**编写数据模型User
package pojo;
/**这个类就是用来封装用户的信息的,比如在界面上需要对用户名进行查询,看是否符合条件,就需要用这个类
* 这个类中需要有用户的一些基本熟悉,如 用户名,用户密码,邮箱,id 所以在编写这个类的时候就需要考虑到
* 这一点
* @author:MrQ
* @date 2021/2/21-18:41
*/
public class User {
private Integer id;
private String username;
private String mima;
private String email;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", mima='" + mima + '\'' +
", email='" + email + '\'' +
'}';
}
public User(Integer id, String username, String mima, String email) {
this.id = id;
this.username = username;
this.mima = mima;
this.email = email;
}
public User() {
}
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 getMima() {
return mima;
}
public void setMima(String mima) {
this.mima = mima;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
把数据库的连接和数据库的操作封装到JdbcUtils类中
package utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.Test;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* @author:MrQ
* @date 2021/2/21-18:46
*/
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
try {
Properties properties = new Properties();
//读取jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中加载数据
properties.load(inputStream);
//System.out.println(properties.getProperty("username"));
//创建数据库连接池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
//System.out.println(dataSource.getConnection());
//System.out.println("哈哈哈哈哈哈!!!");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接池的连接
*
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;//原来这里是返回null
}
/**
* 关闭连接,把busy状态改成free
* @param conn
*/
public static void close(Connection conn){
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
jdbc.properties文件
username=root
password=123456
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.cj.jdbc.Driver
initialSize=5
maxActive=10
编写BaseDao程序
package dao.impl;
/**
* @author:MrQ
* @date 2021/2/22-16:26
*/
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import pojo.Book;
import utils.JdbcUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 为了复用代码所以创建这个类
* 下面的方法中都需要从连接池中获取连接
*/
public abstract class BaseDao {
//使用DButils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* update方法用来执行Insert Update Delete语句
* @return
* 如果返回-1说明执行失败,其他表示影响的行数
* 因为返回类型为int,说明就是收到影响的行数
*/
public int update(String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
//JdbcUtils是自己封装好的类,它的主要功能就是用连接池连接数据库,并且在这个类中定义了
//getConnection和close的方法来获取连接和关闭资源
try {
/**
* 注意:这里一定要return 回去不然怎么调试都是返回下面的-1
*/
return queryRunner.update(connection,sql,args);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return -1;
}
/**
* 查询返回一个javaBean的sql语句
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public<T> Object queryForOne(Class<T> type,String sql,Object ... args){
Connection connection= JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new BeanHandler<T>(type),args);
}catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/**
* 查询返回多个javaBean对象
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> List<T> queryForList(Class<T> type,String sql,Object ... args){
Connection connection= JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new BeanListHandler<T>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/**
* 返回一行一列的sql语句
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @return
*/
public Object queryForSingleValue(String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new ScalarHandler(),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
public int deleteById(String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try{
return queryRunner.update(connection,sql,args);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
JdbcUtils.close(connection);
}
return -1;
}
}
编写UserDao程序
package dao.impl;
import pojo.User;
/**
* @author:MrQ
* @date 2021/2/23-21:56
*/
public class UserDaoImpl extends BaseDao implements UserDao{
//实现了接口,要实现接口中所有的方法
@Override
public User queryUserByUsername(String username) {
String sql = "select * from t_user where username = ?";
return (User) queryForOne(User.class,sql,username);
}
@Override
public int saveUser(User user) {
String sql = "insert into t_user(username,mima,email) " +
"values(?,?,?)";
return update(sql,user.getUsername(),user.getMima(),user.getEmail());
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select * from t_user where username = ?and mima = ?";
return (User) queryForOne(User.class,sql,username,password);
}
}
编写UserService类
package service.impl;
import dao.impl.UserDao;
import dao.impl.UserDaoImpl;
import pojo.User;
/**
* @author:MrQ
* @date 2021/2/25-16:54
*/
public class UserServiceImpl implements UserService{
//要与数据库进行数据交互所以要用一个UserDaoImpl对象
private UserDao userDao= new UserDaoImpl();
@Override
public void RegisitUser(User user) {
userDao.saveUser(user);//返回值为整数表示保存的数量
}
/**
* 如果返回null,说明登录失败,没有找到值与之对应
* @param user
* @return
*/
@Override
public User Login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getMima());//返回的是一个用户的信息
}
/**
*
* @param username
* @return 用户名在数据库中存在,说明这个用户名已经存在了,所以就返回false
*/
@Override
public boolean exitsUsername(String username) {
if(userDao.queryUserByUsername(username) == null){
//System.out.println("用户名可用");
return false;
}
return true;
}
}
编写UserServlet类
package web;
import dao.impl.UserDao;
import dao.impl.UserDaoImpl;
import org.apache.commons.beanutils.BeanUtils;
import pojo.User;
import service.impl.UserService;
import service.impl.UserServiceImpl;
import utils.WebUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.WebConnection;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
/**
* @author:MrQ
* @date 2021/3/2-11:29
*/
public class UserServlet extends BaseServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
/**
* 注销用户
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
public void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//销毁Session中用户登录的信息(或者销毁Session)
req.getSession().invalidate();
//重定向到首页(或其他页面)
resp.sendRedirect(req.getContextPath());
}
/**
* 处理登录的功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理登录的需求
//获取请求的参数
//获取用户名和密码
/**
* 很多地方都需要用到下面的三行代码,从前端获取填入的信息,这样就会重写很多遍这些语句,所以为了提高编码效率、
* 采用Beanutils这个方法,通过Beanutils.populate(Object,Map)这个方法,直接从request中获取填入的信息
* 使代码的冗余性就降低了
*/
UserService userService = new UserServiceImpl();
String username = req.getParameter("username");
String password = req.getParameter("password");
//User user = new User();
Map value = req.getParameterMap();
/**
* 简化代码
*/
//经过这个方法,从前端获取到的客户信息已经传到这里了
User user= (User)WebUtils.copyParamToBean(value,new User());
System.out.println("密码为:"+password);
User loginuser = userService.Login(new User(null, username, password, null));
if(loginuser==null){
System.out.println("用户名或密码错误,跳转到登录界面");
//把错误信息和回显的表单项信息保存到request域中
req.setAttribute("msg","用户名或密码错误");//当程序第一次走到这里,回传的数据将会是null,所以在回传提示的时候需要先判断是否为null
req.setAttribute("username",username);
req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
}else {//登录成功
System.out.println("登录成功,跳转到登录成功界面");
req.getSession().setAttribute("user",loginuser);//把用户名的信息保存到session域中
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
}
}
/**
* 处理注册功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//执行regist的相应操作
//获取界面中用户输入的信息
UserService userService = new UserServiceImpl();
String username = req.getParameter("username");
String password = req.getParameter("password");
String repwd = req.getParameter("repwd");
String email = req.getParameter("email");
String code = req.getParameter("code");
User user = (User)WebUtils.copyParamToBean(req.getParameterMap(), new User());
//检查验证码是否正确 要求验证码为abcde
if("abcde".equalsIgnoreCase(code)){//这个方法忽略大小写
System.out.println("验证码正确,下一步检查验证码是否正确");
//检查用户名是否可用
if(userService.exitsUsername(username)==false){
System.out.println("用户名["+username+"]可用,接下来把数据保存到数据库中");
UserDao userDao = new UserDaoImpl();
//调用Service保存到数据库中
userDao.saveUser(new User(null,username,password,email));
System.out.println("成功入库,接下来跳转到注册成功界面");
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
}else{
//用户名不可用把回显信息传到request域中
req.setAttribute("msg","用户名不可用");
//下面做的是把正确的信息回显过去,让用户少改动
//这里不仅仅需要回传错误信息,没有错误的地方也需要回传过去
req.setAttribute("code",code);//验证码回传
req.setAttribute("email",email);//邮箱回传
req.setAttribute("password",password);//回显密码
req.setAttribute("repwd",repwd);//回显确认密码
System.out.println("用户名["+username+"]不可用,跳回注册界面");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}
}else{
//把回显信息保存到request域中,在页面输出
req.setAttribute("msg","验证码错误");
req.setAttribute("username",username);//用户名回显
req.setAttribute("email",email);//邮箱回传
req.setAttribute("password",password);//回显密码
req.setAttribute("repwd",repwd);//回显确认密码
System.out.println("验证码["+code+"]错误,跳回注册界面");
//跳转到某个界面
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}
}
}
写在最后
我们每次写完一个实用类时,都要对其的方法进行测试以便检查方法的实用性
如
jdbcUtilsTest
UserDaoTest
UserServiceTest
UserServletTest