第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第九天】(商品詳情頁面實現)

https://pan.baidu.com/s/1bptYGAb#list/path=%2F&parentPath=%2Fsharelink389619878-229862621083040html

第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第五天】java

第04項目:淘淘商城(SpringMVC+Spring+Mybatis) 的學習實踐總結【第六天】ajax

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第七天】(redis緩存)redis

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第八天】(solr服務器搭建、搜索功能實現)spring

第04項目:淘淘商城(SpringMVC+Spring+Mybatis)【第九天】(商品詳情頁面實現)json

 


 

1   課程計劃

今天的內容:緩存

一、在taotao-portal工程中調用taotao-search工程發佈的服務。實現商品搜索功能。服務器

二、點擊商品的圖片,打開商品詳情頁面app

a)       商品基本信息框架

b)       延遲加載商品詳情。延遲一秒加載使用ajax

c)       商品的規格參數。按需加載,當用戶點擊商品規格參數tab頁,加載ajax。


需求分析

用戶在首頁中輸入查詢條件,點擊查詢向taotao-portal發送請求,參數就是查詢的條件,頁碼。Taoto-portal調用taotao-search發佈的服務進行搜索,參數應該是查詢條件和頁碼及每頁顯示的記錄數(參數可選)。Taotao-search返回一個json格式的數據(TaotaoResult包裝一個SearchResult對象)。Taotao-portal接收json數據須要把json數據轉換成java對象。把java對象傳遞給jsp頁面,jsp渲染java對象獲得商品查詢結果頁面。

請求url:http://localhost:8082/search.html?q=查詢條件

2.3   Service層

接收兩個參數一、查詢條件二、頁碼。調用taotao-search的搜索服務。接收返回的json數據,把json轉換成java對象返回SearchResult對象。

@Service
public class SearchServiceImpl implements SearchService {

    @Value("${SEARCH_BASE_URL}")
    private String SEARCH_BASE_URL;

    @Override
    public SearchResult search(String queryString, int page) {
        // 調用taotao-search的服務
        // 查詢參數
        Map<String, String> param = new HashMap<>();
        param.put("q", queryString);
        param.put("page", page + "");
        try {
            // 調用服務獲得JSON格式
            String json = HttpClientUtil.doGet(SEARCH_BASE_URL, param);
            // 把字符串轉換成java對象
            TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, SearchResult.class); if (taotaoResult.getStatus() == 200) {
                SearchResult result = (SearchResult) taotaoResult.getData();
                return result;
            }

        } catch (Exception e) {
            e.printStackTrace();

        }
        // 程序正常執行走try{}代碼塊,必然會return rsult;
        // 此處的return null;只是爲了這個方法返回值類型檢查不報錯
        return null;
    }

}

 

2.4    Controller層

功能:接收請求的參數查詢條件和頁碼。調用Service查詢商品列表獲得SearchResult對象。

須要把

Query:回顯的查詢條件

totalPages:總頁數

itemList:商品列表

Page:當前頁碼

傳遞到頁面。返回一個邏輯視圖search字符串。

//首頁商品搜索Controller
@Controller
public class PortalSearchController {

    @Autowired
    private SearchService searchService;
    
