Java web项目综合练习(Estore)
Java web项目综合练习(Estore)
复习day18:
-
ajax代码的书写步骤
2)json格式文本,转js对象的方法是那个
-
项目开发流程介绍
这里学习的JavaWEB项目实战,主要是把前面学习的所有的web相关的技术综合的练习。
-
业务洽谈:客户(企业)提出需求,软件公司派人前去洽谈,第一次确认需求。
-
整理需求:软件公司,不断的和客户进行沟通,反复的确认需求,需要美工和前端工程师制作页面
-
详细设计:技术选型和项目原型架构
-
编码阶段:开工啦
-
测试阶段:测试当前的项目,解决bug
-
试运行,上线。
在开发的流程中的人员配置:
洽谈业务: 老板、项目经理、技术总监、技术总监(需求工程师团队)
详细设计: 项目经理、技术总监、老员工
编码: 码农开工啦
测试阶段:测试工程师,码农开工啦
技术选型:选择适合当前项目的技术
项目的原型架构:导入jar包(项目需要用到哪些技术),准备配置文件,工具类,基本的接口(业务接口)
业务接口:程序员在开发的时候,当前项目需要的大部分接口,已经开发完成(技术总监),程序员只需要根据接口写实现类
-
准备工作
-
项目搭建
-
新建项目
-
-
-
拷贝项目静态资源
将文件夹中的所有数据复制到项目WebRoot文件夹下
复制完成之后,注意要修改当前项目的编码,设置成UTF-8
修改完成之后,部署项目,能看到如下界面,说明拷贝静态资源没有问题。
搜索功能:后期使用lucence和slor这两个技术来完成。
-
功能分析
买家功能:
-
注册
-
Ajax校验用户名
-
登录
-
记住用户名
-
注销(退出)
-
查看商品列表
-
查看商品的详细
-
加入购物车
-
查看购物车列表
-
修改购买的数量
-
删除购物车中的商品
-
三级联动
-
提交订单
-
查看订单列表
-
查看订单详情
-
在线支付(需要公网的IP,才可以完成全部功能,只能看到支付,获取不到支付成功的消息)
-
删除订单
卖家功能:
商品上传
商品后台查看
系统功能:
1. 将一定时间内没有付款的订单,修改为过期状态
2. 权限控制(买家不能访问,卖家添加商品的功能)
3. 配置错误页面(404和500错误使用统一页面显示)
-
技术选型
技术选型:选择实现当前这个项目,需要使用那些技术
前台: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
-
定义项目开发结构
定义项目开发结构:将那些java类,放到那些包中
-
导入项目依赖的jar包
所有jar包
导入lib文件夹:
导入后确认效果:
-
导入工具类
工具类在资料文件夹下的工具类文件夹中:
导入后的效果:
-
配置文件
配置文件在资料文件夹下的jar包文件夹中:
复制到src路径下:
-
配置全站乱码过滤器
复制资料文件夹下全站乱码处理文件夹中(GenericEncodingFilter.java)到项目,放入cn.itcast.filter包中
在web.xml中配置过滤器,效果如红框中所示:
-
数据库设计
我们在实际的开发中,不同的项目使用的数据库也不同,同样,我们的estore项目,也需要设计一个数据库
-
新建数据库
导入资料文件夹中的数据库脚本文件夹下的estore.sql
效果:
-
分析数据库表结构
使用E-R图分析数据库表
矩形:实体(good商品 user用户 order订单)
菱形:实体和实体之间的关系
椭圆:实体中的属性
-
导入与数据库表对应的Java类
复制资料文件夹下的java类文件夹中的所有.java文件到:cn.itcast.domain包中
效果图:
-
普通用户功能(买家)
-
注册
-
页面展示:
总结:
前端js验证:提高用户的注册成功率,让用户能一次性注册成功(给用户很多注册的提示信息)。
后台Servlet验证:防止用户提交非正常的数据。
-
功能分析
-
完善页面(修改form表单)
-
修改表单提交的请求路径
-
修改显示用户错误操作的提示信息
-
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("msg", "昵称不能为空或者昵称超过10个字符");
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);
}
}
-
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;
}
}
}
-
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;
}
}
}
-
使用ajax验证用户名是否已被注册
提示:前端工程师书写javascript代码,不要去动,但是我们自己的javascript代码执行结果也要保留,那么最好的解决方法,就是将结果合并。
-
需求分析
-
页面实现
<%@ 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> </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> </td>
<td align="left">
<input name="Submit" type="submit" value="" class="us_Submit_reg">
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
</table>
</form>
<div class="blank"></div>
</div>
</div>
</div>
<%@include file="inc/footer.jsp"%>
</body>
</html>
-
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);
}
}
-
Service实现
接口: UserService
/**
* 根据用户名查询的方法
* @param username
* @return
*/
int findByName(String username);
实现类:UserServiceImpl
public int findByName(String username) {
return userDao.findByName(username);
}
-
DAO实现
已实现,不再重复。
-
登录
在正式的开发中,使用浏览器测试,火狐,谷歌,IE,搜狗,360,QQ浏览器,测试javascript代码
页面展示;
-
功能分析
-
完善页面
-
修改请求路径
-
修改用户的操作错误提示信息显示位置
-
显示登录名js
<script type="text/javascript">
window.onload = function(){
var data = "${cookie.username.value}";
var username = decodeURI(data);
document.getElementById("_un").value = username;
};
</script>
-
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);
}
}
-
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);
}
-
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("用户登录失败");
}
}
-
首页显示欢迎信息
用户登录之后,头部页面显示用户的昵称:
修改inc目录下的head.jsp
-
查看商品
-
功能分析
-
页面修改:
Ctrl + shift + r :用来搜索文件,根据文件名
Ctrl + shift + t :用来搜索java类,根据类名
-
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);
}
}
-
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();
}
}
-
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("获取商品列表数据失败");
}
}
}
-
商品列表页面实现
-
有商品的情况下遍历循环商品列表
-
显示商品图片
-
显示商品名称
-
显示市场价格和本店价格
-
商品详情
-
功能分析
-
-
Goods.jsp页面完善
-
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);
}
}
-
Service实现
接口:GoodService
/**
* 获取商品数据
* @param gid
* @return
*/
Good findById(int gid);
实现类:GoodServiceImpl
public Good findById(int gid) {
return goodDao.findById(gid);
}
-
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)修改添加商品到购物车的按钮的连接
效果:
-
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);
}
}
-
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);
}
}
-
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("添加购物车数据失败");
}
}
-
修改buyorcart.jsp页面链接
1)完善继续购物和去购物车结算的链接
补充:登陆完成之后,直接跳转之前浏览的页面
-
AddGoodToCartServlet获取当前商品详细页面的路径——查询商品详情的路径,通过请求头:Referer 获取
-
将商品详情的路径保存,保存到session中,为了保证后期也可以使用
-
loginServlet先获取session中的商品详情的路径,判断是否存在,存在,跳转商品详情的路径,不存在,跳转首页
-
查看购物车
-
功能分析
-
-
在购物车对象中添加商品对象
1)修改购物车类,添加一个商品对象做属性,方便在购物车页面中,显示商品信息
注意:还要生成getter和setter方法,重新生成toString方法
-
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);
}
}
-
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;
}
-
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)遍历循环购物车集合显示购物车中的商品信息
2)计算购物车中商品的总计
3)计算购物车中商品一共节省的金额
额外补充:大数据相关概念
-
修改购物车中商品的购买数量
-
功能分析
-
-
页面实现
-
设置onblur事件,启动js函数,函数中的参数购买数量和商品id
2)在js函数中,先验证当前用户输入的数据,是否是数字(使用parseInt()方法,如果是整数返回true),且大于等于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>
-
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已经实现过了,不再重复
-
删除购物车中的商品
-
功能分析
-
-
页面实现
完善删除链接,发送要被删除的商品的gid
-
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);
}
}
-
Service实现
接口:CartService
/**
* 删除购物车商品
* @param uid
* @param gid
*/
void delete(int uid, int gid);
实现类:CartServiceImpl
public void delete(int uid, int gid) {
cartDao.delete(uid,gid);
}
-
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)修改查看购物车列表的servlet,将数据保存到session,方便在同一个会话中使用,在订单页面再次展示购物车数据不需要再从数据库中获取
-
在订单的提交页面显示用户要购买的商品数据
遍历商品集合,计算商品的总价
-
Ajax实现省市县三级联动
功能分析:
第一步:页面加载完成之后,显示省一级地区的数据
第二步:选择省的时候,加载相对应的市的数据
第三步:选择市的时候,加载相对应的县的数据
流程图:
-
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>
-
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);
}
}
-
省市联动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);
}
}
-
省市联动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("获取地区数据失败");
}
}
}
-
订单生成页面修改
-
修改表单请求路径
-
将被选中的省市县数据存入隐藏域中
-
订单生成页面流程分析
-
订单生成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);
}
}
-
订单生成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();
}
}
}
}
-
订单生成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("清空购物车失败");
}
}
-
查看订单列表
-
功能分析
-
-
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);
}
}
-
Service实现
接口:OrderService
/**
* 查询指定用户的所有的订单
* @param uid
* @return
*/
List<Order> findAll(int uid);
实现类:OrderServiceImpl
public List<Order> findAll(int uid) {
return orderDao.findAll(uid);
}
-
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("查询指定的用户订单失败");
}
}
-
页面实现
-
显示订单相关信息
-
根据订单的状态显示不同效果,status==1未支付——在线支付、取消订单,status==2,已支付——查看详细,status==3已过期——查看详细
-
查看订单详情
-
功能分析
-
-
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);
}
}
-
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;
}
-
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("查询指定的订单明细失败");
}
}
-
页面修改
-
在订单编号上添加a标签,链接指向订单详情
-
同样也修改后面的订单的查看详情链接
-
显示订单的信息和相关的商品信息
-
要显示订单的总价
-
取消订单
-
功能分析
-
-
编辑取消订单的链接
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);
}
}
-
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();
}
}
}
-
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("删除指定的订单失败");
}
}
-
管理员功能(卖家)
-
添加商品
-
功能分析
-
-
页面修改:
-
修改表单请求路径
-
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);
}
}
-
Service实现
接口:GoodService
/**
* 添加商品
* @param g
*/
void addGood(Good g);
实现类:GoodServiceImpl
public void addGood(Good g) {
goodDao.addGood(g);
}
-
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);
}
}
-
查看商品(管理员)
为什么,已经存在商品列表功能,还要在后台制作一个商品列表给管理员?
注意:设计一个项目,分角色,角色下有权限,那么不同角色有不同权限,
作为买家,普通用户,无法使用管理员功能
同理,作为管理员,无法使用普通用户功能,只能重新制作一个让管理员使用。
添加完成商品后,从数据库中重新查询所有商品,展示在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);
}
}
-
权限管理
为什么要做权限管理?
商品上传,只有卖家可以使用,买家是不能使用的,需要做权限的控制
如何实现权限管理?
我们要解决,谁,是什么角色,能做哪些操作?
两种权限数据解决方案:
第一种:使用数据库表,来控制用户的权限,一般需要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() {
}
}
-
配置网站错误页面
软件在运行时,会出现各种错误,这些错误不希望用户看到,这时需要配置一个统一的错误页面,当系统出错时,就会跳转到这个错误页面,这个错误页面一般比较友好
在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>
-
定时器扫描过期订单
-
定时任务介绍
-
-
Timer回顾
-
定时扫描过期订单并设置为过期
-
创建监听器,监听ServletContext启动
-
需求:定时扫描过期订单并设置为过期
1:定时扫描,需要用到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 定时器启动,订单早已经过期
//每一个订单,都设置一个定时器。
//每一个订单创建,都会在内存中创建一个定时器对象,而且这个定时器对象一定要两个小时之后才关闭
//在线支付,判断,只要订单过期了,直接设置状态为3。
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
配置文件:
-
Service实现
接口:OrderService
/**
* 扫描过期订单的方法
*/
void saomiao();
实现类:OrderServiceImpl
public void saomiao() {
// 定时任务:获取所有状态为1订单,然后,如果超出时间(2个小时),修改状态:3
//第一步:获取所有状态为1订单
List<Order> list = orderDao.findByStatus(1);
//第二步:循环遍历,做判断
for (Order order : list) {
//第三步:比较时间,现在的时间减去提交订单的时间,大于两个小时,状态改为3
long now = new Date().getTime();
long time = order.getCreatetime().getTime();
if(now - time >= 1000*60*60*2){
//第四步:修改状态为3
orderDao.updateStatus(3,order.getId());
}
}
}
-
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("修改指定的订单状态失败");
}
}
-
在线支付
-
在线支付介绍
-
ICBC 工商银行
在线支付流程一:
总结:商城通过第三方平台和所有银行交易
在线支付流程二:
-
易付宝支付介绍
易宝支付官网:https://www.yeepay.com/
易宝会给商家提供对应的支付接口以及文档,开发人员在开发支付功能的时候,
只需要按照文档中的说明直接完成对应的代码即可。
支付接口及文档下载:
-
编写orders.jsp页面上的支付链接
1)在订单明细页面上添加支付按钮(未支付的订单才有,发送订单编号和金额)
效果:
-
编写pay.jsp
-
修改表单提交请求路径
-
将订单编号和金额写入隐藏域
-
给用户显示订单编号和金额
-
支付的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 = "10001126856"; // 商家编号 10001126856
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);
}
}
-
支付确认页面confirm.jsp
-
显示订单编号和订单金额
-
隐藏域中都是servlet中封装给易宝的数据
-
回调函数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.out.println("收到1,提示用户,已经付款");
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);
}
}