JAVA WEB从入门到精通 day25 项目:网上书城

项目:网上书店

功能分析

网站分为前台和后台。前台为用户使用,后台为管理员管理。 

前台:
    用户模块
        -注册
        -激活:通过电子邮件
        -登陆
        -退出

    图书的分类模块
        -查询图书的分类显示在页面上 
        例如:文学书,动漫书之类 

    图书模块
        -查询所有图书
        -分类查询图书
        -查询图书详情(按图书编号查询)

    购物车模块
        -添加商品
        -清空购物车
        -删除指定商品
        -我的购物车(按用户查询购物车)

    订单模块
        -生成订单
        -我的订单(按用户查询订单)
        -确认收货
        -付款功能



后台
    管理员模块:
        -登录

    图书分类管理模块
        -添加分类
        -查看分类
        -删除分类
        -修改分类

    图书管理模块
        -查看所有图书
        -按图书编号查询
        -修改图书
        -删除图书
        -添加图书

    订单模块
        -查询所有订单
        -按订单状态查询(未付款,未发货之类的)
        -发货

项目的搭建

    1.导包
        数据库相关:数据库驱动,c3p0连接池(jar包和配置文件),DBUtils  
        邮箱相关:JavaMail,activation
        上传相关:commons-fileupload,commons-io 
        其他依赖包 commons-logging
        我们自己制作的工具类等

    2.创建package  
         用户模块
            domain
            dao
            service
            web 
        分类模块
            domain
            dao
            service
            web 
        图书模块
            domain
            dao
            service
            web 
        购物车模块
            domain
            dao
            service
            web 
        订单模块
            domain
            dao
            service
            web  

    3.创建数据库表 
        /*创建数据库*/
        CREATE DATABASE bookstore;

        /*创建用户表*/
        CREATE TABLE 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/*用户状态,有两种是否激活*/
        );

        /*创建图书分类表*/
        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');

        /*创建图书表*/
        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');



        /*创建订单表*/
        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 USER (uid)/*建立主外键关系*/
        );



        /*创建订单项表*/
        CREATE TABLE orderitem (
          iid CHAR(32) PRIMARY KEY,/*主键*/
          COUNT INT,/*数量*/
          subtotal DECIMAL(10,0),/*小计*/
          oid CHAR(32),/*所属订单*/
          bid CHAR(32),/*订单项所指的商品*/
          FOREIGN KEY (oid) REFERENCES orders (oid),/*建立主外键关系*/
          FOREIGN KEY (bid) REFERENCES book (bid)/*建立主外键关系*/
        );

项目前台

用户模块

创建相关类
        -在domain包下创建user类
        -dao包创建UserDao类
        -service包创建UserService类
        -web.servlet包下创建UserServlet

------------------------------注册功能分析-----------------------------------------
        流程分析:
            注册页面regist.jsp : 请求UserServlet的注册方法,发送表单里的数据 

            UserServlet#regist():将表单数据封装到user对象中
                                  对数据进行校验,如果数据有误,将表单数据和错误信息转发回regist.jsp 页面
                                  调用Service层的regist()方法,传递user对象 
                                  -如果抛出异常,将异常信息和表单数据转发到regist.jsp中,为了回显
                                  -如果成功注册,发送激活邮件(收件人,发件人,主题,内容),发送成功保存成功信息转发到msg.jsp中。邮件内容应该包含一个用来激活的url,链接中要有激活码。 

            UserService#regist(User user):
                                  校验用户名是否被注册,如果注册,抛出自定义异常
                                  校验邮箱是否被注册,如果注册,抛出自定义异常 
                                  把user插入到数据库中 

            UserDao:
                    findByUsername(String username):按用户名查询
                    findByEmail(String email):按email查询用户
                    void add(User user):插入用户到数据库中 

-----------------------------激活功能分析-----------------------------------
            流程分析:
            注册成功后向用户邮箱发送一封激活邮件,里面包含一个URL地址,携带了用户的激活码。

            UserServlet#activate():
                                    获取激活码参数,调用service层的activate(String code)激活方法
                                  出现异常,保存异常信息转发到msg页面
                                  激活成功,保存成功信息转发到msg页面

            UserService#activate(String code):
                                使用激活码去查找数据库,得到user对象
                                数据库返回null,抛出异常
                                如果用户的状态为已激活,抛出异常
                                如果用户状态为未激活,则修改用户状态为true,激活状态

            UserDao:
                    findByCode(String code):通过激活码查找用户
                    updateState(String uid,boolean state):修改用户状态

    ------------------------------登录功能分析----------------------------------- 
    流程分析:
            login.jsp:一个表单,包含账号密码

            UserServlet#login():
                                将用户名和密码封装成user对象
                                校验用户名和密码
                                调用service层的login方法
                                如果出现异常就保存异常信息到request中,转发回login.jsp页面 
                                如果登录成功,就保存用户信息到session中,重定向到主页 

            UserService#login(User user):
                                使用username查询数据库,得到user对象。
                                如果结果为null,抛出用户不存在异常。

                                如果存在该用户,比较表单中的用户密码和数据库中的密码是否相同
                                如果不同抛出异常

                                查看用户状态,如果用户状态未激活,抛出异常。

                                前面全部成功,返回user对象。

            UserDao:
                            findByUsername():根据用户名查找用户 



----------------------退出功能分析-------------------------------------------
            UserServlet#quit()
                            :调用session的invalidate()方法销毁用户session,然后返回主页即可

代码实现

    domain包下的User类 
public class User {

    private String uid;           //用户id,主键
    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;
    }
    @Override
    public String toString() {
        return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", email=" + email + ", code="
                + code + ", state=" + state + "]";
    }   
}

登录和注册页面

JAVA WEB从入门到精通 day25 项目:网上书城_第1张图片

JAVA WEB从入门到精通 day25 项目:网上书城_第2张图片

    UserServlet 
    我们继承我们以前编写的BaseServlet,来方便我们使用反射操作。

public class UserServlet extends BaseServlet {
    //依赖service层
    private UserService userservice=new UserService();

    //生成UUID的方法
    public String UUID(){
        return UUID.randomUUID().toString().replaceAll("-", "");
    } 
    //注册功能
    public String regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取表单数据,封装成user对象
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        String email=request.getParameter("email"); 
        User user=new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setEmail(email);
        user.setUid(UUID());
        user.setCode(UUID()+UUID());  
        //对表单数据进行校验,错误信息存放在map集合中
        Map errors=new HashMap();
        //校验用户名
        if(username==null||username.trim().isEmpty()){
            errors.put("username", "用户名不能为空");
        }else if(username.length()<5||username.length()>=16)
        {
            errors.put("username", "用户名必须在6-15位之间");
        }
        //校验密码
        if(password==null||password.trim().isEmpty()){
            errors.put("password", "密码不能为空");
        }else if(password.length()<5||password.length()>=16)
        {
            errors.put("password", "密码必须在6-15位之间");
        }
        //校验邮箱
        if(email==null||email.trim().isEmpty()){
            errors.put("email", "邮箱不能为空");
        }else if(!email.matches("\\w+@\\w+\\.\\w+"))
        {
            errors.put("email", "邮箱错误");
        }

        //判断是否有错误,有的话就将表单数据(为了回显)和错误信息转发到注册页面
        if(errors.size()>0){
            request.setAttribute("errors", errors);
            request.setAttribute("formuser", user);
            return "forward:/jsps/user/regist.jsp";
        } 

        //没错误就调用service层的regist方法
        try {
            userservice.regist(user);
        } catch (UserException e) {
            //抛出异常的话就将异常信息保存在request中,转发到注册页面
            request.setAttribute("msg", e.getMessage());
            request.setAttribute("formuser", user);
            return "forward:/jsps/user/regist.jsp";
        } 

