JavaWeb企業實戰項目(二):用戶登錄-首頁詳情-商品分類

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
步驟實現
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

原理如下
分類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

原理如下
分類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">&yen;${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">&yen;${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">商城價:&yen;${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">&laquo;</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">&raquo;</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代碼要熟練書寫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章