Java web项目综合练习(Estore)

复习day18:

  1. ajax代码的书写步骤

2)json格式文本,转js对象的方法是那个

  1. 项目开发流程介绍

这里学习的JavaWEB项目实战,主要是把前面学习的所有的web相关的技术综合的练习。

  1. 业务洽谈:客户(企业)提出需求,软件公司派人前去洽谈,第一次确认需求。
  2. 整理需求:软件公司,不断的和客户进行沟通,反复的确认需求,需要美工和前端工程师制作页面
  3. 详细设计:技术选型和项目原型架构
  4. 编码阶段:开工啦
  5. 测试阶段:测试当前的项目,解决bug
  6. 试运行,上线。

在开发的流程中的人员配置:

洽谈业务: 老板、项目经理、技术总监、技术总监(需求工程师团队)

详细设计: 项目经理、技术总监、老员工

编码: 码农开工啦

测试阶段:测试工程师,码农开工啦

技术选型:选择适合当前项目的技术

项目的原型架构:导入jar包(项目需要用到哪些技术),准备配置文件,工具类,基本的接口(业务接口)

业务接口:程序员在开发的时候,当前项目需要的大部分接口,已经开发完成(技术总监),程序员只需要根据接口写实现类

  1. 准备工作

    1. 项目搭建

      1. 新建项目

  1. 拷贝项目静态资源

将文件夹中的所有数据复制到项目WebRoot文件夹下

复制完成之后,注意要修改当前项目的编码,设置成UTF-8

修改完成之后,部署项目,能看到如下界面,说明拷贝静态资源没有问题。

搜索功能:后期使用lucence和slor这两个技术来完成。

  1. 功能分析

买家功能:

  1. 注册
  2. Ajax校验用户名
  3. 登录
  4. 记住用户名
  5. 注销(退出)
  6. 查看商品列表
  7. 查看商品的详细
  8. 加入购物车
  9. 查看购物车列表
  10. 修改购买的数量
  11. 删除购物车中的商品
  12. 三级联动
  13. 提交订单
  14. 查看订单列表
  15. 查看订单详情
  16. 在线支付(需要公网的IP,才可以完成全部功能,只能看到支付,获取不到支付成功的消息)
  17. 删除订单

卖家功能:

商品上传

商品后台查看

系统功能:

1. 将一定时间内没有付款的订单,修改为过期状态

2. 权限控制(买家不能访问,卖家添加商品的功能)

3. 配置错误页面(404和500错误使用统一页面显示)

  1. 技术选型

技术选型:选择实现当前这个项目,需要使用那些技术

前台:jsp、JavaScript、css、EL、JSON、AJAX、html、JSTL

后台:Servlet、JavaBean、BeanUtils、DBUtils、C3P0、MD5、JDBC、flexjson、UUID、监听器、过滤器

数据库:MySQL5.6

服务器:tomcat7/ tomcat6

开发工具:MyEclipse

JDK版本:1.7/1.6

J2EE版本: J2EE6.0/ J2EE5.0

操作系统:win7/win10

  1. 定义项目开发结构

定义项目开发结构:将那些java类,放到那些包中

  1. 导入项目依赖的jar包

所有jar包

导入lib文件夹:

导入后确认效果:

  1. 导入工具类

工具类在资料文件夹下的工具类文件夹中:

导入后的效果:

  1. 配置文件

配置文件在资料文件夹下的jar包文件夹中:

复制到src路径下:

  1. 配置全站乱码过滤器

复制资料文件夹下全站乱码处理文件夹中(GenericEncodingFilter.java)到项目,放入cn.itcast.filter包中

在web.xml中配置过滤器,效果如红框中所示:

  1. 数据库设计

我们在实际的开发中,不同的项目使用的数据库也不同,同样,我们的estore项目,也需要设计一个数据库

  1. 新建数据库

导入资料文件夹中的数据库脚本文件夹下的estore.sql

效果:

  1. 分析数据库表结构

使用E-R图分析数据库表

矩形:实体(good商品 user用户 order订单)

菱形:实体和实体之间的关系

椭圆:实体中的属性

  1. 导入与数据库表对应的Java类

复制资料文件夹下的java类文件夹中的所有.java文件到:cn.itcast.domain包中

效果图:

  1. 普通用户功能(买家)

    1. 注册

页面展示:

总结:

前端js验证:提高用户的注册成功率,让用户能一次性注册成功(给用户很多注册的提示信息)。

后台Servlet验证:防止用户提交非正常的数据。

  1. 功能分析

  1. 完善页面(修改form表单)

  1. 修改表单提交的请求路径
  2. 修改显示用户错误操作的提示信息

  1. Servlet实现

StringUtils.isBlank()介绍:

package cn.itcast.web;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import org.apache.commons.lang3.StringUtils;

import cn.itcast.domain.User;

import cn.itcast.service.UserService;

import cn.itcast.service.impl.UserServiceImpl;

public class RegisterServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//接受请求的参数,校验数据

String username = request.getParameter("username");

//非空校验,不能==null,不能==""

