文章結構
1、任務概述
1_用戶激活
2_登錄,
3_退出,
4_抽取公共頁面
5_查詢所有分類
6_首頁熱門商品_最新商品顯示
7_商品詳情顯示
8_基礎分頁操作
9_首頁分類商品帶分頁查詢
開發通用步驟: 1_準備工作 2_Servlet 3_service 4_Dao 5_jsp頁面
2、用戶激活
原理如下:
步驟實現:
1、準備工作(忽略)
用戶點擊郵箱中的激活鏈接,向服務端發送method=active&code=234123adf22234
2、UserServlet___>active
獲取到激活碼
調用service功能,對賬戶進行激活操作
進行信息提示(成功,失敗)
public String active(HttpServletRequest request, HttpServletResponse response) throws Exception{
//獲取驗證碼
request.setCharacterEncoding("utf-8");
String code = request.getParameter("code");
//調用業務層的激活功能
UserService service = new UserServiceImpl();
boolean flag = service.activeUser(code);
//進行激活信息提示
if(flag){
//用戶激活成功,向request放入提示信息,調到login頁面
request.setAttribute("msg", "用戶激活成功,請登錄!");
return "/jsp/login.jsp";
}else{
//用戶激活失敗,向request放入提示信息,調到info頁面
request.setAttribute("msg", "用戶激活失敗,請重新激活!");
return "/jsp/info.jsp";
}
}
3、service_dao
//UserServiceImpl
@Override
public boolean activeUser(String code) throws SQLException {
//實現激活功能
UserDao dao = new UserDaoImpl();
User user = dao.activeUser(code);
if(user!=null){
//如果存在user,則說明code存在
//修改激活狀態,刪除激活碼
user.setState(1);
user.setCode(null);
//對數據庫執行一次真實的更新操作
dao.updateUser(user);
return true;
}else{
//不可根據激活碼查到一個用戶
return false;
}
}
//UserDaoImpl
@Override
public void updateUser(User user) throws SQLException {
String sql = "update user set username = ?,password = ?,name = ?,email = ?,telephone = ?,birthday = ?,sex = ?,state = ?,code = ? where uid = ?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Object[] params = {user.getUsername(),user.getPassword(),user.getName(),user.getEmail(),user.getTelephone(),user.getBirthday(),user.getSex(),user.getState(),user.getCode(),user.getUid()};
System.out.println("code="+user.getUid());
qr.update(sql, params);
}
@Override
public User activeUser(String code) throws SQLException {
String sql = "select * from user where code=?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql,new BeanHandler<User>(User.class),code);
}
4、/jsp/login.jsp
獲取到註冊成功的提示信息
USER LOGIN加:
<div><label style="color: red;">${msg }</label></div>
5、由於info.jsp已經實現過,不需要再設置info.jsp中內容
3、用戶登錄
原理如下:
實現登錄前,要先修改Index中登錄功能的請求路徑:
*_ /jsp/index.jsp 修改登錄鏈接
<a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登錄</a>
*UserServlet__>loginUI
return “/jsp/login.jsp”;
步驟實現:
1、準備工作 /jsp/login.jsp
設置form標籤action,method
設置表單下input標籤的name屬性
2、User_userLogin
*獲取數據
*調用業務層功能
*成功,session存放用戶信息,重定向到首頁
*失敗,request放入失敗信息,轉發到登錄頁面
//UserServlet
public String userLogin(HttpServletRequest request, HttpServletResponse response) throws Exception{
//獲取用戶的賬號密碼並設置用戶數據
request.setCharacterEncoding("utf-8");
User user = new User();
MyBeanUtils.populate(user, request.getParameterMap());
//調用業務層的登錄功能
UserService service = new UserServiceImpl();
User user02 = null;
try {
user02 = service.userLogin(user);
//用戶登錄成功,將用戶信息放入session
request.getSession().setAttribute("userinfo", user02);
response.sendRedirect("index.jsp");
return null;
} catch (Exception e) {
//用戶登錄失敗,彈出失敗信息
String msg = e.getMessage();
System.out.println(msg);
//向request中放入失敗的信息
request.setAttribute("msg", msg);
return "/jsp/login.jsp";
}
}
3、service_dao
PS: service:自定義異常向servlet傳遞2種數據(密碼不存在,用戶未激活)
//UserServiceImpl
@Override
public User userLogin(User user) throws SQLException {
//實現登錄功能,可以利用異常在模塊之間傳遞數據
UserDao dao = new UserDaoImpl();
User uu = dao.userLogin(user);
if(uu==null){
throw new RuntimeException("密碼有誤!");
}else if(uu.getState()==0){
throw new RuntimeException("用戶未激活!");
}else{
return uu;
}
}
//UserDaoImpl
@Override
public User userLogin(User user) throws SQLException {
String sql = "select * from user where username = ? and password = ?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanHandler<User>(User.class),user.getUsername(),user.getPassword());
}
4、/jsp/index.jsp 獲取到了用戶信息
<c:if test="${empty userinfo}">
<li><a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登錄</a></li>
<li><a href="${pageContext.request.contextPath}/UserServlet?method=registUI">註冊</a></li>
</c:if>
<c:if test="${not empty userinfo}">
<li>歡迎:${userinfo.username} </li>
<li><a href="${pageContext.request.contextPath}/UserServlet?method=logOut">退出</a></li>
<li><a href="${pageContext.request.contextPath}/jsp/cart.jsp">購物車</a></li>
<li><a href="${pageContext.request.contextPath}/jsp/order_list.jsp">我的訂單</a></li>
</c:if>
4、用戶退出
原理如下:
步驟實現:
1、準備工作
/jsp/index.jsp 修改連接
<a href="${pageContext.request.contextPath}/UserServlet?method=logOut">退出</a>
2、UserServlet___>logOut
清除session
重新定向到首頁
return null;
//UserServlet
public String logOut(HttpServletRequest request, HttpServletResponse response) throws Exception{
//清楚Session
request.getSession().invalidate();
//重定向到首頁
response.sendRedirect("index.jsp");
return null;
}
5、抽取公共頁面
步驟實現:
1、複製info.jsp___>header.jsp
2、打開/jsp/index.jsp,將頁面部分的導航和菜單區域複製到header.jsp
在header.jsp通過tag導入標籤庫
3、打開其他的所有頁面進行替換
4、打開/jsp/index.jsp,將頁面部分的底部複製到footer.jsp
5、打開其他的所有頁面進行替換
導入代碼:
<%@ include file="/jsp/header.jsp" %>
<%@ include file="/jsp/footer.jsp" %>
6、實現首頁的分類查詢_版本1
原理如下:
步驟實現:
1、準備工作(忽略) http://localhost:8080/store_v5/
2、webContent/index.jsp
<jsp:forward page="IndexServlet"></jsp:forward>
3、創建分類模塊的相關程序
CategoryServlet CategoryService CategoryServiceImp CategoryDao
CategoryDaoImp Category
4、創建IndexServlet
調用業務層獲取全部分類數據
將全部分類信息放入request
轉發到真實的首頁/jsp/index.jsp
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//調用業務層的功能,獲取全部的分類信息,返回集合
CategoryService service = new CategoryServiceImpl();
List<Category> cats;
try {
cats = service.getAllCats();
//將集合放入request裏,轉發到真實的頁面
request.setAttribute("category", cats);
} catch (SQLException e) {
e.printStackTrace();
}
return "/jsp/index.jsp";
}
5、CategoryService
@Override
public List<Category> getAllCats() throws SQLException{
CategoryDao dao = new CategoryDaoImpl();
return dao.getAllCats();
}
6、CategoryDao
@Override
public List<Category> getAllCats() throws SQLException {
String sql = "select * from category";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanListHandler<Category>(Category.class));
}
7、/jsp/header.jsp 獲取全部分類信息,header.jsp中
<c:forEach items="${category }" var="c">
<li><a href="#">${c.cname }</a></li>
</c:forEach>
PS: 由於獲取分類要遍歷數據,需要用到c:forEach標籤,需要導入標籤庫
弊端:當訪問首頁是可以看到全部分類信息,但是如果訪問其它頁面,看不到分類信息
7、實現首頁的分類查詢_版本2
原理如下:
步驟實現:
1、/jsp/header.jsp
當頁面加載完畢之後,向服務端發起Ajax請求,服務端經過處理
將所有分類信息以JSON格式的數據返回,客戶端獲取到返回的所有分類
綁定在頁面的顯示分類區域
頁面底部添加script代碼
$.post(url,{},function(data){},”json”){}
2、CategoryServlet -> getAllCats
//調用業務層獲取全部分類
//將全部分類轉換爲JSON格式的數據
//將全部分類信息響應到客戶端
//CategoryServlet中
public String getAllCats(HttpServletRequest request, HttpServletResponse response) throws Exception {
//調用業務層的功能,獲取全部的分類信息,返回集合
CategoryService service = new CategoryServiceImpl();
List<Category> cats = service.getAllCats();
//將全部分類轉換爲JSON格式的數據
String json = JSONArray.fromObject(cats).toString();
System.out.println(json); //測試輸出
/*將全部分類信息相應到客戶端
告訴瀏覽器本次響應的數據是JSON格式的字符串*/
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(json);
return null;
}
3、調試
觀察本次請求,響應網絡傳輸情況
目的:排除2端錯誤(若網頁沒接收到數據可能是客戶端有誤,若接收到的數據有錯可能是服務端有誤)
4、實現/jsp/header.jsp中AJAX代碼的剩餘部分(先把ul加一個ID,不然取不到)
弊端:如果用戶頻繁的訪問包含分類信息的頁面,每次都要去DB中取獲取分類信息,影響性能
<script>
$(function(){
/* 向服務器CategoryServlet->getAllCats發起ajax請求,服務器經過處理,
將所有分類信息以JSON格式的數據返回,獲取到返回的所有分類綁定在頁面的顯示分類區域 */
var url = "/store_v5/CategoryServlet"; //爲什麼這裏要store_v5
var obj = {"method":"getAllCats"};
$.post(url,obj,function(data){
//alert(data); 測試輸出
$.each(data, function(i, value) {
$("#cats").append("<li><a href='#'>"+value.cname+"</a></li>");
});
},"json");
});
</script>
8、實現首頁的分類查詢_版本3
原理如下:
步驟實現:
1、導入jar包(兩個jedis關聯包)
2、導入JedisUtils工具類(修改參數127.0.0.1)
3、啓動windows版本的redis
4、修改CategoryServlet -> findAllCats
*_在redis中獲取全部分類信息
*_如果無法獲取分類信息,
查詢DB中的分類,轉換爲JSON格式字符串,
將JSON格式字符串向redis緩存一份,之後將JSON格式數據響應到客戶端
*_如果可以獲取到分類信息
直接響應即可
//CategoryServlet中
public String getAllCats(HttpServletRequest request, HttpServletResponse response) throws Exception {
Jedis jedis = JedisUtils.getJedis();
String json = jedis.get("allCats");
if(null==json){
//調用業務層的功能,獲取全部的分類信息,返回集合
CategoryService service = new CategoryServiceImpl();
List<Category> cats = service.getAllCats();
//將全部分類轉換爲JSON格式的數據
json = JSONArray.fromObject(cats).toString();
jedis.set("allCats", json);
System.out.println(json); //測試輸出
System.out.println("Linux服務器中無數據!"); //測試輸出
}else{
System.out.println("Linux服務器中有數據!"); //測試輸出
}
JedisUtils.closeJedis(jedis);
/*將全部分類信息相應到客戶端
告訴瀏覽器本次響應的數據是JSON格式的字符串*/
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(json);
return null;
}
9、實現首頁熱門商品_最新商品查詢
SQL代碼分析:
#查詢商品表中最新的9件商品信息
SELECT * FROM product WHERE pflag=0 ORDER BY pdate DESC LIMIT 0 ,9
#查詢商品表中最熱,最新的9件商品信息
SELECT * FROM product WHERE pflag=0 AND is_hot=1 ORDER BY pdate DESC LIMIT 0 ,9
原理如下:
步驟實現:
1、準備工作(忽略)
2、IndexServlet___>execute
//調用業務層查詢最新商品,查詢最熱商品,返回2個集合
//將2個集合放入到request
//轉發到真實的首頁
//修改IndexServlet中的代碼
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//調用業務層的功能,獲取全部的分類信息,返回集合
ProductService service = new ProductServiceImpl();
try {
List<Product> hots = service.getHots();
List<Product> news = service.getNews();
request.setAttribute("hots", hots);
request.setAttribute("news", news);
} catch (SQLException e) {
e.printStackTrace();
}
return "/jsp/index.jsp";
}
3、建立商品模塊相關程序
ProductServlet ProductService ProductServiceImp
ProductDao ProductDaoImp Product
//ProductDaoImpl
@Override
public List<Product> getHots() throws SQLException {
String sql = "select * from product where pflag = 0 and is_hot=1 order by pdate desc limit 0,9";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanListHandler<Product>(Product.class));
}
@Override
public List<Product> getNews() throws SQLException {
String sql = "select * from product where pflag = 0 order by pdate desc limit 0,9";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanListHandler<Product>(Product.class));
}
//ProductServiceImpl
ProductDao dao = new ProductDaoImpl();
@Override
public List<Product> getHots() throws SQLException{
List<Product> hots = dao.getHots();
return hots;
}
@Override
public List<Product> getNews() throws SQLException{
List<Product> news = dao.getNews();
return news;
}
4、調用service,dao
5、/jsp/index.jsp 獲取最新/最熱9件商品信息
修改index.jsp中熱門商品與最新商品的div內容
//熱門商品
<c:forEach items="${hots }" var="h">
<div class="col-md-2" style="text-align:center;height:200px;padding:10px 0px;">
<a href="product_info.jsp">
<img src="${h.pimage }" width="130" height="130" style="display: inline-block;"></a>
<p>
<a href="product_info.jsp" style='color:#666'>${h.pname }</a></p>
<p>
<font color="#E4393C" style="font-size:16px">¥${h.shop_price }</font></p>
</div>
</c:forEach>
//最新商品
<c:forEach items="${news }" var="n">
<div class="col-md-2" style="text-align:center;height:200px;padding:10px 0px;">
<a href="product_info.jsp">
<img src="${n.pimage }" width="130" height="130" style="display: inline-block;"></a>
<p>
<a href="product_info.jsp" style='color:#666'>${n.pname }</a></p>
<p>
<font color="#E4393C" style="font-size:16px">¥${n.shop_price }</font></p>
</div>
</c:forEach>
10、實現商品詳情查詢
原理如下:
步驟實現:
1、準備工作 /jsp/index.jsp修改連接
修改index.jsp中有關商品圖片或者商品名跳轉的超鏈接
2、ProductServlet___>findProductByPid
//獲取商品pid
//根據商品pid查詢商品信息
//將獲取到的商品放入request
//轉發到/jsp/product_info.jsp
public String findProductByPid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//獲取傳遞過來的參數(商品pid)
String pid = request.getParameter("pid");
//調用業務層的方法(根據pid查信息)
ProductService service = new ProductServiceImpl();
Product product;
try {
product = service.findProductByPid(pid);
//System.out.println(product); 測試輸出
//將獲取到的商品放入request
request.setAttribute("product", product);
} catch (SQLException e) {
e.printStackTrace();
}
//轉發到/jsp/product_info.jsp
return "/jsp/product_info.jsp";
}
3、ProductService -> ProductDao
//ProductDaoImpl添加方法
@Override
public Product findProductByPid(String pid) throws SQLException {
String sql = "select * from product where pid = ?";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanHandler<Product>(Product.class),pid);
}
//ProductServiceImpl添加方法
@Override
public Product findProductByPid(String pid) throws SQLException {
return dao.findProductByPid(pid);
}
4、/jsp/product_info.jsp
修改頂部標籤、商品(圖片、編號、價格、描述)
11、實現商品分頁功能
Web項目基礎中基礎: CRUD、ajax、分頁、下載、上傳
SQL代碼分析:
SELECT * FROM product
#約定 每頁顯示5條數據
SELECT * FROM product LIMIT 0 , 5
SELECT * FROM product LIMIT 5 , 5
SELECT * FROM product LIMIT 10 , 5
SELECT * FROM product LIMIT 15 , 5
第幾天頁(當前頁) 起始值 每頁數據大小
1 0 5
2 5 5
…
結論:
1、(當前頁-1)*(每頁數量)=起始值
2、要想實現分頁,向服務端發起請求的時候,必須傳遞當前頁
原理如下:
步驟實現:
1、創建Page類對象
public class Page {
private List<Product> list;
private int curPage,totalPage,maxNum;
public int getMaxNum() {
return maxNum;
}
public void setMaxNum(int maxNum) {
this.maxNum = maxNum;
}
public List<Product> getList() {
return list;
}
public void setList(List<Product> list) {
this.list = list;
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
@Override
public String toString() {
return "Page [list=" + list + ", curPage=" + curPage
+ ", totalPage=" + totalPage + "]";
}
public Page() {
}
public Page(List<Product> list, int startPage, int endPage, int curPage, int totalPage) {
super();
this.list = list;
this.curPage = curPage;
this.totalPage = totalPage;
}
}
2、ProductServlet中添加findAllProduct方法
這裏的curPage第一次可能爲空,所以要判斷
public String findAllProduct(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//獲取參數(當前頁面)
System.out.println("調用到了這裏");
String curPage = request.getParameter("curPage");
if(curPage==null)curPage="1"; //設置一個默認值
System.out.println(curPage);
int cpage = Integer.parseInt(curPage);
//調用業務層的方法(根據pid查信息)
ProductService service = new ProductServiceImpl();
Page page = null;
try {
page = service.findAllProduct(cpage);
//System.out.println(product); 測試輸出
//將獲取到的商品放入request
request.setAttribute("page", page);
} catch (SQLException e) {
e.printStackTrace();
}
return "/jsp/product_list_COPY.jsp";
}
3、ProductServiceImpl、ProductDaoImpl分別添加對應方法
//ProductServiceImpl
@Override
public Page findAllProduct(int cpage) throws SQLException {
Page page = new Page();
int maxNum = dao.getMaxNum();
page.setMaxNum(maxNum);
int totalPage = (maxNum/12)+1;
if(maxNum%12==0)totalPage-=1;
page.setTotalPage(totalPage);
page.setCurPage(cpage);
page.setList(dao.findAllProduct((cpage-1)*12));
return page;
}
//ProductDaoImpl
@Override
public int getMaxNum() throws SQLException {
String sql = "select count(*) from product";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
Long num = (Long) qr.query(sql, new ScalarHandler());
return num.intValue();
}
@Override
public List<Product> findAllProduct(int num) throws SQLException {
String sql = "select * from product limit ?,12";
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
return qr.query(sql, new BeanListHandler<Product>(Product.class),num);
}
4、header.jsp中把首頁的超鏈接改成ProductServlet
<a class="navbar-brand" href="${pageContext.request.contextPath}/ProductServlet?method=findAllProduct">首頁</a>
5、實現product_list_COPY.jsp中的分頁功能
//顯示分頁商品信息
<c:forEach items="${page.list }" var="p">
<div class="col-md-2">
<a href="ProductServlet?method=findProductByPid&pid=${p.pid}">
<img src="${pageContext.request.contextPath}/${p.pimage}" width="170" height="170" style="display: inline-block;">
</a>
<p><a href="ProductServlet?method=findProductByPid&pid=${p.pid}" style='color:green'>${p.pname}</a></p>
<p><font color="#FF0000">商城價:¥${p.shop_price}</font></p>
</div>
</c:forEach>
//實現分頁功能
<c:if test="${page.curPage!=1 }">
<li><a href="${pageContext.request.contextPath}/ProductServlet?method=findAllProduct&curPage=${page.curPage-1}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>
</c:if>
<c:forEach begin="1" end="${page.totalPage }" var="i">
<c:if test="${page.curPage== i }">
<li><a>${i }</a></li>
</c:if>
<c:if test="${page.curPage!= i }">
<li><a href="${pageContext.request.contextPath}/ProductServlet?method=findAllProduct&curPage=${i }">${i }</a></li>
</c:if>
</c:forEach>
<c:if test="${page.curPage!=page.totalPage }">
<li>
<a href="${pageContext.request.contextPath}/ProductServlet?method=findAllProduct&curPage=${page.curPage+1}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
實現小結:
1、第一次進入頁面的時候不會有curPage的參數,所以要判斷null的情況
2、Page對象中的List專門存儲了查詢的Product對象
3、分頁查詢的代碼要掌握,Limit x,y(x都是從0開始)
4、若query方法返回的不是類對象,整形數據用ScalarHandler,先轉爲Long類型,再用intValue獲取int值
5、若想使用Ajax來調用Servlet的request存值並返回頁面取值。這是不可能的,因爲Ajax函數一般是在頁面加載完成後再調用,所以要藉助index.jsp來間接跳轉
6、分頁功能的JSTL代碼要熟練書寫