Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,35 @@
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.15</version>
<scope>test</scope>
</dependency>
<!--如果是在Spring环境下测试,还需要添加一下依赖-->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand All @@ -105,6 +133,19 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.6.1</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/tencent/wxcloudrun/common/StatusType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.tencent.wxcloudrun.common;

/**
* 响应状态类型枚举
*/
public enum StatusType {
ILLEGAL_CITY_NAME(-1, "出发城市与目的城市需要为中文"),
ILLEGAL_DATE(-2, "不合法的日期,形式:yyyy-MM-dd"),
SERVER_ERROR(-3, "服务异常");

private int code;
private String msg;

StatusType(int code, String msg) {
this.code = code;
this.msg = msg;
}

public int getCode() {
return this.code;
}

public String getMsg() {
return this.msg;
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/tencent/wxcloudrun/config/ApiResponse.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.tencent.wxcloudrun.config;

import com.tencent.wxcloudrun.common.StatusType;
import lombok.Data;

import java.util.HashMap;
Expand All @@ -16,7 +17,7 @@ private ApiResponse(int code, String errorMsg, Object data) {
this.errorMsg = errorMsg;
this.data = data;
}

public static ApiResponse ok() {
return new ApiResponse(0, "", new HashMap<>());
}
Expand All @@ -28,4 +29,7 @@ public static ApiResponse ok(Object data) {
public static ApiResponse error(String errorMsg) {
return new ApiResponse(0, errorMsg, new HashMap<>());
}
public static ApiResponse error(StatusType type) {
return new ApiResponse(type.getCode(), type.getMsg(), new HashMap<>());
}
}
69 changes: 69 additions & 0 deletions src/main/java/com/tencent/wxcloudrun/config/BeanConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.tencent.wxcloudrun.config;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.protocol.HttpContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;


@Configuration
public class BeanConfig {
@Bean
RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
HttpClient httpClient = HttpClientBuilder.create()
/**
* 重定向策略
*/
.setRedirectStrategy(new LaxRedirectStrategy())
/**
* 重试策略
*/
.setRetryHandler(new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
if (executionCount >= 3) {
return false;
}
if (exception instanceof InterruptedIOException) {
return false;
}
if (exception instanceof UnknownHostException) {
return false;
}
if (exception instanceof ConnectTimeoutException) {
return false;
}
if (exception instanceof SSLException) {
return false;
}

HttpClientContext clientContext = HttpClientContext.adapt(context);
HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
return true;
}
return false;
}
})
.build();
factory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(factory);
return restTemplate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.tencent.wxcloudrun.controller;

import com.tencent.wxcloudrun.common.StatusType;
import com.tencent.wxcloudrun.config.ApiResponse;
import com.tencent.wxcloudrun.model.TrainInfo;
import com.tencent.wxcloudrun.service.TrainService;
import com.tencent.wxcloudrun.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.util.List;

@RestController
public class TrainController {
private final Logger logger = LoggerFactory.getLogger(TrainController.class);
private final TrainService trainTicketService;

TrainController(@Autowired TrainService trainTicketService) {
this.trainTicketService = trainTicketService;
}

/**
* 根据出发城市、目的城市以及日期查询火车票
*
* @param fromCity
* @param toCity
* @param date
* @return
*/
@GetMapping(value = "/api/train/ticket")
ApiResponse getTrainTicket(@RequestParam("from") String fromCity,
@RequestParam("to") String toCity,
@RequestParam("date") String date) {
logger.info("/api/train/ticket|from={}|to={}|date={}", fromCity, toCity, date);
if (!isChineseChar(fromCity) || !isChineseChar(toCity)) {
return ApiResponse.error(StatusType.ILLEGAL_CITY_NAME);
}
try {
LocalDate localDate = DateUtils.toDate(date);
List<TrainInfo> ticketInfoList = trainTicketService.search(fromCity, toCity, localDate);
return ApiResponse.ok(ticketInfoList);
} catch (Exception e) {
logger.error("/api/train/ticket|from={}|to={}|date={}|error={}", fromCity, toCity, date, ExceptionUtils.getMessage(e));
return ApiResponse.error(StatusType.SERVER_ERROR);
}
}

/**
* 判断是否为中文
*
* @param str
* @return
*/
private static boolean isChineseChar(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
for (int i = 0; i < str.length(); i++) {
int ch = str.charAt(i);
if (!(19968 <= ch && ch < 40869)) {
return false;
}
}
return true;
}


}
73 changes: 73 additions & 0 deletions src/main/java/com/tencent/wxcloudrun/manager/TuniuManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.tencent.wxcloudrun.manager;

import com.tencent.wxcloudrun.model.TuniuTrain;
import com.tencent.wxcloudrun.utils.RestTemplateUtils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class TuniuManager {

@Autowired
private RestTemplateUtils restTemplateutils;

private static final String BASE_URL = "http://huoche.tuniu.com/yii.php?r=train/trainTicket/getTickets&primary[departureDate]={date}&primary[departureCityName]={fromCity}&primary[arrivalCityName]={toCity}";

/**
* 查询途牛火车票服务
*
* @param fromCity
* @param toCity
* @param date
* @return
*/
public List<TuniuTrain> getTrainInfoList(String fromCity, String toCity, String date) {
TuniuEntity tuniuEntity = restTemplateutils.getForObject(BASE_URL, TuniuEntity.class, buildRequest(fromCity, toCity, date));
if (tuniuEntity == null || tuniuEntity.code == null || tuniuEntity.code != 200) {
return Collections.emptyList();
}
if (tuniuEntity.data != null) {
return tuniuEntity.data.list;
}
return Collections.emptyList();
}

/**
* 构建请求参数
*
* @param from
* @param to
* @param date
* @return
*/
private Map<String, String> buildRequest(String from, String to, String date) {
Map<String, String> paramMap = new HashMap<>();
paramMap.put("fromCity", from);
paramMap.put("toCity", to);
paramMap.put("date", date);
return paramMap;
}

/**
* 途牛响应结果实体
*/
@Data
private static class TuniuEntity {
Integer code;
TuniuData data;
}

@Data
private static class TuniuData {
Integer count;
List<TuniuTrain> list;
}


}
24 changes: 24 additions & 0 deletions src/main/java/com/tencent/wxcloudrun/model/TrainInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.tencent.wxcloudrun.model;


import lombok.Data;

/**
* 火车票信息数据
*/
@Data
public class TrainInfo {
private Integer trainId;
private String trainNum;
private String departStationName;
private String destStationName;
private String departDepartTime;
private String destArriveTime;
private String durationStr;
private Double businessSeatPrice;
private Integer businessSeatLeft;
private Double firstSeatPrice;
private Integer firstSeatLeft;
private Double secondSeatPrice;
private Integer secondSeatLeft;
}
30 changes: 30 additions & 0 deletions src/main/java/com/tencent/wxcloudrun/model/TuniuTrain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.tencent.wxcloudrun.model;

import lombok.Data;

import java.util.List;

/**
* 途牛火车票信息
*/
@Data
public class TuniuTrain {
private Integer trainId;
private String trainNum;
private String departStationName;
private String destStationName;
private String departDepartTime;
private String destArriveTime;
private String durationStr;
private List<SeatInfo> prices;

/**
* 途牛火车票座位信息
*/
@Data
public static class SeatInfo {
private String seatName;
private Integer leftNumber;
private Double price;
}
}
Loading