if(StringUtils.isBlank(username)){

//表示是null或者空字符串

request.setAttribute("msg", "用户名不能为空");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

String nickname = request.getParameter("nickname");

if(StringUtils.isBlank(nickname)|| nickname.length()>10){

//表示是null或者空字符串

request.setAttribute(个字符");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

String password = request.getParameter("password");

if(StringUtils.isBlank(password)){

//表示是null或者空字符串

request.setAttribute("msg", "密码不能为空");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

String confirm_password = request.getParameter("confirm_password");

if(StringUtils.isBlank(confirm_password)){

//表示是null或者空字符串

request.setAttribute("msg", "确认密码不能为空");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

String captcha = request.getParameter("captcha");

if(StringUtils.isBlank(captcha)){

//表示是null或者空字符串

request.setAttribute("msg", "验证码不能为空");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

//校验两次密码必须一致

if(!(password.equals(confirm_password))){

request.setAttribute("msg", "两次密码必须一致");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

//校验验证码

String code = (String)request.getSession().getAttribute("code");

if(!(code.equals(captcha))){

request.setAttribute("msg", "验证码错误");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

//封装数据到User对象

User u = new User();

try {

BeanUtils.populate(u, request.getParameterMap());

} catch (Exception e) {

e.printStackTrace();

}

//调用service方法注册用户

UserService userService = new UserServiceImpl();

int info = userService.register(u);

//根据不同返回值,不同处理

if(info == 1){

//注册成功

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}else if(info == -1){

request.setAttribute("msg", "用户已存在");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}else{

request.setAttribute("msg", "服务器忙,请等等,也许你打个酱油我们就好了");

request.getRequestDispatcher("/register.jsp").forward(request, response);

return;

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:UserService

package cn.itcast.service;

import cn.itcast.domain.User;

public interface UserService {

/**

* 注册的方法

* @param u

* @return

*/

int register(User u);

}

实现类:UserServiceImpl

package cn.itcast.service.impl;

import cn.itcast.dao.UserDao;

import cn.itcast.dao.impl.UserDaoImpl;

import cn.itcast.domain.User;

import cn.itcast.service.UserService;

import cn.itcast.utils.MD5Utils;

public class UserServiceImpl implements UserService {

private UserDao userDao = new UserDaoImpl();

@Override

public int register(User u) {

// 查询当前用户是否存在

int info = userDao.findByName(u.getUsername());

if(info == 1){

//表示,当前用户不存在,可以注册

//对用户的密码进行加密

String password = MD5Utils.getPassword(u.getPassword());

u.setPassword(password);

//将用户的权限设置为user,表示普通用户

u.setRole("user");

int info2 = userDao.register(u);

return info2;

}else{

return info;

}

}

}

  1. DAO实现

接口:UserDao

package cn.itcast.dao;

import cn.itcast.domain.User;

public interface UserDao {

/**

* 查询用户名是否存在的方法

* @param username

* @return

*/

int findUserByUsername(String username);

/**

* 注册用户的方法

* @param u

* @return

*/

int register(User u);

}

实现类:UserDaoImpl

package cn.itcast.dao.impl;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.itcast.dao.UserDao;

import cn.itcast.domain.User;

import cn.itcast.utils.DBUtils;

public class UserDaoImpl implements UserDao {

private QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

@Override

public int findByName(String username) {

String sql = "select * from user where username = ?";

try {

User user = qr.query(sql, new BeanHandler<User>(User.class), username);

if(user == null){

return 1;

}else{

return -1;

}

} catch (SQLException e) {

e.printStackTrace();

return -2;

}

}

@Override

public int register(User u) {

String sql = "insert into user values(null,?,?,?,?)";

try {

int update = qr.update(sql, u.getNickname(),u.getUsername(),u.getPassword(),u.getRole());

return update;

} catch (SQLException e) {

e.printStackTrace();

return -2;

}

}

}

  1. 使用ajax验证用户名是否已被注册

提示:前端工程师书写javascript代码,不要去动,但是我们自己的javascript代码执行结果也要保留,那么最好的解决方法,就是将结果合并。

  1. 需求分析

  1. 页面实现

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<c:set var="root" value="${pageContext.request.contextPath}"/>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>注册</title>

<%@include file="inc/common_head.jsp"%>

<script type="text/javascript">

//获取ajax核心对象

    function getXHR(){

var xmlhttp;

if (window.XMLHttpRequest){

// code for IE7+, Firefox, Chrome, Opera, Safari

xmlhttp=new XMLHttpRequest();

}else{

// code for IE6, IE5

xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

}

return xmlhttp;

}

//定一个标记,用来记住自己的函数(_checkName)执行结果

    var flag = false;

//ajax校验用户名

    function _checkName(_value){

//获取核心对象

        var xhr = getXHR();

//使用方法发出请求

xhr.open("get","${root}/checkName?username="+_value,true);

xhr.send();

//设置等待服务器响应

xhr.onreadystatechange = function(){

if(xhr.readyState == 4 && xhr.status == 200){

//获取响应的数据

                var data = xhr.responseText;

var _username_notice = document.getElementById("username_notice");

//根据返回的响应数据,不同处理

                if(data == 1){

//可以使用

_username_notice.innerHTML = "可以注册";

_username_notice.setAttribute("style","color:green");

flag = true;

}else if(data == -1){

//重复

_username_notice.innerHTML = "重复";

_username_notice.setAttribute("style","color:red");

flag = false;

}else if(data == -3){

//不能为空

_username_notice.innerHTML = "不能为空";

_username_notice.setAttribute("style","color:red");

flag = false;

}else{

//服务器忙

_username_notice.innerHTML = "服务器忙";

_username_notice.setAttribute("style","color:red");

flag = false;

}

//分析:当前校验用户名已经完成,但是,只是填写和验证了用户名,还没有验证其他数据,但是,表单可以提交

//通过分析代码,发现:在原来的表单上,onsubmit属性,绑定了两次函数,后一次绑定,覆盖了前一次的效果

//导致原来js验证,就不起作用。

//原来的js验证需要保留,那么,对表单onsubmit属性,就只能绑定一次函数,

//定义了一个变量,记住自己的函数执行结果,然后将结果和原来的register函数的结果一起运算

//只有两个函数结果都为true的时候,那么表单才可以提交。

}

};

}

</script>

</head>

<body>

<%@include file="inc/header.jsp"%>

<div class="block block1">

<div class="blank"></div>

<div class="usBox">

<div class="usBox_1">

<div class="login_tab">

<ul>

<li onclick="location.href='login.jsp';">

<a href="javascript:;">用户登录</a>

</li>

<li class="active">用户注册</li>

</ul>

</div>

<form id="registForm" action="${root }/register" method="post" name="formUser"

onsubmit="return (register() && flag);">

<table width="100%" border="0" align="left" cellpadding="5"

cellspacing="3">

<!-- 设置获取用户错误操作的提示信息 -->

<caption>${msg }</caption>

<tr>

<td width="25%" align="right">用户名</td>

<td width="65%"><input name="username" type="text"

id="username" onblur="is_registered(this.value);_checkName(this.value);"

class="inputBg" /> <span id="username_notice"

style="color:#FF0000"> *</span></td>

</tr>

<tr>

<td align="right">昵称</td>

<td><input name="nickname" type="text"

id="nickname" onblur="check_nickname(this.value);"

class="inputBg" /> <span id="nickname_notice"

style="color:#FF0000"> *</span></td>

</tr>

<tr>

<td align="right">密码</td>

<td><input name="password" type="password" id="password1"

onblur="check_password(this.value);"

onkeyup="checkIntensity(this.value)" class="inputBg" />

<span style="color:#FF0000"

id="password_notice"> *</span></td>

</tr>

<tr>

<td align="right">密码强度</td>

<td>

<table width="145" border="0" cellspacing="0" cellpadding="1">

<tr align="center">

<td width="33%" style="border-bottom:2px solid #ccc;" id="pwd_lower">弱</td>

<td width="33%" style="border-bottom:2px solid #ccc;" id="pwd_middle">中</td>

<td width="33%" style="border-bottom:2px solid #ccc;" id="pwd_high">强</td>

</tr>

</table>

</td>

</tr>

<tr>

<td align="right">确认密码</td>

<td><input name="confirm_password" type="password"

id="conform_password"

onblur="check_conform_password(this.value);" class="inputBg" />

<span style="color:#FF0000"

id="conform_password_notice"> *</span></td>

</tr>

<tr>

<td align="right">验证码</td>

<td><input type="text" size="8" name="captcha" id="captcha"

class="inputBg" onblur="check_captcha(this.value);" /> <span style="color:#FF0000"

id="captcha_notice"> *</span></td>

</tr>

<tr>

<td align="right"></td>

<td><img src="validatecode.jsp"

style="vertical-align:middle;cursor:pointer;width:130px;height:35px;margin-top:-2px;"

onClick="src='validatecode.jsp?'+Math.random()" /></td>

</tr>

<tr>

<td>&nbsp;</td>

<td><label> <input name="agreement" type="checkbox"

value="1" checked="checked" />我已看过并接受《<a

href="javascript:;" style="color:blue" target="_blank">用户协议</a>》

</label></td>

</tr>

<tr>

<td>&nbsp;</td>

<td align="left">

<input name="Submit" type="submit" value="" class="us_Submit_reg">

</td>

</tr>

<tr>

<td colspan="2">&nbsp;</td>

</tr>

</table>

</form>

<div class="blank"></div>

</div>

</div>

</div>

<%@include file="inc/footer.jsp"%>

</body>

</html>

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import cn.itcast.service.UserService;

import cn.itcast.service.impl.UserServiceImpl;

public class CheckNameServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验数据

String username = request.getParameter("username");

PrintWriter writer = response.getWriter();

if(StringUtils.isBlank(username)){

//表示数据为空

writer.write("-3");

return;

}else{

//调用service方法

UserService userService = new UserServiceImpl();

int info = userService.findByName(username);

//返回结果

writer.write(info+"");

return;

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口: UserService

/**

* 根据用户名查询的方法

* @param username

* @return

*/

int findByName(String username);

实现类:UserServiceImpl

public int findByName(String username) {

return userDao.findByName(username);

}

  1. DAO实现

已实现,不再重复。

  1. 登录

在正式的开发中,使用浏览器测试,火狐,谷歌,IE,搜狗,360,QQ浏览器,测试javascript代码

页面展示;

  1. 功能分析

  1. 完善页面

  1. 修改请求路径
  2. 修改用户的操作错误提示信息显示位置

  1. 显示登录名js

<script type="text/javascript">

window.onload = function(){

var data = "${cookie.username.value}";

var username = decodeURI(data);

document.getElementById("_un").value = username;

};

</script>

  1. Servlect实现

package cn.itcast.web;

import java.io.IOException;

import java.net.URLEncoder;

import javax.servlet.ServletException;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import cn.itcast.domain.User;

import cn.itcast.service.UserService;

import cn.itcast.service.impl.UserServiceImpl;

public class LoginServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//接受参数,校验(username password)

String username = request.getParameter("username");

if(StringUtils.isBlank(username)){

request.setAttribute("msg", "用户名不能为空");

request.getRequestDispatcher("/login.jsp").forward(request, response);

return;

}

String password = request.getParameter("password");

if(StringUtils.isBlank(password)){

request.setAttribute("msg", "密码不能为空");

request.getRequestDispatcher("/login.jsp").forward(request, response);

return;

}

//调用service方法登录用户

UserService userService = new UserServiceImpl();

User loginUser = userService.login(username,password);

//根局不同的返回值,不同处理

if(loginUser == null){

request.setAttribute("msg", "用户名或者密码错误");

request.getRequestDispatcher("/login.jsp").forward(request, response);

return;

}else{

//判断用户是否记住用户名

String remember = request.getParameter("remember");

if("on".equals(remember)){

Cookie cookie = new Cookie("username", URLEncoder.encode(username, "utf-8"));

cookie.setMaxAge(60*60*24*7);

cookie.setPath("/");

response.addCookie(cookie);

}else{

Cookie cookie = new Cookie("username", "");

cookie.setMaxAge(0);

cookie.setPath("/");

response.addCookie(cookie);

}

//将loginUser存入session中,返回主页

request.getSession().setAttribute("loginUser", loginUser);

response.sendRedirect(request.getContextPath());

}

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:UserService

/**

* 用户登录的方法

* @param username

* @param password

* @return

*/

User login(String username, String password);

实现类:UserServiceImpl

public User login(String username, String password) {

//先对用户的明文密码加密

String password2 = MD5Utils.getPassword(password);

return userDao.login(username,password2);

}

  1. DAO实现

接口:userDao

/**

* 用户登陆

* @param username

* @param pwd

* @return

*/

User login(String username, String pwd);

实现类:UserDaoImpl

public User login(String username, String password2) {

String sql = "select * from user where username = ? and password = ?";

try {

return qr.query(sql, new BeanHandler<User>(User.class), username,password2);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("用户登录失败");

}

}

  1. 首页显示欢迎信息

用户登录之后,头部页面显示用户的昵称:

修改inc目录下的head.jsp

  1. 查看商品

    1. 功能分析

页面修改:

Ctrl + shift + r :用来搜索文件,根据文件名

Ctrl + shift + t :用来搜索java类,根据类名

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Good;

import cn.itcast.service.GoodService;

import cn.itcast.service.impl.GoodServiceImpl;

public class FindAllGoodsServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//调用service方法获取数据

GoodService goodService = new GoodServiceImpl();

List<Good> list = goodService.findAll();

//将数据存入request容器,返回goods.jsp

request.setAttribute("list", list);

request.getRequestDispatcher("/goods.jsp").forward(request, response);

//测试的步骤:

//第一:先查看请求是否发出

//第二:服务器是否接收请求,参数是否正确

//第三:是否调用service,dao

//第四:返回的数据,是否正确(跟我们预期是一致的)

//第五:是否将数据返回给页面

//第六:页面是否取出数据展示

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:GoodService

package cn.itcast.service;

import java.util.List;

import cn.itcast.domain.Goods;

public interface GoodService {

/**

* 获取所有商品的方法

* @return

*/

List<Goods> findAllGoods();

}

实现类:GoodServiceImpl

package cn.itcast.service.impl;

import java.util.List;

import cn.itcast.dao.GoodDao;

import cn.itcast.dao.impl.GoodDaoImpl;

import cn.itcast.domain.Goods;

import cn.itcast.service.GoodService;

public class GoodServiceImpl implements GoodService {

private GoodDao goodDao = new GoodDaoImpl();

@Override

public List<Goods> findAllGoods() {

return goodDao.findAllGoods();

}

}

  1. DAO实现

接口:GoodDao

package cn.itcast.dao;

import java.util.List;

import cn.itcast.domain.Goods;

public interface GoodDao {

/**

* 获取所有商品的方法

* @return

*/

List<Goods> findAllGoods();

}

实现类:GoodDaoImpl

package cn.itcast.dao.impl;

import java.sql.SQLException;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.itcast.dao.GoodDao;

import cn.itcast.domain.Goods;

import cn.itcast.utils.DBUtils;

public class GoodDaoImpl implements GoodDao {

@Override

public List<Goods> findAllGoods() {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from goods";

try {

return qr.query(sql, new BeanListHandler<Goods>(Goods.class));

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("获取商品列表数据失败");

}

}

}

  1. 商品列表页面实现

  1. 有商品的情况下遍历循环商品列表
  2. 显示商品图片
  3. 显示商品名称
  4. 显示市场价格和本店价格

  1. 商品详情

    1. 功能分析

  1. Goods.jsp页面完善

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Good;

import cn.itcast.service.GoodService;

import cn.itcast.service.impl.GoodServiceImpl;

public class FindGoodByIdServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//获取参数

String parameter = request.getParameter("gid");

//注意,这里是有问题的

int gid = 0;

try {

gid = Integer.parseInt(parameter);

} catch (Exception e) {

//虽然处理了异常,还是要知道具体的异常信息

e.printStackTrace();

response.sendRedirect(request.getContextPath());

return;

}

//调用service方法获取数据

GoodService goodService = new GoodServiceImpl();

Good good = goodService.findById(gid);

//将数据转发到页面

request.setAttribute("good", good);

request.getRequestDispatcher("/goods_detail.jsp").forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:GoodService

/**

* 获取商品数据

* @param gid

* @return

*/

Good findById(int gid);

实现类:GoodServiceImpl

public Good findById(int gid) {

return goodDao.findById(gid);

}

  1. DAO实现

接口:GoodDao

/**

* 获取商品数据

* @param gid

* @return

*/

Good findById(int gid);

实现类:GoodDaoImpl

public Good findById(int gid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from goods where id = ?";

try {

return qr.query(sql, new BeanHandler<Good>(Good.class),gid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("获取商品详细失败");

}

}

  1. 页面实现

  1. 修改大图连接
  2. 图片资源路径
  3. 修改小图列表资源路径
  4. 显示商品名称
  5. 市场价格
  6. 商城价格
  7. 库存
  8. 商品分类
  9. 商品描述

  1. 购物车

    1. 添加购物车

      1. 功能分析

  1. 页面修改

1)修改添加商品到购物车的按钮的连接

效果:

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.User;

import cn.itcast.service.CartService;

import cn.itcast.service.impl.CartServiceImpl;

public class AddGoodTOCartServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

//================跳转之前页面修改======================

//记住以前的地址

String header = request.getHeader("Referer");

//http://localhost:8080/estore

String str = "http://localhost:8080/estore";

header = header.substring(str.length());

request.getSession().setAttribute("url", header);

//================跳转之前页面修改======================

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取参数(uid gid)

String parameter = request.getParameter("gid");

Integer gid = null;

try {

gid = Integer.parseInt(parameter);

} catch (Exception e) {

e.printStackTrace();

response.sendRedirect(request.getContextPath());

return;

}

int uid = loginUser.getId();

//调用service方法添加商品到购物车

CartService cartService = new CartServiceImpl();

cartService.addGoodTOCart(uid ,gid);

//跳转buyorcart.jsp,让用户自己选择继续购物或者付款

response.sendRedirect(request.getContextPath()+"/buyorcart.jsp");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:CartService

/**

* 添加商品到购物车

* @param gid

* @param uid

*/

void addGoodToCart(int gid, int uid);

实现类:CartServiceImpl

private CartDao cartDao = new CartDaoImpl();

@Override

public void addGoodToCart(int gid, int uid) {

// 查询是否购买过

Cart cart = cartDao.findByGidAndUid(gid,uid);

if(cart == null){

//没买过,添加新的

Cart c = new Cart();

c.setBuynum(1);

c.setGid(gid);

c.setUid(uid);

cartDao.add(c);

}else{

//买过了,修改数量加一

int buynum = cart.getBuynum();

buynum = buynum + 1;

cart.setBuynum(buynum);

cartDao.update(cart);

}

}

  1. DAO实现

接口:CartDao

/**

* 根据用户id和商品id查询数据的方法

* @param gid

* @param uid

* @return

*/

Cart findByGidAndUid(int gid, int uid);

/**

* 添加购物车数据

* @param c

*/

void add(Cart c);

/**

* 修改购物车数据

* @param cart

*/

void update(Cart cart);

实现类:CartDaoImpl

public Cart findByGidAndUid(int gid, int uid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from cart where uid = ? and gid = ?";

try {

return qr.query(sql, new BeanHandler<Cart>(Cart.class), uid,gid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("获取指定的用户和商品的购物车数据失败");

}

}

@Override

public void add(Cart c) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "insert into cart values(?,?,?)";

try {

qr.update(sql, c.getUid(),c.getGid(),c.getBuynum());

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("添加购物车数据失败");

}

}

@Override

public void update(Cart cart) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "update cart set buynum = ? where uid = ? and gid = ?";

try {

qr.update(sql, cart.getBuynum(),cart.getUid(),cart.getGid());

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("添加购物车数据失败");

}

}

  1. 修改buyorcart.jsp页面链接

1)完善继续购物和去购物车结算的链接

补充:登陆完成之后,直接跳转之前浏览的页面

  1. AddGoodToCartServlet获取当前商品详细页面的路径——查询商品详情的路径,通过请求头:Referer 获取

  1. 将商品详情的路径保存,保存到session中,为了保证后期也可以使用
  2. loginServlet先获取session中的商品详情的路径,判断是否存在,存在,跳转商品详情的路径,不存在,跳转首页

  1. 查看购物车

    1. 功能分析

  1. 在购物车对象中添加商品对象

1)修改购物车类,添加一个商品对象做属性,方便在购物车页面中,显示商品信息

注意:还要生成getter和setter方法,重新生成toString方法

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Cart;

import cn.itcast.domain.User;

import cn.itcast.service.CartService;

import cn.itcast.service.impl.CartServiceImpl;

public class FindAllCartServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登陆

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取数据

int uid = loginUser.getId();

//调用service

CartService cartService = new CartServiceImpl();

List<Cart> list = cartService.findAllCart(uid);

//返回数据

request.setAttribute("list", list);

request.getRequestDispatcher("/cart.jsp").forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口: CartService

/**

* 查询当前用户购物车商品数据的方法

* @param uid

* @return

*/

List<Cart> findAllCart(int uid);

实现类; CartServiceImpl

private GoodDao goodDao = new GoodDaoImpl();

@Override

public List<Cart> findAllCart(int uid) {

//第一步:获取所有的购物车数据cart

List<Cart> list = cartDao.findAllCart(uid);

//第二步:获取购物车相对应商品信息

for (Cart cart : list) {

Good good = goodDao.findById(cart.getGid());

cart.setGood(good);

}

return list;

}

  1. DAO实现

接口:CartDao

/**

* 查询当前用户购物车商品数据的方法

* @param uid

* @return

*/

List<Cart> findAllCart(int uid);

实现类:CartDaoImpl

public List<Cart> findAllCart(int uid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from cart where uid = ?";

try {

return qr.query(sql, new BeanListHandler<Cart>(Cart.class), uid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("获取指定的用户的购物车数据失败");

}

}

  1. 页面实现

1)遍历循环购物车集合显示购物车中的商品信息

2)计算购物车中商品的总计

3)计算购物车中商品一共节省的金额

额外补充:大数据相关概念

  1. 修改购物车中商品的购买数量

    1. 功能分析

  1. 页面实现

  1. 设置onblur事件,启动js函数,函数中的参数购买数量和商品id

2)在js函数中,先验证当前用户输入的数据,是否是数字(使用parseInt()方法,如果是整数返回true),且大于等于1

  1. 数据验证完成之后,发送修改数量的请求,请求参数有购买的数量和商品的id

代码:

<script type="text/javascript">

    function _updateBuynum(buynum,gid){

//判断当前用户输入的内容,这个内容,必须是数字,是正整数

//是不是数字

        if(parseInt(buynum)){

//是不是正数

            if(buynum > 0){

//发送请求

location.href='${root }/updateBuynum?gid='+gid+'&buynum='+buynum;

}else{

alert("数字不合法");

}

}else{

alert("数字不合法");

}

}

</script>

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Cart;

import cn.itcast.domain.User;

import cn.itcast.service.CartService;

import cn.itcast.service.impl.CartServiceImpl;

public class UpdateBuynumServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登陆

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//接受参数

String parameter = request.getParameter("gid");

String parameter2 = request.getParameter("buynum");

int gid = 0;

int buynum = 0;

try {

gid = Integer.parseInt(parameter);

buynum = Integer.parseInt(parameter2);

} catch (Exception e) {

e.printStackTrace();

response.sendRedirect(request.getContextPath());

return;

}

int uid = loginUser.getId();

Cart c = new Cart();

c.setBuynum(buynum);

c.setGid(gid);

c.setUid(uid);

//调用service方法

CartService cartService = new CartServiceImpl();

cartService.updateBuynum(c);

//重新获取所有的购物车数据,findAllCartServlet

response.sendRedirect(request.getContextPath()+"/findAllCart");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

Service接口:

/**

* 修改数量的方法

* @param c

*/

void updateBuynum(Cart c);

实现类:

public void updateBuynum(Cart c) {

cartDao.update(c);

}

注意: dao已经实现过了,不再重复

  1. 删除购物车中的商品

    1. 功能分析

  1. 页面实现

完善删除链接,发送要被删除的商品的gid

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.User;

import cn.itcast.service.CartService;

import cn.itcast.service.impl.CartServiceImpl;

public class DeleteCartServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取参数(gid uid)

String parameter = request.getParameter("gid");

int gid = 0;

try {

gid = Integer.parseInt(parameter);

} catch (Exception e) {

e.printStackTrace();

response.sendRedirect(request.getContextPath());

return;

}

int uid= loginUser.getId();

//调用service方法,删除数据

CartService cartService = new CartServiceImpl();

cartService.delete(uid , gid);

//重新获取所有的购物车信息

response.sendRedirect(request.getContextPath()+"/findAllCart");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:CartService

/**

* 删除购物车商品

* @param uid

* @param gid

*/

void delete(int uid, int gid);

实现类:CartServiceImpl

public void delete(int uid, int gid) {

cartDao.delete(uid,gid);

}

  1. DAO实现

接口:CartDao

/**

* 删除购物车商品

* @param uid

* @param gid

*/

void delete(int uid, int gid);

实现类:CartDaoImpl

public void delete(int uid, int gid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "delete from cart where uid = ? and gid = ?";

try {

qr.update(sql, uid,gid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("删除购物车失败");

}

}

Nosql数据库:redis:缓存 mongdb :存储大量文本 ,资金流

提示:如果购物车数据,存在session中,如何通过测试确认?换浏览器,查看购物车数据是否不一致。

如果购物车数据,存在数据库中,如果如何测试确认?每次登录购物车中数据都不会变化。

购物车存数据库,第一:占用空间,第二,大量的增删改查操作,不断与数据库交互,性能慢

如果购物车数据,存在缓存中,如果如何测试确认?在服务器维护之后,购物车数据消失,就存在缓存中。

缓存:在内存中开辟的空间,存取数据的。

备份服务器:平时运行的服务器A,在A停机维护的时候,B服务器对外提供服务。

  1. 订单

    1. 提交订单(重点、难点)

  1. 页面显示购物车商品清单

1)修改查看购物车列表的servlet,将数据保存到session,方便在同一个会话中使用,在订单页面再次展示购物车数据不需要再从数据库中获取

  1. 在订单的提交页面显示用户要购买的商品数据

    遍历商品集合,计算商品的总价

  1. Ajax实现省市县三级联动

功能分析:

第一步:页面加载完成之后,显示省一级地区的数据

第二步:选择省的时候,加载相对应的市的数据

第三步:选择市的时候,加载相对应的县的数据

流程图:

  1. Ajax代码

<script type="text/javascript">

//获取核心对象的方法

        function getXHR(){

var xmlhttp;

if (window.XMLHttpRequest){

// code for IE7+, Firefox, Chrome, Opera, Safari

xmlhttp=new XMLHttpRequest();

}else{

// code for IE6, IE5

xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

}

return xmlhttp;

}

//书写ajax代码步骤:

//第一步:获取核心对象

//第二步:发送请求open方法 send方法

//第三步:设置等待响应

//第四步:获取响应数据,根据业务处理数据

window.onload = function(){

var xhr = getXHR();

xhr.open("GET","${root}/getData?pid=0",true);

xhr.send();

xhr.onreadystatechange = function(){

if(xhr.readyState == 4 && xhr.status == 200){

//data是字符串数据,将他转换成javascript对象

                    var data = xhr.responseText;

//eval 这个函数是将字符串,转换成javascript代码,

//在JSON.parse()出来之后,eval就开始淘汰

                    var arr = JSON.parse(data);

var _province = document.getElementById("province");

for ( var i = 0; i < arr.length; i++) {

//不断创建option,添加到省一级地区的select标签中

                        var _option = document.createElement("option");

_option.setAttribute("value", arr[i].id);

_option.innerHTML = arr[i].name;

_province.appendChild(_option);

}

}

};

};

function _getCity(value){

var _city = document.getElementById("city");

//清空数据

_city.length = 1;

var _district = document.getElementById("district");

//清空数据

_district.length = 1;

var xhr = getXHR();

xhr.open("GET","${root}/getData?pid="+value,true);

xhr.send();

xhr.onreadystatechange = function(){

if(xhr.readyState == 4 && xhr.status == 200){

var data = xhr.responseText;

var arr = JSON.parse(data);

for ( var i = 0; i < arr.length; i++) {

//不断创建option,添加到省一级地区的select标签中

                        var _option = document.createElement("option");

_option.setAttribute("value", arr[i].id);

_option.innerHTML = arr[i].name;

_city.appendChild(_option);

}

}

};

}

function _getDistrict(value){

var _district = document.getElementById("district");

//清空数据

_district.length = 1;

var xhr = getXHR();

xhr.open("GET","${root}/getData?pid="+value,true);

xhr.send();

xhr.onreadystatechange = function(){

if(xhr.readyState == 4 && xhr.status == 200){

var data = xhr.responseText;

var arr = JSON.parse(data);

for ( var i = 0; i < arr.length; i++) {

//不断创建option,添加到省一级地区的select标签中

                        var _option = document.createElement("option");

_option.setAttribute("value", arr[i].id);

_option.innerHTML = arr[i].name;

_district.appendChild(_option);

}

}

};

}

</script>

  1. Servlet代码实现

package cn.itcast.web;

import java.io.IOException;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.PCD;

import cn.itcast.service.PCDService;

import cn.itcast.service.impl.PCDServiceImpl;

import flexjson.JSONSerializer;

public class GetDataServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//获取pid

String parameter = request.getParameter("pid");

int pid = 0;

try {

pid = Integer.parseInt(parameter);

} catch (Exception e) {

e.printStackTrace();

response.sendRedirect(request.getContextPath());

return;

}

//调用service方法

PCDService pcdService = new PCDServiceImpl();

List<PCD> list = pcdService.getData(pid);

//将数据转换成json格式

JSONSerializer serializer = new JSONSerializer();

String serialize = serializer.serialize(list);

//发出响应

response.getWriter().write(serialize);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. 省市联动Service实现

接口:ProvinceService

package cn.itcast.service;

import java.util.List;

import cn.itcast.domain.PCD;

public interface PCDService {

/**

* 获取地区数据的方法

* @param pid

* @return

*/

List<PCD> getData(int pid);

}

实现类:ProvinceServiceImpl

package cn.itcast.service.impl;

import java.util.List;

import cn.itcast.dao.PCDDao;

import cn.itcast.dao.impl.PCDDaoImpl;

import cn.itcast.domain.PCD;

import cn.itcast.service.PCDService;

public class PCDServiceImpl implements PCDService {

private PCDDao pcdDao = new PCDDaoImpl();

@Override

public List<PCD> getData(int pid) {

return pcdDao.getData(pid);

}

}

  1. 省市联动Dao实现

接口: ProvinceDao

package cn.itcast.dao;

import java.util.List;

import cn.itcast.domain.PCD;

public interface PCDDao {

List<PCD> getData(int pid);

}

实现类:ProvinceDaoImpl

package cn.itcast.dao.impl;

import java.sql.SQLException;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.itcast.dao.PCDDao;

import cn.itcast.domain.PCD;

import cn.itcast.utils.DBUtils;

public class PCDDaoImpl implements PCDDao {

@Override

public List<PCD> getData(int pid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from province_city_district where pid = ?";

try {

return qr.query(sql, new BeanListHandler<PCD>(PCD.class), pid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("获取地区数据失败");

}

}

}

  1. 订单生成页面修改

  1. 修改表单请求路径

  1. 将被选中的省市县数据存入隐藏域中

  1. 订单生成页面流程分析

  1. 订单生成Servlet实现

package cn.itcast.web;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Cart;

import cn.itcast.domain.Order;

import cn.itcast.domain.OrderItems;

import cn.itcast.domain.User;

import cn.itcast.service.OrderService;

import cn.itcast.service.impl.OrderServiceImpl;

import cn.itcast.utils.UUIDUtils;

public class AddOrderServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取和封装数据

//封装订单的数据

String oid = UUIDUtils.getUUID();

int uid = loginUser.getId();

double totalprice = 0;

//获取session中的购物车数据,来计算总金额

List<Cart> list = (List<Cart>)request.getSession().getAttribute("list");

//准备一个集合,用来保存OrderItems

List<OrderItems> oiList = new ArrayList<OrderItems>();

for (Cart cart : list) {

totalprice = totalprice + cart.getBuynum() * cart.getGood().getEstoreprice();

//获取所有商品的信息,将数据存入OrderItems,然后,再存入List集合

OrderItems oi = new OrderItems();

//订单编号

oi.setOid(oid);

//商品的编号

oi.setGid(cart.getGood().getId());

oi.setBuynum(cart.getBuynum());

oiList.add(oi);

}

//设置支付状态:1 待付款

int status = 1;

Date createtime = new Date();

//省市县

String province = request.getParameter("province");

String city = request.getParameter("city");

String district = request.getParameter("district");

//详细地址,邮编姓名电话

String detailAddress = request.getParameter("detailAddress");

String zipcode = request.getParameter("zipcode");

String name = request.getParameter("name");

String telephone = request.getParameter("telephone");

String address = province +"(省/市)"+city+"(市/区)"+district+"(县/镇)"+

detailAddress+"邮编:"+zipcode+"姓名:"+name+"电话:"+telephone;

Order o = new Order();

o.setAddress(address);

o.setCreatetime(createtime);

o.setId(oid);

o.setStatus(status);

o.setTotalprice(totalprice);

o.setUid(uid);

o.setOiList(oiList);

//调用service方法添加订单

OrderService orderService = new OrderServiceImpl();

orderService.add(o);

//调用查询全部订单Servlet,查看效果

response.sendRedirect(request.getContextPath()+"/orders.jsp");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. 订单生成Service实现

接口:OrderService

package cn.itcast.service;

import cn.itcast.domain.Order;

public interface OrderService {

/**

* 添加订单的方法

* @param o

*/

void add(Order o);

}

实现类:OrderServiceImpl

package cn.itcast.service.impl;

import java.sql.Connection;

import java.sql.SQLException;

import cn.itcast.dao.CartDao;

import cn.itcast.dao.OrderDao;

import cn.itcast.dao.impl.CartDaoImpl;

import cn.itcast.dao.impl.OrderDaoImpl;

import cn.itcast.domain.Order;

import cn.itcast.service.OrderService;

import cn.itcast.utils.DBUtils;

public class OrderServiceImpl implements OrderService {

private OrderDao orderDao = new OrderDaoImpl();

private CartDao cartDao = new CartDaoImpl();

@Override

public void add(Order o) {

//获取数据库连接

Connection conn = null;

try {

conn = DBUtils.getConnection();

//开启事务

conn.setAutoCommit(false);

//添加订单

orderDao.add(o,conn);

//添加订单明细

orderDao.addOrderItems(o.getOiList(),conn);

//清空购物车

cartDao.clear(o.getUid(),conn);

//提交事务

conn.commit();

//异常回滚

} catch (Exception e) {

e.printStackTrace();

try {

conn.rollback();

} catch (SQLException e1) {

e1.printStackTrace();

}

}

}

}

  1. 订单生成DAO实现

接口:OrderDao

package cn.itcast.dao;

import java.sql.Connection;

import java.util.List;

import cn.itcast.domain.Order;

import cn.itcast.domain.OrderItems;

public interface OrderDao {

/**

* 添加订单

* @param o

* @param conn

*/

void add(Order o, Connection conn);

/**

* 添加订单明细

* @param oiList

* @param conn

*/

void addOrderItems(List<OrderItems> oiList, Connection conn);

}

实现类:OrderDaoImpl

package cn.itcast.dao.impl;

import java.sql.Connection;

import java.sql.SQLException;

import java.util.List;

import org.apache.commons.dbutils.QueryRunner;

import cn.itcast.dao.OrderDao;

import cn.itcast.domain.Order;

import cn.itcast.domain.OrderItems;

public class OrderDaoImpl implements OrderDao {

@Override

public void add(Order o, Connection conn) {

//QueryRunner():创建一个与数据库无关的QueryRunner对象,后期在使用增删改查的方法的时候,手动提供一个连接

QueryRunner qr = new QueryRunner();

String sql = "insert into orders values(?,?,?,?,?,?)";

try {

qr.update(conn, sql, o.getId(),o.getUid(),o.getTotalprice(),o.getAddress(),o.getStatus(),o.getCreatetime());

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("添加订单失败");

}

}

@Override

public void addOrderItems(List<OrderItems> oiList, Connection conn) {

QueryRunner qr = new QueryRunner();

String sql = "insert into orderitems values(?,?,?)";

for (OrderItems oi : oiList) {

try {

qr.update(conn, sql, oi.getOid(),oi.getGid(),oi.getBuynum());

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("添加订单明细失败");

}

}

}

}

接口:CartDao

/**

* 清空购物车

* @param uid

* @param conn

*/

void clear(int uid, Connection conn);

实现类:CartDaoImpl

public void clear(int uid, Connection conn) {

QueryRunner qr = new QueryRunner();

String sql = "delete from cart where uid = ?";

try {

qr.update(conn, sql, uid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("清空购物车失败");

}

}

  1. 查看订单列表

    1. 功能分析

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Order;

import cn.itcast.domain.User;

import cn.itcast.service.OrderService;

import cn.itcast.service.impl.OrderServiceImpl;

public class FindAllOrdersServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取参数

int uid= loginUser.getId();

//调用service方法

OrderService orderService = new OrderServiceImpl();

List<Order> oList = orderService.findAll(uid);

//转发数据到orders.jsp展示数据

request.setAttribute("oList", oList);

request.getRequestDispatcher("/orders.jsp").forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:OrderService

/**

* 查询指定用户的所有的订单

* @param uid

* @return

*/

List<Order> findAll(int uid);

实现类:OrderServiceImpl

public List<Order> findAll(int uid) {

return orderDao.findAll(uid);

}

  1. DAO实现

接口:OrderDao

/**

* 查询指定用户的订单

* @param uid

* @return

*/

List<Order> findAll(int uid);

实现类: OrderDaoImpl

public List<Order> findAll(int uid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql= "select * from orders where uid = ?";

try {

return qr.query(sql, new BeanListHandler<Order>(Order.class), uid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("查询指定的用户订单失败");

}

}

  1. 页面实现

  1. 显示订单相关信息
  2. 根据订单的状态显示不同效果,status==1未支付——在线支付、取消订单,status==2,已支付——查看详细,status==3已过期——查看详细

  1. 查看订单详情

    1. 功能分析

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Order;

import cn.itcast.domain.User;

import cn.itcast.service.OrderService;

import cn.itcast.service.impl.OrderServiceImpl;

public class FindOrderByIdServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取参数oid

String oid = request.getParameter("oid");

//调用service获取数据

OrderService orderService = new OrderServiceImpl();

Order o = orderService.findById(oid);

//转发数据到orders_detail.jsp

request.setAttribute("order", o);

request.getRequestDispatcher("/orders_detail.jsp").forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:OrderService

/**

* 根据订单id获取数据的方法

* @param oid

* @return

*/

Order findById(String oid);

实现类:OrderServiceImpl

private GoodDao goodDao = new GoodDaoImpl();

@Override

public Order findById(String oid) {

// 获取订单数据

Order o = orderDao.findById(oid);

//获取订单明细

List<OrderItems> oiList = orderDao.findOrderItemsByOid(oid);

for (OrderItems oi : oiList) {

//获取商品信息

Good good = goodDao.findById(oi.getGid());

oi.setGood(good);

}

//封装数据返回给调用者

o.setOiList(oiList);

return o;

}

  1. Dao实现

接口:OrderDao

/**

* 根据id查询订单

* @param oid

* @return

*/

Order findById(String oid);

/**

* 根据oid获取订单明细

* @param oid

* @return

*/

List<OrderItems> findOrderItemsByOid(String oid);

实现类: OrderDaoImpl

@Override

public Order findById(String oid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql="select * from orders where id = ?";

try {

return qr.query(sql,new BeanHandler<Order>(Order.class), oid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("查询指定的订单失败");

}

}

@Override

public List<OrderItems> findOrderItemsByOid(String oid) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from orderitems where oid = ?";

try {

return qr.query(sql, new BeanListHandler<OrderItems>(OrderItems.class), oid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("查询指定的订单明细失败");

}

}

  1. 页面修改

  1. 在订单编号上添加a标签,链接指向订单详情
  2. 同样也修改后面的订单的查看详情链接
  3. 显示订单的信息和相关的商品信息
  4. 要显示订单的总价

  1. 取消订单

    1. 功能分析

  1. 编辑取消订单的链接

1)设置取消订单的链接

  1. Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.User;

import cn.itcast.service.OrderService;

import cn.itcast.service.impl.OrderServiceImpl;

public class DeleteOrderServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//获取参数

String oid = request.getParameter("oid");

//调用service方法,删除数据

OrderService orderService = new OrderServiceImpl();

orderService.delete(oid);

//重定向访问,findAllOrdersServlet

response.sendRedirect(request.getContextPath()+"/findAllOrders");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:OrderService

/**

* 删除订单的方法

* @param oid

*/

void delete(String oid);

实现类:

public void delete(String oid) {

//获取连接

Connection conn = null;

try {

conn = DBUtils.getConnection();

//开启事务

conn.setAutoCommit(false);

//删除订单明细

orderDao.deleteOrderItemsByOid(oid,conn);

//删除订单

orderDao.delete(oid,conn);

//提交事务

conn.commit();

//异常回滚

} catch (Exception e) {

e.printStackTrace();

try {

conn.rollback();

} catch (SQLException e1) {

e1.printStackTrace();

}

}

}

  1. DAO实现

接口:OrderDao

/**

* 删除订单明细

* @param oid

* @param conn

*/

void deleteOrderItemsByOid(String oid, Connection conn);

/**

* 删除订单

* @param oid

* @param conn

*/

void delete(String oid, Connection conn);

实现类:OrderDaoImpl

@Override

public void deleteOrderItemsByOid(String oid, Connection conn) {

QueryRunner qr = new QueryRunner();

String sql = "delete from orderitems where oid = ?";

try {

qr.update(conn, sql, oid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("删除指定的订单明细失败");

}

}

@Override

public void delete(String oid, Connection conn) {

QueryRunner qr = new QueryRunner();

String sql="delete from orders where id = ?";

try {

qr.update(conn, sql, oid);

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("删除指定的订单失败");

}

}

  1. 管理员功能(卖家)

    1. 添加商品

      1. 功能分析

页面修改:

  1. 修改表单请求路径
  1. Servlet实现

package cn.itcast.web;

import java.io.File;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.FileUploadException;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

import cn.itcast.domain.Good;

import cn.itcast.domain.User;

import cn.itcast.service.GoodService;

import cn.itcast.service.impl.GoodServiceImpl;

import cn.itcast.utils.DirUtils;

import cn.itcast.utils.UUIDUtils;

public class AddGoodServlet extends HttpServlet {

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//校验登录

User loginUser = (User)request.getSession().getAttribute("loginUser");

if(loginUser == null){

response.sendRedirect(request.getContextPath()+"/login.jsp");

return;

}

//保证图片上传成功

//fileUpload技术,核心对象,DiskFileItemFactory ServletFileUpload FileItem

//DiskFileItemFactory:辅助作用,帮助解析request,将数据解析成一个一个的FileItem

//ServletFileUpload:解析的核心对象,需要绑定DiskFileItemFactory

//FileItem:封装了所有input输入框的数据的对象

DiskFileItemFactory factory = new DiskFileItemFactory();

//将DiskFileItemFactory绑定到ServletFileUpload

ServletFileUpload fileUpload = new ServletFileUpload(factory);

//创建一个map集合用来存储good相关数据

Map<String ,Object> map = new HashMap<String ,Object>();

try {

//解析request对象

List<FileItem> list = fileUpload.parseRequest(request);

//针对集合进行遍历,判断当前fileItem是否是一个普通字段,还是文件上传

for (FileItem item : list) {

//判断当前是否是普通字段

if(item.isFormField()){

//表示,我是普通字段

//获取input的name值

String fieldName = item.getFieldName();

//获取input的value值

String value = item.getString("utf-8");

//将数据保存到一个map集合

map.put(fieldName, value);

}else{

//我是文件上传

//确定upload文件夹的位置,要保存图片在这个文件家中

//String realPath = this.getServletContext().getRealPath("/upload");

//要输出一个文件,要获取文件名

String fileName = item.getName();

//为了防止重复,需要使用UUID,重写文件名

String uuid = UUIDUtils.getUUID();

fileName = uuid + fileName;

//目录打散,在upload文件路径后,再加几层目录,

String dir = DirUtils.getDir(fileName);

//这个文件目录,可能不存在,需要判断,如果不存在,创建

//输出指定位置,要在指定位置下,目录打散

File file = new File("c:/picture",dir);

if(file.exists()){

//存在,什么都不做

}else{

file.mkdirs();

}

//向指定位置输出文件

try {

item.write(new File("c:/picture"+dir,fileName));

} catch (Exception e) {

e.printStackTrace();

}

//保存图片上传地址,后期才能通过路径找到图片

// /upload/11/9/f913990ee3f04e029dd34f7d55a60fb1.jpg

// /upload/14/13/c39e4f0266b745a3b91d2697b9d6c544WIN_20151231_16_46_42_Pro.jpg

map.put("imgurl", "/picture"+dir+"/"+fileName);

}

}

} catch (FileUploadException e) {

e.printStackTrace();

}

//封装数据到good对象

Good g = new Good();

try {

BeanUtils.populate(g, map);

} catch (Exception e) {

e.printStackTrace();

}

//调用service方法添加商品

GoodService goodService = new GoodServiceImpl();

goodService.addGood(g);

//查看所有商品

response.sendRedirect(request.getContextPath()+"/goods_admin.jsp");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. Service实现

接口:GoodService

/**

* 添加商品

* @param g

*/

void addGood(Good g);

实现类:GoodServiceImpl

public void addGood(Good g) {

goodDao.addGood(g);

}

  1. DAO实现

接口:GoodDao

/**

* 添加商品

* @param g

*/

void addGood(Good g);

实现类:GoodDaoImpl

public void addGood(Good g) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "insert into goods values(null,?,?,?,?,?,?,?)";

try {

qr.update(sql, g.getName(), g.getMarketprice(), g.getEstoreprice(),

g.getCategory(), g.getNum(), g.getImgurl(),

g.getDescription());

} catch (SQLException e) {

e.printStackTrace();

throw new RuntimeException("添加商品失败");

}

}

补充内容:

根据演示效果——重新部署服务器之后,会丢失商品图片

解决方案:将图片保存与项目和服务器无关的位置

思路:

1:保证图片上传的时候,一定将图片保存到指定位置(c:/picture)

2: 保存图片的url的时候,路径,一定/picture/11/12/1.jpg。

3:专门设计一个Servlet,接受处理图片请求,在Servlet中,读取图片资源,

使用IO技术,然后使用response对象发出响应

修改请求地址(例如,在商品列表页面):/estore2/pic?imgurl=/picture/8/15/774595f7c5b44fefa7b08b9cc5969e9f.jpg

PictureServlet:

package cn.itcast.web;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public
class
PictureServlet
extends HttpServlet {

public
void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//1)浏览器发送请求给服务器(商品需要图片名称)

// /picture/14/1/85a3510c83ef4fc98afbb4a4a0095e2e2.jpg

String imgurl = request.getParameter("imgurl");

//2)读取服务器硬盘上的图片数据

FileInputStream in = new FileInputStream(new File("c:"+imgurl));

//3)使用IO技术,将数据发送(使用response对象发送数据)

ServletOutputStream out = response.getOutputStream();

byte[] buf =new
byte[1024];

int len = 0;

while((len = in.read(buf)) != -1){

out.write(buf, 0, len);

}

}

public
void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. 查看商品(管理员)

为什么,已经存在商品列表功能,还要在后台制作一个商品列表给管理员?

注意:设计一个项目,分角色,角色下有权限,那么不同角色有不同权限,

作为买家,普通用户,无法使用管理员功能

同理,作为管理员,无法使用普通用户功能,只能重新制作一个让管理员使用。

添加完成商品后,从数据库中重新查询所有商品,展示在goods_admin.jsp页面上

Servlet实现:

package cn.itcast.web;

import java.io.IOException;

import java.util.List;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.Good;

import cn.itcast.service.GoodService;

import cn.itcast.service.impl.GoodServiceImpl;

public
class
QueryAllGoodsAdminServelt
extends HttpServlet {

public
void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

// 调用service方法获取数据

GoodService goodService = new GoodServiceImpl();

List<Good> list = goodService.findAll();

// 将数据存入request容器,返回goods.jsp

request.setAttribute("list", list);

request.getRequestDispatcher("/goods_admin.jsp").forward(request, response);

}

public
void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doGet(request, response);

}

}

  1. 权限管理

为什么要做权限管理?

商品上传,只有卖家可以使用,买家是不能使用的,需要做权限的控制

如何实现权限管理?

我们要解决,谁,是什么角色,能做哪些操作?

两种权限数据解决方案:

第一种:使用数据库表,来控制用户的权限,一般需要5张表(用户表 角色表 权限表 用户角色表 角色权限表)

5张表之间的关系:

第二种:使用配置文件管理权限

在用户表中直接设置用户的角色,将角色的权限设置在配置文件中,后期用户访问的时候,将用户的请求路径和角色权限配置文件中的内容比较,如果一致表示用户拥有该权限。

在用户表中直接设置用户的角色——用户和角色都在一张表。

将角色的权限设置在配置文件中——使用一个txt文件,保存角色对应的权限

将用户的请求路径和角色权限配置文件中的内容比较——request获取请求路径,要与配置文件的中内容一致,有权限

如何定义配置角色权限配置文件?

普通用户权限,存放在user.txt

管理员权限,存在admin.txt

普通用户权限user.txt:

管理员权限admin.txt:

第二种解决方案代码实现:

使用什么技术做权限的控制?

过滤器。

实现步骤:

第一步:创建两个集合,准备加载权限的数据

第二步:在过滤器初始化的时候,加载权限的数据

第三步:获取用户的请求

第四步:开始比对,用户的请求和用户所具有的权限是否一致

第五步:一致,放行,不一致,抛出异常

代码实现:

package cn.itcast.filter;

import java.io.BufferedReader;

import java.io.File;

import
java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import
javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.domain.User;

public
class PrivilegeFilter implements Filter{

//第一步:创建两个集合,准备加载权限的数据

//创建集合存放user的权限

private List<String> userList = new ArrayList<String>();

//创建集合存放admin的权限

private List<String> adminList = new ArrayList<String>();

@Override

public
void init(FilterConfig config) throws ServletException {

System.out.println("==================权限数据开始加载==============");

//第二步:在过滤器初始化的时候,加载权限的数据

//如何确定user.txt文件的位置。WEB-INF/classes

//先获取servletContext对象,通过他来调用getRealPath(),获取到的是配置文件路径

String realPath = config.getServletContext().getRealPath("WEB-INF/classes/user.txt");

//服务器上路径:C:\apache-tomcat-7.0.52\webapps\estore2\WEB-INF\classes/user.txt

// C:\apache-tomcat-7.0.52\webapps\estore2\WEB-INF\classes/user.txt

//System.out.println(realPath);

try {

//可以通过BufferedReader读取配置文件,一行一行的读取

BufferedReader reader = new BufferedReader(new FileReader(new File(realPath)));

String line = null;

while( (line = reader.readLine()) != null){

//将数据存入集合

userList.add(line);

}

} catch (Exception e) {

e.printStackTrace();

}

System.out.println(userList);

String realPath2 = config.getServletContext().getRealPath("WEB-INF/classes/admin.txt");

try {

BufferedReader reader = new BufferedReader(new FileReader(new File(realPath2)));

String line = null;

while((line = reader.readLine()) != null){

adminList.add(line);

}

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(adminList);

System.out.println("==================权限数据加载完成 ==============");

}

@Override

public
void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest)request;

HttpServletResponse res = (HttpServletResponse)response;

//第三步:获取用户的请求,将请求和配置文件中权限进行比对,如果一致,放行,不一致,抛出异常

//获取用户的请求

String requestURI = req.getRequestURI();

//requestURI——————/estore2/findAllGoods

requestURI = requestURI.substring(req.getContextPath().length());

// /findAllGoods

System.out.println(requestURI);

//有一些页面和Servlet请求,不需要管理

//需要知道,那些请求需要被关管理,发现,只有请求,包含在集合中,就需要被管理

boolean isUser = userList.contains(requestURI);

boolean isAdmin = adminList.contains(requestURI);

if(isUser || isAdmin){

//表示这个请求,是一个需要被管理的权限

//第四步:开始比对,用户的请求和用户所具有的权限是否一致

//获取用户的登录信息loginUser role :记录用户的角色,这个角色对应的权限配置文件

User loginUser = (User)req.getSession().getAttribute("loginUser");

if(loginUser == null){

res.sendRedirect(req.getContextPath()+"/login.jsp");

return;

}else{

//可以获取角色,可以进行比对

if("user".equals(loginUser.getRole()) && isUser){

//"user".equals(loginUser.getRole())

//判断你的角色是否是一个普通用户

//isUser==true:用户请求,是请求了一个普通用户权限

//isUser==false:用户请求,是请求了一个管理员用户权限

//当前用户是一个普通用户,而且,请求的权限是普通用户权限

//放行

chain.doFilter(req, res);

}else
if("admin".equals(loginUser.getRole()) && isAdmin){

//当前用户是一个管理员用户,他请求的权限也是管理员权限

//放行

chain.doFilter(req, res);

}else{

//表示当前用户的角色和权限不一致

throw
new RuntimeException("权限不足,请联系超级管理员!");

}

}

}else{

//不需要管理的权限

chain.doFilter(req, res);

}

}

@Override

public
void destroy() {

}

}

  1. 配置网站错误页面

软件在运行时,会出现各种错误,这些错误不希望用户看到,这时需要配置一个统一的错误页面,当系统出错时,就会跳转到这个错误页面,这个错误页面一般比较友好

在web.xml中添加如下配置即可

<!-- 配置全站错误页面 -->

<error-page>

<error-code>404</error-code>

<location>/404.jsp</location>

</error-page>

<error-page>

<error-code>500</error-code>

<location>/500.jsp</location>

</error-page>

  1. 定时器扫描过期订单

    1. 定时任务介绍

  1. Timer回顾

  1. 定时扫描过期订单并设置为过期

    1. 创建监听器,监听ServletContext启动

需求:定时扫描过期订单并设置为过期

:定时扫描,需要用到Timer TimeTask 类,在哪里使用这两个类?

需要在项目启动的时候,扫描订单。

2:什么对象可以监控到项目启动

ServletContextListener,可以监听项目启动和关闭

3:定时器中的任务是什么?

获取状态为1的订单,比对创建时间,如果时间超出两个小时,就设置过期(状态:3)

注册监听器

package cn.itcast.listener;

import java.util.Timer;

import java.util.TimerTask;

import javax.servlet.ServletContextEvent;

import javax.servlet.ServletContextListener;

import cn.itcast.service.OrderService;

import cn.itcast.service.impl.OrderServiceImpl;

public
class SaoMiaoListener implements ServletContextListener{

@Override

public
void contextInitialized(ServletContextEvent sce) {

//开启定时扫描任务

//创建定时器

Timer timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public
void run() {

System.out.println("===================定时扫描过期订单启动================");

//调用service方法,执行定时任务

OrderService orderService = new OrderServiceImpl();

orderService.saomiao();

System.out.println("===================定时扫描过期订单完成================");

}

//0:立即执行

//1000*60*60*2:两个小时执行一次

}, 0 ,1000*60*60*2);

//2:00:00 定时器启动 2:20:00,创建了订单 4:00:00 定时器启动 6:00:00 定时器启动,订单早已经过期

//每一个订单,都设置一个定时器。

//每一个订单创建,都会在内存中创建一个定时器对象,而且这个定时器对象一定要两个小时之后才关闭

}

@Override

public
void contextDestroyed(ServletContextEvent sce) {

}

}

配置文件:

  1. Service实现

接口:OrderService

/**

* 扫描过期订单的方法

*/

void saomiao();

实现类:OrderServiceImpl

public
void saomiao() {

订单,然后,如果超出时间(2个小时),修改状态:3

订单

List<Order> list = orderDao.findByStatus(1);

//第二步:循环遍历,做判断

for (Order order : list) {

long now = new Date().getTime();

long time = order.getCreatetime().getTime();

if(now - time >= 1000*60*60*2){

orderDao.updateStatus(3,order.getId());

}

}

}

  1. Dao实现

接口:OrderDao

/**

* 获取指定状态的订单

* @param i :指定状态

* @return

*/

List<Order> findByStatus(int i);

/**

* 修改指定的订单状态

* @param i

* @param id

*/

void updateStatus(int i, String id);

实现类:OrderDaoImpl

@Override

public List<Order> findByStatus(int i) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "select * from orders where status = ?";

try {

return qr.query(sql, new BeanListHandler<Order>(Order.class), i);

} catch (SQLException e) {

e.printStackTrace();

throw
new RuntimeException("查询指定状态的订单失败");

}

}

@Override

public
void updateStatus(int i, String id) {

QueryRunner qr = new QueryRunner(DBUtils.getDataSource());

String sql = "update orders set status = ? where id = ?";

try {

qr.update(sql, i,id);

} catch (SQLException e) {

e.printStackTrace();

throw
new RuntimeException("修改指定的订单状态失败");

}

}

  1. 在线支付

    1. 在线支付介绍

ICBC 工商银行

在线支付流程一:

总结:商城通过第三方平台和所有银行交易

在线支付流程二:

  1. 易付宝支付介绍

易宝支付官网:https://www.yeepay.com/

易宝会给商家提供对应的支付接口以及文档,开发人员在开发支付功能的时候,

只需要按照文档中的说明直接完成对应的代码即可。

支付接口及文档下载:

  1. 编写orders.jsp页面上的支付链接

1)在订单明细页面上添加支付按钮(未支付的订单才有,发送订单编号和金额)

效果:

  1. 编写pay.jsp

  1. 修改表单提交请求路径
  2. 将订单编号和金额写入隐藏域
  3. 给用户显示订单编号和金额

  1. 支付的Servlet实现

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.utils.PaymentUtil;

/*

* 支付的Servlet程序

*/

public
class
PayServlet
extends HttpServlet {

public
void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 获取订单号、金额、银行编码

String orderid = request.getParameter("orderid"); // 订单号

String money = request.getParameter("money"); // 金额

String pd_FrpId = request.getParameter("pd_FrpId"); // 银行编码

// 根据易宝接口准备参数

String p0_Cmd = "Buy";

String p1_MerId =

String p2_Order = orderid; // 订单号

String p3_Amt = "0.01"; // 金额,单位是元

String p4_Cur = "CNY";

String p5_Pid = "";

String p6_Pcat = "";

String p7_Pdesc = "";

// 支付成功回调地址 ---- 第三方支付公司会访问、用户访问

// 第三方支付可以访问网址

// 需要独立外网网卡

String p8_Url = "http://127.0.0.1:8080/estore2/callback"; // 回调地址

String p9_SAF = "";

String pa_MP = "";

String pr_NeedResponse = "1";

// 将所有数据,进行数字签名,加密算法由支付公司提供:注册时,第三方支付平台提供给商家的加密算法的摘要

String keyValue = "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl"; // 密钥

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);

// 将所有数据发送易宝指定地址

request.setAttribute("pd_FrpId", pd_FrpId);

request.setAttribute("p0_Cmd", p0_Cmd);

request.setAttribute("p1_MerId", p1_MerId);

request.setAttribute("p2_Order", p2_Order);

request.setAttribute("p3_Amt", p3_Amt);

request.setAttribute("p4_Cur", p4_Cur);

request.setAttribute("p5_Pid", p5_Pid);

request.setAttribute("p6_Pcat", p6_Pcat);

request.setAttribute("p7_Pdesc", p7_Pdesc);

request.setAttribute("p8_Url", p8_Url);

request.setAttribute("p9_SAF", p9_SAF);

request.setAttribute("pa_MP", pa_MP);

request.setAttribute("pr_NeedResponse", pr_NeedResponse);

request.setAttribute("hmac", hmac);

// 跳转确认支付页面

request.getRequestDispatcher("/confirm.jsp").forward(request, response);

}