        //注册成功就发送邮件,我们将邮件的一些参数放在配置文件中
        Properties prop=new Properties();
        //加载邮件相关配置文件prop.load(this.getClass().getClassLoader().getResourceAsStream("email.properties"));
        String host=prop.getProperty("host");     //获取邮箱主机
        String ename=prop.getProperty("ename");   //获取邮箱用户名
        String epasswd=prop.getProperty("epasswd");//获取用户密码
        String from=prop.getProperty("from");     //获取发件人
        String to=user.getEmail();                //获取收件人
        String subject=prop.getProperty("subject");//获取邮件主题
        String content=prop.getProperty("content");//获取邮件内容
        content=MessageFormat.format(content, user.getCode()); 
        Properties props = new Properties(); 
        props.setProperty("mail.host", host);//设置服务器主机名
        props.setProperty("mail.smtp.auth", "true");//设置需要认证
        Authenticator auth = new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication () {
                return new PasswordAuthentication(ename, epasswd);//用户名和密码
        }
        };
        Session session=Session.getInstance(props, auth);
        MimeMessage msg=new MimeMessage(session);   //获取MimeMessage对象
        try{
        msg.setFrom(new InternetAddress(from));   //设置发件人
        msg.setRecipients(RecipientType.TO, to);  //设置收件人

        msg.setSubject(subject);  //设置主题
        msg.setContent(content, "text/html;charset=utf-8"); //设置正文
        Transport.send(msg); //发送邮件
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
        request.setAttribute("msg", "恭喜注册成功。请到邮箱激活");

        return "forward:/jsps/msg.jsp";
    }

    //激活方法
    public String activate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //获取激活码
        String code=request.getParameter("code");
        try { 
            //调用service的激活方法,成功就保存成功信息转发到msg页面 
            userservice.activate(code);
            request.setAttribute("msg", "恭喜您,激活成功");
            return "forward:/jsps/msg.jsp";
        } catch (UserException e) { 
            //出现异常就保存异常信息转发到msg页面
            request.setAttribute("msg",e.getMessage());
            return "forward:/jsps/msg.jsp";
        }
    }

    //登录功能
    public String login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取登录的账号密码,并封装
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        User user=new User();
        user.setUsername(username);
        user.setPassword(password); 
        Map errors=new HashMap();
        //校验用户名
        if(username==null||username.trim().isEmpty()){
            errors.put("username", "用户名不能为空");
        }else if(username.length()<5||username.length()>=16)
        {
            errors.put("username", "用户名必须在6-15位之间");
        }
        //校验密码
        if(password==null||password.trim().isEmpty()){
            errors.put("password", "密码不能为空");
        }else if(password.length()<5||password.length()>=16)
        {
            errors.put("password", "密码必须在6-15位之间");
        }
        if(errors.size()>0){
            request.setAttribute("errors", errors);
            request.setAttribute("formuser", user);
            return "forward:/jsps/user/login.jsp";
        } 
        //如果登录成功,就将用户信息保存在session中,否则保存错误信息返回登陆页面
        try {
            User _user=userservice.login(user); 
            request.getSession().setAttribute("sessionuser", _user);
            request.getSession().setAttribute("cart", new Cart());
            return "redirect:/index.jsp";
        } catch (UserException e) {
            request.setAttribute("msg", e.getMessage());
            request.setAttribute("formuser", user);
            return "forward:/jsps/user/login.jsp";

        }
    } 
    //退出功能
    public String quit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.getSession().invalidate();
        return "redirect:/index.jsp";
    }

}
    UserService :处理业务逻辑 

public class UserService { 
    //依赖dao层
    private UserDao userdao=new UserDao(); 

    //注册功能
    public void regist(User formuser) throws UserException{ 

        //调用dao层方法校验用户名是否被注册,如果已注册抛出自定义异常
        User user=userdao.findByUsername(formuser.getUsername());
        if(user!=null) throw new UserException("用户名已被注册");  

        //校验邮箱是否被使用,如果已使用抛出自定义异常
        user=userdao.findByEmail(formuser.getEmail());
        if(user!=null) throw new UserException("邮箱已被使用"); 

        //添加用户
        userdao.addUser(formuser);
    } 

    //激活功能
    public void activate(String code) throws UserException{ 
        //根据激活码查找用户
        User user=userdao.findByCode(code);
        //如果为空,抛出用户不存在异常
        if(user==null) throw new UserException("用户不存在"); 
        //不为空,如果用户状态为未激活,则将状态设置为激活
        if(user.isState()==false) userdao.updateState(user.getUid(), true);
        //如果已激活,则抛出异常
        else throw new UserException("用户已经激活,请勿重复激活"); 
    }  

    //登录功能
    public User login(User formuser) throws UserException{ 
        //判断用户是否存在,如果不存在抛出自定义异常
        User user=userdao.findByUsername(formuser.getUsername());
        if(user==null) throw new UserException("用户不存在");  

        //判断用户输入的密码是否和数据库里的密码相同,不同则抛出异常
        if(!user.getPassword().equals(formuser.getPassword())) throw new UserException("您的密码错误"); 

        //判断用户是否激活,未激活抛出异常
        if(user.isState()==false) throw new UserException("您的账号未激活"); 
        //返回user对象
        return user;
    }
}
UserDao :对数据的操作  

