<%-- 页面转发 --%>
<%-- 由于我的页面在jsp文件夹下,所以用jstl表达式发出一个index请求给IndexServlet类处理 --%>
/**
* Servlet的父类,通过其来进行页面转发操作 implementation class BaseServlet
*/
public class BaseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void service(HttpServletRequest request, HttpServletResponse response) {
try {
// 1. 通过this.getClass()获取子类对象
Class extends BaseServlet> clazz = this.getClass();
// 2. 获取请求路径中的方法名
String method = request.getParameter("method");
// 3. 判断是否有该方法名
if (!method.equals("") || !method.equals(null)) {
// 4. 获取方法对象
Method met = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
// 5. 执行方法,获取方法返回值路径
String path = (String) met.invoke(this, request, response);
// 6. 判断路径是否为空
if (path != null) {
// 7. 执行转发页面
request.getRequestDispatcher("/jsp/" + path + ".jsp").forward(request, response);
} // end if 判断路径是否为空
} // end if 判断是否有该方法名
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Servlet implementation class IndexServlet
*/
@WebServlet("/index")
public class IndexServlet extends BaseServlet {
private static final long serialVersionUID = 1L;
public String index(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 跳转首页
return "index";
}
}
8.1 创建用户数据表
创表语句,以MySQL数据库为例
CREATE TABLE `user` (
`uid` varchar(600) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`username` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`realname` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`phone` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`birthday` date DEFAULT NULL,
`sex` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`state` int(11) DEFAULT NULL,
`code` varchar(600) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
8.2 创建User.java
entity实体类
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public String uid;
public String username;
public String password;
public String realname;
public String email;
public String phone;
public Date birthday;
public String sex;
public Integer state = 0; // 0 未激活,1 激活
public String code;
// 读写方法略...,自行用工具添加
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", realname=" + realname
+ ", email=" + email + ", phone=" + phone + ", birthday=" + birthday + ", sex=" + sex + ", state="
+ state + ", code=" + code + "]";
}
}
8.3 创建UserDao.java
user表持久层接口类
/**
* 数据插入,用户注册方法
* @param user
* @return
* @throws Exception
*/
public Integer register(User user) throws Exception;
/**
* 获取指定激活码的用户
* @param code
* @return
* @throws Exception
*/
public User getUserByCode(String code) throws Exception;
8.4 创建UserDaoImpl.java
user表持久层接口实现类
// 使用 BeanFactory 来初始化 productDao
private QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
@Override
public Integer register(User user) throws Exception {
String sql = "insert into user values (?,?,?,?,?,?,?,?,?,?)";
int i = qr.update(sql, user.getUid(), user.getUsername(), user.getPassword(),
user.getRealname(), user.getEmail(), user.getPhone(),
user.getBirthday(), user.getSex(), user.getState(), user.getCode());
return i;
}
@Override
public User getUserByCode(String code) throws Exception {
String sql = "select * from user where code = ?";
return qr.query(sql, new BeanHandler<>(User.class), code);
}
8.4.1 补充数据库连接工具类
public class DataSourceUtils {
private static ComboPooledDataSource ds = new ComboPooledDataSource();
private static ThreadLocal tl=new ThreadLocal<>();
/**
* 从线程中获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
//从线程中获取conneciton
Connection conn = tl.get();
if(conn==null){
conn=ds.getConnection();
//和当前线程绑定
tl.set(conn);
}
return conn;
}
// 获取数据源
public static DataSource getDataSource() {
return ds;
}
// 释放资源
public static void closeResource( Statement st, ResultSet rs) {
closeResultSet(rs);
closeStatement(st);
}
// 释放资源
public static void closeResource(Connection conn, Statement st, ResultSet rs) {
closeResource(st, rs);
closeConn(conn);
}
// 释放 connection
public static void closeConn(Connection conn) {
if (conn != null) {
try {
conn.close();
//和线程解绑
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
// 释放 statement ctrl + shift + f 格式化代码
public static void closeStatement(Statement st) {
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
}
// 释放结果集
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
}
//开启事务
public static void startTransaction() throws SQLException{
getConnection().setAutoCommit(false);
}
/**
* 事务提交且释放连接
*/
public static void commitAndClose(){
Connection conn = null;
try {
conn=getConnection();
//事务提交
conn.commit();
//关闭资源
conn.close();
//解除版定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 事务回滚且释放资源
*/
public static void rollbackAndClose(){
Connection conn = null;
try {
conn=getConnection();
//事务回滚
conn.rollback();
//关闭资源
conn.close();
//解除版定
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
8.4.2 c3p0.properties
c3p0连接池
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/webShop(webShop为自己的数据库名,用请将括号内的字删掉)
c3p0.user=root
c3p0.password=123456
8.4.3 EncodingFilter.java
请求响应字符编码设置过滤器类
@WebFilter("/*")
public class EncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 设置字符编码
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
// 沿着请求链继续执行
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
8.5 UserService.java
user表服务层接口类
/**
* 数据插入,用户注册方法
* @param user
* @return
* @throws Exception
*/
public Integer register(User user) throws Exception;
/**
* 获取指定激活码的用户
* @param code
* @return
* @throws Exception
*/
public User active(String code) throws Exception;
8.6 UserServiceImpl.java
user表服务层接口实现类
@Override
public Integer register(User user) throws Exception {
Integer i = udao.register(user);
// 注册成功之后,发送激活邮件
// 展示的消息中,添加的链接,主要是给用户点击了之后,再次返回我们的应用中
String emailMsg = "小哥哥,欢迎你加入我们的大家庭," + "让我们快点激活回去吧";
MailUtils.sendMail(user.getEmail(), emailMsg);
return i;
}
@Override
public User active(String code) throws Exception {
// 1. 通过获取的 code 来找一个用户
User user = udao.getUserByCode(code);
// 2. 判断用户是否为空
if(user == null) {
return null;
}
// 3. 如果不为空,则修改用户的状态(未激活 -> 激活)
user.setState(1); // 已经修改了 user 的数据,接着需要把数据同步到数据库中
// 4. 更新用户数据
udao.updateUser(user);
return user;
}
8.6.1 邮件服务器和客户端
public class MailUtils {
public static void sendMail(String email, String emailMsg)
throws AddressException, MessagingException {
// 1.创建一个程序与邮件服务器会话对象 Session
Properties props = new Properties();
//设置发送的协议
props.setProperty("mail.transport.protocol", "SMTP");
//设置发送邮件的服务器
props.setProperty("mail.host", "localhost");
props.setProperty("mail.smtp.auth", "true");// 指定验证为true
// 创建验证器
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//设置发送人的帐号和密码
return new PasswordAuthentication("service", "123");
}
};
Session session = Session.getInstance(props, auth);
// 2.创建一个Message,它相当于是邮件内容
Message message = new MimeMessage(session);
//设置发送者
message.setFrom(new InternetAddress("[email protected]"));
//设置发送方式与接收者
message.setRecipient(RecipientType.TO, new InternetAddress(email));
//设置邮件主题
message.setSubject("用户激活");
//设置邮件内容
message.setContent(emailMsg, "text/html;charset=utf-8");
// 3.创建 Transport用于将邮件发送
Transport.send(message);
}
}
8.7 创建UserServlet.java
servlet表现层类
/**
* 用户激活
* @param request
* @param response
* @return
*/
public String active(HttpServletRequest request, HttpServletResponse response) {
// 1. 获取邮箱中发送过来的激活码 --- Servlet 接收参数
String code = request.getParameter("code");
// 2. 对比我们的激活码,确定对方真的是已注册用户 --- Service 做验证服务
User user = null;
try {
user = us.active(code);
} catch (Exception e) {
e.printStackTrace();
}
if(user == null) {
request.setAttribute("msg", "抱歉,认证没通过,请重新激活");
} else {
request.setAttribute("msg", "恭喜,激活成功");
}
// 3. 提示信息
return "msg";
}
/**
* 跳转注册页面
* @param request
* @param response
* @return
*/
public String registerUI(HttpServletRequest request, HttpServletResponse response) {
return "register";
}
/**
* 注册用户
* @param request
* @param response
* @return
* @throws Exception
*/
public String register(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 接收页面的数据,并且进行封装数据。
User user = new User();
// 在数据封装之前,加载转换器,转换时间的格式
ConvertUtils.register(new DateConverter(), Date.class);
BeanUtils.populate(user, request.getParameterMap());
// 2. 将页面没有提交的数据,进行手动绑定
// 我们在添加用户的时候,不可能手动给设置 id 值,可以使用随机值
// 使用随机值,一定程度上将用户的信息隐蔽起来,不容易访问得到
user.setUid(UUIDUtils.getId());
// 设置激活码
user.setCode(UUIDUtils.getCode());
// 3. 调用 UserService 来执行注册操作。
Integer i = us.register(user);
if(i == 1) {
// c. 转发 msg 页面,提示。
request.setAttribute("msg", "恭喜你,注册成功了,请去邮箱激活...");
}
// 发送激活邮件(主要是发送一个激活邮件,然后点击跳回本项目,修改用户的状态值)
return "msg";
}
8.7.1 BeanUtils.java
随机码工具类
public class UUIDUtils {
/**
* 随机生成id
* @return
*/
public static String getId(){
// 使用 UUID 类的 randomUUID() 方法来获取一个随机值
// 调用 toString() 方法来转成字符串
// 如果随机码中,有-字符,则调用 split() 方法来去掉
// 最后,使用 toUpperCase() 方法全部转成大写
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}
/**
* 生成随机码
* @return
*/
public static String getCode(){
return getId();
}
}
8.7.2 DateConverter.java
日期转换工具类
public class DateConverter implements Converter{
// Class 就是我们希望转换的对象
// Object 就是我们想要操作的值
@Override
public Object convert(Class clazz, Object obj) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse((String) obj);
return date;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
1.在userDao.java
中添加selectUname方法
/**
* 根据用户名查找用户信息
*
* @param name
* @return
* @throws Exception
*/
public User selectUname(String name) throws Exception;
2.在userDaoImpl.java
中实现selectUname方法
@Override
public User selectUname(String name) throws Exception {
String sql = "select * from user where username = ?";
return qr.query(sql, new BeanHandler<>(User.class), name);
}
3. 在UserService.java
中添加login方法
/**
* 用户登录操作
*
* @param name
* @return
* @throws Exception
*/
public User login(String name) throws Exception;
4. 在UserServiceImpl.java
中实现login方法
@Override
public User login(String name) throws Exception {
return udao.selectUname(name);
}
5.在UserServlet.java
中添加login方法
// 用户激活状态值
private static final int STATE_NUM = 1;
/**
* 用户登录
*
* @param request
* @param response
* @return
*/
public String login(HttpServletRequest request, HttpServletResponse response) {
// 1. 接收用户名和密码
String name = request.getParameter("username");
String pass = request.getParameter("password");
try {
// 2. 调用 UserService 完成登录操作
User user = us.login(name);
// 3. 判断 user 是否为空
if (user == null || user.getRealname() == null) {
request.setAttribute("msg", "用户名不存在,请重新登录");
return "msg";
} else {
// 判断密码是否正确
if (!user.getPassword().equals(pass)) {
request.setAttribute("msg", "用户密码不正确,请检查重新登录");
return "msg";
} else {
// 判断用户是否激活
if (STATE_NUM != user.getState()) {
request.setAttribute("msg", "用户未激活!请去邮箱激活");
return "msg";
} else {
// 4. 将 user 放入 session 域中
request.getSession().setAttribute("user", user);
} // end if 用户是否激活
} // end if 密码是否正确
} // end if user是否为空
} catch (Exception e) {
e.printStackTrace();
}
// 5. 跳转首页
return "index";
}