Migo商城2.0 门户首页左侧商品类目显示 十四

Migo商城2.0 门户首页左侧商品类目显示 十四

新建后台提供系统服务,这里就不再新建专门提供服务的项目了(也是因为访问的网址里有rest这个字眼了)

先看下jd的商品类目返回的数据格式:

因为扒的页面是jd之前的,没有添加这么多,缺少了1 3 4部分,其实也就添加了几个键值对,不影响数据结构的设计

本项目要实现的数据结构(部分数据):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
"data": [
{
"u": "/products/1.html",
"n": "<a href='/products/1.html'>图书、音像、电子书刊</a>",
"i": [
{
"u": "/products/2.html",
"n": "电子书刊",
"i": [
"/products/3.html|电子书",
"/products/4.html|网络原创",
"/products/5.html|数字杂志",
"/products/6.html|多媒体图书"
]
},
{
"u": "/products/7.html",
"n": "音像",
"i": [
"/products/8.html|音乐",
"/products/9.html|影视",
"/products/10.html|教育音像"
]
},
{
"u": "/products/11.html",
"n": "英文原版",
"i": [
"/products/12.html|少儿",
"/products/13.html|商务投资",
"/products/14.html|英语学习与考试",
"/products/15.html|小说",
"/products/16.html|传记",
"/products/17.html|励志"
]
}
}

因为没有设计专门的rest服务工程,这里将结构pojo放在common工程中以供通用,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.migo.pojo;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

/**
* Author 知秋
* Created by kauw on 2016/10/9.
*/
public class CatNode {
// 序列化成json数据时为 u ,不明白请谷歌
@JsonProperty("u")
private String url;
@JsonProperty("n")
private String name;
@JsonProperty("i")
private List items;

public List getItems() {
return items;
}

public void setItems(List items) {
this.items = items;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.migo.pojo;

import java.util.List;

/**
* Author 知秋
* Created by kauw on 2016/10/9.
*/
public class ItemCatResult {
private List data;

public List getData() {
return data;
}

public void setData(List data) {
this.data = data;
}
}

为更好的符合类的名字的含义,和更好的理解性,对ItemCatResult 稍做改造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.migo.pojo;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.List;

/**
* Author 知秋
* Created by kauw on 2016/10/9.
*/
public class ItemCatResult {
@JsonProperty("data")
private List<CatNode> catNodes=new ArrayList<>();

public List<CatNode> getCatNodes() {
return catNodes;
}

public void setCatNodes(List<CatNode> catNodes) {
this.catNodes = catNodes;
}
}

前台访问的URL : URL_Serv: "http://tomcat.migo.com/rest/webs/item/cat?callback=category.getDataService" lib-v1.js 1173行

后台代码:

service

tb_item_cat表中取数据,单表查询,可以使用通用mapper

返回结果:ItemCatResult

参数:没有

业务逻辑:根据parentid查询子节点列表,并递归调用



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* 查询,并生成jd页面类似的树状结构
* @return
*/
public ItemCatResult getItemCatList(){
ItemCatResult itemCatResult=new ItemCatResult();

//调用递归方法查询商品分类列表
List catList=getItemCatList(0L);
//返回结果
itemCatResult.setCatNodes(catList);
return itemCatResult;
}

private List getItemCatList(long parentId) {
//根据parentId查询列表


ItemCat example=new ItemCat();
example.setParentId(parentId);
List<ItemCat> catList = super.queryListByWhere(example);
List resultList=new ArrayList();
int count=0;
for (ItemCat itemCat : catList) {
//如果是父节点
if (itemCat.getIsParent()) {
CatNode node=new CatNode();
node.setUrl("/products/"+itemCat.getId()+".html");
//如果当前节点为第一级节点
if (itemCat.getParentId()==0) {
node.setName("<a href='/products/"+itemCat.getId()+".html'>"+itemCat.getName()+"</a>");
}else {
node.setName(itemCat.getName());
}
node.setItems(getItemCatList(itemCat.getId()));
//将node添加到列表
resultList.add(node);
count++;
//第一层只取14条记录
if (parentId==0&&count>=14){
break;
}
}else {
//如果是最底层叶子节点
String item = "/products/"+itemCat.getId()+".html|" + itemCat.getName();
resultList.add(item);
}
}
return resultList;
}

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.migo.controller.webs;

import com.migo.pojo.ItemCatResult;
import com.migo.service.ItemCatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* Author 知秋
* Created by kauw on 2016/11/17.
*/
@Controller
@RequestMapping("webs/item/cat")
public class WebsItemCatController {
private static final Logger logger= LoggerFactory.getLogger(WebsItemCatController.class);
@Autowired
private ItemCatService itemCatService;

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<ItemCatResult> getItemCatList(){
try {
if (logger.isInfoEnabled()) {
logger.info("查询商品类目数据服务");
}
ItemCatResult itemCatList = this.itemCatService.getItemCatList();
return ResponseEntity.ok(itemCatList);
} catch (Exception e) {
logger.error("查询商品类目数据服务 失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}

}
}

测试:

因为前端门户系统访问后台服务系统相当于跨域请求,这里,得使用jsonp,不了解的可以谷歌一下,回头有时间我会安利一下这个东西的原理,其实很简单,无非就是访问个js片段,具体看下面三点

1、 jsonp通过script标签的src可以跨域请求的特性,加载资源

2、 将加载的资源(通过一个方法名将数据进行包裹)当做是js脚本解析

3、 定义一个回调函数,获取传入的数据

添加callback参数

修改controller代码

MappingJacksonValue要求springmvc必须是4.1以上版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.migo.controller.webs;

import com.migo.pojo.ItemCatResult;
import com.migo.service.ItemCatService;
import com.migo.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* Author 知秋
* Created by kauw on 2016/11/17.
*/
@Controller
@RequestMapping("webs/item/cat")
public class WebsItemCatController {
private static final Logger logger= LoggerFactory.getLogger(WebsItemCatController.class);
@Autowired
private ItemCatService itemCatService;

@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> getItemCatList(String callback){
try {
if (logger.isInfoEnabled()) {
logger.info("查询商品类目数据服务");
}
ItemCatResult itemCatList = this.itemCatService.getItemCatList();
if (StringUtils.isEmpty(callback)) {
String json = JsonUtils.objectToJson(itemCatList);

return ResponseEntity.ok((Object) json);
}
//如果字符串不为空,需要支持jsonp调用
MappingJacksonValue mappingJacksonValue=new MappingJacksonValue(itemCatList);
mappingJacksonValue.setJsonpFunction(callback);
return ResponseEntity.ok((Object) mappingJacksonValue);
} catch (Exception e) {
logger.error("查询商品类目数据服务 失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}

}
}

运行结果:

进一步改造jsonp的支持

这是之前写的一个关于消息转换器的Demo,拿出一个类来足以说明了,看代码注释即可(可以处理输入和输出)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.zhiqiu.messageconverter;

import com.zhiqiu.domain.DemoObj;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.Charset;

/**
* Author 知秋
* Created by kauw on 2016/10/1.
*/
public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj>{
/**
* 表明只处理DemoObj这个类
* Class类的isAssignableFrom(Class cls)方法,
* 如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,
* 或者是参数cls表示的类或接口的父类,则返回true。
* 形象地:自身类.class.isAssignableFrom(自身类或子类.class) 返回true
* @param clazz
* @return
*/
@Override
protected boolean supports(Class<?> clazz) {
return DemoObj.class.isAssignableFrom(clazz) ;
}

/**
*
*处理请求数据
*/
@Override
protected DemoObj readInternal(Class<? extends DemoObj> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
String temp= StreamUtils.copyToString(inputMessage.getBody(),
Charset.forName("utf-8"));
String[] tempArr=temp.split("-");
return new DemoObj(new Long(tempArr[0]),tempArr[1]);
}
/**
* @author kauw 2016/10/1
* @time 23:45
* 处理如何输出数据到response
*/
@Override
protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {

String out="hello:"+obj.getId()+"-"+obj.getName();
outputMessage.getBody().write(out.getBytes());
}
}

因为StringHttpMessageConverter默认字符集为ISO-8859-1 如下部分源码码所示,修改springmvc配置文件的 mvc:annotation-driven,在自定义的转换器里去做就可以了,这里重写上面的 writeInternal方法

1
2
3
4
5
6
7
8
9
10
public class StringHttpMessageConverter extends AbstractHttpMessageConverter<String> {

public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");


private final Charset defaultCharset;

private final List<Charset> availableCharsets;

private boolean writeAcceptCharset = true;

common工程中添加自定义消息转换器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.migo.messageconverter;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class CallbackMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {

// 做jsonp的支持的标识,在请求参数中加该参数
private String callbackName;

@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException,
HttpMessageNotWritableException {
// 从threadLocal中获取当前的Request对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes()).getRequest();
String callbackParam = request.getParameter(callbackName);
if (StringUtils.isEmpty(callbackParam)) {
// 没有找到callback参数,直接返回json数据
super.writeInternal(object, outputMessage);
} else {
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
try {
String result = callbackParam + "(" + super.getObjectMapper().writeValueAsString(object)
+ ");";
IOUtils.write(result, outputMessage.getBody(), encoding.getJavaName());
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}

}

public String getCallbackName() {
return callbackName;
}

public void setCallbackName(String callbackName) {
this.callbackName = callbackName;
}

}

manage工程中配置springmvc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="com.migo.controller" />
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:properties/*.properties" />
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.migo.messageconverter.CallbackMappingJackson2HttpMessageConverter">
<property name="callbackName" value="callback"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>

<!-- 配置多媒体解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"/>
</bean>

</beans>

controller修改如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.migo.controller.webs;

import com.migo.pojo.ItemCatResult;
import com.migo.service.ItemCatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
* Author 知秋
* Created by kauw on 2016/11/17.
*/
@Controller
@RequestMapping("webs/item/cat")
public class WebsItemCatController {
private static final Logger logger= LoggerFactory.getLogger(WebsItemCatController.class);
@Autowired
private ItemCatService itemCatService;

/* @RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> getItemCatList(String callback){
try {
if (logger.isInfoEnabled()) {
logger.info("查询商品类目数据服务");
}
ItemCatResult itemCatList = this.itemCatService.getItemCatList();
if (StringUtils.isEmpty(callback)) {
String json = JsonUtils.objectToJson(itemCatList);

return ResponseEntity.ok((Object) json);
}
//如果字符串不为空,需要支持jsonp调用
MappingJacksonValue mappingJacksonValue=new MappingJacksonValue(itemCatList);
mappingJacksonValue.setJsonpFunction(callback);
return ResponseEntity.ok((Object) mappingJacksonValue);
} catch (Exception e) {
logger.error("查询商品类目数据服务 失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}

}*/
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<ItemCatResult> getItemCatList(){
try {
if (logger.isInfoEnabled()) {
logger.info("查询商品类目数据服务");
}
ItemCatResult itemCatList = this.itemCatService.getItemCatList();


return ResponseEntity.ok(itemCatList);
} catch (Exception e) {
logger.error("查询商品类目数据服务 失败", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}

}
}

重启项目进行测试:结果如下图:

您的支持将鼓励我继续创作!