我们先写网站的注册登录这一块功能,首先在domain包里先写User类,关于domain包给大家解释一下,在mvc结构里,domain是主控制层,对应数据库实体setter,getter和toString方法,为dao层做好准备。那么dao层又是干嘛的呢?dao层主要就是数据访问层,也就是操作表单,对数据进行访问,这里不会涉及复杂逻辑,主要就是对表的增删查改,完全根据domain的要求来查找数据,所以我们要对每个要操作的数据库定义一个dao,对具体操作定义一个方法说明。
讲完这些,我们开始写代码,domain里写的十分简单,就不做太多解释,不过需要注意的是我们在这个类下面加了一个注册验证,只要不符合验证,会在提交表单时进行提示。
package cn.itcast.estore.domain;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
/**
* 用户表
*
*/
public class User implements Serializable{
private int id;
private String username;
private String password;
private String nickname;
private String email;
private String role;
private int state;
private String activecode;
private Timestamp updatetime;
public int getId() {
return id;
}
public void setId(int 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 getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getActivecode() {
return activecode;
}
public void setActivecode(String activecode) {
this.activecode = activecode;
}
public Timestamp getUpdatetime() {
return updatetime;
}
public void setUpdatetime(Timestamp updatetime) {
this.updatetime = updatetime;
}
public Map<String, String> validateRegist() {
Map<String, String> map = new HashMap<String, String>();
if (username == null || username.trim().isEmpty()) {
map.put("username.message", "用户名不能为空");
}
if (password == null || password.trim().isEmpty()) {
map.put("password.message", "密码不能为空");
}
if (nickname == null || nickname.trim().isEmpty()) {
map.put("nickname.message", "昵称不能为空");
}
if (email == null || email.trim().isEmpty()) {
map.put("email.message", "邮箱不能为空");
}
return map;
}
}
写完domain,然后我们开始写Dao层里的UserDao
package cn.itcast.estore.dao;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.utils.DataSourceUtils;
import cn.itcast.estore.utils.Md5Utils;
public class UserDao {
// 添加用户操作
public void addUser(User user) throws SQLException {
// 1.创建QueryRunner
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
// 2.执行sql语句
// 默认用户role=user state=0 代表未激活
String sql = "insert into users values(null,?,?,?,?,'user','0',?,null)";
runner.update(sql, user.getUsername(), Md5Utils.md5(user.getPassword()), user.getNickname(), user.getEmail(),
user.getActivecode());
}
public User findUserByActiveCode(String activecode) throws SQLException {
// 1.创建QueryRunner
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
// 2.执行sql语句
String sql = "select * from users where activecode=?";
return runner.query(sql, new BeanHandler<User>(User.class), activecode);
}
public void activeUserByActivecode(String activecode) throws SQLException {
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "update users set state=1 where activecode=?";
runner.update(sql, activecode);
}
public User findUserByUserNameAndPassword(String username, String password) throws SQLException {
// 1.创建QueryRunner
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select * from users where username=? and password=?";
return runner.query(sql, new BeanHandler<User>(User.class), username, Md5Utils.md5(password));
}
}
然后我们再到service包里写UserService,先定义好一个接口,在里面写都要实现哪些service
package cn.itcast.estore.service;
import cn.itcast.estore.domain.User;
public interface UserService {
// 注册操作
public void regist(User user) throws Exception;
// 登录操作
public User login(String username, String password) throws Exception;
// 激活操作
public void activeUser(String activecode) throws Exception;
}
写完接口后我们开始实现接口,有了前面的User和UserDao,接口实现便理所应当,
package cn.itcast.estore.service;
import java.sql.SQLException;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import cn.itcast.estore.dao.UserDao;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.exception.ActiveUserException;
import cn.itcast.estore.exception.LoginException;
import cn.itcast.estore.exception.RegistException;
import cn.itcast.estore.utils.MailUtils;
public class UserServiceImpl implements UserService{
// 注册功能
public void regist(User user) throws RegistException {
// 调用dao中添加用户操作的方法
try {
new UserDao().addUser(user);
// 发送邮件操作
String emailMsg = "注册成功,请在15分钟内<a href='http://localhost:8080/bookEstore/user?method=activeuser&activecode="
+ user.getActivecode()
+ "'>激活</a>,激活码是"
+ user.getActivecode();
MailUtils.sendMail(user.getEmail(), emailMsg);
} catch (SQLException e) {
throw new RegistException("注册失败");
} catch (Exception e) {
throw new RegistException("邮件发送失败");
}
}
public void activeUser(String activecode) throws RegistException,
ActiveUserException {
// 调用一个dao中的方法,根据activecode查找用户
UserDao dao = new UserDao();
User user = null;
try {
user = dao.findUserByActiveCode(activecode);
} catch (SQLException e) {
throw new RegistException("根据激活码查找用户失败");
}
long time = System.currentTimeMillis() - user.getUpdatetime().getTime();
if (time > 15 * 60 * 1000) {
throw new ActiveUserException("激活码过期");
}
// 进行激活操作
try {
dao.activeUserByActivecode(activecode);
} catch (SQLException e) {
e.printStackTrace();
throw new ActiveUserException("激活失败");
}
}
public User login(String username, String password) throws LoginException {
UserDao dao = new UserDao();
User user = null;
try {
user = dao.findUserByUserNameAndPassword(username, password);
if (user == null) {
throw new LoginException("用户名或密码不正确");
}
// 判断用户的状态。
if (user.getState() == 0) {
// 用户状态未激活,不能进行登录操作
throw new LoginException("用户未激活");
}
} catch (SQLException e) {
throw new LoginException("登录失败");
}
return user;
}
}
最后我们开始写UserServlet,在UserServlet中首先我们得到请求参数,判断当前是什么操作,然后通过判断,执行相应操作所对应的方法。比如register方法,对应的就是注册操作。
接下来我们较为详细的说明一下注册操作的过程,在register.jsp及User部分已经写好了关于表单验证的操作,所以在servlet里,我们只要写一个验证码操作就可以了。验证码通过后,我们将请求对象全部封装到JavaBean中,然后进行服务器段的数据校验。封装激活码等操作。完成这些操作后调用UserService操作,完成注册操作。
package cn.itcast.estore.web.servlet;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import cn.itcast.estore.domain.User;
import cn.itcast.estore.exception.ActiveUserException;
import cn.itcast.estore.exception.LoginException;
import cn.itcast.estore.exception.RegistException;
import cn.itcast.estore.service.UserServiceImpl;
public class UserServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 得到请求参数method,判断当前是什么操作
String method = request.getParameter("method");
if ("login".equals(method)) { // 登录操作台
login(request, response);
} else if ("regist".equals(method)) { // 注册操作
regist(request, response);
} else if ("logout".equals(method)) {
// 注销操作
logout(request, response);
} else if ("activeuser".equals(method)) {
activecode(request, response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
// 激活用户操作
public void activecode(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 1.得到激活码
String activecode = request.getParameter("activecode");
// 2.调用UserService中的方法完成激活操作
UserServiceImpl service = new UserServiceImpl();
try {
service.activeUser(activecode);
} catch (RegistException e) {
e.printStackTrace();
response.getWriter().write(
e.getMessage() + ",重新<a href='" + request.getContextPath()
+ "/regist.jsp'>注册</a>");
return;
} catch (ActiveUserException e) {
e.printStackTrace();
response.getWriter().write(
e.getMessage() + ",重新<a href='" + request.getContextPath()
+ "/regist.jsp'>注册</a>");
return;
}
response.getWriter().write(
"用户激活成功,请<a href='" + request.getContextPath()
+ "/index.jsp'>回首页</a>");
return;
}
// 注销操作
public void logout(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession().invalidate(); // 销毁session
Cookie cookie = new Cookie("autologin", "");
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
// 登录操作
public void login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到用户名与密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2.调用service中登录方法
UserServiceImpl service = new UserServiceImpl();
try {
User user = service.login(username, password);
if (user != null) {
// 用户如果登录成功,判断是否勾选了记住用户名.
String saveUsername = request.getParameter("remember");
if ("on".equals(saveUsername)) {
// 记住用户名
Cookie cookie = new Cookie("saveusername",
URLEncoder.encode(username, "utf-8")); // 存储utf-8码
cookie.setMaxAge(7 * 24 * 60 * 60); // 可以记住7天
cookie.setPath("/");
response.addCookie(cookie);
} else {
Cookie cookie = new Cookie("saveusername",
URLEncoder.encode(username, "utf-8")); // 存储utf-8码
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
}
// 自动登录
String autologin = request.getParameter("autologin");
if ("on".equals(autologin)) {
// 勾选了自动登录,就将用户名与密码存储到cookie中.
Cookie cookie = new Cookie("autologin", URLEncoder.encode(
username, "utf-8") + "%itcast%" + password);
cookie.setMaxAge(7 * 24 * 60 * 60);
cookie.setPath("/");
response.addCookie(cookie);
} else {
Cookie cookie = new Cookie("autologin", URLEncoder.encode(
username, "utf-8") + "%itcast%" + password);
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
}
// 登录成功后,将用户存储到session中.
request.getSession().invalidate();
request.getSession().setAttribute("user", user);
response.sendRedirect(request.getContextPath() + "/index.jsp");
return;
} else {
request.setAttribute("login.message", "用户名或密码错误");
request.getRequestDispatcher("/page.jsp").forward(request,
response);
return;
}
} catch (LoginException e) {
e.printStackTrace();
request.setAttribute("login.message", e.getMessage());
request.getRequestDispatcher("/page.jsp")
.forward(request, response);
return;
}
}
// 注册操作
public void regist(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 验证码操作
String checkcode = request.getParameter("checkcode");
String _checkcode = (String) request.getSession().getAttribute(
"checkcode_session");
request.getSession().removeAttribute("checkcode_session");
if (_checkcode == null || (!_checkcode.equals(checkcode))) {
request.setAttribute("regist.message", "验证码不正确");
request.getRequestDispatcher("/regist.jsp").forward(request,
response);
return;
}
// 1.得到请求参数,封装到javaBean中.
User user = new User();
try {
BeanUtils.populate(user, request.getParameterMap());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 进行服务器端数据校验
Map<String, String> map = user.validateRegist();
if (map.size() > 0) {
// 说明有错误信息
request.setAttribute("map", map);
request.getRequestDispatcher("/regist.jsp").forward(request,
response);
return;
}
// 手动封装一个激活码
user.setActivecode(UUID.randomUUID().toString());
// 2.调用service操作
UserServiceImpl service = new UserServiceImpl();
try {
service.regist(user);
response.getWriter().write(
"注册成功,激活后请<a href='" + request.getContextPath()
+ "/index.jsp'>登录</a>");
} catch (RegistException e) {
request.setAttribute("regist.message", e.getMessage());
request.getRequestDispatcher("/regist.jsp").forward(request,
response);
return;
}
}
}
登录,及激活功能与注册功能类似,就不再作太多介绍,不过再多说几句关于验证码,密码的事情,验证码是通过WEB-INF中的txt文档,然后经过utils包里的CheckImgServlet处理实现的,密码是通过MD5加密储存在数据库中,注册时候发送邮件用的也是工具类,我用的是搜狐邮箱,大家可以随便改那个MailUtil工具类(已经把密码删了,所以上传的那个工具类需要改为自己的邮箱账号及密码),最后提醒大家把邮箱设置里的STMP开启,要不可能会无法发送邮件。项目里面用到的一些util类,我直接给大家发布出来,大家都全部加到utils包里,方便以后直接使用。最后一个问题就是配置web.xml文件,写servlet时生成的默认url-pattern会和servlet-name一样,我们这个项目统一改为servlet-name的前面单词小写,如
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>cn.itcast.estore.web.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>cn.itcast.estore.web.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>