    @RequestMapping("/search")
    public String search(@RequestParam("q")String queryString, 
            @RequestParam(defaultValue="1")Integer page, Model model) {
        
        if (queryString != null) {
            try {
                //防止字符串亂碼
                queryString = new String(queryString.getBytes("iso8859-1"), "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        SearchResult searchResult = searchService.search(queryString, page);
        //向頁面傳遞參數
        model.addAttribute("query", queryString);
        model.addAttribute("totalPages", searchResult.getPageCount());
        model.addAttribute("itemList", searchResult.getItemList());
        model.addAttribute("page", page);
        
        return "search";
        
    }
}

 

2.5    存在的問題

搜索結果中圖片展現不出來,image字段中存儲的圖片是多張,使用逗號分隔。

修改方法:

Pojo:

package com.taotao.common.pojo;

public class Item {
    private String id;
    private String title;
    private String sell_point;
    private long price;
    private String image;
    private String category_name;
    private String item_des;
    
    public String[] getImages() {
        if(image != null) {
            String[] images = image.split(",");
            return images;
        }
        return null;
    }

 

3   商品詳情頁面展現

3.1    需求分析

須要在taotao-portal中調用taotao-rest發佈的服務,查詢商品詳情。

一、商品的基本信息

二、商品的描述

三、商品的規格

 

當用戶請求商品詳情頁面時,只須要把商品基本信息展現出來,爲了快速響應用戶。商品的描述能夠延遲加載,延遲一秒鐘加載。商品的規格參數按需加載,當用戶點擊商品規格參數的標籤頁此時再加載。

 

3.2    服務發佈

須要在taotao-rest工程中發佈服務

一、取商品基本信息的服務

二、取商品描述的服務

三、取商品規格的服務

須要把商品信息添加到緩存中。設置商品的過時時間,過時時間爲一天。須要緩存同步。

 

3.2.1   取商品基本信息

Dao層

查詢的表tb_item

Service層

接收商品id,根據商品id查詢商品基本信息。返回一個商品的pojo,使用taotaoResult包裝返回。

/**
 * 商品信息管理Service
 * 
 * @author kangy
 *
 */
@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private TbItemMapper itemMapper;

    @Override
    public TaotaoResult getItemBaseInfo(long itemId) {
//        根據商品ID查詢商品信息
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
//        使用TaoTaoresult包裝一下
        return TaotaoResult.ok(item);
    }

}
View Code ItemServiceImpl

Controller層

接收商品id調用Service查詢商品信息,返回商品對象,使用TaotaoResult包裝。

Url:/rest/item/info/{itemId}

@RestController
@RequestMapping("/item")
public class ItemController {

    @Autowired
    private ItemService itemService;
    
    @RequestMapping("/info/{itemId}")
    public TaotaoResult getItemBaseInfo(@PathVariable Long itemId) {
        TaotaoResult result = itemService.getItemBaseInfo(itemId);
        return result;
    }
    
}

 

添加緩存邏輯

Redis的hash類型中的key是不能設置過時時間。若是還須要對key進行分類能夠使用折中的方案。

Key的命名方式:

Itheima:javaee16:01=劉備

Itheima:javaee16:02=張飛


 

商品key的定義:

基本信息:

REDIS_ITEM_KEY:商品id:base=json

描述:

REDIS_ITEM_KEY:商品id:desc=json

規格參數:

REDIS_ITEM_KEY:商品id:param=json

/**
 * 商品信息管理Service
 * 
 * @author kangy
 *
 */
@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private TbItemMapper itemMapper;
    @Value("${REDIS_ITEM_KEY}")
    private String REDIS_ITEM_KEY;
    @Value("${REDIS_ITEM_EXPIRE}")
    private Integer REDIS_ITEM_EXPIRE;

    @Autowired
    private JedisClient jedisClient;

    @Override
    public TaotaoResult getItemBaseInfo(long itemId) {

        try {
            // 添加緩存邏輯
            // 從緩存中取商品信息,商品id對應的信息
            String json = jedisClient.get(REDIS_ITEM_KEY + ":" + itemId + ":base");
            // 判斷是否有值
            // commons.lang3.StringUtils
            if (!StringUtils.isBlank(json)) {
                // 把json轉換成java對象
                TbItem item = JsonUtils.jsonToPojo(json, TbItem.class);
                return TaotaoResult.ok(item);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

//        根據商品ID查詢商品信息
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
//        使用TaoTaoresult包裝一下
        try {
            // 把商品信息寫入緩存
            jedisClient.set(REDIS_ITEM_KEY + ":" + itemId + ":base", JsonUtils.objectToJson(item));
            // 設置key的有效期
            jedisClient.expire(REDIS_ITEM_KEY + ":" + itemId + ":base", REDIS_ITEM_EXPIRE);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return TaotaoResult.ok(item);
    }

}
public class ItemServiceImpl

 

3.2.2   取商品描述信息

根據商品id取商品描述信息。單表查詢tb_item_desc。

Dao層

使用逆向工程

Service層

接收商品id根據商品id查詢商品描述。返回商品描述的pojo。使用TaotaoResult包裝。

須要添加緩存邏輯。

    @Override
    public TaotaoResult getItemDesc(long itemId) {

        // 添加緩存邏輯
        try {
            // 1.從緩存中取商品描述,商品id對應的信息
            String json = jedisClient.get(REDIS_ITEM_KEY + ":" + itemId + ":desc");
            // 判斷是否有值
            // commons.lang3.StringUtils
            if (!StringUtils.isBlank(json)) {
                // 把json轉換成java對象
                TbItemDesc itemDesc = JsonUtils.jsonToPojo(json, TbItemDesc.class);
                return TaotaoResult.ok(itemDesc);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 2.根據商品id查詢商品描述
        TbItemDesc itemDesc = itemDescMapper.selectByPrimaryKey(itemId);

        try {
            // 3.把商品描述寫入緩存
            jedisClient.set(REDIS_ITEM_KEY + ":" + itemId + ":desc", JsonUtils.objectToJson(itemDesc));
            // 設置key的有效期
            jedisClient.expire(REDIS_ITEM_KEY + ":" + itemId + ":desc", REDIS_ITEM_EXPIRE);

        } catch (Exception e) {
            e.printStackTrace();
        }

        // 4.使用TaoTaoresult包裝一下
        return TaotaoResult.ok(itemDesc);
    }

 

3.2.3  取商品規格參數

須要從tb_item_param_item表中根據商品id取出商品的規格參數信息。返回pojo對象,使用TaotaoResult包裝。

Service層

接收商品id調用mapper查詢商品規格參數,返回規格參數pojo使用TaotaoResult包裝。

添加緩存邏輯。

    @Override
    public TaotaoResult getItemParam(long itemId) {
        // 添加緩存
        try {
            // 添加緩存邏輯
            // 從緩存中取商品信息,商品id對應的信息
            String json = jedisClient.get(REDIS_ITEM_KEY + ":" + itemId + ":param");
            // 判斷是否有值
            if (!StringUtils.isBlank(json)) {
                // 把json轉換成java對象
                TbItemParamItem paramItem = JsonUtils.jsonToPojo(json, TbItemParamItem.class);
                return TaotaoResult.ok(paramItem);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 根據商品id查詢規格參數
        // 設置查詢條件
        TbItemParamItemExample example = new TbItemParamItemExample();
        TbItemParamItemExample.Criteria criteria = example.createCriteria();
        criteria.andItemIdEqualTo(itemId);
        // 執行查詢
        List<TbItemParamItem> list = itemParamItemMapper.selectByExampleWithBLOBs(example);
        
        if (list != null && list.size() > 0) {
            TbItemParamItem paramItem = list.get(0);
            try {
                // 把商品信息寫入緩存
                jedisClient.set(REDIS_ITEM_KEY + ":" + itemId + ":param", JsonUtils.objectToJson(paramItem));
                // 設置key的有效期
                jedisClient.expire(REDIS_ITEM_KEY + ":" + itemId + ":param", REDIS_ITEM_EXPIRE);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return TaotaoResult.ok(paramItem);
        }
        return TaotaoResult.build(400, "無此商品規格");
    }

3.3    使用taotao-portal調用服務

需求分析

當用戶訪問商品詳情頁面時,須要加載商品基本信息。延遲加載商品描述、按需加載商品的規格參數。

商品基本信息的查詢

當商品頁面展現時,數據已經到位。

請求的url:/item/{itemId}.html

接收商品id,調用taotao-rest的服務,查詢商品的基本信息。獲得一個json字符串。須要把json轉換成java對象。而後在jsp頁面渲染。

@Service
public class ItemServiceImpl implements ItemService {
    @Value("${REST_BASE_URL}")
    private String REST_BASE_URL;
    @Value("${ITEM_INFO_URL}")
    private String ITEM_INFO_URL;

    @Override
    public TbItem getItemById(Long itemId) {
        try {
            //調用rest的服務查詢商品基本信息
            String json = HttpClientUtil.doGet(REST_BASE_URL + ITEM_INFO_URL + itemId);
            if(!StringUtils.isBlank(json)) {
                TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, ItemInfo.class);
                //須要判斷並強轉變量類型
                if(taotaoResult.getStatus() == 200) {
                    TbItem item = (TbItem) taotaoResult.getData();
                    return item;
                }
            
            }
        
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }

}

 

Controller層

接收頁面傳遞過來的商品id,調用Service查詢商品基本信息。傳遞給jsp頁面。返回邏輯視圖,展現商品詳情頁面。

@Controller
public class ItemController {

    @Autowired
    private ItemService itemService;

    @RequestMapping("/item/{itemId}")
    public String showItem(@PathVariable Long itemId, Model model) {
        TbItem item = itemService.getItemById(itemId);
        model.addAttribute("item", item);

        return "item";

    }

}

 

商品POJO:

package com.taotao.portal.pojo;

import com.taotao.pojo.TbItem;

public class ItemInfo extends TbItem {
    
    public String[] getImages() {
        String image = getImage();
        if (image != null) {
            String[] images = image.split(",");
            return images;
        }
        
        return null;
    }

}

 

商品描述延遲加載

當商品詳情頁面加載完畢後延遲一秒鐘ajax請求商品詳情。

請求的URL:/item/desc/{itemId}.html

參數:商品id

返回值:商品描述信息(html片斷)

Service層

接收商品id,調用taotao-rest的服務根據商品id查詢商品描述信息。獲得json數據。把json轉換成java對象。從java對象中把商品描述取出來。返回商品描述字符串。

參數:商品id

返回值:字符串(商品描述的html片斷)

    /**
     * 取商品描述
     */
    @Override
    public String getItemDescById(Long itemId) {
        try {
            // 調用rest的服務查詢商品描述基本信息
            String json = HttpClientUtil.doGet(REST_BASE_URL + ITEM_DESC_URL + itemId);
            // 轉換成java對象
            TaotaoResult taotaoResult = TaotaoResult.formatToPojo(json, TbItemDesc.class);

            if (taotaoResult.getStatus() == 200) {
                TbItemDesc itemDesc = (TbItemDesc) taotaoResult.getData();
                // 取商品描述信息
                String result = itemDesc.getItemDesc();
                return result;
            }

        } catch (Exception e) {
            e.printStackTrace();// TODO: handle exception
        }

        return null;

    }

 

Controller層

接收商品id,調用Service查詢商品的描述信息,返回一個字符串,是商品描述的片斷。須要使用@ResponseBody。

    @RequestMapping(value="/item/desc/{itemId}", produces=MediaType.TEXT_HTML_VALUE+";charset=utf-8")
    @ResponseBody
    public String getItemDesc(@PathVariable Long itemId) {
        String string = itemService.getItemDescById(itemId);
        return string;
    }

 

商品規格參數展現

按需加載。當用戶點擊規格參數tab頁時觸發一個單擊事件,在事件中異步加載規格參數信息。規格參數內容是html片斷。返回字符串。

    @Override
    public String getItemParam(Long itemId) {
        try {
            String json = HttpClientUtil.doGet(REST_BASE_URL + ITEM_PARAM_URL + itemId);
            //把json轉換成java對象
            TaotaoResult taotaoResult = TaotaoResult.formatToList(json, TbItemParamItem.class);
            if (taotaoResult.getStatus() == 200) {
                TbItemParamItem itemParamItem = (TbItemParamItem) taotaoResult.getData();
                String paramData = itemParamItem.getParamData();
                //生成html
                // 把規格參數json數據轉換成java對象
                List<Map> jsonList = JsonUtils.jsonToList(paramData, Map.class);
                StringBuffer sb = new StringBuffer();
                sb.append("<table cellpadding=\"0\" cellspacing=\"1\" width=\"100%\" border=\"0\" class=\"Ptable\">\n");
                sb.append("    <tbody>\n");
                for(Map m1:jsonList) {
                    sb.append("        <tr>\n");
                    sb.append("            <th class=\"tdTitle\" colspan=\"2\">"+m1.get("group")+"</th>\n");
                    sb.append("        </tr>\n");
                    List<Map> list2 = (List<Map>) m1.get("params");
                    for(Map m2:list2) {
                        sb.append("        <tr>\n");
                        sb.append("            <td class=\"tdTitle\">"+m2.get("k")+"</td>\n");
                        sb.append("            <td>"+m2.get("v")+"</td>\n");
                        sb.append("        </tr>\n");
                    }
                }
                sb.append("    </tbody>\n");
                sb.append("</table>");
                //返回html片斷
                return sb.toString();
            }
                 
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return "";
    }

Controller層

頁面的ajax請求Controller,請求的url://item/param/{itemId}.html

響應一個字符串。規格參數的片斷。@ResponseBody。

@RequestMapping(value="/item/param/{itemId}", produces=MediaType.TEXT_HTML_VALUE+";charset=utf-8")
    @ResponseBody
    public String getItemParam(@PathVariable Long itemId) {
        String string = itemService.getItemParam(itemId);
        return string;
    }

5.2    用戶註冊

5.2.1   需求分析

請求方法爲post,客戶端提交表單。包含

username //用戶名

password //密碼

phone //手機號

email //郵箱

接收參數調用mapper向user表中添加記錄。返回taotaoResult對象。若是成功200失敗400異常500.

5.2.2   Dao層

能夠使用逆向工程生成代碼

5.2.3   Service層

接收TbUser對象,補全user的屬性。向tb_user表插入記錄。返回taoTaoResult。

    @Override
    public TaotaoResult createUser(TbUser user) {
        user.setUpdated(new Date());
        user.setCreated(new Date());
        //spring框架的MD5工具加密
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        userMapper.insert(user);
        return TaotaoResult.ok();
    }

Controller層

    //建立用戶的方法
    @RequestMapping("/register")
    public TaotaoResult createUser(TbUser user) {
        try {
            TaotaoResult result = userService.createUser(user);
            return result;
            
        } catch (Exception e) {
            return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
        }
        
        
    }

 

 

 

 

==========================================================

參考資料:

end

相關文章
相關標籤/搜索