一、完整代码已上传到github:https://github.com/LazyTraveller/estore
二、需求分析
1.整个项目是分成前台页面和后台管理两部分组成。
* 前台:提供用户浏览,购买,查看订单等功能。
* 后台:提供管理员管理商城,提供添加图书、分类等功能。
2.根据网上商城的需求分成以下几个模块。
1.用户模块
* 前台:
1.注册功能(包含发送一封邮件给用户,用户需要点击激活链接才能登陆)
2.激活链接功能(注册后,点击链接激活后,才能登陆成功 -- 实现方式可以修改用户的状态(可以规定0代表没有激活,1代码已经激活))
3.登陆功能(注册成功后,可以登陆--实现方式根据用户名和密码以及用户状态(1状态代表已经激活))
4.退出功能(用户登陆成功,会把用户信息存入到session中,通过销毁session完成退出功能)
* 后台:
1.登陆后台功能
2.分类模块
* 前台:
1.查询分类的功能
* 后台:
1.查看分类功能
2.增加分类功能
3.修改分类功能
4.删除分类功能
3.商品模块
* 前台:
1.查询所有分类的商品
2.查询某一个分类的商品
3.查询某个商品的详情
* 后台:
1.添加商品(上传商品图片)
2.修改商品
3.删除商品
4.查询商品
4.订单模块
* 前台
1.生成订单
2.按用户查找订单
3.查看某个订单
* 后台
1.查询所有订单
2.查询某个状态订单
三、页面设计(一般由美工完成)
依据页面原型进行开发。
四、数据库的设计
一个实体就会对应一个数据库中表.
* 用户:
* 编号(主键)
* 用户名
* 密码
* 邮箱
* 激活码(发送邮件时显示的激活码)
* 状态 0:未激活 1:已经激活
* 分类
* 编号(主键)
* 名称
* 图书
* 编号(主键)
* 名称
* 作者
* 价格
* 图片(存放图片的地址)
* 分类编号(外键) -- 和分类是一对多的关系,所以在图书表中创建外键指向分类表中的主键
* 订单
* 编号(主键)
* 时间
* 金额
* 地址
* 状态
* 用户编号(外键)-- 和用户是一对多的关系,所以在订单表中创建外键指向用户表中的主键
* 订单图书中间表:
* 订单项编号(主键)
* 图书编号(外键)-- 和图书表是一对多的关系,所以在订单图书中间表中创建外键指向图书表中的主键
* 订单编号(外键)-- 和订单表是一对多的关系,所以在订单图书中间表中创建外键指向订单表中的主键
* 数量
* 小计
五、编写代码,部署上线,后期维护。
一、根据页面原型进行功能扩展美化
前台原型页面:
后台原型页面:
二、搭建开发环境
*创建estore的项目,把原型的文件拷贝进去
*开发架构:Servlet+JSP+javaBean+JDBC
*向lib中导入jar包
*创建包架构
三、进行开发
在cn.itcast.servlet包中创建模板servlet,用于调用方法,在下面使用时需要更改servlet的名称
*编写通用的BaseServlet
package cn.itcast.servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* BaseServlet通用的Servlet
* @author Administrator
*
*/
public class BaseServlet extends HttpServlet{
private static final long serialVersionUID = -7510809537032738047L;
/**
* 服务器会调用该service方法
*/
public void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 设置编码
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 可以进行一些判断控制
// 对用户有一些要求:给我传过来取你要调用的方法 http://localhost/estore/demo?method=xxxUser
// addUser方法的签名也有要求:addUser(HttpServletRequest request, HttpServletResponse response)
// 参数必须是HttpServletRequest request,HttpServletResponse response
// 获取method参数
String methodName = req.getParameter("method");
// 如果methodName忘了传入了
if(methodName == null || methodName.trim().isEmpty()){
throw new RuntimeException("亲,请您传入method参数!!");
}
// 通过反射的技术,来完成该事
// 获取Class对象,获取method对象。
Class clazz = this.getClass();
// 通过clazz获取method对象
Method method = null;
try {
method = clazz.getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException("亲,您传入的"+methodName+"不存在!!");
}
try {
// method肯定有值了,让method方法执行
String result = (String) method.invoke(this, req,resp);
// /jsps/msg.jsp
if(result != null && !result.trim().isEmpty()){
req.getRequestDispatcher(result).forward(req, resp);
}
} catch (Exception e) {
System.out.println("程序内部错误");
throw new RuntimeException(e);
}
}
}
ServletDemo.java(调用ServletBean判断执行调用哪些方法)
package cn.itcast.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 测试
* @author Administrator
*/
public class ServletDemo extends BaseServlet {
private static final long serialVersionUID = 2947357007498494328L;
public String addUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("addUser...");
// 想做重定向
// response.sendRedirect("");
return "ss";
}
public void updateUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("updateUser...");
}
public void deleteUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("deleteUser...");
}
}
用户的模块
*在MySQL中创建数据库
并关联到c3p0-config.xml
com.mysql.jdbc.Driver
jdbc:mysql:///estore
root
root
在cn.itcast.vo包中创建
user.java javabean封装对象
package cn.itcast.vo;
/**
* 用户的JavaBean
* @author Administrator
*
*/
public class User {
private String uid;
private String username;
private String password;
private String email;
private int state;
private String code;
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 int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
前台页面分析:
几个jsp组合成一个前台页面
实现注册功能:
1.用户输入数据(用户名,密码,邮箱)
*主键
*把用户的默认状态设置成0(未激活的状态)
*默认生成激活码code字段
2.需要给注册的用户的邮箱发送一封邮件
3.流程 regist.jsp-->UerServlet(指定regist方法的名称)-->调用userService--》调用UserDao
regist.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
注册
注册
${msg }
编写和用户相关的Servlet:
UserServlet.java
package cn.itcast.servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import cn.itcast.service.UserService;
import cn.itcast.vo.User;
/**
* 和用户相关的Servlet
* 先改继承BaseServlet
* @author Administrator
*/
public class UserServlet extends BaseServlet {
private static final long serialVersionUID = -8230838990948681763L;
/**
* 注册用户的方法
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String registUser(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 接收数据
// 封装数据
// 处理数据
// 显示数据
// 接收数据
Map map = request.getParameterMap();
// 封装数据
User user = new User();
try {
BeanUtils.populate(user, map);
// 处理数据
UserService us = new UserService();
// 注册用户
boolean flag = us.registUser(user);
// 根据返回的结果,调用不同页面进行处理
// 注册失败了
if(flag == false){
// 向request域中存入消息
request.setAttribute("msg", "注册失败!!");
}else{
// 向request域中存入消息
request.setAttribute("msg", "注册成功,请您激活!!");
}
} catch (Exception e) {
e.printStackTrace();
}
// 在BaseServlet中完成了转发的功能
return "/jsps/msg.jsp";
}
/**
* 邮件激活用户的方法
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String active(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 先获取code激活码77cec5d12a5840dd88dd6f9a7f0ad2c467c55972837e484d9851fad028169407
String code = request.getParameter("code");
// 处理数据
UserService us = new UserService();
// 通过激活码查询的用户
User user = us.findUserByCode(code);
// 如果用户为空,说明没有查到用户
if(user == null){
request.setAttribute("msg", "激活失败了");
}else{
// 修改用户的状态,状态默认值0,修改成1.
user.setState(1);
// 再调用UserService修改方法
us.updateUser(user);
// 设置信息
request.setAttribute("msg", "激活成功了,请您登陆!!");
}
return "/jsps/msg.jsp";
}
/**
* 用户登陆的功能
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 获取数据
* 封装数据
* 处理数据
* 显示数据
*/
Map map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map);
UserService us = new UserService();
// 登陆功能
User existUser = us.login(user);
// 如果登陆失败,给出用户提示
if(existUser == null){
request.setAttribute("msg", "用户名或者密码错误或者未激活!!");
return "/jsps/msg.jsp";
}else{
// 如果登陆成功,把用户的信息保存到session中,转发到首页
request.getSession().setAttribute("existUser", existUser);
// 转发main.jsp的页面上
return "/jsps/main.jsp";
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 用户退出的功能
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String exit(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取session,直接销毁
request.getSession().invalidate();
return "/jsps/main.jsp";
}
}
在cn.itcast.service包中创建(业务层)
Userservice.java
package cn.itcast.service;
import cn.itcast.dao.UserDao;
import cn.itcast.dao.UserDaoImple;
import cn.itcast.utils.MailUtil;
import cn.itcast.utils.MyUUIDUtil;
import cn.itcast.vo.User;
/**
* 用户相关的业务类
* @author Administrator
*
*/
public class UserService {
/**
* 业务层注册用户
* @param user
* @return
*/
public boolean registUser(User user) {
// 调用持久层代码注册用户
UserDao dao = new UserDaoImple();
// 添加业务
/**
* 用户的主键(字符串类型)
* 设置用户的状态为0
* 生成激活码
*/
// 生成主键
user.setUid(MyUUIDUtil.getUUID());
// 设置状态码为0 -- 未激活的状态
user.setState(0);
// 生成激活码
String code = MyUUIDUtil.getUUID()+MyUUIDUtil.getUUID();
user.setCode(code);
// 发送一封邮件
MailUtil.sendMail(user.getEmail(), code);
return dao.saveUser(user);
}
/**
* 通过code查询用户
* @param code
* @return
*/
public User findUserByCode(String code) {
UserDao dao = new UserDaoImple();
return dao.findUserByCode(code);
}
/**
* 修改的方法
* @param user
*/
public void updateUser(User user) {
UserDao dao = new UserDaoImple();
dao.updateUser(user);
}
public User login(User user) {
UserDao dao = new UserDaoImple();
return dao.login(user);
}
}
持久层:
在cn.itcast.dao添加userdao接口
package cn.itcast.dao;
import cn.itcast.vo.User;
public interface UserDao {
boolean saveUser(User user);
User findUserByCode(String code);
void updateUser(User user);
User login(User user);
}
UserDaolmple.java是userDao的实现类(同一个包):
package cn.itcast.dao;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.itcast.utils.MyJdbcUtil;
import cn.itcast.vo.User;
/**
* 用户相关的持久层代码
* @author Administrator
*
*/
public class UserDaoImple implements UserDao {
/**
* 注册用户
*/
public boolean saveUser(User user) {
boolean flag = false;
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "insert into user values (?,?,?,?,?,?)";
Object [] params = {user.getUid(),user.getUsername(),user.getPassword(),user.getEmail(),user.getState(),user.getCode()};
try {
// 执行注册的方法
int count = runner.update(sql, params);
// 根据返回值进行判断
if(count > 0){
flag = true;
}
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return flag;
}
/**
* 通过code查询用户
*/
public User findUserByCode(String code) {
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "select * from user where code = ?";
try {
return runner.query(sql, new BeanHandler(User.class), code);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 修改用户的所有的信息
*/
public void updateUser(User user) {
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "update user set username = ? , password = ?,email = ?,state = ?,code = ? where uid = ?";
Object [] params = {user.getUsername(),user.getPassword(),user.getEmail(),user.getState(),user.getCode(),user.getUid()};
try {
runner.update(sql, params);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 登陆的功能
*/
public User login(User user) {
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "select * from user where username = ? and password = ? and state = ?";
try {
return runner.query(sql, new BeanHandler(User.class), user.getUsername(),user.getPassword(),1);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
在cn.iscast.utils包中创建MyUUIDUtil.java,获取唯一的序列字符串
package cn.itcast.utils;
import java.util.UUID;
/**
* 随机生成字符串
* @author Administrator
*
*/
public class MyUUIDUtil {
/**
* 随机的生成字符串
* @return
*/
public static String getUUID(){
return UUID.randomUUID().toString().replace("-", "");
}
}
邮件的功能
*邮件的服务器
安装提供的邮件的服务器
*电子邮箱
*邮箱的协议
发送邮件协议 SMTP协议
接受邮件的协议 POP3协议
*IMAP协议(不是所有的邮箱支持)
先安装邮件的服务器
链接:https://pan.baidu.com/s/1B6_xsKTnKFLd8xlTHpwGkg
提取码:mmyc
双击安装
配置邮件服务器 点击设置 选择单域名 修改域名
申请账号 点击新账号
然后安装邮件的客户端
*网页版 --以前的版本登录后失效的时间
*客户端软件 --不是有该问题 默认的时间去接受邮件
双击安装,一路继续
配置客户端,与服务器绑定,填写自己申请的账号密码
实现注册的时候发送一封邮件:
发送邮件工具类,在cn.itcast.utils包中创建一个MailUtils.ajva
用于获取服务器链接
package cn.itcast.utils;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
/**
* 发送邮件工具类
* @author Administrator
*/
public class MailUtil {
/**
* 发送邮件
* @param to 发送给谁
* @param code 激活码
*/
public static void sendMail(String to,String code){
// 1.属性对象
Properties props = new Properties();
// 发送邮件的协议
props.setProperty("mail.smtp", "localhost");
// 2.创建一个对象Session.
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("[email protected]", "123");
}
});
// 3.创建一个代表邮件的对象:
Message message = new MimeMessage(session);
try {
// 设置发件人:
message.setFrom(new InternetAddress("[email protected]"));
// 设置收件人:
// TO:收件人.
// CC:抄送
// BCC:暗送,密送
message.setRecipient(RecipientType.TO, new InternetAddress(to));
// 设置邮件的主题:
message.setSubject("ESTORE官方网站的激活邮件");
// 设置邮件的正文:
message.setContent("欢迎来到ESTROE购物天堂
http://192.168.35.64/estore/user?method=active&code="+code+"
", "text/html;charset=UTF-8");
// 发送邮件:
Transport.send(message);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
和UserService.java结合使用实现通过邮件验证注册
public boolean registUser(User user) {
// 调用持久层代码注册用户
UserDao dao = new UserDaoImple();
// 添加业务
/**
* 用户的主键(字符串类型)
* 设置用户的状态为0
* 生成激活码
*/
// 生成主键
user.setUid(MyUUIDUtil.getUUID());
// 设置状态码为0 -- 未激活的状态
user.setState(0);
// 生成激活码
String code = MyUUIDUtil.getUUID()+MyUUIDUtil.getUUID();
user.setCode(code);
// 发送一封邮件
MailUtil.sendMail(user.getEmail(), code);
return dao.saveUser(user);
}
在USerServlet.java中添加邮件激活方法
*从连接发送code的激活码
*在数据库中保存了一个激活码
*获取到get请求发送过来的激活码,去数据库中进行查询,如果查询到了返回user,修改用户的状态为state=1(激活状态)
/**
* 邮件激活用户的方法
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String active(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 先获取code激活码77cec5d12a5840dd88dd6f9a7f0ad2c467c55972837e484d9851fad028169407
String code = request.getParameter("code");
// 处理数据
UserService us = new UserService();
// 通过激活码查询的用户
User user = us.findUserByCode(code);
// 如果用户为空,说明没有查到用户
if(user == null){
request.setAttribute("msg", "激活失败了");
}else{
// 修改用户的状态,状态默认值0,修改成1.
user.setState(1);
// 再调用UserService修改方法
us.updateUser(user);
// 设置信息
request.setAttribute("msg", "激活成功了,请您登陆!!");
}
return "/jsps/msg.jsp";
}
UserDao.java中添加:
User findUserByCode(String code);
在UserDaoImple.java:
/**
* 通过code查询用户
*/
public User findUserByCode(String code) {
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "select * from user where code = ?";
try {
return runner.query(sql, new BeanHandler(User.class), code);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
登录功能:
login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
登录
登录
${msg }
在UserServlet.java中添加方法,封装数据:
/**
* 用户登陆的功能
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 获取数据
* 封装数据
* 处理数据
* 显示数据
*/
Map map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, map);
UserService us = new UserService();
// 登陆功能
User existUser = us.login(user);
// 如果登陆失败,给出用户提示
if(existUser == null){
request.setAttribute("msg", "用户名或者密码错误或者未激活!!");
return "/jsps/msg.jsp";
}else{
// 如果登陆成功,把用户的信息保存到session中,转发到首页
request.getSession().setAttribute("existUser", existUser);
// 转发main.jsp的页面上
return "/jsps/main.jsp";
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
在UserServlet.java中添加方法:
public User login(User user) {
UserDao dao = new UserDaoImple();
return dao.login(user);
}
在UserDao.java中添加
User login(User user);
在UserDaoiImple.java
/**
* 登陆的功能
*/
public User login(User user) {
QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
String sql = "select * from user where username = ? and password = ? and state = ?";
try {
return runner.query(sql, new BeanHandler(User.class), user.getUsername(),user.getPassword(),1);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
top.jsp
您好:${ existUser.username } |
我的购物车 |
退出功能:
top.jsp
退出
在UserServlet.java中添加
/**
* 用户退出的功能
* @param request
* @param response
* @return
* @throws ServletException
* @throws IOException
*/
public String exit(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取session,直接销毁
request.getSession().invalidate();
return "/jsps/main.jsp";
}
完整的代码已经上传到github。