注册是本项目的第一步,首先要分析注册的流程。
第一步:创建用户相关类
** domain:User
** dao:UserDao
** service:UserService
** servlet:UserServlet
注:包名习惯以:cn.域名.项目名.相关类名:如:cn.baidu.bookstore.domain.User
第二步:用户注册流程如下图
第三步:用户激活功能如下图
接下来就是代码的设计
1、 建立相应的数据库,并建立以下几张表:
tb_user
tb_category
tb_book
tb_orders
tb_orderitem
表的架构如下
2、导包
数据库用c3p0连接池链接,所以需要用到和c3p0相关的包
c3p0-0.9.2-pre1.jar,这是核心包,其依赖包为:mchange-commons-0.2.jar ,还有mysql-connector-java-5.1.28-bin.jar 驱动架包
当然还需要commons-dbutils这样的工具包,方便我们设计;commons-beanutils-1.8.3.jar创建javabean的工具包,其依赖包commons-logging-1.1.1.jar
项目需要发送邮件激活注册,与javamail相关的包有:mail.jar,activation.jar。同时用要用到ajax相关的包,由于包比较多,这里不再一一列出。
导入配置文件,c3p0配置文件如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <c3p0-config> 3 <!-- 默认配置0~1 --> 4 <default-config> 5 <property name="jdbcUrl">jdbc:mysql://localhost:3306/数据库名</property> 6 <property name="driverClass">com.mysql.jdbc.Driver</property> 7 <property name="user">root</property> 8 <property name="password">数据库密码</property> 9 10 <property name="acquireIncrement">3</property> 11 <property name="initialPoolSize">10</property> 12 <property name="minPoolSize">2</property> 13 <property name="maxPoolSize">10</property> 14 </default-config>> 15 </c3p0-config>
为了以后便于把邮件发送人修改,我统一把与邮件有关的设置在一个配置文件中。代码如下:
host=smtp.qq.com //主机,采用qq邮箱的服务器 uname=邮箱(不带后面的@qq.com) pwd=邮箱的密码 from=邮箱的全部名称 subject=\u8FD9\u662F\u6765\u81EAYouth\u7F51\u4E0A\u4E66\u57CE\u7684\u6FC0\u6D3B\u90AE\u4EF6 //主题,这里已经转码了 content=<a href\="http\://localhost/bookstore/UserServlet?method\=active&code\={0}">\u70B9\u51FB\u8FD9\u91CC\u5B8C\u6210\u6FC0\u6D3B</a> 激活链接
3、创建包。
关于注册界面,需要创建如下包和类
com.youth.bookstore.user.domain---->User(javabean类),这是User的领域对象类,其中的字段必须要数据库对应,包括uid,uname,password,email,code,state
com.youth.bookstore.user.Dao --->UserDao,这是User持久层
com.youth.bookstore.user.service --->UserService和UserException类,前者为业务层,后者为继承了exception的异常类,用于抛出异常信息
com.youth.bookstore.user.web.servlet --->UserServlet,这是User的表述层
这是MVC设计模式,就是把表述层、业务层、数据层分开,这样做的好处是有利于以后的移植,同时表述层值依赖于业务层,业务层值只依赖于持久层,持久层与数据库打交道,极大的减少了各类之间的耦合度。
4、类的设计
1、UserDao类必须具备五个方法.
1、User findByUsername(String name) //通过用户名查找用户
2、User findByEmail(String name) //通过email查找用户
3、void add(User user) //添加用户
4、 User findByCode(String code) //通过激活码来查找用户
5、void updateState(String uid,boolean state) //更新用户状态,用户已激活,则其state为true,,否则为false
2、UserService类的设计
1、void regist(User form) throws UserException //用户注册,如果用户名以及邮箱已被注册,则抛出UserException异常,否则在数据库中添加注册
UserException类为自己写的类,继承自Exception。
2、void active(String code) throws UserException //用户激活,首先查看用户的激活状态,如果已经激活或激活码不存在,则抛出异常
3、UserServlet类的设计
1、激活方法
2、注册方法
每个类的具体代码如下:
1、UserDao.java
package com.youth.bookstore.user.dao; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import cn.itcast.jdbc.TxQueryRunner; import com.youth.bookstore.user.domain.User; /** * User持久层 * @author 11937 * */ public class UserDao { private QueryRunner qr = new TxQueryRunner(); /** * 按用户名查询 * @param username * @return */ public User findByUsername(String username){ try { String sql = "select * from tb_user where username=?"; return qr.query(sql, new BeanHandler<User>(User.class),username); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 按用户邮箱查询 * @param email * @return */ public User findByEmail(String email){ try { String sql = "select * from tb_user where email=?"; return qr.query(sql, new BeanHandler<User>(User.class),email); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 添加用户 * @param user */ public void add(User user){ try { String sql = "insert into tb_user values(?,?,?,?,?,?)"; Object[] params = {user.getUid(),user.getUsername(), user.getPassword(),user.getEmail(), user.getCode(),user.isState()}; qr.update(sql, params); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 按激活码查询 * @param code * @return */ public User findByCode(String code){ try { String sql = "select * from tb_user where code=?"; return qr.query(sql, new BeanHandler<User>(User.class),code); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 更新用户激活状态信息 * @param uid * @param state */ public void updateState(String uid,boolean state){ try { String sql = "update tb_user set state=? where uid=?"; qr.update(sql, state,uid); } catch (SQLException e) { throw new RuntimeException(e); } } }
2、UserService.java
package com.youth.bookstore.user.service; import com.youth.bookstore.user.dao.UserDao; import com.youth.bookstore.user.domain.User; /** * User业务层 * @author 11937 * */ public class UserService { private UserDao userDao = new UserDao(); /** * 注册功能 * @param user * @throws UserException */ public void regist(User form) throws UserException{ User user = userDao.findByUsername(form.getUsername()); if(user != null) throw new UserException("用户名已被注册"); user = userDao.findByEmail(form.getEmail()); if(user != null) throw new UserException("邮箱已被注册"); userDao.add(form); } /* * 激活功能 */ public void active(String code) throws UserException{ /* * 1、使用code查询数据库 ,得到user */ User user = userDao.findByCode(code); /* * 2、校验,如果user不存在,抛异常 */ if(user == null) throw new UserException("激活码无效!"); /* * 3、再次校验,用户是否已经激活 */ if(user.isState()) throw new UserException("您已经激活过了,请直接登录!"); /* * 4、激活成功 */ userDao.updateState(user.getUid(), true); } }
3、UserException.java
package com.youth.bookstore.user.service; public class UserException extends Exception{ public UserException() { super(); // TODO Auto-generated constructor stub } public UserException(String message) { super(message); } }
4、 UserServlet.java
package com.youth.bookstore.user.web.servlet; import java.io.IOException; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.mail.MessagingException; import javax.mail.Session; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.commons.CommonUtils; import cn.itcast.mail.Mail; import cn.itcast.mail.MailUtils; import cn.itcast.servlet.BaseServlet; import com.youth.bookstore.user.domain.User; import com.youth.bookstore.user.service.UserException; import com.youth.bookstore.user.service.UserService; /** * User表述层 * @author 11937 * */ public class UserServlet extends BaseServlet { private UserService userService = new UserService(); /** * 激活功能 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String active(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1、获取参数激活码 * 2、调用service方法激活 * > 保存异常信息到request域,转发到msg.jsp * 3、保存成功信息到request域,转发到msg.jsp */ String code = request.getParameter("code"); try { userService.active(code); request.setAttribute("msg", "恭喜,您已激活成功,请赶快登录吧!"); } catch (UserException e) { request.setAttribute("msg", e.getMessage()); } return "f:/jsps/msg.jsp"; } /** * 注册功能 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1.封装表单数据到form对象中 * 2.补全uid、code * 3、输入校验 * >保存错误信息、form到request域,转发到regist.jsp * 4、调用service方法完成注册 * >保存错误信息、form到request域,转发到regist.jsp * 5、发邮件 * 6、保存成功信息转发到regist.jsp */ //封装表单数据 User form = CommonUtils.toBean(request.getParameterMap(), User.class); //补全 form.setUid(CommonUtils.uuid()); form.setCode(CommonUtils.uuid() + CommonUtils.uuid()); /*输入校验 * 1.创建一个map,用来封装错误信息 */ Map<String,String> errors = new HashMap<String,String>(); String username = form.getUsername(); if(username == null || username.trim().isEmpty()){ errors.put("username", "用户名不能为空"); }else if(username.length() < 3 || username.length() >10){ errors.put("username", "用户名长度必须在3~10之间"); } String password = form.getPassword(); if(password == null || password.trim().isEmpty()){ errors.put("password", "密码不能为空"); }else if(password.length() < 3 || password.length() >10){ errors.put("password", "密码长度必须在3~10之间! "); } String email = form.getEmail(); if(email == null || email.trim().isEmpty()){ errors.put("email", "邮箱不能为空"); }else if(!email.matches("\\w+@\\w+\\.\\w+")){ errors.put("email", "Email格式错误 "); } /* * 3、判断是否存在错误信息 */ if(errors.size() > 0){ //保存错误信息 //保存表单数据 //转发至regist.jsp request.setAttribute("errors", errors); request.setAttribute("form", form); return "f:/jsps/user/regist.jsp"; } /* * 调用service的regist方法 */ try { userService.regist(form); } catch (UserException e) { //保存错误信息 //保存表单数据 //转发至regist.jsp request.setAttribute("msg", e.getMessage()); request.setAttribute("form", form); return "f:/jsps/user/regist.jsp"; } /* * 说明userService执行成功 */ /* * 发送邮件 * 准备配置文件 */ //获取配置文件内容 Properties props = new Properties(); props.load(this.getClass().getClassLoader(). getResourceAsStream("email_template.properties")); String host = props.getProperty("host"); //获取主机 String uname = props.getProperty("uname"); //获取用户名 String pwd = props.getProperty("pwd"); String from = props.getProperty("from"); String to = form.getEmail(); //获取发件人 String subject = props.getProperty("subject"); String content = props.getProperty("content"); //获取邮件内容 //{0}为占位符的格式 //MessageFormat.format('{0}或者{1}出错','name','password') content = MessageFormat.format(content,form.getCode()); //替换{0} Session session = MailUtils.createSession(host, uname, pwd); Mail mail = new Mail(from,to,subject,content); try{ MailUtils.send(session, mail); } catch(Exception e){ throw new RuntimeException(e); } /* 1、保存成功信息 * 2、转发到msg.jsp */ request.setAttribute("msg", "恭喜,注册成功!请马上到邮箱激活 "); return "f:/jsps/msg.jsp"; } }
5、User.java
package com.youth.bookstore.user.domain; /** * User的领域对象 * * @author 11937 * */ public class User { /** * 对应数据库 */ private String uid; // 主键 private String username; private String password; private String email; private String code; // 激活码 private boolean state; // 激活状态 public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } 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; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public boolean isState() { return state; } public void setState(boolean state) { this.state = state; } public User(String uid, String username, String password, String email, String code, boolean state) { super(); this.uid = uid; this.username = username; this.password = password; this.email = email; this.code = code; this.state = state; } @Override public String toString() { return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", email=" + email + ", code=" + code + ", state=" + state + "]"; } public User() { super(); } }
6、数据库建立如下:
CREATE DATABASE bookstore; /*用户表*/ CREATE TABLE tb_user( uid CHAR(32) PRIMARY KEY,/*主键*/ username VARCHAR(50) NOT NULL,/*用户名*/ `password` VARCHAR(50) NOT NULL,/*密码*/ email VARCHAR(50) NOT NULL,/*邮箱*/ `code` CHAR(64) NOT NULL,/*激活码*/ state BOOLEAN/*用户状态,有两种是否激活*/ ); SELECT * FROM tb_user; /*分类*/ CREATE TABLE category ( cid CHAR(32) PRIMARY KEY,/*主键*/ cname VARCHAR(100) NOT NULL/*分类名称*/ ); INSERT INTO category(cid,cname) VALUES ('1','JavaSE'); INSERT INTO category(cid,cname) VALUES ('2','JavaEE'); INSERT INTO category(cid,cname) VALUES ('3','Javascript'); SELECT * FROM category; /*图书表*/ CREATE TABLE book ( bid CHAR(32) PRIMARY KEY,/*主键*/ bname VARCHAR(100),/*图书名*/ price DECIMAL(5,1),/*单价*/ author VARCHAR(20),/*作者*/ image VARCHAR(200),/*图片*/ cid CHAR(32),/*所属分类*/ FOREIGN KEY (cid) REFERENCES category(cid)/*建立主外键关系*/ ); INSERT INTO book VALUES ('1','Java编程思想(第4版)','75.6','qdmmy6','book_img/9317290-1_l.jpg','1'); INSERT INTO book VALUES ('2','Java核心技术卷1','68.5','qdmmy6','book_img/20285763-1_l.jpg','1'); INSERT INTO book VALUES ('3','Java就业培训教程','39.9','张孝祥','book_img/8758723-1_l.jpg','1'); INSERT INTO book VALUES ('4','Head First java','47.5','(美)塞若','book_img/9265169-1_l.jpg','1'); INSERT INTO book VALUES ('5','JavaWeb开发详解','83.3','孙鑫','book_img/22788412-1_l.jpg','2'); INSERT INTO book VALUES ('6','Struts2深入详解','63.2','孙鑫','book_img/20385925-1_l.jpg','2'); INSERT INTO book VALUES ('7','精通Hibernate','30.0','孙卫琴','book_img/8991366-1_l.jpg','2'); INSERT INTO book VALUES ('8','精通Spring2.x','63.2','陈华雄','book_img/20029394-1_l.jpg','2'); INSERT INTO book VALUES ('9','Javascript权威指南','93.6','(美)弗兰纳根','book_img/22722790-1_l.jpg','3'); SELECT * FROM book; /*订单表*/ CREATE TABLE orders ( oid CHAR(32) PRIMARY KEY,/*主键*/ ordertime DATETIME,/*订单生成时间*/ total DECIMAL(10,0),/*订单合计*/ state SMALLINT(1),/*订单状态:未付款、已付款但未发货、已发货但未确认收货、收货已结束*/ uid CHAR(32),/*订单的主人*/ address VARCHAR(200),/*订单的收货地址*/ FOREIGN KEY (uid) REFERENCES tb_user(uid)/*建立主外键关系*/ ); SELECT * FROM orders; /*订单项表*/ CREATE TABLE orderitem ( iid CHAR(32) PRIMARY KEY,/*主键*/ `count` INT,/*数量*/orderitem subtotal DECIMAL(10,0),/*小计*/ oid CHAR(32),/*所属订单*/ bid CHAR(32),/*订单项所指的商品*/ FOREIGN KEY (oid) REFERENCES orders (oid),/*建立主外键关系*/ FOREIGN KEY (bid) REFERENCES book (bid)/*建立主外键关系*/ ); SELECT * FROM orderitem;
总结:在设计过程中,有一个问题我几乎弄了一个下午,就是我在发送邮件的时候,邮箱服务器指定为stmp.qq.com时,用qq邮箱给其他邮箱发邮件时,如果发给对方的是qq邮箱,对方可以接收到邮件,但是无法打开设定的超链接,我查看了它的源码,在相应位置处,确实是一个a标签,同时链接也并有错误,单独把链接复制过来去访问,则可以成功。我用此qq邮箱给163邮箱发送邮件,163邮箱可以直接点开链接。后来我又用163邮箱给qq发送邮件,发现根本无法连接163服务器,我确认已经登录网页163邮箱,打开了了 POP3/SMTP/IMAP,但是依旧没有解决此问题,希望看到这篇博客的博友,如果好的解决方案,请分享到下面,感激不尽。
写于2015-12-18 21:22:16。