接口对接知识点总结

目的

将严选和京东的货物商品详情拉取下来,添加到融e购中去。抽象的说就是拉取数据源,将其转为本地数据,将本地数据和目标数据源匹配,上传数据。

接口

  • pull()获取数据
  • transform()转变数据
  • push()提交数据

知识点总结

问题1

如何提交post请求,并接收返回的JSON内容?

总结

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
 /**
* @param url
* @param map 接收键值对的请求参数
* @param encoding 编码规则 utf-8
* @return 返回JSON对象
*/
public static JSONObject httpclientPost(String url, Map<String, String> map, String encoding) throws ParseException, IOException {
String body = "";
//创建httpclient对象
CloseableHttpClient client = HttpClients.createDefault();
//创建post方式请求对象
HttpPost httpPost = new HttpPost(url);
//装填参数
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
}
//设置参数到请求对象中
httpPost.setEntity(new UrlEncodedFormEntity(nvps, encoding));
//设置header信息
//指定报文头【Content-type】、【User-Agent】
//httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
//httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//执行请求操作,并拿到结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost);
//获取结果实体
HttpEntity entity = response.getEntity();
JSONObject jsonObject = null;
if (entity != null) {
//按指定编码转换结果实体为String类型
body = EntityUtils.toString(entity, encoding);
// 如果返回的不是JSON内容,这里删去,将返回类型设置为String,并返回body即可
jsonObject = JSONObject.parseObject(body);
}
EntityUtils.consume(entity);
//释放链接
response.close();
return jsonObject;
}

问题2

当同一接口类出现了不同实现类应该怎么区分?比如pull()接口有JD和严选两个实现类

回答

  • 可以使用工厂模式,Spring有个方法可以获取该接口的所有实现类applicationContext.getBeansOfType

    • 定义枚举类
    1
    2
    3
    public enum DataSourceCode {
    YX, RYG,JD
    }
    • 定义需要工厂处理的接口
    1
    2
    3
    4
    5
    6
    public interface DataPullService {
    // 业务方法
    void msg();
    // 得到枚举的值(必须有)
    DataSourceCode getCode();
    }
    • 实现接口,这里有多个实现类,这里举例一个
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Service
    public class RYGPullServiceImpl implements DataPullService {
    @Override
    public void msg() {
    System.out.println("业务逻辑");
    }
    // 融e购的就返回DataSourceCode.RYG,JD的就返回DataSourceCode.JD
    @Override
    public DataSourceCode getCode() {
    return DataSourceCode.RYG;
    }
    }
    • 定义工厂类实现ApplicationContextAware
    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
    @Component
    public class DataPullModeFactory implements ApplicationContextAware {
    // DataSourceCode 枚举类
    // DataPullService 需要工厂的接口
    private static Map<DataSourceCode, DataPullService> trafficBeanMap;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    Map<String, DataPullService> map = applicationContext.getBeansOfType(DataPullService.class);
    trafficBeanMap = new HashMap<>();
    map.forEach((key, value) -> trafficBeanMap.put(value.getCode(), value));
    }
    // 根据Controller传来的字段不同匹配之后返回不同的实现类
    public static <T extends DataPullService> T getTrafficMode(String code) {
    DataSourceCode sqlTypeEnum = null;
    // 将String字符串转枚举类型
    try {
    sqlTypeEnum = DataSourceCode.valueOf(code.toUpperCase());
    T t = (T) trafficBeanMap.get(sqlTypeEnum);
    return t;
    } catch (IllegalArgumentException ex) {
    log.error("没有该枚举类型");
    }
    // 当字符串和枚举类型不匹配返回null
    return null;
    }
    }
  • 在引入@Autowired注解的前提下再引入@Qualifier("XXX")其中XXX为接口实现类的注解@Service("XXX")的字段,或者引入@Resource(name = "XXX"),原因是@Autowired 是通过 byType,要求接口只能有一个实现类,@Resource 可以通过 byName 和 byType的方式注入

1
2
3
4
5
6
7
8
9
10
11
// Service类
@Service("XXX")
public interface DataPullService {
// 抽象逻辑
}
// 这两种方式都是按照类型引入,解决了同一接口拥有多种实现类的调用
@Autowired
@Qualifier("XXX")
private DataPullService dataPullService;
@Resource(name = "XXX")
private DataPullService dataPullService;

问题3

需求中获取图片传给我们的是一个css字符串,从字符串中获取图片url,该如何获取?

