web項目
1.關於web項目目的:
將web階段所有學過的知識點複習總結.
2.關於web項目功能:
功能:
1、用戶註冊
2、用戶登錄
3、添加商品(上傳)
4、商品查看-- 列表查詢
5、商品詳情頁面
6、將商品添加購物車
7、查看購物車
8、修改購物車
9、生成訂單
10、訂單查看(取消)
11、在線支付
12、銷售榜單查看
會對項目進行重構.
會使用註解+動態代理實現細粒度權限控制.
添加關於ajax操作
對於訂單操作時,使用ajax
在線支付功能
3.系統分析
1.通過UML用例圖來確定當前用戶以及所具有的功能
遊客(未登錄): 註冊、登陸、商品查看
商城註冊用戶 : 商品查看、添加商品到購物車、購物車管理、生成訂單、訂單管理、在線支付
管理員 : 添加商品、商品管理、查看訂單 、榜單查看(導出)
2.系統設計
1.技術選型
JSTL + JSP + Servlet + JavaBean + BeanUtils + FileUpload + JavaMail + DBUtils(JDBC) + C3P0 + MySQL + MyEclipse10+ Tomcat7.0 + JDK6 + Windows
MVC 模式
JavaEE 三層結構
DAO 模式
2.數據庫設計
E-R圖 實體關係圖.
對於我們當前項目有這些實體 用戶 商品 購物車 訂單
通過E-R圖可以分析出我們數據庫中表與表之間的關係,以及每一個表中的屬性。
create table users (
id int primary key auto_increment,
username varchar(40),
password varchar(100),
nickname varchar(40),
email varchar(100),
role varchar(100) ,
state int ,
activecode varchar(100),
updatetime timestamp );
商品表
create table products(
id varchar(100) primary key ,
name varchar(40),
price double,
category varchar(40),
pnum int ,
imgurl varchar(100),
description varchar(255));
訂單表
create table orders(
id varchar(100) primary key,
money double,
receiverinfo varchar(255),
paystate int,
ordertime timestamp,
user_id int ,
foreign key(user_id) references users(id)
);
用戶與訂單之間存在 一對多關係 : 在多方添加一方主鍵作爲外鍵
訂單和商品之間存在 多對多關係 : 創建第三張關係表,引入兩張表主鍵作爲外鍵 (聯合主鍵)
訂單項
create table orderitem(
order_id varchar(100),
product_id varchar(100),
buynum int ,
primary key(order_id,product_id),
foreign key(order_id) references orders(id),
foreign key(product_id) references products(id)
);
設置數據庫環境
數據庫 :create database estoresystem;
--------------------------------------------------------------------
4.環境搭建
1.導入jar包
導入mysql驅動 mysql driver / mysql-connector-java-5.0.8-bin.jar
導入c3p0 c3p0/c3p0-0.9.1.2.jar 將c3p0-config.xml 複製src下 將DataSourceUtils複製 cn.itcast.estore.utils ----- 配置c3p0-config.xml數據庫連接參數
導入dbutils apache commons\dbutils\commons-dbutils-1.4.jar
導入beanutils commons-beanutils-1.8.3.jar commons-logging-1.1.1.jar
導入fileupload commons-fileupload-1.2.1.jar commons-io-1.4.jar
導入javamail mail.jar
導入jstl jstl.jar standard.jar
2.創建包結構
cn.itcast.estore.web.servlet
cn.itcast.estore.web.filter
cn.itcast.estore.web.listener
cn.itcast.estore.service
cn.itcast.estore.dao
cn.itcast.estore.domain
cn.itcast.estore.utils
3.創建domain
UML中類圖畫法
4.工程發佈
將estore項目配置虛擬主機,以頂級域名方式進行發佈
在瀏覽器上直接輸入www.estore.com就可以訪問到我們的工程.
1.在tomcat的conf目錄下的server.xml文件中配置
1.修改tomcat的端口 80.
2.配置虛擬主機
<Engine name="Catalina" defaultHost="www.estore.com">
<Host name="www.estore.com" appBase="D:\java1110\workspace\estore" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<Context path="" docBase="D:\java1110\workspace\estore\WebRoot"/>
</Host>
3.在C:\Windows\System32\drivers\etc\hosts文件中配置
127.0.0.1 www.estore.com
注意:在啓動tomcat時,不需要將工程estore工程部署到tomcat.
=========================================================================================
功能實現:
1.註冊操作
1.一次性驗證碼
2.表單的js校驗(非空校驗)
服務器端的校驗
3.全局編碼過濾器
4.密碼md5加密
5.發送激活郵件
6.通用錯誤頁面配置
2.實現註冊功能
1.修改靜態頁面
直接創建一個jsp,將page.html頁面內容複製到home.jsp頁面.
在index.jsp中添加一個請求轉發操作
<jsp:forward page="/home.jsp"/>
2.在home.jsp頁面上添加一個註冊的連接。
<a href="${pageContext.request.contextPath}/regist.jsp">註冊</a>
3.創建一個regist.jsp頁面
頁面上有
1.username
2.password
3.email
4.nickname
還需要一個repassword 確認密碼
還需要一個驗證碼
4.在頁面上產生驗證碼
1.將new_words.txt複製到WEB-INF目錄下.
2.在regist.jsp頁面上
<img src="${pageContext.request.contextPath}/checkImg" οnclick="change();" id="cimg">
注意編碼問題.
5.完成註冊的流程
regist.jsp---->RegistServlet-----UserService UserDao
關於用戶的role與state
對於註冊的用戶它的role我們默認設置爲"user",state默認設置爲0 代表沒有激活,
對於激活碼,我們在註冊時,要生成。通過uuid生成.
註冊成功後跳轉到 regist_success.jsp頁面,在頁面上顯示3秒後跳轉到首頁.
問題:
1.怎樣讓3秒數字變化.
通過js代碼來完成
var interval;
window.onload = function() {
interval = window.setInterval("fun()", 1000); //設置1秒調用一次fun函數
};
function fun() {
var time = document.getElementById("s").innerHTML;
//判斷如果等於0了,不在進行調用fun函數,
if (time == 0) {
window.clearInterval(interval);
return;
}
document.getElementById("s").innerHTML = (time - 1);
}
2.關於亂碼處理
使用全局的編碼過濾器
EncodingFilter完成post與get請求的編碼處理.
6.關於註冊操作的校驗問題
1.表單校驗
就是通過js代碼完成.
1.在<form οnsubmit="return checkForm();">
2.校驗,只校驗非空.
function checkNull(fieldName){
var value = document.getElementById(fieldName).value;
var reg = /^\s*$/; //代表0個或多個空字符。
if(reg.test(value)){
document.getElementById(fieldName+"_message").innerHTML="<font color='red'>"+fieldName+"不能爲空</font>";
return false;
}else{
return true;
}
}
2.服務器端校驗
在javaBean中做一個校驗方法
public Map<String, String> validation() {
Map<String, String> map = new HashMap<String, String>();
if (username == null || username.trim().length() == 0) {
map.put("regist.username.error", "用戶名不能爲空");
}
if (password == null || password.trim().length() == 0) {
map.put("regist.password.error", "密碼不能爲空");
}
return map;
}
在通過BeanUtils將請求參數封裝到javaBean後,調用校驗方法.
如果判斷Map集合中有數據,說明存儲了錯誤信息,就跳轉到regist.jsp頁面。
在頁面上展示錯誤信息,使用jstl標籤。
7.關於發送激活郵件
郵箱 [email protected]
密碼 abc123
關於激活郵件發送我們在UserService中的regist方法中完成。
關於MailUtils工具使用:
1.props.setProperty("mail.host", "自己郵箱的smtp");
2.return new PasswordAuthentication("郵箱帳戶", "密碼");
3.message.setFrom(new InternetAddress("發送者郵箱"));
注意:關於發送的信息問題:
String emailMsg="註冊成功,
請<a href='http://www.estore.com/activeUser?activeCode="+user.getActivecode()+"'>激活</a>,
激活碼爲:"+user.getActivecode();
8.關於激活用戶操作
http://www.estore.com/activeUser?activeCode=d104ed31-0a5f-4eb4-8377-085c9be5f6e4
1.創建一個ActiveUserServlet
1.得到激活碼,
2.調用service中激活操作
注意:激活是有時間限制的。
3.在service中完成操作時有兩件事要做:
1.根據激活碼查找用戶
2.判斷用戶激活碼沒有過期,進行激活操作.
9.md5加密
mysql中:UPDATE users SET PASSWORD=MD5(PASSWORD);
在UserDao的addUser方法中,對user.getPassword()使用Md5Utils工具進行加密。
10.驗證碼
在所有操作前,通過requst獲取請求中的驗證三,與session中存儲的驗證碼進行對比。
從session中獲取完成後,馬上刪除。
在CheckImgServlet中有一句話:
request.getSession().setAttribute("checkcode_session", word);
String checkCode = request.getParameter("checkcode");
String _checkCode = (String) request.getSession().getAttribute(
"checkcode_session");
request.getSession().removeAttribute("checkcode_session");//從session中刪除。
if (!checkCode.equals(_checkCode)) {
request.setAttribute("regist.message", "驗證碼不正確");
request.getRequestDispatcher("/regist.jsp").forward(request,
response);
return;
}
================================================================================================================
2.登錄操作
1.登錄操作中具有的功能
1.請求信息的校驗
1.客戶端校驗
2.服務器端校驗
2.請住用戶名操作
3.自動登錄操作
4.註銷功能
登錄注意事項:
1.注意用戶是否激活
2.注意密碼已經進行了md5加密。
用戶登錄成功後,將用戶存儲到session中.
2.登錄代碼實現:
1.登錄基本流程
1.在home.jsp頁面上有登錄窗口。
2.創建一個LoginServlet
完成登錄操作 ,在LoginServlet中
1.得到用戶名與密碼
2.調用service完成登錄操作.
3.在service中判斷用戶是否可以登錄,以及用戶是否激活
4.在home.jsp頁面上,完成錯誤信息展示以及用戶登錄的提示。
------------------------------------------------------------
2.記住用戶名操作
原理:當用戶登錄成功後,會判斷用戶是否勾選了記住用戶名,如果勾選了,將用戶名存儲到cookie中。
下一次在訪問登錄頁面,直接從cookie中獲取用戶名,顯示在用戶名文本框上。
問題:cookie中不能存中文?
存:Cookie cookie = new Cookie("remember", URLEncoder.encode(user.getUsername(), "utf-8"));
取:
window.οnlοad=function(){//頁面加載成功後跳用這個函數。
var username=document.getElementById("username");
window.de
username.value=window.decodeURIComponent("${cookie.remember.value}","utf-8");
};
關於刪除cookie:
1.setMaxAge(0/-1) 0代表立即刪除 -1代表關閉瀏覽器後才刪除。
2.刪除cookie時,必須與原cookie的path值一致.
-----------------------------------------------------------------------
3.自動登錄
原理:用戶登錄成功,判斷是否勾選了自動登錄,如果勾選了,將用戶名與密碼存儲到cookie中。
需要一個Filter,當用戶訪問工程時,在Filter中從cookie取出用戶名與密碼,進行登錄操作。
注意事項:
1.存密碼時,注意加密。
2.如果用戶已經登錄,不需要在登錄。
3.如果訪問的資源路徑不需要自動登錄,那麼不進行自動登錄。
4.第一個用戶自動登錄,又使用了第二個用戶登錄,它沒有勾選自動登錄,
這時,需要將自動登錄的cookie刪除。
-------------------------------------------------------------------------
4.註銷
在home.jsp頁面有註解的連接。
<a href="${pageContext.request.contextPath}/logout">註銷</a>
創建一個LogOutServlet完成註解功能
session.invalidate();
問題:銷燬session的方式:
1.關閉服務器
2.invalidate()
3.自動超時
在tomcat/conf/web.xml文件中配置超時時間
<session-config>
<session-timeout>30</session-timeout>
</session-config>
4.setMaxInactiveInterval(int interval)
手動設置session超時時間.
注意:如果我們有自動登錄操作,那麼當我們完成註銷操作後,會跳轉到首頁,
這時,如果在cookie中存儲了用戶名與密碼,就會進行自動登錄,那麼
註銷的效果就看不到了,所以要看到效果,可以將自動登錄的cookie刪除。
問題:
1.一個用戶在兩個瀏覽器登錄
要想解決,需要將數據存儲到數據庫中。
可以使用session共享服務器來解決.
2.兩個用戶在同一個瀏覽器登錄
會出現共享session問題,簡單說,第一個用戶購買的物品,存儲在session中。
第二個用戶登錄後,直接就可以看到第一個用戶購買的商品。
解決方案:在每一個用戶登錄時,先銷燬session.
============================================================================================================
商品操作:
1.添加商品(上傳操作)
1.在home.jsp頁面上有一個連接
<a href="${pageContext.request.contextPath}/addProduct.jsp">添加商品</a>
2.創建addProduct.jsp頁面
問題:頁面上有什麼組件?
查看products表中的數據.
文件上傳時瀏覽器端注意:
1.method=post
2.encType="multipart/form-data"
3.<input type="file" name="f">
3.根據表中的數據創建Product類
private String id; // 商品編號
private String name; // 名稱
private double price; // 價格
private String category; // 分類
private int pnum; // 數量
private String imgurl; // 圖片路徑
private String description; // 描述
4.編寫AddProductServlet
完成添加商品操作----其實是文件上傳.
1.DiskFileItemFactory
2.ServletFileUpload
3.FileItem
在這個servlet中要完成兩件事情:
1.文件上傳
問題:
1.上傳文件中文名亂碼
upload.setHeaderEncoding("utf-8");
2.上傳文件名稱獲取?
item.getName(); 得到的有可能包含路徑。
3.上傳文件名稱重複
uuid獲取隨機名稱
4.上傳文件隨機目錄。
通過文件名的hashCode進行計算,隨機得到目錄.
5.關於上傳文件保存位置
對於我們這個項目,上傳的商品圖片,是允許瀏覽器直接訪問的,
所以我們保存到WebRoot下的upload目錄下.
2.向products表中添加數據。
1.得到所有數據封裝到Product對象中.
BeanUtils.populate(product,Map);
這個Map怎樣得到?
手動創建一個Map<String,String[]> 將數據手動封裝.
問題:關於id怎樣封裝?
uuid獲取.
問題:關於imgurl怎樣封裝?
map.put("imgurl", new String[]{"/upload"+uuidDir+"/"+uuidname})
2.調用service,dao完成添加操作.
3.添加成功後,跳轉到首面.
---------------------------------------------------------------
2.查看商品
1.查看全部
index.jsp---->findAllProduct------->home.jsp
1.創建一個FindAllProductServlet
在這個servlet中查詢出所有商品List<Product>,將其存儲到request域,在請求轉發到home.jsp頁面
2.在home.jsp頁面展示
<div class="art-content-layout overview-table">
<div class="art-content-layout-row">
<c:forEach items="${ps}" var="p" varStatus="vs">
<div class="art-layout-cell">
<div class="overview-table-inner">
<h4>${p.name }</h4>
<img src="${pageContext.request.contextPath}${p.imgurl}" width="55px" height="55px"
alt="an image" class="image" />
<p>價格: ¥${p.price }</p>
<p>速速搶購</p>
</div>
</div>
<c:if test="${vs.count%5==0}">
</div> <!-- 判斷當前已經有5個商品了,這 一行結束,在重新開啓一行 -->
<div class="art-content-layout-row">
</c:if>
</c:forEach>
<!-- end cell -->
</div>
<!-- end row -->
</div>
<!-- end table -->
--------------------------------------------------
2.查看商品詳細信息
它有兩個入口,一個是點擊速速搶購.還有點擊圖片也可以查看商品詳細信息.
1.<a href="${pageContext.request.contextPath}/findProductById?id=${p.id}">速速搶購</a>
2.在圖片上添加一個onclick
function findProductById(id){
location.href="http://www.estore.com/findProductById?id="+id;
};
查看商品詳細信息:
1.創建FindProductByIdServlet
1.得到商品id
2.根據id調用service,dao完成查詢商品操作.
2.創建productInfo.jsp頁面,展示商品信息
關於展示商品時,
<img>展示商品圖片,可以通過它的width與height屬性來控制圖片的大小。
在開發中還有另外一種處理方式:使用商品圖片的縮略圖。
我們可以自己編程,去獲取一個上傳圖片的縮略圖。
在展示時,直接得到它的縮略圖來展示 .
在文件上傳完成後,添加這兩名話就會產生圖片的縮略圖
// 生成縮略圖
PicUtils putils = new PicUtils(dest.getCanonicalPath());// 獲取上傳文件的絕對磁盤路徑。
putils.resize(200, 200);// 就會產生一個200*200的縮略圖.
使用縮略圖
1.在Product類中添加一個方法
public String getImgurl_s() {
int index = imgurl.lastIndexOf(".");
return imgurl.substring(0, index) + "_s" + imgurl.substring(index);
}
2.在productInfo.jsp頁面上
<img src="${pageContext.request.contextPath}${p.imgurl_s}">
==========================================================================================================
購物車
我們使用的session來存儲購物車,在數據庫中沒有關於購物車中商品信息。
1.添加商品到購物車
在productInfo.jsp頁面有連接。
問題:怎樣將商品添加到購物車,購物車我們使用什麼數據結構來存儲商品信息?
購物車我們使用Map<Product,Integer>
在productInfo.jsp頁面上連接,它要傳遞商品的id
function addProductToCart(id){
location.href="${pageContext.request.contextPath}/addProductToCart?id="+id;
}
創建一個AddProductToCartServlet
1.根據id得到商品
2.得到購物車
3.將商品添加到購物車
注意:我們使用的購物車其實是一個HashMap<Product,Integer>,對於HashMap,它的維護主鍵唯一性,是使用
key值的hashCode與equals方法,也就是說,對於我們的購物車,它是使用Product的hashCode與equals方法
來保證,我們同一個商品的數量的變化.
簡單說,對於我們就需要重寫Product類的equals方法與hashCode方法。
--------------------------------------------------------------------------------------
2.查看購物車商品
有兩個入口
1.添加商品到購物車成功後,有提示,查看購物車
2.在首面有查看購物車
查看購物車,我們直接就是一個jsp頁面上將購物車中商品展示出來就可以。
因爲購物車就存儲在session中.
創建一個showCart.jsp,用於展示購物車中所有商品.
購物車中商品總價怎樣獲取:每個商品的單價*商品數量
<c:set var="totalMoney" value="${totalMoney+c.key.price*c.value}"/>
-----------------------------------------------------------------------------------------
3.改變購物車中商品數量
1.加操作
點擊加按鈕,要訪問一個servlet,在servlet中,獲取購物車中商品,對其數量進行操作.
function changeCount(id,count){
location.href="${pageContext.request.contextPath}/changeCount?id="+id+"&count="+count;
}
在服務器端:
Product p=new Product();
p.setId(id);
cart.put(p, count);
問題:怎樣控制邊界?
如果數量減到0,相當於將商品從購物車中刪除。
如果數量加到比商品庫存還大,就讓它等於最大值.
在js代碼中控制
//控制邊界
if (count <= 0) {
//刪除
var flag = window.confirm("要刪除商品嗎?");
if (flag) {
count = 0;
} else {
count = 1;
}
} else if (count >= pnum) {
alert("最大購物數量"+pnum);
count = pnum;
}
注意:如果購物數量爲0,這時會以服務器端將商品從購物車中刪除。
關於文本框中數量修改:
對於文本框,可以添加一個onblur事件
注意:在js中數據是無類型的,操作時,有的進修傳參數,想要傳遞的是一個數值類型,
但是,js將其做爲字符串處理了,就需要使用parseInt() parseFloat()來轉換成數值類型。
數字文本框:
在<input type="text">這個文本框中只能輸入數字,不能輸入其它的字符。
原理:給文本框添加onkeydown事件,當觸發事件時,獲取按下的鍵的鍵碼值,如果它的鍵碼是數字0-9之間的就可以執行,
如果不是,阻止事件的默認行爲 .
1.問題:怎樣獲取按下的鍵碼值
2.問題:怎樣阻止事件的默認行爲
function a(e){
var keyCode;
if(e&&e.preventDefault){
//判斷是firefox瀏覽器
keyCode=e.which;
}else{
//ie瀏覽器
keyCode=window.event.keyCode;
}
//alert(keyCode);
//0-9之間的鍵碼值是48-57
if(!(keyCode>=48&&keyCode<=57||keyCode==8)){
//阻止事件的默認行爲
if(e&&e.preventDefault){
// e對象存在,preventDefault方法存在 ---- 火狐瀏覽器
e.preventDefault();
}else{
// 不支持e對象,或者沒有preventDefault方法 ---- IE
window.event.returnValue = false;
}
}
};
---------------------------------------------------------------------------
從購物車中刪除商品
1.連接提交時,將商品id攜帶到服務器
<a href="${pageContext.request.contextPath}/removeProductFromCart?id=${c.key.id}">刪除</a>
2.創建RemoveProductFromCartServlet 將要刪除的商品從購物車中刪除
// 得到要刪除的商品的id
String id = request.getParameter("id");
// 得到購物車,從購物車中將商品刪除,
Map<Product, Integer> cart = (Map<Product, Integer>) request
.getSession().getAttribute("cart");
Product p = new Product();
p.setId(id);
cart.remove(p);
//如果購物車中無商品,將購物車刪除。
if (cart.size() == 0) {
request.getSession().removeAttribute("cart");
}
關於刪除商品時的提示處理:
方式1:
<a href="javascript:void(0)" οnclick="removeProduct('${c.key.id}')">刪除</a>
function removeProduct(id) {
var flag = window.confirm("要刪除商品碼?");
if(flag){
//要刪除
location.href="${pageContext.request.contextPath}/removeProductFromCart?id="+id;
}
}
方式2:通過阻止事件的默認行爲來控制
<a href="${pageContext.request.contextPath}/removeProductFromCart?id=${c.key.id}"
οnclick="deleteProduct(event)">刪除</a>
function deleteProduct(e) {
var flag = window.confirm("要刪除商品碼?");
if (!flag) {
//不刪除,阻止連接的默認行爲 執行。
//阻止事件的默認行爲
if (e && e.preventDefault) {
// e對象存在,preventDefault方法存在 ---- 火狐瀏覽器
e.preventDefault();
} else {
// 不支持e對象,或者沒有preventDefault方法 ---- IE
window.event.returnValue = false;
}
}
};
============================================================================================================
訂單操作
1.生成訂單
1.在showCart.jsp頁面上,有一個連接,進行結算中心,
應該跳轉到一個order.jsp頁面.在這個頁面上輸入訂單的相關信息。
輸入完成後,提交信息,生成訂單。
2.表單提交,訪問一個AddOrderServlet,完成生成訂單操作.
1.將數據封裝到Order對象中.
Order order=new Order();
//它封裝了訂單的 送貨地址,總價.
BeanUtils.populate(order, request.getParameterMap());
String id=UUID.randomUUID().toString();
order.setId(id);//封裝訂單的id
order.setPaystate(0);//默認值爲0,代表未支付。如果爲1,代表支付.
//封裝user_id
//從session中獲取當前用戶.
User user=(User) request.getSession().getAttribute("user");
int user_id=user.getId();
order.setUser_id(user_id);
問題:我們生成訂單,會對幾張表操作?
1.insert into orders
2.insert into orderItem
3.update products set pnum=pnum-?;
對於訂單操作,必須添加事務處理.
3.對DataSourceUtils進行修改
// 獲取綁定到ThreadLocal中的Connection。
public static Connection getConnectionByTransaction() throws SQLException {
Connection con = tl.get();
if (con == null) {
con = dataSource.getConnection();
tl.set(con);
}
return con;
}
// 開啓事務
public static void startTransaction(Connection con) throws SQLException {
if (con != null)
con.setAutoCommit(false);
}
// 事務回滾
public static void rollback(Connection con) throws SQLException {
if (con != null)
con.rollback();
}
public static void closeConnection(Connection con) throws SQLException {
if (con != null) {
con.commit();// 事務提交
con.close();
tl.remove();
}
}
注意:在dao中在使用QueryRunner時,不要使用有參數構造,要使用無參數構造,
使用QueryRunner的batch,update方法時,要帶Connection參數,而Connection對象的獲取是
通過getConnectionByTransaction來獲取的。
------------------------------------------------------------------------------
查看訂單:
1.查看訂單時,如果當前用戶是admin角色,可以查看所有人訂單,如果用戶是user,只能查看自己訂單。
2.查看訂單實現:
1.select * from orders;----->List<Order>
2.查詢訂單中商品的信息。
3.代碼實現:
1.點擊查看訂單時,訪問一個ShowOrderServlet,查詢出所有訂單信息
select * from orders;----->List<Order>
將List集合存儲到request域,跳轉到showOrder.jsp頁面在,展示所有信息.
response.getWriter().write("訂單生成成功,<a href='"+request.getContextPath()+"/showOrder'>查看訂單</a>");
<a href="${pageContext.request.contextPath}/showOrder"></a>
2.在showOrder.jsp頁面展示訂單:
問題:展示訂單時,想要顯示當前訂單是哪個用戶的,怎樣得到用戶名?
我們需要將orders與users表關聯查詢.
String sql = "select users.username,users.nickname,orders.* from orders,users where users.id=orders.user_id ";
查詢出的數據要封裝到Order對象中,但是不能封裝username,nickname,所以我們在Order類中添加了兩個屬性
private String username;
private String nickname;
-------------------------------------
3.查看訂單中商品詳細信息 ajax完成
1.查找某一個訂單中所有商品信息的sql語句
SELECT
數據
FROM
orderitem,products
WHERE
orderitem.product_id=products.id
AND
orderitem.order_id="訂單id";
2.使用ajax完成操作
1.得到XMLHttpRequest對象
2.onreadstatechange 註冊回調函數
3.open
4.send
5.在回調函數中操作.
我們查詢出訂單中商品信息,以json格式返回.
---------------------------------------------------------------------------------------------
刪除訂單
1.在showOrder.jsp頁面有刪除訂單的連接。點擊連接時,將訂單的id傳遞到服務器端,完成根據id刪除訂單操作.
問題:如果訂單是已經支付的怎樣處理?如果是沒有支付怎樣處理?
我們人爲規定,如果是已支付訂單,不能刪除。如果是未支付訂單可以刪除。
<c:if test="${order.paystate==0}">
<a href="#">刪除</a>
</c:if>
<c:if test="${order.paystate!=0}">
刪除
</c:if>
問題:對於未支付訂單,刪除時,怎樣操作?
需要做三件事情:
1.delete from orders where id=?;
2.delte from orderitem where order_id=?
3.update products set pnum=pnum+? where id=?;
在操作時,需要先刪除orderitem表中數據,在刪除orders中數據。
我們最後要修改products表中的數據,而它需要的buynum,與product_id都是在orderitem表中存在的。
分析完成上面操作,我們在代碼實現時,步驟:
1.select * from orderitem where order_id=?;----->List<OrderItem>
2.delete from orderitem where order_id=?;
3.delete from order where id=?
4.updat products set pnum=pnum+buynum where id=product_id;
我們操作時,需要對多表進行操作,也需要事務控制.
2.代碼實現:
1.在showOrder.jsp頁面添加連接路徑.
<a href="${pageContext.request.contextPath}/delOrder?orderid=${order.id}">刪除</a>
2.創建DelOrderServlet
1.得到要刪除的訂單id.
2.調用service完成刪除訂單操作.
3.在OrderService中創建一個方法 delOrderById(String orderid);
在這個方法中.
1.開啓事務
2.根據orderid查詢出所有的orderitem中數據.得到一個List<Orderitem>
3.根據orderid在orderitem中刪除數據
4.根據orderid在orders事刪除數據
5.根據List<OrderItem>在products表中修改數據.
6.如果有異常,事務回滾,沒問題,事務提交,資源釋放。
--------------------------------------------------------------------------------
訂單支付:
在線支付---新的知識點
1.在showOrder.jsp頁面,如果當訂單狀態是爲支付,我們將其設置成一個連接。
<a href='${pageContext.request.contextPath}/pay.jsp?orderid=${order.id}&money=${order.money}'>未支付</a>
2.創建一個pay.jsp頁面,它就是我們的支付頁面。
在頁面上得到訂單號,金額信息,並且可以選擇支付的銀行.
3.完成在線支付
1.什麼是在線支付?在線支付實現方式?
通過網絡直接完成訂單的支付。
有兩種方式:
1.直接與銀行做對接
優點:不會有延遲。
缺點:開發,維護費用比較高.銀行接口變動,需要更改。
這種方式不適合中小商戶。
2.使用第三方支付
優點:方便,不用處理是怎樣支付
缺點:有延遲,會收取一定費用。
這種方式比較適合中小商戶。
2.我們使用的是第三方支付
現在使用的比較多第三方支付 支付寶 財富通 快錢
我們使用 易寶支付(http://www.yeepay.com/)
在線支付條件:
1.可以上網。
2.需要開通網銀.
開發在線支付條件:
1.可以上網.
2.需要一個獨立ip.
3.需要在易寶支付申請一個商家賬號。 10001126856
在線支付流程:
查看圖
--------------------------------------------
在線支付代碼實現:
1.pay.jsp,頁面上有訂單號,金額以及選擇的銀行。
2.OnLinePayServlet,這個servlet就完成數據的收集,以及向第三方支付發送數據過程.
問題:
1.要發送給第三方支付的信息有哪些?
2.發送給第三方支付的路徑是什麼?
https://www.yeepay.com/app-merchant-proxy/node
以上這兩個問題,我們需要查詢易寶支付開發手冊。
重要屬性:p8_Url 是易寶支付反饋信息時的路徑。
hmac=數據+密鑰+算法.
密鑰:L69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
3.創建一個CallBackServlet,用於接收第三方支付返回的信息.
http://www.estore.com/callBack?p1_MerId=10001126856&r0_Cmd=Buy&r1_Code=1&r2_TrxId=315223279200392I&r3_Amt=0.01&r4_Cur=RMB&r5_Pid=&r6_Order=asdflkasdiej&r7_Uid=&r8_MP=&r9_BType=1&ru_Trxtime=20141222105450&ro_BankOrderId=2636414683141222&rb_BankId=BOC-NET&rp_PayDate=20141222105443&rq_CardNo=&rq_SourceFee=0.0&rq_TargetFee=0.0&hmac=1852414bf1f5f63587a59e40cd8c35f2
關於第三方返回信息重點:
r9_BType 交易結果返回類型
爲“1”: 瀏覽器重定向; 如果關閉瀏覽器,就可能接收不到信息。
爲“2”: 服務器點對點通訊.---要求必須返回一個success,否則會一直髮送。
-----------------------------------------------------------------------------------------------
在線支付完成後,修改訂單的狀態。
update order set paystate=1 where id=r6_order;
=================================================================================================
下載銷售榜單
就是一個文件下載操作.
問題:怎樣獲取到下載文件中的數據?
要在已經支付的訂單中查找銷售的商品名稱以及數量。
select
products.name,sum(buynum) totalSaleNum
from
products,orderitem,orders
where
orderitem.product_id=products.id
and
orders.id=orderitem.order_id
and
orders.paystate=1
group by
pname
order by
totalSaleNum
下載操作:
1.下載榜單連接
<a href="${pageContext.request.contextPath}/download">
2.創建一個DownloadServlet
1.得到數據
2.根據數據,通過response.getWriter()流寫回到瀏覽器端.
3. 榜單文件是什麼格式?
導出Excel 使用 POI類庫
csv 格式文件 , 逗號分隔文件
1) 信息當中有,在兩端加 雙引號
2) 信息當中有" 在之前加雙引號 轉義
文件下載
設置Content-Type、Content-Disposition 頭信息
文件流輸出 (輸出文件內容)
Excel 默認讀取字符集gbk
==============================================================================================
權限
1.url級別權限控制(粗粒度權限控制)
原理:得到當前的訪問的資源路徑,得到當前用戶角色,來判斷當前用戶是否有權限訪問該資源.
1.得到資源路徑.
String uri=request.getRequestURI();
String contextPath=request.getContextpath();
String path=uri.substring(contextPath.length());
2.當到當前用戶角色,通過角色,判斷當前用戶是否有權限訪問path資源。
1.得到當前用戶
request.getSession().getAttribute("user");
2.做配置文件,在配置文件中聲明每個角色具有的權限。
amdin.properties
user.properties.
實現:
1.添加商品----->admin
2.下載榜單----->admin
3.添加商品到購物車 購物車操作。-----user
3.關於訂單操作 user admin
代碼實現:
1.創建兩個配置文件
user.properties 配置關於user角色具有的權限
admin.properties 配置關於admin角色具有的權限.
將配置文件放置在WEB-INF下.
2.創建一個PrivilegeFilter進行權限控制
1.在其init方法中將配置文件中內容讀取出來裝入到admins,users集合中。
2.得到請求資源路徑,判斷是否需要權限.
3.創建一個自定義異常,如果權限不足,拋出這個異常。
在web.xml文件中配置全局異常處理.
<error-page>
<exception-type>cn.itcast.estore.exception.PrivilegeException</exception-type>
<location>/error/privilege.jsp</location>
</error-page>
=========================================================================================================================
重構
1.一個請求一個servlet,現在要做一個模塊一個servlet,也就是說,多個請求會訪問同一個servlet.
UserServlet 註冊 登錄 註銷 激活
CartServlet 關於購物車操作
ProductServlet 關於商品操作 注意:我們重構時沒有將添加商品處理.
OrderServlet 關於訂單操作
2.對servlet中的操作在進行一次重構
原因:
在UserServlet中
if ("regist".equals(method)) {
regist(request, response);
} else if ("login".equals(method)) {
login(request, response);
}
在ProductServlet中
if ("findProductById".equals(method)) {
findProductById(request, response);
} else {
// 默認就是查詢所有.
findAllProduct(request, response);
}
上面的代碼,操作是一致的,我們可以在一次進行抽取。生成一個BaseServlet.
它的代碼
String methodName = request.getParameter("method");
Method method = this.getClass().getDeclaredMethod(methodName,
HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this, request, response);
舉例分析:
http://www.estore.com/user?method=login
1.知道要訪問的是UserServlet。
2.因爲UserServlet extends BaseServlet,這時就會訪問
BaseServlet中的service方法。
3.在BaseServlet中
request.getParameter("method");--->login
4.得到指定的servlet中指定方法
Method method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class, HttpServletResponse.class);
這句話就相當於得到了UserServlet中的login方法。
5.method.invoke(this,request,response);
這句話就相錄於
UserServlet.login(request,response);
-----------------------------
以上重載操作後,
在訪問servlet中的方法時,只需要 /url-pattern值?method=方法名。
2.細粒度(annotation+動態代理)
原理:在service中的方法上添加一個註解,註解的值代表的是訪問這個功能所需要的權限名稱。
我們的service的獲取,是通過一個工廠獲取的,而在工廠中返回的是service的動態代理對象。
在動態代理中去控制是否有權限訪問當前操作。
代碼實現:
1.創建一個註解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface PrivilegeInfo {
String value();
}
2.抽取service
抽取出接口.例如:
public interface ProductService {
// 添加商品
@PrivilegeInfo("添加商品")
public void addProduct(Product p) throws Exception;
// 查詢所有商品
public List<Product> findAll() throws Exception;
// 根據id查詢商品
public Product findById(String id) throws Exception;
// 下載榜單數據
@PrivilegeInfo("下載榜單")
public List<Product> downloadSell(User user) throws PrivilegeException,
Exception
}
3.創建ServiceFactory
在serviceFactory中通過動態代理生成一個service代理對象,返回這個代理對象.
在servlet中使用的都是通過ServiceFactory獲取的service對象,也就動態代理對象。
ProductService service = ProductServiceFactory.getInstance();
4.在動態代理的InvocationHandler的invoke方法中處理。
1.判斷方法上是否有註解,也就知道,是否需要權限控制.
boolean flag = method
.isAnnotationPresent(PrivilegeInfo.class);
2.得到註解中的屬性值,也就得到了訪問該方法的權限名稱
String pname = method.getAnnotation(
PrivilegeInfo.class).value();
3.得到當前用戶(對於需要權限控制的方法,在其方法的第一個參數,都設置爲User)
User user = (User) args[0];
4.得到user的role,在權限配置文件中查找這個角色所具有的權限名稱
List<String> pnames = Arrays.asList(ResourceBundle
.getBundle("privilege").getString(role)
.split(","));
5.判斷這個角色是否可以執行該方法.
if (!pnames.contains(pname)) {
throw new PrivilegeException();
}
問題:拋出異常不跳轉到指定的頁面?
原因:我們操作是在invoke方法中執行的。而invoke方法拋出的是Throwable,我們自己拋出的PrivilegeException,
會被包裝。
在外面捕獲不到。
在開如,我們對頁面的權限控制可以使用url級別,而對具體的行爲執行,可能通過細粒度權限控制。
JavaWeb網上商城
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.