1. 需要做的事情
l 商品詳情頁實現
1、商品查詢服務事項
2、商品詳情展示
3、添加緩存
2. 實現商品詳情頁功能
2.1. 功能分析
1、Taotao-portal接收頁面請求,接收到商品id。
2、調用taotao-rest提供的商品詳情的服務,把商品id作爲參數傳遞給服務。接收到商品詳細。
3、渲染結果,展示商品詳細頁面
4、爲了提高響應速度,商品詳情頁的內容需要分步驟加載。
第一步:先展示商品基本信息,例如商品的名稱、圖片、價格。
第二步:展示商品的描述,此時商品頁面已經展示完畢,需要ajax請求商品描述。展示的時機是頁面加載完畢後一秒鐘。
第三步:展示商品規格。當用戶點擊商品規格選項卡時展示。使用ajax請求商品規格。
5、在搜索頁面點擊商品的圖片或者商品名稱請求商品詳情頁面。
商品詳情頁請求的url:/item/{itemId}.html
商品描述請求的url:/item/desc/{itemId}.html
商品規格請求的url:/item/param/{itemId}.html
2.2. 處理流程
2.3. Taotao-rest服務
需要實現三個服務:
1、根據商品id查詢商品詳細表。
2、根據商品id查詢商品描述表
3、根據商品id查詢商品規格參數表。
2.3.1. Mapper
因爲都是單表查詢所以使用逆向工程生成的mapper文件即可。
tb_item
tb_item_desc
tb_item_param_item
2.3.2. Service
- @Service
- public class ItemServiceImplimplements ItemService {
- @Autowired
- private TbItemMapperitemMapper;
- @Autowired
- private TbItemDescMapperitemDescMapper;
- @Autowired
- private TbItemParamItemMapperitemParamItemMapper;
- /**
- * 根據id取商品信息
- * <p>Title: getItemById</p>
- * <p>Description:</p>
- * @param id
- * @return
- * @throws Exception
- * @see com.taotao.rest.service.ItemService#getItemById(java.lang.Long)
- */
- @Override
- public TbItem getItemById(Longid) throws Exception {
- TbItem tbItem = itemMapper.selectByPrimaryKey(id);
- return tbItem;
- }
- /**
- * 根據id取商品描述
- * <p>Title: getItemDescById</p>
- * <p>Description:</p>
- * @param id
- * @return
- * @throws Exception
- * @see com.taotao.rest.service.ItemService#getItemDescById(java.lang.Long)
- */
- @Override
- public TbItemDesc getItemDescById(Longid) throws Exception {
- TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(id);
- return itemDesc;
- }
- /**
- * 根據商品id取規格參數
- * <p>Title: getItemParamById</p>
- * <p>Description:</p>
- * @param id
- * @return
- * @throws Exception
- * @see com.taotao.rest.service.ItemService#getItemParamById(java.lang.Long)
- */
- @Override
- public TbItemParamItem getItemParamById(Longid) throws Exception {
- TbItemParamItemExample example = new TbItemParamItemExample();
- Criteria criteria =example.createCriteria();
- criteria.andItemIdEqualTo(id);
- List<TbItemParamItem> list = itemParamItemMapper.selectByExampleWithBLOBs(example);
- TbItemParamItem itemParamItem = null;
- if (null !=null && !list.isEmpty()) {
- itemParamItem = list.get(0);
- }
- return itemParamItem;
- }
- }
2.3.3. Controller
- @Controller
- @RequestMapping("/items")
- public class ItemController {
- @Autowired
- private ItemService itemService;
- @RequestMapping("/item/{id}")
- @ResponseBody
- public TaotaoResult getItemById(@PathVariable Longid) {
- //有效性驗證
- if (id ==null) {
- return TaotaoResult.build(400,"參數中必須包含id");
- }
- TbItem tbItem = null;
- //根據id查詢商品信息
- try {
- tbItem = itemService.getItemById(id);
- } catch (Exception e) {
- e.printStackTrace();
- //發生異常時返回異常信息
- return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
- }
- return TaotaoResult.ok(tbItem);
- }
- @RequestMapping("/itemdesc/{id}")
- @ResponseBody
- public TaotaoResult getItemDescById(@PathVariable Longid) {
- //有效性驗證
- if (id ==null) {
- return TaotaoResult.build(400,"參數中必須包含id");
- }
- TbItemDesc tbItemDesc = null;
- //根據id查詢商品明細信息
- try {
- tbItemDesc = itemService.getItemDescById(id);
- } catch (Exception e) {
- e.printStackTrace();
- //發生異常時返回異常信息
- return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
- }
- return TaotaoResult.ok(tbItemDesc);
- }
- @RequestMapping("/itemparam/{id}")
- @ResponseBody
- public TaotaoResult getItemParamById(@PathVariable Longid) {
- //有效性驗證
- if (id ==null) {
- return TaotaoResult.build(400,"參數中必須包含id");
- }
- TbItemParamItem tbItemParamItem = null;
- //根據id查詢商品規格參數信息
- try {
- tbItemParamItem = itemService.getItemParamById(id);
- } catch (Exception e) {
- e.printStackTrace();
- //發生異常時返回異常信息
- return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
- }
- return TaotaoResult.ok(tbItemParamItem);
- }
- }
2.4. Portal商品詳情頁實現
2.4.1. 商品POJO
由於頁面展示商品信息時,需要展示圖片列表。多張圖片在數據庫中存儲的格式是存儲在同一個字段中使用逗號分隔的。所以商品展示時需要在pojo中做處理。故此在portal中自定義一個商品的pojo類。
- public class Item {
- private Long id;
- private String title;
- private String sellPoint;
- private Long price;
- private Integer num;
- private String barcode;
- private String image;
- private Long cid;
- private Byte status;
- private Date created;
- private Date updated;
- //省略get、set方法。。。。。。
- //添加此方法拆分圖片列表
- public String[] getImages() {
- if (image != null && image != "") {
- String[] strings = image.split(",");
- return strings;
- }
- return null;
- }
- }
2.4.2. Service
- @Service
- public class ItemServiceImplimplements ItemService {
- @Value("${REST_BASE_URL}")
- private String REST_BASE_URL;
- @Value("${ITEMS_ITEM_URL}")
- private String ITEMS_ITEM_URL;
- @Value("${ITEMS_ITEMDESC_URL}")
- private String ITEMS_ITEMDESC_URL;
- @Value("${ITEMS_ITEMPARAM_URL}")
- private String ITEMS_ITEMPARAM_URL;
- @Override
- public Item getItemById(Longid) throws Exception {
- // 查詢商品信息
- String result = HttpClientUtil.doGet(REST_BASE_URL +ITEMS_ITEM_URL + id);
- // 轉換成java對象
- TaotaoResult taotaoResult = TaotaoResult.formatToPojo(result,Item.class);
- Item item =null;
- if (taotaoResult.getStatus() == 200) {
- item = (Item)taotaoResult.getData();
- }
- return item;
- }
- @Override
- public TbItemDesc geTbItemDescById(Longid) throws Exception {
- // 查詢商品信息
- String result = HttpClientUtil.doGet(REST_BASE_URL +ITEMS_ITEMDESC_URL + id);
- // 轉換成java對象
- TaotaoResult taotaoResult = TaotaoResult.formatToPojo(result, TbItemDesc.class);
- TbItemDesc itemDesc = null;
- if (taotaoResult.getStatus() == 200) {
- itemDesc = (TbItemDesc) taotaoResult.getData();
- }
- return itemDesc;
- }
- @Override
- public String geTbItemParamItemById(Longid) throws Exception {
- // 查詢商品信息
- String result = HttpClientUtil.doGet(REST_BASE_URL +ITEMS_ITEMPARAM_URL + id);
- // 轉換成java對象
- TaotaoResult taotaoResult = TaotaoResult.formatToPojo(result, TbItemParamItem.class);
- String resultHtml = "";
- if (taotaoResult.getStatus() == 200) {
- try {
- TbItemParamItem itemParamItem = (TbItemParamItem)taotaoResult.getData();
- //取規格參數信息
- String paramData = itemParamItem.getParamData();
- //把規格參數轉換成java對象
- List<Map> paramList = JsonUtils.jsonToList(paramData, Map.class);
- //拼裝html
- resultHtml ="<table cellpadding=\"0\" cellspacing=\"1\" width=\"100%\" border=\"0\" class=\"Ptable\">\n" +
- " <tbody>\n";
- for (Map map :paramList) {
- resultHtml +=
- " <tr>\n" +
- " <th class=\"tdTitle\" colspan=\"2\">"+map.get("group")+"</th>\n" +
- " </tr>\n";
- List<Map> params = (List<Map>)map.get("params");
- for (Map map2 :params) {
- resultHtml +=
- " <tr>\n" +
- " <td class=\"tdTitle\">"+map2.get("k")+"</td>\n" +
- " <td>"+map2.get("v")+"</td>\n" +
- " </tr>\n" ;
- }
- }
- resultHtml += " </tbody>\n" +
- "</table>";
- } catch (Exception e){
- //如果轉換髮送異常,忽略。返回一個空字符串。
- e.printStackTrace();
- }
- }
- return resultHtml;
- }
- }
2.4.3. Controller
- @Controller
- public class ItemController {
- @Autowired
- private ItemService itemService;
- @RequestMapping("/item/{id}")
- public String showItem(@PathVariable Longid, Model model) throws Exception {
- //取商品信息
- Item item = itemService.getItemById(id);
- //把結果傳遞給頁面
- model.addAttribute("item",item);
- //返回邏輯視圖
- return "item";
- }
- @RequestMapping(value="/item/desc/{id}", produces=MediaType.TEXT_HTML_VALUE+";charset=utf-8")
- @ResponseBody
- public String showItemDesc(@PathVariable Longid) throws Exception {
- //取商品描述
- TbItemDesc itemDesc = itemService.geTbItemDescById(id);
- //返回商品描述信息
- return itemDesc.getItemDesc();
- }
- @RequestMapping(value="/item/param/{id}", produces=MediaType.TEXT_HTML_VALUE+";charset=utf-8")
- @ResponseBody
- public String showItemParam(@PathVariable Longid) throws Exception {
- //取規格參數
- String itemParamItem = itemService.geTbItemParamItemById(id);
- //返回規格參數信息
- return itemParamItem;
- }
- }
2.4.4. 效果:
2.5. 添加緩存邏輯
- @Override
- public TbItem getItemById(Long id) throws Exception {
- //緩存中命中
- //在redis中無法對hash中的可以做expire。所以使用另外一種方法:key的命名方法爲“主key:id”
- String itemCache = jedisCluster.get(TB_ITEM_KEY + ":" + id);
- try {
- if (!StringUtils.isBlank(itemCache)) {
- TbItem tbItem = JsonUtils.jsonToPojo(itemCache, TbItem.class);
- return tbItem;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- //如果緩存中沒有數據,查詢數據庫
- TbItem tbItem = itemMapper.selectByPrimaryKey(id);
- //把數據緩存起來
- try {
- jedisCluster.set(TB_ITEM_KEY + ":" + id, JsonUtils.objectToJson(tbItem));
- //設置過期時間,有效期一天
- jedisCluster.expire(TB_ITEM_KEY + ":" + id, 60*60*24);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return tbItem;
- }
3. 緩存同步
Redis是內存數據庫也屬於稀缺資源,所以不應該永久佔用,所以要設置過期時間。當商品內容更新後,需要同步緩存。同步方法參見內容部分的緩存同步方法。