1
2
.ssd-module-wrap .M155981154483112{width:750px; background-size:100% 100%; background-image:url(//img30.360buyimg.com/sku/jfs/t1/73828/1/1315/122974/5cf8d522Eb33a4aa5/ccf3bf9a5a7fcc96.jpg); height:750px}
.ssd-module-wrap .M155981154486513{width:750px; background-size:100% 100%; background-image:url(//img30.360buyimg.com/sku/jfs/t1/80988/2/1326/216723/5cf8d522E2958353e/4d83696bb4d7cef8.jpg); height:955px}

回答

我采用的是正则匹配,将所有匹配该正则的字符串提取出来

1
2
3
4
5
6
7
8
9
10
List<String> strs = new ArrayList<String>();
// 以'//'开头 中间有许多其他的字符数据符号等用'.*'表示,匹配多种图片格式用'(gif|jpg|jpeg|bmp|png)'
String pattern = "//.*?(gif|jpg|jpeg|bmp|png)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(response);
while(m.find()) {
// 每匹配到一个符合要求的就将它添加到list中
// 这里因为获取到的url是不完整的,所有自行添加了http:
strs.add("http:"+m.group());
}

问题4

遇到需要自行截取字符串的需求,该是用什么方法?

回答

我采用的是substring的方法,但是有时候我们并不知道从哪个固定的索引开始截取,所以还必须使用indexOf方法,两者结合起来用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 /**
* 截取起始和终止之间的数据,不包含起始和终止
* @param str
* @param strStart
* @param strEnd
* @return
*/
public static String subString(String str, String strStart, String strEnd) {

/* 找出指定的2个字符在 该字符串里面的 位置 */
int strStartIndex = str.indexOf(strStart) + strStart.length();
int strEndIndex = str.indexOf(strEnd);

/* index为负数 即表示该字符串中没有该字符 */
if (strStartIndex < 0) {
return "字符串 :" + str + "中不存在 " + strStart + ", 无法截取目标字符串";
}
if (strEndIndex < 0) {
return "字符串 :" + str + "中不存在 " + strEnd + ", 无法截取目标字符串";
}
/* 开始截取 */
String result = str.substring(strStartIndex, strEndIndex);
return result;
}

问题5

需求中需要将javaBean转为xml,需要怎么操作?

回答

可以pom引入Jackson,fastJSon不支持javabean和xml的互转

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 将javaBean转为xml
public static String toXml(Object object) {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setDefaultUseWrapper(false);
// 字段为null,自动忽略,不再序列化
// xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
String xml = null;
try {
xml = xmlMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.append(xml);
String xmlMsg = sb.toString();
return xmlMsg;
}

在需要转xml的bean中添加注解来进行配置,告诉jackson需要如何转变

1
2
3
4
5
6
7
8
9
10
11
@Data
// 设置转xml的root标签
@JacksonXmlRootElement(localName = "body")
public class goods {
// 对于list的属性
@JacksonXmlElementWrapper(localName = "basicproperties")
@JacksonXmlProperty(localName = "basicproperty")
private List<basicproperty> basicproperties;
// 对于普通的属性 如果不添加注解 则是属性名当做标签,在这就是<sku_open_flag></sku_open_flag>
private String sku_open_flag;
}

问题6

如何将获取的JSON信息快速生成JavaBean?

回答

可以通过该网站生成,将JSON复制到其中,点击生成实体类即可

问题7

需求:接收图片的url,如果图片宽度不符合要求,则改变图片宽度,读取图片二进制内容进行BASE64编码,获取编码后的内容

回答

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
public class imageUtils {
static BASE64Encoder encoder = new sun.misc.BASE64Encoder();

public static String getBase64ByImgUrl(String url, String ImgCategoryId) {

URL urls = null;
try {
urls = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}

BufferedImage bi;
try {
bi = ImageIO.read(urls);
if ("101".equals(ImgCategoryId)) {
int width = bi.getWidth();
// 所有宽度不足708的 全部设置宽度为708
if (width < 708) {
BufferedImage imageNew = new BufferedImage(708, bi.getHeight(), BufferedImage.TYPE_INT_BGR);
Graphics2D g = (Graphics2D) imageNew.getGraphics();
g.drawImage(bi, 0, 0, 708, bi.getHeight(), null);
g.dispose();
imageNew.flush();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(imageNew, "png", baos);
byte[] bytes = baos.toByteArray();
return encoder.encodeBuffer(bytes).trim();
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, "png", baos);
byte[] bytes = baos.toByteArray();
return encoder.encodeBuffer(bytes).trim();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

问题7

如何将二进制文件进行Base64处理?

回答

java8之后可以采用java.util套件中新增的Base64工具类

1
2
3
4
5
6
7
8
9
final Base64.Decoder decoder = Base64.getDecoder();
final Base64.Encoder encoder = Base64.getEncoder();
final String text = "字串文字";
final byte[] textByte = text.getBytes("UTF-8");
//编码
final String encodedText = encoder.encodeToString(textByte);
System.out.println(encodedText);
//解码
System.out.println(new String(decoder.decode(encodedText), "UTF-8"));

问题8

需求:从List中每次取n个数据返回

回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static Map groupList(List list,int n){
int listSize=list.size();
int toIndex=n;
Map map = new HashMap();
int keyToken = 0;
for(int i = 0;i<list.size();i+=n){
if(i+n>listSize){
toIndex=listSize-i;
}
List newList = list.subList(i,i+toIndex);
map.put("keyName"+keyToken, newList);
keyToken++;
}
return map;
}

问题9

需求:sign需要32位MD5加密

回答

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
/**
* 32位小写MD5
*
* @param str
* @return
*/
public static String parseStrToMd5L32(String str) {

if (null == str) {
log.info(".parseStrToMd5L32() str is null.");
return str;
}
String reStr = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(str.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
int bt = b & 0xff;
if (bt < 16) {
sb.append(0);
}
sb.append(Integer.toHexString(bt));
}
reStr = sb.toString();
return reStr;
} catch (Exception e) {
log.error(".parseStrToMd5L32() Exception={},param={}", e, str);
throw new RuntimeException(e);
}
}

/**
* 32位大写MD5
*
* @param str
* @return
*/
public static String parseStrToMd5U32(String str) {
String reStr = parseStrToMd5L32(str);
if (null != reStr) {
reStr = reStr.toUpperCase();
}
return reStr;
}

问题10

需求:时间戳格式要求为yyyy-MM-dd HH:mm:ss,比如2019-09-06 14:08:23

回答

1
2
3
4
5
6
7
8
private static SimpleDateFormat defForMat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
/**
* 获取时间格式为yyyy-MM-dd HH:mm:ss
*/
public static String getDateTimeBySeparate() {
String timestamp = format(defForMat, new Date());
return timestamp;
}

问题11

如何将转换javaBean、JSONObject、JSONArray?使用fastJson

回答

1
2
3
4
5
6
7
8
9
10
11
12
// 整个JSONObject转javaBean
YXresult jsonsRootBean = JSONObject.toJavaObject(json, YXresult.class);
// JSONObject某个key转为一个javaBean
goodsDTO bean = jsonObject.getObject("bean", goodsDTO.class);
// String转JSONObject
JSONObject jsonObject = JSONObject.parseObject(string);
// JSONObject转JSONArray
JSONArray atrr = jsonObject.getJSONArray("atrr");
/**
* string 转为 JSONArray 该string格式为 [{"inventory":1718,"skuId":300005474}, *{"inventory":19,"skuId":3576043}]
*/
JSONArray resultArray = JSONArray.parseArray(result);

问题12

从List中如何获取相同的内容,组成一个新的List

回答

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
public static List<Attribute> getNewList(List<Attribute> list) {
HashMap<String, XXX> tempMap = new HashMap<>();
for (XXX attribute : list) {
//获取属性id
//将属性id相同的内容合并
String propId = attribute.getPropId();
//containsKey(Object key)该方法判断Map集合中是否包含指定的键名,如果包含返回true,不包含返回false
//containsValue(Object value)该方法判断Map集合中是否包含指定的键值,如果包含返回true,不包含返回false
if (tempMap.containsKey(propId)) {
Attribute p = new Attribute();
p.setCatId(attribute.getCatId());
p.setCatName(attribute.getCatName());
p.setPropId(attribute.getPropId());
p.setIsMust(attribute.getIsMust());
p.setPropName(attribute.getPropName());
List enumNameList = tempMap.get(propId).getEnumNameList();
String enumName = attribute.getEnumName();
if (tempMap.get(propId).getEnumName() != null) {
p.setEnumNameList(Arrays.asList(tempMap.get(propId).getEnumName(), attribute.getEnumName()));
} else {
List arrList = new ArrayList(enumNameList);
arrList.add(enumName);
p.setEnumNameList(arrList);
}
//HashMap不允许key重复,当有key重复时,前面key对应的value值会被覆盖
tempMap.put(propId, p);
} else {
tempMap.put(propId, attribute);
}
}

//去除重复 编号id 的 list
List<Attribute> newList = new ArrayList<>();
for (String temp : tempMap.keySet()) {
newList.add(tempMap.get(temp));
}
return newList;

}
赏个🍗吧
0%