商品详情页
访问的链接:item.jd.com/商品ID.html
模拟它,我们的链接:www.jt.com/item/商品ID.html
查询商品数据
后台系统提供接口,利用httpclient方式。
获取商品详情
返回值问题:采用SysResult。原因:可以通过状态判断是否调用正常,如果200成功,才去获取数据,否则抛出异常。如果只按返回结果为空来判断,那很多特殊情况我们就无从判别。例如:按ID去查询,ID就不存在,返回为空,当做没有查询到记录,这显示是不合理的。这也就是为什么专门去构造一个SysResult对象。接口返回调用的状态、信息等内容。
注意:
可以引入后台系统中的Item对象,也可以在前台系统中创建新的pojo。使用哪种方式呢?依赖后台会加进很多class,所以重新创建的好。而且后台的pojo的JTA注解都可以去掉。
com.jt.web.pojo.Item
package com.jt.web.pojo;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonIgnore;
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 Integer status;
private Date created;
private Date updated;
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSellPoint() {
return sellPoint;
}
public void setSellPoint(String sellPoint) {
this.sellPoint = sellPoint;
}
public Long getPrice() {
return price;
}
public void setPrice(Long price) {
this.price = price;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public String getBarcode() {
return barcode;
}
public void setBarcode(String barcode) {
this.barcode = barcode;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public Long getCid() {
return cid;
}
public void setCid(Long cid) {
this.cid = cid;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@JsonIgnore //json序列化时将java bean中的一些属性忽略掉
public String[] getImages() {
if (null != getImage()) {
return getImage().split(",");
}
return null;
}
@Override
public String toString() {
return "Item [id=" + id + ", title=" + title + ", sellPoint=" + sellPoint + ", price=" + price
+ ", num=" + num + ", barcode=" + barcode + ", image=" + image + ", cid=" + cid + ", status="
+ status + ", created=" + getCreated() + ", updated=" + getUpdated() + "]";
}
}
注意:重点在于image存放了多张图片,链接之间用逗号隔开,增加getImages方法来查分获取image数组。
在com.jt.manage.controller.ItemController增加查询方法。
/**
* 通过id查询商品数据
*
* @param id
* @return
*/
@RequestMapping("query/{id}")
@ResponseBody
public SysResult queryList(@PathVariable("id") Long id) {
try {
Item item = this.itemService.queryById(id);
if (item != null && item.getId() != null) {
return SysResult.ok(item);
}
} catch (Exception e) {
e.printStackTrace();
return SysResult.build(202, "查询失败! id = " + id);
}
return SysResult.build(201, "查询不到商品数据 id = " + id);
}
com.jt.web.service.ItemService
public Item queryItemById(Long itemId) {
// 数据从后台管理系统中获取,通过Httpclient获取
String url = MANAGE_URL + "/item/query/" + itemId;
Item item = null;
try {
String jsonData = this.httpClientService.doGet(url);
SysResult sysResult = SysResult.formatToPojo(jsonData, Item.class);
item = (Item) sysResult.getData();
} catch (Exception e) {
e.printStackTrace();
}
return item;
}
com.jt.web.controller.ItemController
package com.jt.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.jt.manage.pojo.Item;
import com.jt.manage.pojo.ItemDesc;
import com.jt.web.service.ItemService;
@RequestMapping("item")
@Controller
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("{itemId}")
public ModelAndView showItem(@PathVariable("itemId") Long itemId) {
ModelAndView mv = new ModelAndView("item");
// 查询商品信息
Item item = this.itemService.queryItemById(itemId);
mv.addObject("item", item);
return mv;
}
}
标题显示商品标题
item.jsp
<title>${item.title} - 京淘</title>
商品价格
使用JSTL标签进行格式化:
groupingUsed是否千位符, Digits保留几位小数
¥<fmt:formatNumber groupingUsed="false" maxFractionDigits="2" minFractionDigits="2" value="${item.price / 100 }"/>
通过EL表达式展示商品属性
<div class="dt">商品编号:</div><div class="dd">
<span>${item.id }</span>
</div>
……
<div class="detail-content">
${itemDesc.itemDesc }
</div>
显示商品规格参数数据
com.jt.web.controller.ItemController
package com.jt.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.jt.manage.pojo.ItemDesc;
import com.jt.web.pojo.Item;
import com.jt.web.service.ItemService;
@RequestMapping("item")
@Controller
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("{itemId}")
public ModelAndView showItem(@PathVariable("itemId") Long itemId) {
ModelAndView mv = new ModelAndView("item");
// 查询商品信息
Item item = this.itemService.queryItemById(itemId);
mv.addObject("item", item);
//加载商品描述信息
ItemDesc itemDesc = this.itemService.queryItemDescByItemId(itemId);
mv.addObject("itemDesc", itemDesc);
// 加载商品规格参数
String itemParam = this.itemService.queryItemParamItemByItemId(itemId);
mv.addObject("itemParam", itemParam);
return mv;
}
}
com.jt.web.service.ItemService
package com.jt.web.service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.jt.common.service.RedisService;
import com.jt.common.spring.exetend.PropertyConfig;
import com.jt.common.vo.SysResult;
import com.jt.manage.pojo.ItemDesc;
import com.jt.manage.pojo.ItemParamItem;
import com.jt.web.pojo.Item;
@Service
public class ItemService {
@Autowired
private ApiService apiService;
@PropertyConfig
private String MANAGE_URL;
@Autowired
private RedisService redisService;
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final String REDIS_ITEM_KEY = "URL_WEB_ITEM_";
private static final String REDIS_ITEM_DESC_KEY = "URL_WEB_ITEM_DESC_";
private static final String REDIS_ITEM_PARAM_ITEM_KEY = "URL_WEB_ITEM_PARAM_ITEM_";
public Item queryItemById(Long itemId) {
String key = REDIS_ITEM_KEY + itemId;
// 从缓存中命中
try {
String redisData = this.redisService.get(key);
if (StringUtils.isNoneEmpty(redisData)) {
return MAPPER.readValue(redisData, Item.class);
}
} catch (Exception e1) {
e1.printStackTrace();
}
// 数据从后台管理系统中获取,通过Httpclient获取
String url = MANAGE_URL + "/item/query/" + itemId;
Item item = null;
try {
String jsonData = this.apiService.doGet(url);
SysResult sysResult = SysResult.formatToPojo(jsonData, Item.class);
item = (Item) sysResult.getData();
} catch (Exception e) {
e.printStackTrace();
}
if (null != item) {
// 写入到缓存中
try {
this.redisService.set(key, MAPPER.writeValueAsString(item),
60 * 60 * 24 * 10);
} catch (Exception e) {
e.printStackTrace();
}
}
return item;
}
public ItemDesc queryItemDescByItemId(Long itemId) {
String key = REDIS_ITEM_DESC_KEY + itemId;
// 从缓存中命中
try {
String redisData = this.redisService.get(key);
if (StringUtils.isNoneEmpty(redisData)) {
return MAPPER.readValue(redisData, ItemDesc.class);
}
} catch (Exception e1) {
e1.printStackTrace();
}
String url = MANAGE_URL + "/item/query/item/desc/" + itemId;
ItemDesc itemDesc = null;
try {
String jsonData = this.apiService.doGet(url);
SysResult sysResult = SysResult.formatToPojo(jsonData, ItemDesc.class);
itemDesc = (ItemDesc) sysResult.getData();
} catch (Exception e) {
e.printStackTrace();
}
if (null != itemDesc) {
// 写入到缓存中
try {
this.redisService.set(key, MAPPER.writeValueAsString(itemDesc),
60 * 60 * 24 * 10);
} catch (Exception e) {
e.printStackTrace();
}
}
return itemDesc;
}
/**
* 加载商品规格参数
*
* @param itemId
* @return
*/
public String queryItemParamItemByItemId(Long itemId) {
String key = REDIS_ITEM_PARAM_ITEM_KEY + itemId;
// 从缓存中命中
try {
String redisData = this.redisService.get(key);
if (StringUtils.isNoneEmpty(redisData)) {
return redisData;
}
} catch (Exception e1) {
e1.printStackTrace();
}
String url = MANAGE_URL + "/item/param/item/query/" + itemId;
String strResult = null;
try {
String jsonData = this.apiService.doGet(url);
SysResult sysResult = SysResult.formatToPojo(jsonData, ItemParamItem.class);
ItemParamItem itemParamItem = (ItemParamItem) sysResult.getData();
String paramData = itemParamItem.getParamData();
ArrayNode arrayNode = (ArrayNode) MAPPER.readTree(paramData);
StringBuilder sb = new StringBuilder();
sb.append("<table cellpadding=\"0\" cellspacing=\"1\" width=\"100%\" border=\"0\" class=\"Ptable\"><tbody>");
for (JsonNode jsonNode : arrayNode) {
sb.append("<tr><th class=\"tdTitle\" colspan=\"2\">" + jsonNode.get("group").asText()
+ "</th></tr><tr>");
ArrayNode params = (ArrayNode) jsonNode.get("params");
for (JsonNode param : params) {
sb.append("<tr><td class=\"tdTitle\">" + param.get("k").asText() + "</td><td>"
+ param.get("v").asText() + "</td></tr>");
}
}
sb.append("</tbody></table>");
strResult = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
if (null != strResult) {
// 写入到缓存中
try {
this.redisService.set(key, strResult, 60 * 60 * 24 * 30);
} catch (Exception e) {
e.printStackTrace();
}
}
return strResult;
}
public void updateRedis(Long itemId) {
this.redisService.del(REDIS_ITEM_KEY + itemId);
this.redisService.del(REDIS_ITEM_DESC_KEY + itemId);
this.redisService.del(REDIS_ITEM_PARAM_ITEM_KEY + itemId);
}
}
上面这种方式是在类中拼接html代码,这样做不是很好,如果格式变化,就需要修改类重新发布。那也可以在jsp页面循环,也有问题,在jsp页面解析json比较麻烦。当然也可以用js来解析json。它也有问题,如果使用js来生成,那搜索引擎是抓不到这动态生成的内容的。