一. 创建动态Web工程
参考:Tomcat学习_Archer__13的博客-CSDN博客
①web目录存放web工程的资源文件,例如:html页面、css文件、js文件等,将写好的web页面放到该目录下(首页、用户登录页面、用户注册页面);
②web目录下的WEB-INF目录是受服务器保护的目录,浏览器无法直接访问此目录的内容;
③在WEB-INF目录下创建一个lib目录用来存放所需要的第三方jar包;
④scr目录存放自己编写的java代码,并在src下创建以下目录;
二. 编写登录和注册页面
1. index.jsp页面
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core_1_1" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
<% //获取当前工程的路径
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
<base href="<%=basePath%>">
</head>
<body>
<%-- 如果用户还没有登录,显示登录和注册菜单--%>
<c:if test="${empty sessionScope.user}">
<a href="pages/user/login.jsp"><input type = "button" value = "登录"/></a>
<a href="pages/user/regist.jsp"><input type = "button" value = "注册"/></a>
</c:if>
<%-- 如果用户已经登录,显示欢迎用户和注销--%>
<c:if test="${not empty sessionScope.user}">
欢迎${sessionScope.user.username}
<a href="userServlet?action=logout"><input type = "button" value = "注销"/></a>
</c:if>
</body>
</html>
2.login.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
<base href="http://localhost:8080/StudyProject_war_exploded/">
</head>
<body>
<form action=" " method="post">
用户名:<input type="text" name="username"> <br/>
密码:<input type="password" name="password"> <br/>
<input type="submit" value="登录">
</form>
</body>
</html>
3.regist.html页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
<base href="http://localhost:8080/StudyProject_war_exploded/">
</head>
<body>
<form action=" " method="post">
用户名:<input type="text" name="username"> <br/>
用户密码:<input type="password" name="password"> <br/>
确认密码:<input type="password" name="password"> <br/>
电子邮箱:<input type="text" name="email"> <br/>
验证码:<input type="text" name="code" style="width: 60px"/> <img src="kaptcha.jpg" onclick="this.src='kaptcha.jpg?d='+new Date()" style="width: 80px; height: 25px;"/> <br/>
<input type="submit" value="注册">
</form>
</body>
</html>
三. 创建数据库和表
创建一个数据库studyproject,在该数据库下创建一个user表
create table user{
id int primary key auto_increment,
username varchar(20) not null unique,
password varchar(32) not null,
email varchar(200)
};
insert into user(username,password,email) values('admin','admin','admain@163.com');
四. 编写数据库表对应的JavaBean对象
在pojo包下创建User类
package server.pojo;
public class User {
private Integer id;
private String username;
private String password;
private String email;
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;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
public User() {
}
public User(Integer id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
}
五. 连接数据库(utils)
1. 创建jdbc.properties文件,将其放在src下(必须是src目录下第一级),文件内容为:
url=jdbc:mysql://localhost:3306/studyproject
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=10
2. 在utils包下创建一个工具类JdbcUtils.java文件,用来连接数据库
package server.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DataSource source;
static{
try {
Properties properties = new Properties();
//读取jdbc.properties属性
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中加载数据
properties.load(is);
//创建数据库连接池
source = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() {
Connection conn = null;
try {
conn = source.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
//关闭连接
public static void closeResource(Connection conn){
try {
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
六. Dao持久层 —— 操作数据库
1. 在dao.impl包下编写BaseDao类,用来操作数据库(更新、查询)
package server.dao.impl;
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 server.utils.JdbcUtils;
import java.sql.Connection;
import java.util.List;
public abstract class BaseDao {
//使用dbutils操作数据库
private QueryRunner queryRunner = new QueryRunner();
//更新数据
public int updateData(String sql, Object ... args) {
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.update(conn, sql, args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.closeResource(conn);
}
return -1;
}
//返回一条数据
public <T> T queryOneData(Class<T> type,String sql, Object ... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn,sql,new BeanHandler<T>(type),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.closeResource(conn);
}
return null;
}
//返回多条数据
public <T> List<T> queryList(Class<T> type, String sql, Object ... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn,sql,new BeanListHandler<T>(type),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.closeResource(conn);
}
return null;
}
//返回一个值(一行或一列)
public Object querySingleValues(String sql, Object ... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn,sql,new ScalarHandler(),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.closeResource(conn);
}
return null;
}
}
2. 在dao包下编写UserDao接口,用来查询数据库中的用户信息和将用户信息保存到数据库中
package server.dao;
import server.pojo.User;
public interface UserDao {
//根据用户名查询用户信息,如果返回null说明没有这个用户
public User queryUserByUsername(String username);
//根据用户名和密码查询用户信息,如果返回null说明用户名或密码错误
public User queryUserByUsernameAndPassword(String username,String password);
//保存用户信息
public int saveUser(User user);
}
3. 在dao.impl包下编写一个UserDaoImpl类,继承BaseDao类并实现UserDao接口
package server.dao.impl;
import server.dao.UserDao;
import server.pojo.User;
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select id, username, password, email from user where username = ?";
return queryOneData(User.class,sql,username);
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select id, username, password, email from user where username = ? and password = ?";
return queryOneData(User.class,sql,username,password);
}
@Override
public int saveUser(User user) {
String sql = "insert into user(username,password,email) values(?,?,?)";
return updateData(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
}
七. Service业务层 —— 注册和登录
1. 在Service包下编写UserService接口,实现用户注册和登录
package server.service;
import server.pojo.User;
public interface UserService {
//用户注册,如果用户名已存在,则需要重新注册一个新的用户名(用户名不可以重复)
public void registUser(User user);
//用户登录,如果登录失败会返回null
public User login(User user);
//判断用户名是否存在,返回true表示用户名存在,返回flase表示用户名可用
public boolean existUsername(String username);
}
2. 在service.impl包下编写UserServiceImpl类来实现UserService接口。
package server.service.impl;
import server.dao.UserDao;
import server.dao.impl.UserDaoImpl;
import server.pojo.User;
import server.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void registUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
}
@Override
public boolean existUsername(String username) {
if(userDao.queryUserByUsername(username) == null){
return false;
}else {
return true;
}
}
}
八. Web层 —— 实现Servlet程序
Servlet程序用于接收客户端请求然后调用Service层的服务来执行
1. 编写BaseServlet类,用于获取隐藏域中的值来执行相应的方法
package server.web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8"); // 解决post请求中文乱码问题
resp.setContentType("text/html; charset=UTF-8"); // 解决响应中文乱码问题
String action = req.getParameter("action");
try {
//获取action业务鉴别字符串,得到相应的业务方法
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
//调用目标业务方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 编写WebServlet工具类,一次性把所有请求的参数注入到JavaBean中
package server.utils;
import org.apache.commons.beanutils.BeanUtils;
import java.util.Map;
public class WebUtils {
public static <T> T copyParamToBean(Map value, T bean){
try {
BeanUtils.populate(bean, value); //把所有请求注入到JavaBean中
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
2. 编写UserServlet类,并继承BaseServlet类,执行相应的请求
package server.web;
import server.pojo.User;
import server.service.UserService;
import server.service.impl.UserServiceImpl;
import server.utils.WebUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
@WebServlet("/userServlet")
public class UserServlet extends BaseServlet {
private UserService userService = new UserServiceImpl();
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取客户端的请求
User user = WebUtils.copyParamToBean(req.getParameterMap(),new User());
//2.用户登录
User loginUser = userService.login(user);
if(loginUser == null){
//登录失败,跳回登录页面
req.setAttribute("msg","用户名或密码错误!");
req.setAttribute("username",user.getUsername());
req.getRequestDispatcher("pages/user/login.jsp").forward(req,resp);
}else{
//登录成功,跳到首页index.jsp
req.getSession().setAttribute("user",loginUser);
req.getRequestDispatcher("index.jsp").forward(req,resp);
}
}
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Session中的验证码
String token = (String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
//删除Session中的验证码
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
String code = req.getParameter("code");
//1.获取客户端的请求
User user = WebUtils.copyParamToBean(req.getParameterMap(),new User());
//2.用户注册
if(token != null && token.equalsIgnoreCase(code)){ //检查验证码是否正确
if(userService.existUsername(user.getUsername())){ //注册不成功
req.setAttribute("msg","用户名已存在");
req.setAttribute("username",user.getUsername());
req.setAttribute("email",user.getEmail());
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp); //跳转到注册页面
}else{
userService.registUser(user); //注册成功
req.getRequestDispatcher("index.jsp").forward(req,resp); //跳转到首页
}
}else {
// 把回显信息,保存到Request域中
req.setAttribute("msg", "验证码错误!");
req.setAttribute("username", user.getUsername());
req.setAttribute("email", user.getEmail());
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
}
}
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//销毁Session
req.getSession().invalidate();
//重定向到首页
resp.sendRedirect("index.jsp");
}
}
4. 将loginin.jsp和regist.jsp修改如下,用于接收服务器回传的信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
<base href="http://localhost:8080/StudyProject_war_exploded/">
</head>
<body>
<form action="userServlet" method="post">
<input type="hidden" name="action" value="login">
用户名:<input type="text" name="username" value="${empty requestScope.username ? "" : requestScope.username}"> <br/>
密码:<input type="password" name="password"> <br/>
<input type="submit" value="登录"> <br/>
<div>
${empty requestScope.msg ? "请输入用户名和密码" : requestScope.msg}
</div>
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
<% //获取当前工程的路径
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
<base href="<%=basePath%>">
</head>
<body>
<form action="userServlet" method="post">
<input type="hidden" name="action" value="regist">
用户名:<input type="text" name="username" value="${empty requestScope.username ? "" : requestScope.username}"> <br/>
用户密码:<input type="password" name="password"> <br/>
确认密码:<input type="password" name="password"> <br/>
电子邮箱:<input type="text" name="email" value="${empty requestScope.email ? "" : requestScope.email}"> <br/>
验证码:<input type="text" name="code" style="width: 60px"/> <img src="kaptcha.jpg" onclick="this.src='kaptcha.jpg?d='+new Date()" style="width: 80px; height: 25px;"/> <br/>
<input type="submit" value="注册"> <br/>
<div>
${empty requestScope.msg ? "" : requestScope.msg}
</div>
</form>
</body>
</html>