[TOC]
## 步骤 1 : 明确需求,首页需要什么数据?
那么首页需要什么数据呢? 从**首页展示需求分析**上来看:
1. 在横向导航栏上提供4个分类连接
2. 在纵向导航栏上提供全部17个分类连接
3. 当鼠标移动到某一个纵向分类连接的时候,显示这个分类下的**推荐产品列表**
4. 按照每种分类显示5个商品的方式,显示所有17种分类
注:**推荐产品列表**就是如图所示的一个分类右边的产品列表。
![](https://box.kancloud.cn/036257969f2b10ea748ed6127c1b7891_960x456.png)
## 步骤 2 : Category
Category新增两个瞬时字段products和productsByRow。
~~~
List<Product> products;
List<List<Product>> productsByRow;
~~~
products比较好理解,代表一个分类下有多个产品。
productsByRow这个属性的类型是`List<List<Product>> productsByRow`。
即一个分类又对应多个 `List<Product>`,提供这个属性,是为了在首页竖状导航的分类名称右边显示推荐产品列表。
如截图所示,一个分类会对应多行产品,而一行产品里又有多个产品记录。
为了实现界面上的这个功能,为Category类设计了
List<List<Product>> productsByRow
这样一个集合属性
![](https://box.kancloud.cn/074f19a2fc5824755da5a5ae0d4b5c6f_932x472.png)
~~~
package com.dodoke.tmall.pojo;
import java.util.List;
public class Category {
private Integer id;
private String name;
/* 如下是非数据库字段 */
private List<Product> products;
private List<List<Product>> productsByRow;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public List<List<Product>> getProductsByRow() {
return productsByRow;
}
public void setProductsByRow(List<List<Product>> productsByRow) {
this.productsByRow = productsByRow;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name == null ? null : name.trim();
}
}
~~~
## 步骤 3 : ProductService
ProductService新增加3个方法
~~~
public void fill(List<Category> categorys);
public void fill(Category category);
public void fillByRow(List<Category> categorys);
~~~
~~~
package com.dodoke.tmall.service;
import java.util.List;
import com.dodoke.tmall.pojo.Category;
import com.dodoke.tmall.pojo.Product;
public interface ProductService {
void add(Product c);
void delete(int id);
void update(Product c);
Product get(int id);
List list(int categoryId);
void setFirstProductImage(Product p);
/**
* 为分类填充产品集合
*
* @param categorys
*/
public void fill(List<Category> categorys);
/**
* 为多个分类填充产品集合
*
* @param category
*/
public void fill(Category category);
/**
* 为多个分类填充推荐产品集合,即把分类下的产品集合,按照8个为一行,拆成多行,以利于后续页面上进行显示
*
* @param categorys
*/
public void fillByRow(List<Category> categorys);
}
~~~
## 步骤 4 : ProductServiceImpl
ProductServiceImpl为ProductService中新增加的三个方法提供实现。
1. 为分类填充产品集合
`public void fill(Category category);`
2. 为多个分类填充产品集合
`public void fill(List<Category> categorys);`
3.为多个分类填充推荐产品集合,即把分类下的产品集合,按照8个为一行,拆成多行,以利于后续页面上进行显示
`public void fillByRow(List<Category> categorys);`
~~~
package com.dodoke.tmall.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.dodoke.tmall.mapper.ProductMapper;
import com.dodoke.tmall.pojo.Category;
import com.dodoke.tmall.pojo.Product;
import com.dodoke.tmall.pojo.ProductExample;
import com.dodoke.tmall.pojo.ProductImage;
import com.dodoke.tmall.service.CategoryService;
import com.dodoke.tmall.service.ProductImageService;
import com.dodoke.tmall.service.ProductService;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductMapper productMapper;
@Autowired
CategoryService categoryService;
@Autowired
ProductImageService productImageService;
@Override
public void add(Product p) {
p.setCreateDate(new Date());
productMapper.insert(p);
}
@Override
public void delete(int id) {
productMapper.deleteByPrimaryKey(id);
}
@Override
public void update(Product p) {
productMapper.updateByPrimaryKeySelective(p);
}
@Override
public Product get(int id) {
Product p = productMapper.selectByPrimaryKey(id);
setFirstProductImage(p);
setCategory(p);
return p;
}
private void setCategory(Product p) {
int categoryId = p.getCategoryId();
Category category = categoryService.get(categoryId);
p.setCategory(category);
}
@Override
public List list(int categoryId) {
ProductExample example = new ProductExample();
example.createCriteria().andCategoryIdEqualTo(categoryId);
example.setOrderByClause("id desc");
List result = productMapper.selectByExample(example);
setFirstProductImage(result);
setCategory(result);
return result;
}
public void setCategory(List<Product> ps) {
for (Product p : ps) {
setCategory(p);
}
}
/**
* 根据productId和图片类型查询出所有的单个图片,然后把第一个取出来放在firstProductImage上。
*
* @param p
* 产品
*/
@Override
public void setFirstProductImage(Product p) {
List<ProductImage> pis = productImageService.list(p.getId(), ProductImageService.type_single);
if (!pis.isEmpty()) {
ProductImage pi = pis.get(0);
p.setFirstProductImage(pi);
}
}
/**
* 给多个产品设置图片
*
* @param ps
* 产品集合
*/
public void setFirstProductImage(List<Product> ps) {
for (Product p : ps) {
setFirstProductImage(p);
}
}
/**
* 为分类填充产品集合
*
* @param categorys
*/
@Override
public void fill(Category c) {
List<Product> ps = list(c.getId());
c.setProducts(ps);
}
/**
* 为多个分类填充产品集合
*
* @param category
*/
@Override
public void fill(List<Category> cs) {
for (Category c : cs) {
fill(c);
}
}
/**
* 为多个分类填充推荐产品集合,即把分类下的产品集合,按照8个为一行,拆成多行,以利于后续页面上进行显示
*
* @param categorys
*/
@Override
public void fillByRow(List<Category> cs) {
// 把分类下的产品集合,按照8个为一行,拆成多行,以利于后续页面上进行显示
int productNumberEachRow = 8;
// 将categorylist中每个category拿出来循环
for (Category c : cs) {
// 获取每个分类中对应的产品,在使用fillByRow(List<Category> cs)这个方法前,需要先使用fill方法,注入分类中的所有产品,因此在这里才可以取出产品
List<Product> products = c.getProducts();
// 每一行产品的list
List<List<Product>> productsByRow = new ArrayList<>();
for (int i = 0; i < products.size(); i += productNumberEachRow) {
int size = i + productNumberEachRow;
// 界限判断
size = size > products.size() ? products.size() : size;
// 该方法返回的是父list的一个子集合,从fromIndex(包含),到toIndex(不包含)
List<Product> productsOfEachRow = products.subList(i, size);
productsByRow.add(productsOfEachRow);
}
c.setProductsByRow(productsByRow);
}
}
}
~~~
## 步骤 5 : ForeController
home()方法映射首页访问路径 "forehome".
1. 查询所有分类
2. 为这些分类填充产品集合
3. 为这些分类填充推荐产品集合
4. 服务端跳转到home.jsp
~~~
package com.dodoke.tmall.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.dodoke.tmall.pojo.Category;
import com.dodoke.tmall.service.CategoryService;
import com.dodoke.tmall.service.OrderItemService;
import com.dodoke.tmall.service.OrderService;
import com.dodoke.tmall.service.ProductImageService;
import com.dodoke.tmall.service.ProductService;
import com.dodoke.tmall.service.PropertyValueService;
import com.dodoke.tmall.service.UserService;
@Controller
@RequestMapping("")
public class ForeController {
@Autowired
CategoryService categoryService;
@Autowired
ProductService productService;
@Autowired
UserService userService;
@Autowired
ProductImageService productImageService;
@Autowired
PropertyValueService propertyValueService;
@Autowired
OrderService orderService;
@Autowired
OrderItemService orderItemService;
@RequestMapping("forehome")
public String home(Model model) {
List<Category> cs= categoryService.list();
productService.fill(cs);
productService.fillByRow(cs);
model.addAttribute("cs", cs);
return "fore/home";
}
}
~~~
## 步骤 6 : home.jsp
home.jsp涉及多个页面,将在后续讲解**home.jsp**
- 项目简介
- 功能一览
- 前台
- 后台
- 开发流程
- 需求分析-展示
- 首页
- 产品页
- 分类页
- 搜索结果页
- 购物车查看页
- 结算页
- 确认支付页
- 支付成功页
- 我的订单页
- 确认收货页
- 确认收货成功页
- 评价页
- 需求分析-交互
- 分类页排序
- 立即购买
- 加入购物车
- 调整订单项数量
- 删除订单项
- 生成订单
- 订单页功能
- 确认付款
- 确认收货
- 提交评价信息
- 登录
- 注册
- 退出
- 搜索
- 前台需求列表
- 需求分析后台
- 分类管理
- 属性管理
- 产品管理
- 产品图片管理
- 产品属性设置
- 用户管理
- 订单管理
- 后台需求列表
- 表结构设计
- 数据建模
- 表与表之间的关系
- 后台-分类管理
- 可运行的项目
- 静态资源
- JSP包含关系
- 查询
- 分页
- 增加
- 删除
- 编辑
- 修改
- 做一遍
- 重构
- 分页方式
- 分类逆向工程
- 所有逆向工程
- 后台其他页面
- 属性管理实现
- 产品管理实现
- 产品图片管理实现
- 产品属性值设置
- 用户管理实现
- 订单管理实现
- 前端
- 前台-首页
- 可运行的项目
- 静态资源
- ForeController
- home方法
- home.jsp
- homePage.jsp
- 前台-无需登录
- 注册
- 登录
- 退出
- 产品页
- 模态登录
- 分类页
- 搜索
- 前台-需要登录
- 购物流程
- 立即购买
- 结算页面
- 加入购物车
- 查看购物车页面
- 登录状态拦截器
- 其他拦截器
- 购物车页面操作
- 订单状态图
- 生成订单
- 我的订单页
- 我的订单页操作
- 评价产品
- 总结