JavaWeb企业实战项目(二):用户登录-首页详情-商品分类

Web项目系列文章推荐:
JavaWeb企业实战项目(一):环境搭建-用户注册-邮件发送
JavaWeb企业实战项目(三):商品模块
JavaWeb企业实战项目(四):订单模块
JavaWeb企业实战项目(五):后台模块1
JavaWeb企业实战项目(六):后台模块2
待更新

文章结构

        • 1、任务概述
        • 2、用户激活
        • 3、用户登录
        • 4、用户退出
        • 5、抽取公共页面
        • 6、实现首页的分类查询_版本1
        • 7、实现首页的分类查询_版本2
        • 8、实现首页的分类查询_版本3
        • 9、实现首页热门商品_最新商品查询
        • 10、实现商品详情查询
        • 11、实现商品分页功能

1、任务概述

1_用户激活
2_登录,
3_退出,
4_抽取公共页面
5_查询所有分类
6_首页热门商品_最新商品显示
7_商品详情显示
8_基础分页操作
9_首页分类商品带分页查询

开发通用步骤: 1_准备工作 2_Servlet 3_service 4_Dao 5_jsp页面

2、用户激活

原理如下
JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第1张图片
步骤实现
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、用户登录

原理如下
JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第2张图片
实现登录前,要先修改Index中登录功能的请求路径
*_ /jsp/index.jsp 修改登录链接
登录
*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、用户退出

原理如下
JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第3张图片
步骤实现
1、准备工作
  /jsp/index.jsp 修改连接
  退出
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

原理如下
JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第4张图片
步骤实现
1、准备工作(忽略) http://localhost:8080/store_v5/
2、webContent/index.jsp
  
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

原理如下
JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第5张图片
步骤实现
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("
  • "+value.cname+"
  • "
    ); }); },"json"); }); </script>

    8、实现首页的分类查询_版本3

    原理如下
    JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第6张图片
    步骤实现
    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

    原理如下
    JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第7张图片
    步骤实现
    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、实现商品详情查询

    原理如下
    JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第8张图片
    步骤实现
    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、要想实现分页,向服务端发起请求的时候,必须传递当前页
      
    原理如下
    JavaWeb企业实战项目(二):用户登录-首页详情-商品分类_第9张图片
    步骤实现
    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
    首页
    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代码要熟练书写

    你可能感兴趣的:(JavaWeb项目)