SpringBoot-項目3-商品(首頁,詳情頁)

創建商品表及商品分類表

# 商品表
CREATE TABLE `t_product` (
  `id` int(20) NOT NULL COMMENT '商品id',
  `category_id` int(20) DEFAULT NULL COMMENT '分類id',
  `item_type` varchar(100) DEFAULT NULL COMMENT '商品系列',
  `title` varchar(100) DEFAULT NULL COMMENT '商品標題',
  `sell_point` varchar(150) DEFAULT NULL COMMENT '商品賣點',
  `price` bigint(20) DEFAULT NULL COMMENT '商品單價',
  `num` int(10) DEFAULT NULL COMMENT '庫存數量',
  `image` varchar(500) DEFAULT NULL COMMENT '圖片路徑',
  `status` int(1) DEFAULT 1 COMMENT '商品狀態  1:上架   2:下架   3:刪除',
  `priority` int(10) DEFAULT NULL COMMENT '顯示優先級',
  `created_time` datetime DEFAULT NULL COMMENT '創建時間',
  `modified_time` datetime DEFAULT NULL COMMENT '最後修改時間',
  `created_user` varchar(50) DEFAULT NULL COMMENT '創建人',
  `modified_user` varchar(50) DEFAULT NULL COMMENT '最後修改人',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 商品分類表
分類表(id,title,image,desc,isdelete,created_user,created_time,modified_user,modified_time)

54. 將商品相關頁面添加到攔截器白名單

當前項目中的登錄攔截器默認是攔截/**路徑 ,則所有請求路徑默認都需要登錄,而主頁、商品詳情等頁面應該不需要登錄就可以訪問,所以,需要將/web/index.html/web/product.html添加到配置攔截器的白名單中!

55. 創建商品數據的實體類

cn.demo.store.entity包中創建Product實體類:

/**
 * 商品數據的實體類
 */
public class Product extends BaseEntity {

  private static final long serialVersionUID = 6884621327188442341L;

  private Integer id;
  private Integer categoryId;
  private String itemType;
  private String title;
  private String sellPoint;
  private Long price;
  private Integer num;
  private String image;
  private Integer status;
  private Integer priority;
  
  // 生成get/set方法,toString()方法,hashCode/equals等方法
  
}

56. 主頁-熱銷排行-持久層

(a) 規劃需要的SQL語句

查詢熱銷排行商品的SQL語句是(此頁面熱銷商品只顯示4個):

select * from t_product where status=1 order by priority desc limit 0,4

(b) 設計抽象方法

cn.demo.store.mapper包下創建ProductMapper 接口,並添加抽象方法:

/**
 * 處理商品數據的持久層接口
 */
public interface ProductMapper {
  
  /**
   * 查詢熱銷商品排行的前4個商品
   * @return 熱銷商品排行的前4個商品
   */
  List<Product> findHotList();

}

© 配置映射並測試

src/main/resources/mappers下創建ProductMapper.xml,用於配置以上抽象方法的映射:

<mapper namespace="cn.demo.store.mapper.ProductMapper">

  <resultMap type="cn.demo.store.entity.Product" id="ProductEntityMap">
    <id column="id" property="id"/>
    <result column="category_id" property="categoryId"/>
    <result column="item_type" property="itemType"/>
    <result column="sell_point" property="sellPoint"/>
    <result column="created_user" property="createdUser"/>
    <result column="created_time" property="createdTime"/>
    <result column="modified_user" property="modifiedUser"/>
    <result column="modified_time" property="modifiedTime"/>
  </resultMap>
  
  <!-- 查詢熱銷商品排行的前4個商品 -->
  <!-- List<Product> findHotList() -->
  <select id="findHotList" resultMap="ProductEntityMap">
    SELECT * FROM t_product WHERE status=1 ORDER BY priority DESC LIMIT 0, 4
  </select>

</mapper>

src/test/javacn.demo.store.mapper包中創建ProductMapperTests測試類,測試以上抽象方法:

@RunWith(SpringRunner.class)
@SpringBootTest 
public class ProductMapperTests {
  
  @Autowired
  private ProductMapper mapper;
  
  @Test
  public void findByParent() {
    List<Product> list = mapper.findHotList();
    System.err.println("count=" + list.size());
    for (Product item : list) {
      System.err.println(item);
    }
  }

}

57. 主頁-熱銷排行-業務層

(a) 規劃業務流程、業務邏輯,並創建可能出現的異常

(b) 設計抽象方法

cn.demo.store.service包中創建ProductService接口,添加抽象方法:

/**
 * 處理商品數據的業務層接口
 */
public interface ProductService {

  /**
   * 查詢熱銷商品排行的前4個商品
   * @return 熱銷商品排行的前4個商品
   */
  List<Product> getHotList();
  
}

© 實現抽象方法並測試

cn.demo.store.service.impl包中創建ProductServiceImpl,實現ProductService接口,在類的聲明之前添加@Service註解,在類中添加@Autowired private ProductMapper productMapper;持久層對象:

@Service
public class ProductServiceImpl implements ProductService {
  
  @Autowired 
  private ProductMapper productMapper;
  
}

在具體實現接口的抽象方法之前,先將持久層中的方法複製到業務層實現類,並改爲私有方法,並實現:

@Service
public class ProductServiceImpl implements ProductService {
  
  @Autowired 
  private ProductMapper productMapper;
  
  private List<Product> findHotList() {
    return productMapper.findHotList();
  }
  
}

然後,再重寫接口中的抽象方法,抽象方法將依賴於私有方法來實現:

/**
 * 處理商品數據的業務層實現類
 */
@Service
public class ProductServiceImpl implements ProductService {

  @Autowired
  private ProductMapper productMapper;
  
  @Override
  public List<Product> getHotList() {
    List<Product> products = findHotList();
    // 將不需要響應給前端的數據設置爲null
    for (Product product : products) {
      product.setCategoryId(null);
      product.setStatus(null);
      product.setPriority(null);
      product.setCreatedUser(null);
      product.setCreatedTime(null);
      product.setModifiedUser(null);
      product.setModifiedTime(null);
    }
    return products;
  }
  
  private List<Product> findHotList() {
    return productMapper.findHotList();
  }

}

完成後,在src/test/javacn.demo.store.service包中創建ProductServiceTests測試類,測試以上方法:

@RunWith(SpringRunner.class)
@SpringBootTest 
public class ProductServiceTests {
  
  @Autowired
  private ProductService service;
  
  @Test
  public void getHotList() {
    List<Product> list = service.getHotList();
    System.err.println("count=" + list.size());
    for (Product item : list) {
      System.err.println(item);
    }
  }

}

58. 主頁-熱銷排行-控制器層

(a) 處理新創建的異常類型

(b) 設計需要處理的請求

  • 請求路徑:/products/list/hot
  • 請求參數:無
  • 請求方式:GET
  • 響應數據:JsonResult<>

© 處理請求並測試

cn.demo.store.controller中創建ProductController,並處理請求:

@RestController
@RequestMapping("products")
public class ProductController extends BaseController {

  @Autowired
  private ProductService productService;
  
  // http://localhost:8080/products/list/hot
  @GetMapping("list/hot")
  public JsonResult<List<Product>> getHotList() {
    List<Product> data = productService.getHotList();
    return new JsonResult<>(OK, data);
  }
  
}

在攔截器的配置中,添加新的白名單:

patterns.add("/products/**");

完成後,打開瀏覽器進行測試。

59. 主頁-熱銷排行-前端頁面

先將頁面中第180行的``標籤設置id="hot-list",它是顯示熱銷排行數據的區域的容器,然後,再添加代碼加載數據並顯示

  <script type="text/javascript">
  $(document).ready(function() {
    showHotList();
  });
  
  function showHotList() {
    console.log("準備熱銷商品列表……");
    $("#hot-list").empty();
    $.ajax({
      "url":"/products/list/hot",
      "type":"get",
      "dataType":"json",
      "success":function(json) {
        var list = json.data;
        console.log("count=" + list.length);
        for (var i = 0; i < list.length; i++) {
          console.log(list[i].title);
          var html = '<div class="col-md-12">'
            + '<div class="col-md-7 text-row-2"><a href="product.html">#{title}</a></div>'
            + '<div class="col-md-2">¥#{price}</div>'
            + '<div class="col-md-3"><img src="#{image}collect.png" class="img-responsive" /></div>'
            + '</div>';
          
          html = html.replace(/#{title}/g, list[i].title);
          html = html.replace(/#{price}/g, list[i].price);
          html = html.replace(/#{image}/g, list[i].image);
            
          $("#hot-list").append(html);
        }
      }
    });
  }
  </script>



60. 商品-顯示詳情-持久層

(a) 規劃需要的SQL語句

查詢商品詳情的SQL語句大致是:

select * from t_product where id=?

(b) 設計抽象方法

ProductMapper接口中添加:

  /**
   * 根據商品id查詢商品詳情
   * @param id 商品id
   * @return 匹配的商品詳情,如果沒有匹配的數據,則返回null
   */
  Product findById(Integer id);

© 配置映射並測試

ProductMapper.xml中配置映射:

  <!-- 根據商品id查詢商品詳情 -->
  <!-- Product findById(Integer id) -->
  <select id="findById" resultMap="ProductEntityMap">
    SELECT * FROM t_product WHERE id=#{id}
  </select>

ProductMapperTests中測試:

  @Test
  public void findById() {
    Integer id = 10000017;
    Product result = mapper.findById(id);
    System.err.println(result);
  }

61. 商品-顯示詳情-業務層

(a) 規劃業務流程、業務邏輯,並創建可能出現的異常

需要創建ProductNotFoundException

(b) 設計抽象方法

ProductService接口中添加:

  /**
   * 根據商品id查詢商品詳情
   * @param id 商品id
   * @return 匹配的商品詳情
   */
  Product getById(Integer id);

© 實現抽象方法並測試

ProductServiceImpl中,先將持久層接口中的方法複製過來,改爲私有方法並實現:

  /**
   * 根據商品id查詢商品詳情
   * @param id 商品id
   * @return 匹配的商品詳情,如果沒有匹配的數據,則返回null
   */
  private Product findById(Integer id) {
    return productMapper.findById(id);
  }

然後,重寫接口中的抽象方法:

  @Override
  public Product getById(Integer id) {
    // 調用自身私有方法查詢數據
    Product product = findById(id);
    // 檢查查詢結果數據是否爲null
    if (product == null) {
      // 是:拋出ProductNotFoundException
      throw new ProductNotFoundException("獲取商品詳情失敗!嘗試訪問的商品數據不存在!");
    }

    // 將不必要響應給客戶端的屬性值設爲null
    product.setCategoryId(null);
    product.setStatus(null);
    product.setPriority(null);
    product.setCreatedUser(null);
    product.setCreatedTime(null);
    product.setModifiedUser(null);
    product.setModifiedTime(null);
    // 返回數據
    return product;
  }

最後,在ProductServiceTests中測試:

  @Test
  public void getById() {
    try {
      Integer id = 10080017;
      Product result = service.getById(id);
      System.err.println(result);
    } catch (ServiceException e) {
      System.err.println(e.getClass().getName());
      System.err.println(e.getMessage());
    }
  }

62. 商品-顯示詳情-控制器層

(a) 處理新創建的異常類型

需要處理ProductNotFoundException

(b) 設計需要處理的請求

  • 請求路徑:/products/{id}/details
  • 請求參數:@PathVariable("id") Integer id
  • 請求方式:GET
  • 響應數據:JsonResult

© 處理請求並測試

ProductController 中添加處理請求的方法:

  // http://localhost:8080/products/10000017/details
  @GetMapping("{id}/details")
  public JsonResult<Product> getById(@PathVariable("id") Integer id) {
    Product data = productService.getById(id);
    return new JsonResult<>(OK, data);
  }

63. 商品-顯示詳情-前端頁面

創建js文件jquery-getUrlParam.js(此文件是從頁面讀取所需的參數)

(function ($) {
	$.getUrlParam = function (name) {
		var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
		var r = window.location.search.substr(1).match(reg);
		if (r != null) 
			return unescape(r[2]);
		return null;
	}
})(jQuery);

product.html中添加代碼:

<script type="text/javascript" src="../js/jquery-getUrlParam.js"></script>
<script type="text/javascript">
  var id = $.getUrlParam("id");
  
  $(document).ready(function() {
    $.ajax({
      "url":"/products/" + id + "/details",
      "type":"get",
      "dataType":"json",
      "success":function(json) {
        if (json.state == 2000) {
          $("#product-title").html(json.data.title);        
          $("#product-sell-point").html(json.data.sellPoint)
          $("#product-price").html(json.data.price);       
          // $("#product-image-5-big").attr("src", json.data.image + "5_big.png");
          // $("#product-image-5").attr("src", json.data.image + "5.jpg");
          for (var i = 1; i <= 5; i++) {
            $("#product-image-" + i + "-big").attr("src", json.data.image + i + "_big.png");
            $("#product-image-" + i).attr("src", json.data.image + i + ".jpg");
          }
        } else {
          alert(json.message);
          // location.href = "index.html";
        }
      }
    });
  });
</script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章