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代码要熟练书写

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