public class UserDao {
    private QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource()); 

    //按照用户名查询用户 
    public User findByUsername(String username){

        try {
            String sql="select * from user where username=?";
            User user=qr.query(sql, new BeanHandler(User.class), username);

            return user;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    } 

    //按照email查询用户   
    public User findByEmail(String email){
        String sql="select * from user where email=?";
        try {
            return qr.query(sql, new BeanHandler(User.class), email);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }  
    //按照激活码查询用户
    public User findByCode(String code){
        String sql="select * from user where code=?";
        try {
            return qr.query(sql, new BeanHandler(User.class), code);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    } 

    //修改用户状态功能  
    public void updateState(String uid,boolean state){
        String sql="update user set state=? where uid=?";
        try {
            qr.update(sql,state,uid);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    } 

    //添加用户
    public void addUser(User user){
        try {

            String sql="insert into 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);
        }
    }       
}

图书分类模块

创建相关类
            domain包创建Category类
            dao包创建CategoryDao类
            service包创建CategoryService类
            servlet包下创建CategoryServlet 

-------------------------查询所有图书分类功能分析-------------------------
        CategoryDao:
                    findAll():查找所有图书分类,封装成list返回 

        CategoryService:
                    findAll():调用dao层方法,返回List

        CategoryServlet:
                    findAll():调用service层的方法,得到List
                    保存在request域中,转发到left.jsp页面

        left.jsp:遍历查询得到的图书分类,显示在页面上 

代码实现

domain下创建Category类  

public class Category {
    private String cid; //分类id
    private String cname;//分类名称
    public String getCid() {
        return cid;
    }
    public void setCid(String cid) {
        this.cid = cid;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    @Override
    public String toString() {
        return "Category [cid=" + cid + ", cname=" + cname + "]";
    }

}
CategoryServlet

public class CategoryServlet extends BaseServlet  { 
    //依赖service层
    private CategoryService categoryservice=new CategoryService();

    //查找所有分类
    public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //调用service的查找所有分类功能,得到list集合保存在request域中,转发到显示页面
        request.setAttribute("categorylist", categoryservice.findAll());
        return "forward:/jsps/left.jsp";
    }

}
    CategoryService:处理业务逻辑 

public class CategoryService { 
    //依赖dao层,同时还依赖Book的dao层
    private CategoryDao categorydao=new CategoryDao();  
    private BookDao bookdao=new BookDao(); 

    //查找所有分类
    public List findAll(){
        return categorydao.findAll();
    }  

    //后台功能:添加分类
    public void add(Category category) throws CategoryException { 
        //判断分类是否存在,存在就抛出异常
        Category _category=categorydao.isExist(category.getCname());
        if(_category!=null) throw new CategoryException("分类已存在"); 
        //添加分类
        categorydao.add(category);
    } 

    //后台功能:删除分类
    public void delete(String cid) throws CategoryException { 
        //调用bookdao的通过分类查找图书的方法,获取该分类下图书的数量
        int count=bookdao.findBycid(cid); 
        //如果数量大于0,则抛出异常
        if(count>0) throw new CategoryException("该分类下还有图书,不能删除该分类");
        categorydao.delete(cid);
    }  

    //通过cid加载分类功能
    public Category load(String cid) {
        return categorydao.load(cid);
    } 

    //编辑分类功能
    public void edit(Category category) throws CategoryException { 
        //判断分类是否存在
        Category _category=categorydao.isExist(category.getCname());
        if(_category!=null) throw new CategoryException("分类已存在"); 
        //调用dao层的编辑方法
        categorydao.edit(category);
    }
}
    CategoryDao:进行数据的操作  

    public class CategoryDao {
    QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource()); 

    //查找所有分类功能,返回list集合
    public List findAll(){
        String sql="select * from category";
        try {
            return  qr.query(sql, new BeanListHandler(Category.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //添加分类功能
    public void add(Category category) {
        try {
            String sql="insert into category values(?,?)";
            Object []params={category.getCid(),category.getCname()};
            qr.update(sql,params);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }   
    }

    //通过分类名称判断分类是否存在的方法
    public Category isExist(String cname){
        try {
            String sql="select * from category where cname=?";
            return qr.query(sql, new BeanHandler(Category.class),cname);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    } 

    //删除分类
    public void delete(String cid) {
        String sql="delete from category where cid=?";
        try {
            qr.update(sql, cid);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //通过分类id返回分类对象的方法
    public Category load(String cid) {
        try {
            String sql="select * from category where cid=?";
            return qr.query(sql, new BeanHandler(Category.class),cid);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //编辑分类的方法
    public void edit(Category category) {
        try {
            String sql="update category set cname=? where cid=?";
            Object[] params={category.getCname(),category.getCid()};
            qr.update(sql,params);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}
left.jsp:显示分类的页面 

<body>
<div>
    <a href="">全部分类a>
div>

<c:forEach items="${categorylist}" var="category">
<div>
    
    <a href="">${category.cname }a>
div>
c:forEach>
body>

JAVA WEB从入门到精通 day25 项目:网上书城_第3张图片

图书模块

创建相关类
            在book.domain包下创建book类
            在book.dao包下创建BookDao类
            在book.service包下创建BookService类、
            在book.web.servlet包下创建BookServlet


-----------------------------查询所有图书功能分析-----------------------------

            BookDao:
                    findAll():查询所有图书,返回List集合

            BookService:
                    findAll():调用dao层方法,返回List集合 

            BookServlet:
                    findAll():调用service层的findAll方法,获取List集合。
                    保存到request域,转发到显示页面。

            list.jsp:循环遍历图书集合,显示图书  



-------------------------按照图书分类查找图书功能分析----------------------
            BookDao:
                    findBookByCategory(String cid):通过传进来的cid查询图书,返回List集合

            BookService:
                    findBookByCategory(String cid):调用dao层方法,返回List集合 

            BookServlet:
                    ffindBookByCategory(String cid):获取页面传入的cid,调用service层方法,获取List集合。
                    保存到request域,转发到显示页面。

            list.jsp:循环遍历图书集合,显示图书 


--------------------------加载图书详情功能分析-----------------------------

            BookDao:
                    load(String bid):通过图书编号查找指定图书,返回book对象


            BookService:
                    load(String bid):调用dao层方法查找指定图书,返回book对象

            BookServlet:
                    load(String bid):
                                    获取页面传递的bid,调用service层load方法获得book对象。
                                    然后保存在request中,转发到显示的页面。

            desc.jsp:显示图书详情。 

代码实现

    domain下创建Book类  

public class Book {
    private String bid;      //图书编号
    private String bname;    //图书名字
    private double price;    //图书价格 
    private String author;   //作者
    private String image;    //图片路径
    private Category category; //数据库中为cid,这里可以直接对应对象
    public String getBid() {
        return bid;
    }
    public void setBid(String bid) {
        this.bid = bid;
    }
    public String getBname() {
        return bname;
    }
    public void setBname(String bname) {
        this.bname = bname;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public Category getCategory() {
        return category;
    }
    public void setCategory(Category category) {
        this.category = category;
    }
    @Override
    public String toString() {
        return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + ", auther=" + author + ", image=" + image
                + ", category=" + category + "]";
    }

}
    BookServlet  

public class BookServlet extends BaseServlet { 
    //依赖service层
    private BookService bookservice=new BookService(); 

    //查找所有图书功能
    public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //调用service层的findAll方法获取图书的集合,存放在request中,转发到list页面
        request.setAttribute("booklist", bookservice.findAll());
        return "forward:/jsps/book/list.jsp";
    } 

    //通过分类查找图书功能
    public String findBookByCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //获取分类编号
        String cid=request.getParameter("cid"); 
        //获取该分类下的图书的集合,存放在request中,转发到list页面
        request.setAttribute("booklist", bookservice.findBookByCatyegory(cid));
        return "forward:/jsps/book/list.jsp";
    } 

    //加载图书详情功能
    public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取图书编号
        String bid=request.getParameter("bid"); 
        //调用service层的方法,获取book对象,存放在request中,转发到desc页面
        request.setAttribute("book", bookservice.load(bid));
        return "forward:/jsps/book/desc.jsp";
    }

}
    BookService:处理业务逻辑

public class BookService { 
    //依赖dao层
    private BookDao bookdao=new BookDao(); 

    //查找所有图书的功能
    public List findAll(){
        return bookdao.findAll();
    } 

    //通过分类查找图书的功能
    public List findBookByCatyegory(String cid){
        return bookdao.findBookByCategory(cid);
    } 

    //加载图书的功能
    public  Book load(String bid){
        return bookdao.load(bid);
    } 

    //后台功能:添加图书功能
    public void add(Book book) {
        bookdao.add(book);
    } 

    //后台功能:删除图书功能
    public void delete(String bid) {
        bookdao.delete(bid);
    } 
    //后台功能:编辑图书功能
    public void edit(Book book) {
        bookdao.edit(book);

    }

}
BookDao:对数据进行操作

public class BookDao {
    QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource()); 
    //查找所有图书的功能
    public List findAll(){
        String sql="select * from book where del=0";
        try {
            return qr.query(sql, new BeanListHandler(Book.class));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //通过分类查找图书功能
    public List findBookByCategory(String cid){
        String sql="select * from book where cid=? and del=0";
        try {
            return qr.query(sql, new BeanListHandler(Book.class),cid);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    } 

    //加载图书功能
    public Book load(String bid){
        String sql="select * from book where bid=? ";
        try {
            Map map= qr.query(sql, new MapHandler(),bid);
            Book book=CommonUtils.toBean(map, Book.class);
            Category category=CommonUtils.toBean(map, Category.class); 
            book.setCategory(category);
            return book;

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //根据分类查找该分类下图书的数量
    public int findBycid(String cid){
        try {
            String sql="select count(*) from book where cid=? and del=0";
            Number num=(Number) qr.query(sql, new ScalarHandler(),cid);
            return num.intValue();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //添加图书的功能
    public void add(Book book) {
        try {
            String sql="insert into book values(?,?,?,?,?,?)";
            Object []params={book.getBid(),book.getBname(),book.getPrice(),book.getAuthor(),book.getImage(),book.getCategory().getCid()};
            qr.update(sql, params);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    } 
    //删除图书
    public void delete(String bid){
        try {
            String sql="update book set del=true where bid=?";
            qr.update(sql, bid);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    //编辑图书
    public void edit(Book book) {
        try {
            String sql="update book set bname=?,price=?,author=?,cid=? where bid=?";
            Object []params={book.getBname(),book.getPrice(),book.getAuthor(),book.getCategory().getCid(),book.getBid()};
            qr.update(sql, params);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }   
    }

}
list.jsp:显示图书 

<body> 

<c:forEach items="${booklist}" var="book">
  <div class="icon">
    <a href=""><img src="" border="0"/>a>
      <br/>
    <a href="">${book.bname }a>
  div>
 c:forEach> 


  body>
desc.jsp:显示图书详情的页面  

<body>
  <div>
    <img src="" border="0"/>
  div>
  <ul>
    <li>书名:${book.bname }li>
    <li>作者:${book.author }li>
    <li>单价:${book.price }li>
  ul>
  <form id="form" action="" method="post">
    <input type="hidden" name="m" value="add">
    <input type="hidden" name="bid" value="${book.bid }">
    <input type="text" size="3" name="count" value="1"/>
  form>
  <a href="javascript:document.getElementById('form').submit();">a>
  body>

list.jsp
JAVA WEB从入门到精通 day25 项目:网上书城_第4张图片

desc.jsp

JAVA WEB从入门到精通 day25 项目:网上书城_第5张图片

购物车模块

    购物车的存储?
            购物车可以存放在cookie,session和数据库中。
            要看具体的需求。我们使用session来实现购物车。不涉及到数据库的操作。

    购物车结构
            购物车里存放的是商品条目。
            商品条目包括商品和商品数量。比如 火腿肠 十包

    所以我们创建购物车包
            在domain包下创建两个类
                    CartItem.java:商品条目,包含商品和商品数目属性 
                    Cart:购物车,包含一个集合来存放多个商品条目,和操作商品条目的方法。
                    我们在Cart类里完成对购物车条目的操作
                    -add(CartItem cartitem):添加商品条目
                    -clear();清除购物车
                    -delete(String bid):根据图书id删除指定商品条目 
                    -Collection getCartitems():查看我的购物车 

            由于我们购物车不涉及到数据库操作,所以我们没有dao层和service层的操作。

            我们在Servlet包下创建cartServlet
                为了保证每个用户有自己的购物车,购物车应该在用户登录成功时给用户创建一个购物车,然后存放在session中。
                所以我们需要修改登录的servlet,在用户登录成功后创建一个购物车。

            CartServlet:
                    add方法:
                            获取session中存放的购物车
                            获取页面传入的图书编号和图书数量
                            根据图书编号查找到相关的图书,返回图书对象
                            然后商品条目中添加图书和数量 
                            然后把商品条目添加到购物车中,返回到list页面
                    clear方法;
                            清空购物车
                            调用cart的clear方法

                    delete方法:
                            获取页面传入的图书编号
                            根据编号调用cart的delete方法 

            list.jsp:
                    从session中获取购物车,然后遍历购物车商品,进行显示。
                    删除就调用servlet中的delete方法
                    清空就调用servlet中的clear方法   
我们在domain包下创建两个实体类,一个购物车条目类,一个购物车类 

购物车条目类CartItem 

public class CartItem {
    private Book book; //商品
    private int count;//商品数量 
    //获取商品×数量的价格
    public double getSubtotal(){
        BigDecimal d1=new BigDecimal(book.getPrice()+"");
        BigDecimal d2=new BigDecimal(count+"");
        return d1.multiply(d2).doubleValue();
    }
    public Book getBook() {
        return book;
    }
    public void setBook(Book book) {
        this.book = book;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    @Override
    public String toString() {
        return "CartItem [book=" + book + ", count=" + count + "]";
    }

}
Cart.java 购物车类,购物车存放在session中,不涉及数据库操作,所以我们直接在类中定义一些方法 

public class Cart {
    //为了购物车查询,删除等操作方便,我们使用Map集合来存放商品条目
    Map map=new LinkedHashMap(); 

    //总计金额
    //使用普通的计算时会造成一些误差,所以我们需要BigDecimal进行精确计算
    public double getTotal(){
        BigDecimal total=new BigDecimal("0");
        for(CartItem cartitem:map.values()){
            BigDecimal subtotal=new BigDecimal(cartitem.getSubtotal()+"");
            total=total.add(subtotal);
        }
        return total.doubleValue();
    } 

    //添加商品条目
    public void add(CartItem cartitem){
        //判断购物车有没有这个条目,有的话就把数量加起来即可,没有就放入购物车
        if(map.containsKey(cartitem.getBook().getBid())){
            CartItem c1=map.get((cartitem).getBook().getBid());
            c1.setCount(c1.getCount()+cartitem.getCount());
            map.put(c1.getBook().getBid(),c1);
        }else{
            map.put(cartitem.getBook().getBid(), cartitem);
        }
    }

    //清空购物车
    public void clear(){
        map.clear();
    }

    //删除指定商品条目
    public void delete(String bid){
        map.remove(bid);
    }

    //查询我的购物车
    public Collection getCartitems(){
        return map.values();
    } 
}
CartServlet 

public class CartServlet extends BaseServlet {

    //添加商品方法
    public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //从session中获取购物车
        Cart cart=(Cart) request.getSession().getAttribute("cart"); 
        //获取商品编号
        String bid=request.getParameter("bid");  
        //获取商品数量
        int count=Integer.parseInt(request.getParameter("count"));
        //通过图书编号获取图书对象
        Book book=new BookService().load(bid);  
        //创建购物车条目
        CartItem cartitem=new CartItem(); 
        //将图书设置到购物车条目
        cartitem.setBook(book);
        cartitem.setCount(count);  
        //将购物车条目添加到购物车中 
        cart.add(cartitem);
        return "forward:/jsps/cart/list.jsp";
    } 

    //清除购物车的方法
    public String clear(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cart cart=(Cart) request.getSession().getAttribute("cart");
        cart.clear();
        return "forward:/jsps/cart/list.jsp";
    } 
    //删除购物车条目的方法
    public String delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Cart cart=(Cart) request.getSession().getAttribute("cart");
        String bid=request.getParameter("bid");
        cart.delete(bid);
        return "forward:/jsps/cart/list.jsp";
    }

}
显示购物车页面 

<body>
<h1>购物车h1>

<c:choose>
    <c:when test="${empty sessionScope.cart or fn:length(sessionScope.cart.cartitems) eq 0}">
        <img  src="/bookstore/images/cart.png" width="500" align="center">
    c:when>
    <c:otherwise>

<table border="1" width="100%" cellspacing="0" background="black">
    <tr>
        <td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
            <a href="/bookstore/CartServlet?m=clear">清空购物车a>
        td>
    tr>
    <tr>
        <th>图片th>
        <th>书名th>
        <th>作者th>
        <th>单价th>
        <th>数量th>
        <th>小计th>
        <th>操作th>
    tr>
  
<c:forEach items="${sessionScope.cart.cartitems }" var="cartitem">
    <tr>
        <td><div><img src=""/>div>td>
        <td>${cartitem.book.bname}td>
        <td>${cartitem.book.author}td>
        <td>${cartitem.book.price}td>
        <td>${cartitem.count}td>
        <td>${cartitem.subtotal}td>
        <td><a href="/bookstore/CartServlet?m=delete&bid=${cartitem.book.bid }">删除a>td>
    tr>
c:forEach>

    <tr>
        <td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
            ${sessionScope.cart.total}
        td>
    tr>
    <tr>
        <td colspan="7" align="right" style="font-size: 15pt; font-weight: 900">
            <a id="buy" href="">a>
        td>
    tr>
table>
c:otherwise>
c:choose>
  body>

订单模块

        相关类的创建。

        domain包下创建 Order订单类和OrderItem 订单条目类。
        我们订单类和订单条目是相互依赖的,比如我们删除订单,那里面的条目也肯定删除。
        我们不可能不创建订单,而直接添加订单条目,所以说两者的依赖很强。
        我们在加载订单时,还得把订单项也加载出来。 

        我们在dao包下创建OrderDao

        我们在Service包下创建OrderService 

        在servlet包下创建OrderServlet

---------------------------生成订单功能分析-----------------------------------------

        订单是根据购物车中的信息生成的。

        OrderServlet#add():
                            获取session中的购物车cart
                            创建Order对象,
                            通过cart生成order。
                            通过CartItem商品条目生成订单条目
                            将订单条目添加到订单中 

                            如果生成订单成功,就清除购物车。
                            然后调用service层的add(Order order)方法
                            保存生成的订单到request域中,转发到订单页面。

        OrderService#add(Order order):
                            将订单保存在数据库中。
                            将多个订单条目保存在数据库中。
                            保存订单条目时可能会出现异常,但这时订单却正常保存,这就会出现错误。
                            所以我们需要用事务来操作。

        OrderDao:
                            addOrder();添加订单
                            addOrderItemList(List list):将订单条目集合添加到数据库中。可以使用批处理一起完成。

        desc.jsp:获取订单信息,显示订单。 


-------------------------显示我的订单功能分析----------------------------------------

        OrderServlet#myorders():
                            从gsession中获取当前用户user,再获取用户的uid
                            使用uid调用service的方法,得到用户的所有订单集合List
                            保存在request中,转发到我的订单页面

        OrderService#myorders(String uid):
                            调用dao层的方法,得到我的订单集合List

        OrderDao#findbyId(String uid):
                            使用uid查询当前用户的所有订单。
                            循环遍历每个订单,为每个订单加载他的订单条目
                            返回订单集合 



-------------------------在支付页面加载订单功能分析------------------------------

        当点击我的订单页面的付款功能时,要发送给servlet一个订单编号oid

        OrderServlet#load();
                        获取oid
                        调用service的load(String oid)方法获取订单。
                        将order存放在request域中,转发到付款页面,在付款页面显示当前订单。

        OrderService#load(String oid):
                        调用dao的load方法获取Order对象

        OrderDao#load(String oid);
                        通过oid查询到订单对象。
                        为订单对象添加订单条目。
                        返回订单对象

----------------------------------确认收货功能分析------------------------------------------
        点击确认收货,发送请求到servlet,包含当前订单oid 

        OrderServlet#confirm():
                            获取oid 
                            调用service的confirm功能
                            如果抛出异常,就将异常信息保存到request域中
                            如果成功,就保存成功信息
                            转发到msg页面

        OrderService#confirm(String oid):
                            获取oid 
                            调用dao层的confirm方法,判断订单状态是否为3 
                            如果不为3,就抛出异常
                            如果为3,就调用更新状态的方法,将订单状态更新为4 

        orderDao:
                    confirm(String oid);查询订单状态
                    updateState(String oid,int state):更新订单状态



---------------------------------在线支付功能分析--------------------------------------------------
        支付的两种方式
        -电商与银行直接关联
        -电商通过和第三方支付平台关联,例如支付宝,财付通,易宝等
        网站使用第三方支付平台,需要实名认证备案等等。
        比较麻烦,但是易宝支付有一个测试账户,可以供我们测试。

        ++++++易宝支付++++++++++
        易宝给了我们一个支付网关,只要我们的程序付款时重定向到这个支付地址,就可以完成支付。
        完成支付需要14个参数。
            支付请求参数
            可以参考易宝的使用说明。

            最后一个参数hmac:十三个参数值+易宝给我们的私人keyValue+md5算法  算出来hmac ,

            hmac是为了防止数据被更改,后台会计算我们给出的数据和hmac,如果hmac和我们传递的hmac不同,就说明数据被修改了 


        易宝的应答机制
            我们向易宝发出一次请求,易宝响应两次通知。
                支付成功数据服务器点对点通知:易宝直接访问电商,没有客户端什么事;必须使用的方式
                    我们收不到这个通知,因为我们没有固定ip。
                    易宝有一个重发机制,如果它访问你,你不给它发送信息,就会一直发。
                    所以电商需要返回一个以SUCCESS开头的字符串。

                引导客户浏览器重定向:有可能会在重定向的过程中将浏览器关闭,可能会造成一些问题。可以不使用这种方式。


---------------------------支付之去银行-------------------------------
        我们页面传递订单编号和选择的银行,然后跳转到servlet#pay()方法
        Servlet#Pay():
                        准备易宝支付的13个参数,算出hmac
                        然后重定向到支付网关即可。


----------------------------支付成功回调电商callback方法-------------------
            Servlet#callback():
                            1.获取易宝支付回应的12个参数 
                            2.校验访问者身份是否为易宝支付,有可能不法分子来访问这个方法。(通过易宝传递的11个参数,与keyValue生成hmac,然后和易宝发送的hmac进行对比)
                            3.查看订单状态是否为1,如果为1,修改订单状态,增加积分
                            4.判断回调方式
                                -如果是点对点,回馈success开头的字符串
                            5.保存成功信息,转发到msg.jsp页面  

代码实现

我们在domain包下创建两个实体类,Order订单类和OrderItem订单条目类  

Order类 

public class Order {
    private String oid;      //订单编号
    private Date ordertime; //下单时间
    private double total;   //订单总计
    private int state;//代表订单的四种状态,1表示未付款,2表示付款但未发货,3表示发货了但是还没收货,4表示交易成功
    private User owner;//下单人
    private String address;//下单地址
    private List orderitemList;  //订单里的订单条目


    public List getOrderitemList() {
        return orderitemList;
    }
    public void setOrderitemList(List orderitemList) {
        this.orderitemList = orderitemList;
    }
    public String getOid() {
        return oid;
    }
    public void setOid(String oid) {
        this.oid = oid;
    }
    public Date getOrdertime() {
        return ordertime;
    }
    public void setOrdertime(Date ordertime) {
        this.ordertime = ordertime;
    }
    public double getTotal() {
        return total;
    }
    public void setTotal(double total) {
        this.total = total;
    }
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
    }
    public User getOwner() {
        return owner;
    }
    public void setOwner(User owner) {
        this.owner = owner;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Order [oid=" + oid + ", ordertime=" + ordertime + ", total=" + total + ", state=" + state + ", owner="
                + owner + ", address=" + address + "]";
    }

}
OrderItem订单条目类 

public class OrderItem {
    private String iid;       //订单条目编号
    private int count;        //商品数量 
    private double subtotal;  //商品小计
    private Order order;      //订单条目所属订单
    private Book book;        //所购买的商品
    public String getIid() {
        return iid;
    }
    public void setIid(String iid) {
        this.iid = iid;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }
    public double getSubtotal() {
        return subtotal;
    }
    public void setSubtotal(double subtotal) {
        this.subtotal = subtotal;
    }
    public Order getOrder() {
        return order;
    }
    public void setOrder(Order order) {
        this.order = order;
    }
    public Book getBook() {
        return book;
    }
    public void setBook(Book book) {
        this.book = book;
    }
    @Override
    public String toString() {
        return "OrderItem [iid=" + iid + ", count=" + count + ", subtotal=" + subtotal + ", order=" + order + ", book="
                + book + "]";
    }

}
OrderServlet 

public class OrderServlet extends BaseServlet { 
    //依赖service层
    private OrderService orderservice=new OrderService(); 

    //添加订单方法
    public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
         * 获取session中的购物车cart
         *  创建Order对象,
         *  通过cart生成order
         * 
         */
        Order order=new Order();
        Cart cart= (Cart) request.getSession().getAttribute("cart");
        order.setOid(UUID.randomUUID().toString().replaceAll("-", ""));
        order.setOrdertime(new Date());
        order.setTotal(cart.getTotal());
        order.setState(1);
        User u=(User)request.getSession().getAttribute("sessionuser");
        order.setOwner(u); 

        /*
         * 创建订单条目,添加到订单中
         * 订单条目中需要的值从购物车商品条目中获取
         */
        List<OrderItem> orderitemList=new ArrayList<OrderItem>(); 
        for(CartItem cartitem:cart.getCartitems()){
            OrderItem orderitem=new OrderItem();
            orderitem.setIid(UUID.randomUUID().toString().replaceAll("-", ""));
            orderitem.setCount(cartitem.getCount());
            orderitem.setSubtotal(cartitem.getSubtotal());
            orderitem.setOrder(order);
            orderitem.setBook(cartitem.getBook());
            orderitemList.add(orderitem);
        } 

        //将订单条目集合设置到购物车中
        order.setOrderitemList(orderitemList); 
        //订单生成后清空购物车
        cart.clear();
        //调用service添加订单
        orderservice.add(order); 
        //将订单保存在request域中,转发到页面
        request.setAttribute("order",order);
        return "forward:/jsps/order/desc.jsp";
    }

    //显示我的订单功能
    public String myorders(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //从session中获取当前用户 
        User user=(User) request.getSession().getAttribute("sessionuser");  
        //通过用户的uid获取订单集合
        List<Order> list=orderservice.myorders(user.getUid()); 
        //将订单集合保存在request域中
        request.setAttribute("orders", list);
        return "forward:/jsps/order/list.jsp";
    }

    //加载详细订单的功能
    public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //获取订单编号
        String oid=request.getParameter("oid"); 
        //调用service的加载订单方法
        Order order=orderservice.load(oid); 
        //将获取的订单保存在request中
        request.setAttribute("order", order);
        return "forward:/jsps/order/desc.jsp";
    }

    //确认收货功能
    public String confirm(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //获取订单编号
        String oid=request.getParameter("oid");
        try { 
            //如果收货成功就保存成功信息,如果出现异常,就保存异常信息
            orderservice.confirm(oid);
            request.setAttribute("msg", "收货成功");
        } catch (OrderException e) {
            request.setAttribute("msg", e.getMessage());
        }
        return "forward:/jsps/msg.jsp";
    } 

    //支付功能
    public String pay(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //准备易宝支付的十三参数
        String p0_Cmd="Buy";
        String  p1_MerId="10001126856";
        String p2_Order=request.getParameter("oid");
        String p3_Amt="0.01";
        String p4_Cur="CNY";
        String p5_Pid="";
        String p6_Pcat="";
        String p7_Pdesc=""; 
        String p8_Url="http://localhost:8080/bookstore/OrderServlet?m=callback";
        String p9_SAF="";
        String pa_MP="";
        String pd_FrpId=request.getParameter("pd_FrpId");
        String pr_NeedResponse="1";
        String keyValue="69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl";
        //计算hmac
        String hmac=PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt, p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP, pd_FrpId, pr_NeedResponse, keyValue);       

        //将url和参数连接起来
        StringBuilder url=new StringBuilder("https://www.yeepay.com/app-merchant-proxy/node");
        url.append("?p0_Cmd=").append(p0_Cmd);
        url.append("&p1_MerId=").append(p1_MerId);
        url.append("&p2_Order=").append(p2_Order);
        url.append("&p3_Amt=").append(p3_Amt);
        url.append("&p4_Cur=").append(p4_Cur);
        url.append("&p5_Pid=").append(p5_Pid);
        url.append("&p6_Pcat=").append(p6_Pcat);
        url.append("&p7_Pdesc=").append(p7_Pdesc);
        url.append("&p8_Url=").append(p8_Url);
        url.append("&p9_SAF=").append(p9_SAF);
        url.append("&pa_MP=").append(pa_MP);
        url.append("&pd_FrpId=").append(pd_FrpId);
        url.append("&pr_NeedResponse=").append(pr_NeedResponse);
        url.append("&keyValue=").append(keyValue);
        url.append("&hmac=").append(hmac);

        //重定向到支付网关

        response.sendRedirect(url.toString());
        return null;
    }

     //支付成功后的回调参数
    public String callback(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取参数  
        String p1_MerId=request.getParameter("p1_MerId");
        String r0_Cmd=request.getParameter("r0_Cmd");
        String r1_Code=request.getParameter("r1_Code");
        String r2_TrxId=request.getParameter("r2_TrxId");
        String r3_Amt=request.getParameter("r3_Amt");
        String r4_Cur=request.getParameter("r4_Cur");
        String r5_Pid=request.getParameter("r5_Pid");
        String r6_Order=request.getParameter("r6_Order");
        String r7_Uid=request.getParameter("r7_Uid");
        String r8_MP=request.getParameter("r8_MP");
        String r9_BType=request.getParameter("r9_BType"); 
        String hmac=request.getParameter("hmac"); 
        String keyValue="69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl";

        boolean bool=PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd, r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid, r8_MP, r9_BType, keyValue);
        //判断易宝返回的hmac和我们计算出来的是否相同,不相同就发送错误信息
        if(!bool){
            request.setAttribute("msg", "请勿进行非法操作");
            return "forward:/jsps/msg.jsp";
        } 

        //修改订单状态
        orderservice.pay(r6_Order);
        //如果点对点的响应。就发送success
        if(r9_BType.equals("2")){
            response.getWriter().print("success");
        }
        request.setAttribute("msg", "支付成功");



        return "forward:/jsps/msg.jsp";
    }

}
OrderService :对订单进行业务逻辑操作 

public class OrderService { 
    //依赖dao层
    private OrderDao orderdao=new OrderDao(); 
    //添加订单操作
    public void add(Order order){
        try {
            //对插入进行事务操作,添加订单和添加订单条目
            JdbcUtils.beginTransaction();
            orderdao.addOrder(order);
            orderdao.addOrderItemList(order.getOrderitemList());
            JdbcUtils.commitTransaction();
        } catch (Exception e) {
            try {
                JdbcUtils.rollbackTransaction();
            } catch (SQLException e1) {
                throw new RuntimeException(e);
            }
        }

    }
    //我的订单
    public List myorders(String uid) {
        return orderdao.findById(uid);
    }
    public Order load(String oid) {

        return orderdao.load(oid);
    }
    //确认收货
    public void confirm(String oid) throws OrderException{
        int state=orderdao.confirm(oid);
        if(state!=3) throw new OrderException("订单出现异常");
        orderdao.updateState(oid, 4);

    } 
    //支付功能
    public void pay(String oid){
        int state=orderdao.confirm(oid);
        if(state==1){
            orderdao.updateState(oid, 2);
        }   
    } 

    //后台功能:查询所有订单功能
    public List findAll() {
        return orderdao.findAll();

    } 

    //根据订单状态查询订单功能
    public List findByState(String state) {

        return orderdao.findByState(state);
    }
}
OrderDao:对订单进行数据操作 

public class OrderDao {
    private QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());

    //添加订单操作
    public void addOrder(Order order){
        String sql="insert into orders values(?,?,?,?,?,?)"; 
        //我们需要处理数据库的Date类型和util包下的Date类型之间的转换
        Timestamp timestamp=new Timestamp(order.getOrdertime().getTime());
        Object []params={order.getOid(),timestamp,order.getTotal(),order.getState(),order.getOwner().getUid(),order.getAddress()};
        try {
            qr.update(sql,params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //添加订单条目功能
    public void addOrderItemList(List list){
        try {
            //这里我们需要多次插入商品条目,所以使用批处理来插入
            //批处理的参数是一个二维数组,二维数组是n个一维数组组成,每个一维数组中存放了一次执行sql语句所需要的参数
            String sql="insert into orderitem values(?,?,?,?,?)";
            Object [][]params=new Object[list.size()][];
            for(int i=0;iget(i);
                params[i]=new Object[]{item.getIid(),item.getCount(),item.getSubtotal(),item.getOrder().getOid(),item.getBook().getBid()};
            }
            qr.batch(sql, params);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }  

    //通过用户id查询订单
    public List findById(String uid){
        try {
            //查询用户所有订单,然后遍历订单,为订单的内容订单条目赋值
            String sql="select * from orders where uid=?";
            List orderlist=qr.query(sql, new BeanListHandler(Order.class),uid); 
            for(Order order:orderlist){ 
                //为订单加载订单条目功能
                loadOrderItems(order);
            }
            return orderlist;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    //记载订单条目功能
    private void loadOrderItems(Order order) {
        try {
            //因为我们查询的订单条目还包含book对象,所以需要连接查询,这时查出来的就不是一个对象,而是订单条目对象和book对象,我们使用MapListHandler来来存储
            String sql="select * from orderitem,book where orderitem.bid=book.bid and oid=? ";
            List >maplist=qr.query(sql, new MapListHandler(),order.getOid()); 

            //maplist是一个map集合,里面很多map,每一个map对应一行记录,我们需要把每一行map变为订单条目对象和book对象,然后把book对象设置给订单条目
            List orderitemlist=toOrderItemList(maplist);
            order.setOrderitemList(orderitemlist);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    //将map集合变成订单条目的功能
    private List toOrderItemList(List> maplist) {
        List orderitemlist=new ArrayList();
        for(Map map:maplist){ 
            //将单个map转换成订单条目的功能
            OrderItem item=toOrderItem(map);
            orderitemlist.add(item);
        }
        return orderitemlist;
    }

    //将单个map集合转换成订单条目的功能
    private OrderItem toOrderItem(Map map) {
        OrderItem orderItem = CommonUtils.toBean(map, OrderItem.class);
        Book book=CommonUtils.toBean(map, Book.class);
        orderItem.setBook(book);
        return orderItem;
    }

    //加载订单详情的功能
    public Order load(String oid) {
        try {
            //查询所有订单,然后遍历订单,为订单的内容订单条目赋值
            String sql="select * from orders where oid=?";
            Order order=qr.query(sql, new BeanHandler(Order.class),oid); 

            loadOrderItems(order);
            return order;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    } 

    //确认收货的功能
    public int confirm(String oid){
        String sql="select * from orders where oid=?";
        Order order;
        try {
            order = qr.query(sql, new BeanHandler(Order.class),oid);
            return order.getState();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    } 
    //更新订单状态的功能
    public void updateState(String oid,int state){
        String sql="update orders set state=? where oid=?";
        try {
            qr.update(sql,state,oid);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //查询所有订单
    public List findAll() {
        try {
            //查询所有订单,然后遍历订单,为订单的内容订单条目赋值
            String sql="select * from orders";
            List orderlist=qr.query(sql, new BeanListHandler(Order.class)); 
            for(Order order:orderlist){
                loadOrderItems(order);
            }
            return orderlist;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //通过订单状态查询订单
    public List findByState(String state) {
        try {
            //查询所有订单,然后遍历订单,为订单的内容订单条目赋值
            String sql="select * from orders where state=?";
            List orderlist=qr.query(sql, new BeanListHandler(Order.class),state); 
            for(Order order:orderlist){
                loadOrderItems(order);
            }
            return orderlist;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

JAVA WEB从入门到精通 day25 项目:网上书城_第6张图片

后台功能

图书分类模块

        我们只需要在Category模块下创建一个AdminCategoryServlet 
        dao层和service层都不需要改变。 

-------------------------------查看所有分类功能分析------------------------------------ 

        调用service层的查看所有分类的功能,返回List
        存放到request域中,转发回显示分类的页面。 


----------------------------------添加分类功能分析--------------------------------
        AdminCategoryServlet#add:
                    获取用户输入的分类名称
                    我们添加分类id 
                    然后封装成category对象 
                    调用service的add(Category category)方法 
                    如果成功,就保存成功信息到request域,转发到msg页面
                    如果出现异常,就保存异常信息到request域,转发到msg页面

        AdminCategoryService#add(Category category):
                    先调用dao层的分类是否存在方法,判断分类是否存在,存在就抛出异常
                    不存在就调用dao 层的add方法,添加分类

        AdminCategoryDao#add(Category category):
                    isExist(String cname):判断分类是否存在
                    add(Category category):添加分类 


--------------------------------删除分类功能分析----------------------------------
            删除链接应该向servlet传送分类id :cid 

            AdminCategoryServlet#delete():
                                        获取cid 
                                        调用service的delete(String cid)方法删除分类
                                        出现异常,保存异常信息转发到msg页面
                                        没出现异常调用findAll方法,显示当前所有分类

            CategoryService#delete(String cid);
                                        调用BookDao的findBycid(String cid)方法获取当前分类下的图书数量
                                        如果当前分类下有图书,则抛出异常,不能删除该分类
                                        如果没有图书,调用dao层的删除方法 

            CategoryDao:
                        delete(String cid):删除分类


--------------------------------修改分类功能分析------------------------------------
            第一步,先加载以前的分类
                点击修改按钮,要向servlet传送cid 
                AdminCategoryServlet#load():
                                        获取cid
                                        通过cid获取category对象
                                        然后转发到页面
                                        在页面上显示当前分类的信息 


            第二步:设置好修改信息后,点击修改,要向servlet传递cid和cname
                AdminCategoryServlet#edit():
                                        获取cid和cname,封装成category对象
                                        调用service的edit(Category category)方法修改
                                        如果出现异常,保存异常信息转发到msg页面
                                        没有异常,保存成功信息转发到msg页面

                AdminCategoryService#edit(Category):
                                        先判断当前输入的分类名称是否存在
                                        存在就抛出异常
                                        不存在就调用dao层的edit(Category)方法修改 


                AdminCategoryDao#edit(Category category)
                                        :修改分类信息。 

代码实现

ADminCategoryServlet 


public class AdminCategoryServlet extends BaseServlet {
    private CategoryService categoryservice=new CategoryService();
    //查看所有分类功能
    public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List list=categoryservice.findAll(); 
        request.setAttribute("categorylist", list);
        return "forward:/adminjsps/admin/category/list.jsp";
    }

    //添加分类功能
    public String  add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String cname=request.getParameter("cname");
        String cid=UUID.randomUUID().toString().replaceAll("-", "");
        Category category=new Category();
        category.setCname(cname);
        category.setCid(cid);
        try {
            categoryservice.add(category);
            request.setAttribute("msg", "添加分类成功");
            return "forward:/adminjsps/msg.jsp";
        } catch (CategoryException e) {
            request.setAttribute("msg", e.getMessage());
            return "forward:/adminjsps/msg.jsp";
        }
    }  
    //删除分类功能
    public String  delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String cid=request.getParameter("cid");
        try{
        categoryservice.delete(cid);
        return findAll(request,response);
        }catch (Exception e) {
            request.setAttribute("msg", e.getMessage());
            return "forward:/adminjsps/msg.jsp";
        }
    }

    //加载分类信息
    public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String cid=request.getParameter("cid");
        Category category= categoryservice.load(cid);
        request.setAttribute("category", category);
        return "forward:/adminjsps/admin/category/mod.jsp";
    }

    //编辑分类功能
    public String  edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //获取用户输入参数,封装成分类对象
        String cid=request.getParameter("cid");
        String cname=request.getParameter("cname");
        Category category =new Category();
        category.setCid(cid);
        category.setCname(cname);
        try {
            categoryservice.edit(category);
            request.setAttribute("msg", "修改成功");
            return "forward:/adminjsps/msg.jsp";

        } catch (Exception e) {
            request.setAttribute("msg", e.getMessage());
            return "forward:/adminjsps/msg.jsp";
        }
    }


}

图书管理模块

相关类的创建
                我们需要创建两个Servlet
                -AdminBookServlet :用来管理图书
                -AdminAddBookServlet:专门用来添加图书,因为图书添加需要上传功能,上传的servlet的getParamter方法是不能使用的。

------------------------------------查看所有图书功能分析----------------------------
                        点击查询所有图书按钮,请求AdminBookServlet的findAll方法

                        AdminBookServlet#findAll():
                                                调用service的findAll方法,获取所有图书集合List
                                                将其保存在request域中,然后转发到list页面。 

                        list.jsp:循环显示book信息 




------------------------------------加载图书详情功能----------------------------- 
                        点击图书就跳转到Servlet的load方法,加载图书详情,需要传递图书编号bid。

                        AdminBookServlet#load():
                                                获取bid
                                                根据bid调用service的load(String bid)方法获取book 
                                                获取图书分类集合List
                                                将图书分类集合和book对象保存在request域中,转发到图书详情页面 desc.jsp 

                        desc.jsp:
                                显示图书的详细信息。 



---------------------------------添加图书功能-------------------------------------
                    添加图书涉及到上传图书图片
                    创建工厂
                    创建解析器 
                    解析request得到表单内容 

                    把普通表单项封装到book对象中
                    保存上传文件,把文件的路径设置给book的image属性 
                    调用service的add方法把book对象保存到数据库中 


----------------------------------删除图书功能------------------------------
                    book表和orderitem表有关联关系。比如别人的订单有图书,但我把这个图书给删了,那么数据库就会出现问题。
                    为了解决这个问题,我们的删除图书并不是真正的从数据库删除掉,而是给book表添加一个del字段,为boolean类型,表示是否已删除。

                    所以我们需要修改dao层的与查询有关的方法,需要添加条件 where del=false;
                    删除图书,就是将del列修改为true 

                    AdminBookServlet#delete():
                                            获取bid
                                            调用service层方法删除图书
                                            然后调用findAll方法显示当前所有图书 


--------------------------------编辑图书功能----------------------------------
                    AdminBookServlet#edit();
                                            获取表单数据,封装成book对象
                                            调用service的编辑方法,对图书信息进行编辑 


---------------------------------为登录添加过滤器--------------------------
                    过滤订单,购物车等相关页面和servlet 
                    判断session中是否有用户信息,有的话就放行。没有就返回到登陆页面 
AdminBookServlet 


public class AdminBookServlet extends BaseServlet {
    private BookService bookservice=new BookService();
    private CategoryService categoryservice=new CategoryService();
    //查看所有图书
    public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List booklist=bookservice.findAll();
        request.setAttribute("booklist", booklist);
        return "forward:/adminjsps/admin/book/list.jsp";
    }

    //加载图书详细信息
    public String load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String bid=request.getParameter("bid");
        Book book=bookservice.load(bid);
        List categorylist=categoryservice.findAll();
        request.setAttribute("categorylist", categorylist);
        request.setAttribute("book", book);
        return "forward:/adminjsps/admin/book/desc.jsp";
    } 

    //加载所有图书分类
    public String loadcategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List categorylist=categoryservice.findAll();
        request.setAttribute("categorylist", categorylist);
        return "forward:/adminjsps/admin/book/add.jsp";
    }
    //删除图书
    public String delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String bid=request.getParameter("bid");
        bookservice.delete(bid);
        return findAll(request,response);
    } 
    //编辑图书

    public String edit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Book book=CommonUtils.toBean(request.getParameterMap(), Book.class);
        Category category=CommonUtils.toBean(request.getParameterMap(), Category.class);
        book.setCategory(category);
        bookservice.edit(book);
        request.setAttribute("msg", "修改成功");
        return "forward:/adminjsps/msg.jsp";
    }

}
专门添加图书的servlet 

public class AdminAddBookServlet extends HttpServlet {
    private BookService bookservice=new BookService();
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
        //创建工厂和解析器
        DiskFileItemFactory factory=new DiskFileItemFactory();
        ServletFileUpload fileupload=new ServletFileUpload(factory); 
        //设置最大上传限制
        fileupload.setFileSizeMax(15*1024);
        try {
            //获取表单
            List list=fileupload.parseRequest(request); 
            Map  map=new HashMap(); 
            //把所有普通表单项先存放在map集合中,然后封装成book对象
            //再获取文件的存放位置,设置给book对象
            for(FileItem fileitem:list){
                //判断是否为普通表单项
                if(fileitem.isFormField()){
                map.put(fileitem.getFieldName(), fileitem.getString("utf-8"));
                }
            }
            Book book=(Book) CommonUtils.toBean(map, Book.class); 

            //保存文件到指定位置
            String filepath=request.getServletContext().getRealPath("/book_img");
            //为了防止文件名重复,我们在前面加上uuid
            String filename=UUID.randomUUID().toString().replaceAll("-", "")+"_"+list.get(1).getName();
            File file=new File(filepath,filename);
            list.get(1).write(file); 
            //将图片位置设置给book
            book.setImage("book_img/"+filename);
            book.setBid(UUID.randomUUID().toString().replaceAll("-", "")); 
            //把Category对象设置给Book 
            Category category=CommonUtils.toBean(map, Category.class);
            book.setCategory(category);
            //调用service的add方法添加图书
            bookservice.add(book); 

            //校验图片的大小
            Image image=new ImageIcon(file.getAbsolutePath()).getImage();
            if(image.getHeight(null)>200||image.getWidth(null)>200){
                //删除已保存的图片
                file.delete();
                request.setAttribute("msg", "您上传的图片尺寸过大");
                request.getRequestDispatcher("/adminjsps/msg.jsp").forward(request, response);
                return ;
            } 

            request.setAttribute("msg", "添加图书成功");
            request.getRequestDispatcher("/adminjsps/msg.jsp").forward(request, response);
        } catch (Exception e) {
            if(e instanceof FileUploadBase.FileSizeLimitExceededException ){
                request.setAttribute("msg", "您上传的图片超过15kb");
                request.getRequestDispatcher("/adminjsps/msg.jsp").forward(request, response);
            }
        }
    }

}

订单模块

------------------------------查询所有订单功能------------------------------
                AdminOrderServlet#findAll():
                                            调用service的findAll方法,返回一个订单集合
                                            保存在request域中,转发到显示页面 


-----------------------通过订单状态查询订单功能--------------------------------                                         
                AdminOrderServlet#findByState():
                                            获取订单状态参数state
                                            调用Service的findByState(String state)获取订单集合
                                            保存在request域中,转发到显示页面  

代码实现

public class AdminOrderServlet extends BaseServlet {
    private OrderService orderservice=new OrderService();
    //查询所有订单
    public String findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List orderlist=orderservice.findAll();
        request.setAttribute("orderlist", orderlist);
        return "forward:/adminjsps/admin/order/list.jsp";
    }

    //按订单状态查询所有订单
    public String findByState(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String state=request.getParameter("state");
        List orderlist=orderservice.findByState(state);
        request.setAttribute("orderlist", orderlist);
        return "forward:/adminjsps/admin/order/list.jsp";
    }
}

JAVA WEB从入门到精通 day25 项目:网上书城_第7张图片

JAVA WEB从入门到精通 day25 项目:网上书城_第8张图片

JAVA WEB从入门到精通 day25 项目:网上书城_第9张图片

JAVA WEB从入门到精通 day25 项目:网上书城_第10张图片

我们的网上书城项目到这儿就结束了,还有很多功能没完善。自己的笔记也做得非常粗糙。以后肯定会修正。

你可能感兴趣的:(java,web基础)