public
void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

  1. 支付确认页面confirm.jsp

  1. 显示订单编号和订单金额
  2. 隐藏域中都是servlet中封装给易宝的数据

  1. 回调函数Servlet

package cn.itcast.web;

import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import cn.itcast.utils.PaymentUtil;

@SuppressWarnings({"serial","unused"})

public
class CallbackServlet extends HttpServlet {

public
void doGet(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 rb_BankId = request.getParameter("rb_BankId");

String ro_BankOrderId = request.getParameter("ro_BankOrderId");

String rp_PayDate = request.getParameter("rp_PayDate");

String rq_CardNo = request.getParameter("rq_CardNo");

String ru_Trxtime = request.getParameter("ru_Trxtime");

String hmac = request.getParameter("hmac");

// 将响应所有数据加密,比较hmac

String keyValue = "69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl";

boolean isvalid = 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);

if (isvalid) {

// 区分两次通知处理方式

if (r9_BType.equals("1")) {

// 给用户提示付款成功,查看付款结果

System.,提示用户,已经付款");

response.setContentType("text/html;charset=utf-8");

response.sendRedirect(request.getContextPath() + "/pay_success.jsp");

} else
if (r9_BType.equals("2")) {

// 收到易宝到款通知,修改订单状态

System.out.println("收到2 ,修改订单状态....");

}

} else {

throw
new RuntimeException("数字签名错误,假冒易宝!");

}

}

public
void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

Java web项目综合练习(Estore)的更多相关文章

  1. 一款基于SSM框架技术的全栈Java web项目(已部署可直接体验)

    概述 此项目基于SSM框架技术的Java Web项目,是全栈项目,涉及前端.后端.插件.上线部署等各个板块,项目所有的代码都是自己编码所得,每一步.部分都有清晰的注释,完全不用担心代码混乱,可以轻松. ...

  2. JAVA WEB项目中各种路径的获取

    JAVA WEB项目中各种路径的获取 标签: java webpath文件路径 2014-02-14 15:04 1746人阅读 评论(0) 收藏 举报  分类: JAVA开发(41)  1.可以在s ...

  3. 怎么将java web 项目导入idea 中

    1.将 java web 项目导 入idea 中, 显示 然后进行 Configure 配置. 2. 点击 open module settings. 3. 4. 选择jar包. 5. 6. 配置to ...

  4. 在cmd命令行使用Maven Archetype插件 generate命令创建简单的java web项目

    前提: 1.下载apache-maven:https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache ...

  5. Java Web项目报错java.lang.NullPointerException at org.apache.jsp.front.index_jsp._jspInit(index_jsp.java:30)

    环境:myeclipse+tomcat6+jdk6 今天搭建了一个Java Web项目,访问index.jsp时报如下错误: 严重: Servlet.service() for servlet jsp ...

  6. 使用Spring Boot来加速Java web项目的开发

    我想,现在企业级的Java web项目应该或多或少都会使用到Spring框架的. 回首我们以前使用Spring框架的时候,我们需要首先在(如果你使用Maven的话)pom文件中增加对相关的的依赖(使用 ...

  7. Linux(Centos)之安装tomcat并且部署Java Web项目

    1.准备工作 a.下载tomcat linux的包,地址:http://tomcat.apache.org/download-80.cgi,我们下载的版本是8.0,下载方式如图:          b ...

  8. 阿里云部署Java web项目初体验(转)

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了如何在阿里云上安装JDK.Tomcat以及其配置过程.最后以一个实例来演示在 ...

  9. 【转】Java Web 项目获取运行时路径 classpath

    Java Web 项目获取运行时路径 classpath 假设资源文件放在maven工程的 src/main/resources 资源文件夹下,源码文件放在 src/main/java/下, 那么ja ...

随机推荐

  1. java.lang.IllegalAccessError: tried to access method com.google.common.base.Stopwatch.<init>()V from 解决

    在用spark的yarn-cluster模式跑fpgrowth进行频繁项集挖掘的时候,报如下错误: ERROR yarn.ApplicationMaster: User class threw exc ...

  2. 一键安装Redmine

    群英汇·项目管理系统:http://www.ossxp.com/HelpCenter/00040_Redmine 其中包含中文说明及管理手册 一键安装下载:http://bitnami.org/sta ...

  3. c#注释

    c#的注释分为:这里不能不说一下什么是注释. 注释本身不会执行,只是说明性文字,只供程序员阅读. 注释又分为:单行注释,多行注释,文档注释. 单行注释://开始 多行注释:/*开始, */结束. 文档 ...

  4. torisegit 保存帐号密码

    设置 -> git 编辑本地 .git/config 增加 [credential] helper = store

  5. 8个不可不知的Mac OS X专用命令行工具【转】

    OS X的终端下通用很多Unix的工具和脚本.如果从Linux迁移到OS X会发现很多熟悉的命令和脚本工具,其实并没有任何区别. 但是OS X也提供了很多其他系统所没有的特别的命令行工具.我们推荐8个 ...

  6. 引用Excel.dll 时找不到类型怎么办

    将引用(Microsoft.Office.Interop.Excel)的属性"嵌入互操作类型"由True修改为False即可

  7. android 控件自定义样式

    一.按钮(Button) 方式1.存在.9图片或图片时   可在drawable文件夹下新建xml文件style_button_one.xml,代码如下 <?xml version=" ...

  8. openstack私有云布署实践【10.2 计算nova - controller节点配置(办公网环境)】

    一.首先登录controller1创建nova数据库,并赋于远程和本地访问的权限.     mysql -u root -p   CREATE DATABASE nova; GRANT ALL PRI ...

  9. JavaScript忍者秘籍——驯服线程和定时器

    1.定时器和线程 - 设置和清除定时器 JavaScript提供了两种方式,用于创建定时器以及两个相应的清除方法.这些方法都是window对象上的方法. 方法 格式 描述 setTimeout   i ...

  10. php笔记(八)PHP类与对象之抽象类

    <?php //通过abstract关键字定义一个抽象类 abstract class ACanEat{ //通过abstract关键字定一个不用具体实现的抽象方法eat() abstract ...