parent
275599c5fb
commit
cf42b08ad0
@ -1,432 +0,0 @@
|
|||||||
package ${domain};
|
|
||||||
package com.example.module;
|
|
||||||
|
|
||||||
import okhttp3.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
public class ApiClient {
|
|
||||||
private static ApiClient ourInstance = null;
|
|
||||||
|
|
||||||
public static void init(String serverUrl, String appKey, String appSecret) {
|
|
||||||
init(serverUrl, appKey, appSecret, DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void init(String serverUrl, String appKey, String appSecret, int connectTimeout, int readTimeout) {
|
|
||||||
ourInstance = new ApiClient(serverUrl, appKey, appSecret, connectTimeout, readTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ApiClient getInstance() {
|
|
||||||
if (ourInstance == null) {
|
|
||||||
System.err.print("ApiClient need init");
|
|
||||||
}
|
|
||||||
return ourInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
//基本请求参数KEY
|
|
||||||
private static final String P_APP_KEY = "app_key";
|
|
||||||
private static final String P_TYPE = "type";
|
|
||||||
private static final String P_TARGET = "target";
|
|
||||||
private static final String P_FILE_NAME = "file_name";
|
|
||||||
private static final String P_TIMESTAMP = "timestamp";
|
|
||||||
private static final String P_METHOD = "method";
|
|
||||||
private static final String P_SIGN = "sign";
|
|
||||||
private static final String P_TOKEN = "token_id";
|
|
||||||
private static final String P_ENHANCED = "enhanced";
|
|
||||||
//参数类型
|
|
||||||
private static final String TYPE_JSON = "json";
|
|
||||||
private static final String TYPE_FILE = "file";
|
|
||||||
//应用码
|
|
||||||
private String appKey;
|
|
||||||
//应用安全码
|
|
||||||
private String appSecret;
|
|
||||||
//服务器地址
|
|
||||||
private String serverUrl;
|
|
||||||
//公钥
|
|
||||||
private PublicKey publicKey = null;
|
|
||||||
private OkHttpClient httpClient = null;
|
|
||||||
//默认参数
|
|
||||||
private static final int DEFAULT_CONNECT_TIMEOUT = 3;//秒
|
|
||||||
private static final int DEFAULT_READ_TIMEOUT = 30;//秒
|
|
||||||
//请求配置
|
|
||||||
private int connectTimeout;//3秒
|
|
||||||
private int readTimeout;//30秒
|
|
||||||
private boolean needCheckRequest = true; // 是否在客户端校验请求
|
|
||||||
private boolean needEnableParser = true; // 是否对响应结果进行解释
|
|
||||||
|
|
||||||
private Before before = null;
|
|
||||||
private After after = null;
|
|
||||||
private String token = "";
|
|
||||||
private boolean debug = false;
|
|
||||||
|
|
||||||
private ApiClient(String serverUrl, String appKey, String appSecret, int connectTimeout, int readTimeout) {
|
|
||||||
this.connectTimeout = connectTimeout;
|
|
||||||
this.readTimeout = readTimeout;
|
|
||||||
this.appKey = appKey;
|
|
||||||
this.appSecret = appSecret;
|
|
||||||
this.serverUrl = serverUrl;
|
|
||||||
this.httpClient = new OkHttpClient.Builder()
|
|
||||||
.readTimeout(readTimeout, TimeUnit.SECONDS)
|
|
||||||
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublicKey(PublicKey publicKey) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Callback<T extends ApiResponse> {
|
|
||||||
void call(T response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Before {
|
|
||||||
void call(ApiRequest request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface After {
|
|
||||||
void call(ApiRequest request, ApiResponse response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAfter(After after) {
|
|
||||||
this.after = after;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBefore(Before before) {
|
|
||||||
this.before = before;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends ApiResponse> T execute(ApiRequest<T> request, boolean isEnhanced, ProgressRequestBody.ProgressListener listener) {
|
|
||||||
if (before != null) {
|
|
||||||
before.call(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查请求参数
|
|
||||||
T t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
if (isEnhanced && publicKey == null) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "publicKey can not be null.");
|
|
||||||
}
|
|
||||||
if (t.hasError()) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
//装载请求参数
|
|
||||||
String currentTime = String.valueOf(System.currentTimeMillis());
|
|
||||||
RequestBody requestBody = new MultipartBody.Builder()
|
|
||||||
.addFormDataPart(P_APP_KEY, appKey)
|
|
||||||
.addFormDataPart("isEnhanced", "false")
|
|
||||||
.addFormDataPart("encryptData", null, ProgressRequestBody.createProgressRequestBody(encode(request, isEnhanced), listener))
|
|
||||||
.addFormDataPart(P_TIMESTAMP, currentTime)
|
|
||||||
.addFormDataPart(P_SIGN, sign(request, currentTime))
|
|
||||||
.addFormDataPart(P_ENHANCED, String.valueOf(isEnhanced))
|
|
||||||
.addFormDataPart(P_TOKEN, token)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Request build = new Request.Builder()
|
|
||||||
.url(serverUrl + request.apiMethod())
|
|
||||||
.post(requestBody)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Response response = httpClient.newCall(build).execute();
|
|
||||||
String responseJson = decryptResponse(response, isEnhanced);
|
|
||||||
t = MapperUtil.toJava(responseJson, request.responseClass());
|
|
||||||
|
|
||||||
} catch (ConnectException e) {
|
|
||||||
t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
t.addError(ErrorType.SYSTEM_ERROR, "网络异常!");
|
|
||||||
} catch (SocketTimeoutException e) {
|
|
||||||
t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
t.addError(ErrorType.SYSTEM_ERROR, "请求超时!");
|
|
||||||
} catch (IOException e) {
|
|
||||||
t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
t.addError(ErrorType.SYSTEM_ERROR, "请求异常!");
|
|
||||||
} finally {
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends ApiResponse> void execute(ApiRequest<T> request, Callback callback) {
|
|
||||||
execute(request, false, callback, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T extends ApiResponse> void execute(final ApiRequest<T> request, final boolean isEnhanced, final Callback callback, ProgressRequestBody.ProgressListener listener) {
|
|
||||||
if (before != null) {
|
|
||||||
before.call(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查请求参数
|
|
||||||
T t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
if (isEnhanced && publicKey == null) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "publicKey can not be null.");
|
|
||||||
}
|
|
||||||
if (t.hasError()) {
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(t);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
//装载请求参数
|
|
||||||
String currentTime = String.valueOf(System.currentTimeMillis());
|
|
||||||
RequestBody requestBody = new FormBody.Builder()
|
|
||||||
.add(P_APP_KEY, appKey)
|
|
||||||
.add(P_METHOD, request.apiMethod())
|
|
||||||
.add(P_TYPE, TYPE_JSON)
|
|
||||||
// .add(P_TARGET, null, ProgressRequestBody.createProgressRequestBody(encode(request, isEnhanced), listener))
|
|
||||||
.add(P_TIMESTAMP, currentTime)
|
|
||||||
.add(P_SIGN, sign(request, currentTime))
|
|
||||||
.add(P_ENHANCED, String.valueOf(isEnhanced))
|
|
||||||
.add(P_TOKEN, token)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Request build = new Request.Builder()
|
|
||||||
.url(serverUrl + request.apiMethod())
|
|
||||||
.post(requestBody)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
httpClient.newCall(build).enqueue(new okhttp3.Callback() {
|
|
||||||
public void onFailure(Call call, IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
T t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
if (e instanceof ConnectException) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "网络异常!");
|
|
||||||
} else if (e instanceof SocketTimeoutException) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "请求超时!");
|
|
||||||
} else {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "请求异常!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResponse(Call call, Response response) throws IOException {
|
|
||||||
T t = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
String responseJson = decryptResponse(response, isEnhanced);
|
|
||||||
t = MapperUtil.toJava(responseJson, request.responseClass());
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
t = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "服务器走了下神!");
|
|
||||||
}
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
T baseResponse = MapperUtil.toJava("{}", request.responseClass());
|
|
||||||
baseResponse.addError(ErrorType.SYSTEM_ERROR, "请求异常!");
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, baseResponse);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(baseResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void fileUpload(final FileUploadRequest request, final Callback<FileUploadResponse> callback, ProgressRequestBody.ProgressListener listener) {
|
|
||||||
if (before != null) {
|
|
||||||
before.call(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
//检查文件是否存在
|
|
||||||
if (!request.isExist()) {
|
|
||||||
FileUploadResponse fileUploadResponse = new FileUploadResponse();
|
|
||||||
fileUploadResponse.addError(ErrorType.BUSINESS_ERROR, "文件不存在!");
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, fileUploadResponse);
|
|
||||||
}
|
|
||||||
callback.call(fileUploadResponse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//装载请求参数
|
|
||||||
String currentTime = String.valueOf(System.currentTimeMillis());
|
|
||||||
MultipartBody.Builder builder = new MultipartBody.Builder()
|
|
||||||
.addFormDataPart(P_APP_KEY, appKey)
|
|
||||||
.addFormDataPart(P_METHOD, request.apiMethod())
|
|
||||||
.addFormDataPart(P_TYPE, TYPE_FILE)
|
|
||||||
.addFormDataPart(P_TIMESTAMP, currentTime)
|
|
||||||
.addFormDataPart(P_SIGN, sign(request, currentTime))
|
|
||||||
.addFormDataPart(P_TOKEN, token);
|
|
||||||
|
|
||||||
if (request.getFile() != null) {
|
|
||||||
builder.addFormDataPart(P_TARGET, request.getFile().getName(), ProgressRequestBody.createProgressRequestBody(MediaType.parse("image/*"), request.getFile(), listener));
|
|
||||||
builder.addFormDataPart(P_FILE_NAME, request.getFileName());
|
|
||||||
} else {
|
|
||||||
builder.addFormDataPart(P_TARGET, null, ProgressRequestBody.createProgressRequestBody(Base64Util.encodeToString(request.getBytes()), listener));
|
|
||||||
builder.addFormDataPart(P_FILE_NAME, request.getFileName());
|
|
||||||
}
|
|
||||||
MultipartBody multipartBody = builder.build();
|
|
||||||
|
|
||||||
Request build = new Request.Builder()
|
|
||||||
.url(serverUrl)
|
|
||||||
.post(multipartBody)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
httpClient.newCall(build).enqueue(new okhttp3.Callback() {
|
|
||||||
public void onFailure(Call call, IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
FileUploadResponse t = MapperUtil.toJava("{}", FileUploadResponse.class);
|
|
||||||
if (e instanceof ConnectException) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "网络异常!");
|
|
||||||
} else if (e instanceof SocketTimeoutException) {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "请求超时!");
|
|
||||||
} else {
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "请求异常!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResponse(Call call, Response response) throws IOException {
|
|
||||||
|
|
||||||
FileUploadResponse t = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
String responseJson = decryptResponse(response, false);
|
|
||||||
t = MapperUtil.toJava(responseJson, FileUploadResponse.class);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
t = new FileUploadResponse();
|
|
||||||
t.addError(ErrorType.BUSINESS_ERROR, "服务器走了下神!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (after != null) {
|
|
||||||
after.call(request, t);
|
|
||||||
}
|
|
||||||
if (callback != null) {
|
|
||||||
callback.call(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对请求进行加密编码
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String encode(ApiRequest request, boolean isEnhanced) {
|
|
||||||
String json = MapperUtil.toJson(request);
|
|
||||||
if (isEnhanced) {
|
|
||||||
return RSAUtil.encrypt2Base64(json.getBytes());
|
|
||||||
} else {
|
|
||||||
return AESUtil.encrypt2Base64(json.getBytes(), appSecret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对响应进行解密
|
|
||||||
*
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String decryptResponse(Response response, boolean isEnhanced) throws IOException {
|
|
||||||
String responseString = response.body().string();
|
|
||||||
String responseJson;
|
|
||||||
if (isEnhanced) {
|
|
||||||
responseJson = RSAUtil.decrypt2String(responseString);
|
|
||||||
} else {
|
|
||||||
responseJson = AESUtil.decrypt2String(responseString, appSecret);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug) {
|
|
||||||
System.out.println("加密响应结果:" + responseString);
|
|
||||||
System.out.println("响应结果:" + responseJson);
|
|
||||||
}
|
|
||||||
return responseJson;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对请求进行签名
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private String sign(ApiRequest request, String currentTime) {
|
|
||||||
if (request instanceof FileUploadRequest) {//文件签名、对文件字节生成的信息摘要签名
|
|
||||||
FileUploadRequest fileUploadRequest = (FileUploadRequest) request;
|
|
||||||
String encode = MD5Util.encode(fileUploadRequest.getFile() != null ? toByteArray(fileUploadRequest.getFile()) : fileUploadRequest.getBytes());
|
|
||||||
return MD5Util.encode(appSecret + encode + currentTime);
|
|
||||||
} else {//普通参数签名、此处JSON是经过排序生成的JSON字符串,因此验签时也需要排序
|
|
||||||
String json = MapperUtil.toJson(request);
|
|
||||||
return MD5Util.encode(appSecret + json + currentTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] toByteArray(File file) {
|
|
||||||
File f = file;
|
|
||||||
if (!f.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
|
|
||||||
BufferedInputStream in = null;
|
|
||||||
try {
|
|
||||||
in = new BufferedInputStream(new FileInputStream(f));
|
|
||||||
int buf_size = 1024;
|
|
||||||
byte[] buffer = new byte[buf_size];
|
|
||||||
int len = 0;
|
|
||||||
while (-1 != (len = in.read(buffer, 0, buf_size))) {
|
|
||||||
bos.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
return bos.toByteArray();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTokenId(String token) {
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDebug() {
|
|
||||||
return debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDebug(boolean debug) {
|
|
||||||
this.debug = debug;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package ${domain};
|
|
||||||
|
|
||||||
import ${domain}.request.*;
|
|
||||||
import ${domain}.response.*;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ApiTest - 测试用例
|
|
||||||
*
|
|
||||||
* @author author
|
|
||||||
* @version 0.0.1
|
|
||||||
* @since 2019-06-11
|
|
||||||
*/
|
|
||||||
public class ApiTest {
|
|
||||||
|
|
||||||
private ApiClient apiClient;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
//实例化API请求客户端
|
|
||||||
ApiClient.init("http://localhost:8080/api", "app_key", "1234567890123456");
|
|
||||||
apiClient = ApiClient.getInstance();
|
|
||||||
ApiClient client = ApiClient.getInstance();
|
|
||||||
|
|
||||||
// 以下为对称加密公钥,对重要关键请求加密,可不设
|
|
||||||
String cryptPublicKeyBase64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTrwfsrJjCF+pP4S3A/wrD4U1txg53EuBC1mPt" +
|
|
||||||
"3vGXvSK2U0YNRVR3Q65ooHnPKmk4LwI8v+7+ATTxUg3qkuRiDuzBa5zLkYKM50LOgEWSdOKzbnbx" +
|
|
||||||
"a5FnE7IXawNt1p8+MVN1TTI7J/fZy6g1x0WBy1odE5Osru4WfZNOqQtjHwIDAQAB";
|
|
||||||
client.setPublicKey(RSAUtil.parsePublicKey(cryptPublicKeyBase64));
|
|
||||||
|
|
||||||
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
|
|
||||||
//设置发送网络请求前的统一操作
|
|
||||||
client.setBefore(new ApiClient.Before() {
|
|
||||||
public void call(ApiRequest request) {
|
|
||||||
System.out.println("请求参数" + MapperUtil.toJson(request));
|
|
||||||
System.out.println("请求方法" + request.apiMethod());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//设置网络请求完成后的统一操作
|
|
||||||
client.setAfter(new ApiClient.After() {
|
|
||||||
public void call(ApiRequest request, ApiResponse response) {
|
|
||||||
System.out.println("响应参数" + MapperUtil.toJson(response));
|
|
||||||
Date end = new Date();
|
|
||||||
System.out.println(simpleDateFormat.format(end));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFileUpload() {
|
|
||||||
{//无进度显示
|
|
||||||
final Date start = new Date();
|
|
||||||
|
|
||||||
//文件上传请求
|
|
||||||
FileUploadRequest fileUploadRequest = new FileUploadRequest();
|
|
||||||
fileUploadRequest.setFile(new File("D:\\1.PNG"));
|
|
||||||
apiClient.fileUpload(fileUploadRequest, new ApiClient.Callback<FileUploadResponse>() {
|
|
||||||
public void call(FileUploadResponse response) {
|
|
||||||
Date end = new Date();
|
|
||||||
System.out.println("无进度显示" + (end.getTime() - start.getTime()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{//有进度显示
|
|
||||||
final Date start = new Date();
|
|
||||||
|
|
||||||
//文件上传请求
|
|
||||||
FileUploadRequest fileUploadRequest = new FileUploadRequest();
|
|
||||||
fileUploadRequest.setFile(new File("D:\\1.PNG"));
|
|
||||||
apiClient.fileUpload(fileUploadRequest, new ApiClient.Callback<FileUploadResponse>() {
|
|
||||||
public void call(FileUploadResponse response) {
|
|
||||||
Date end = new Date();
|
|
||||||
System.out.println("有进度显示" + (end.getTime() - start.getTime()));
|
|
||||||
}
|
|
||||||
}, new ProgressRequestBody.ProgressListener() {
|
|
||||||
public void onProgress(long totalBytes, long remainingBytes, boolean done) {
|
|
||||||
System.out.println((totalBytes - remainingBytes) * 100 / totalBytes + "%");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(3000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<#list apiList as item>
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test${item.targetRequest}() {
|
|
||||||
${item.targetRequest} request = new ${item.targetRequest}();
|
|
||||||
${item.targetResponse} response = apiClient.execute(request);
|
|
||||||
Assert.assertTrue(!response.hasError());
|
|
||||||
}
|
|
||||||
</#list>
|
|
||||||
}
|
|
@ -0,0 +1,59 @@
|
|||||||
|
package ${domain};
|
||||||
|
|
||||||
|
import ${domain}.request.*;
|
||||||
|
import ${domain}.response.*;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ApiTest - 测试用例
|
||||||
|
*
|
||||||
|
* @author author
|
||||||
|
* @version 0.0.1
|
||||||
|
* @since 2019-06-11
|
||||||
|
*/
|
||||||
|
public class ApiTest {
|
||||||
|
|
||||||
|
private ApiClient apiClient;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
//实例化API请求客户端
|
||||||
|
ApiClient.init("http://localhost:8080/api", "app_key", "1234567890123456");
|
||||||
|
apiClient = ApiClient.getInstance();
|
||||||
|
ApiClient client = ApiClient.getInstance();
|
||||||
|
client.setDebug(true);
|
||||||
|
|
||||||
|
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
|
||||||
|
//设置发送网络请求前的统一操作
|
||||||
|
client.setBefore(new ApiClient.Before() {
|
||||||
|
public void call(ApiRequest request) {
|
||||||
|
System.out.println("请求参数" + MapperUtil.toJson(request));
|
||||||
|
System.out.println("请求方法" + request.apiMethod());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//设置网络请求完成后的统一操作
|
||||||
|
client.setAfter(new ApiClient.After() {
|
||||||
|
public void call(ApiRequest request, ApiResponse response) {
|
||||||
|
System.out.println("响应参数" + MapperUtil.toJson(response));
|
||||||
|
Date end = new Date();
|
||||||
|
System.out.println(simpleDateFormat.format(end));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
<#list apiList as item>
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test${item.targetRequest}() {
|
||||||
|
${item.targetRequest} request = new ${item.targetRequest}();
|
||||||
|
${item.targetResponse} response = apiClient.execute(request);
|
||||||
|
Assert.assertTrue(!response.hasError());
|
||||||
|
}
|
||||||
|
</#list>
|
||||||
|
}
|
@ -1,59 +0,0 @@
|
|||||||
package ${domain};
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileUploadRequest - 文件上传请求
|
|
||||||
*
|
|
||||||
* @author wangbing
|
|
||||||
* @version 0.0.1
|
|
||||||
* @since 2017-01-01
|
|
||||||
*/
|
|
||||||
public class FileUploadRequest implements ApiRequest<FileUploadResponse> {
|
|
||||||
private String fileName;
|
|
||||||
private File file;
|
|
||||||
private byte[] bytes;
|
|
||||||
|
|
||||||
public void setFile(File file) {
|
|
||||||
this.file = file;
|
|
||||||
this.fileName = file.getName();
|
|
||||||
this.bytes = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFile(byte[] bytes, String fileName) {
|
|
||||||
this.bytes = bytes;
|
|
||||||
this.fileName = fileName;
|
|
||||||
this.file = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExist() {
|
|
||||||
if ((file != null && file.exists()) || bytes != null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getBytes() {
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName() {
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void check() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public String apiMethod() {
|
|
||||||
return "api.file.upload";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<FileUploadResponse> responseClass() {
|
|
||||||
return FileUploadResponse.class;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package ${domain};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileUploadResponse - 文件上传响应
|
|
||||||
*
|
|
||||||
* @author wangbing
|
|
||||||
* @version 0.0.1
|
|
||||||
* @since 2017-01-01
|
|
||||||
*/
|
|
||||||
public class FileUploadResponse extends ApiResponse {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件ID
|
|
||||||
*/
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* url地址
|
|
||||||
*/
|
|
||||||
private String url;
|
|
||||||
|
|
||||||
private String attribute1;
|
|
||||||
|
|
||||||
private String attribute2;
|
|
||||||
|
|
||||||
private String attribute3;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAttribute1() {
|
|
||||||
return attribute1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttribute1(String attribute1) {
|
|
||||||
this.attribute1 = attribute1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAttribute2() {
|
|
||||||
return attribute2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttribute2(String attribute2) {
|
|
||||||
this.attribute2 = attribute2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAttribute3() {
|
|
||||||
return attribute3;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttribute3(String attribute3) {
|
|
||||||
this.attribute3 = attribute3;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,259 +0,0 @@
|
|||||||
package ${domain}.action;
|
|
||||||
|
|
||||||
import ${domain}.${module}.mgr.*;
|
|
||||||
import ${domain}.${module}.req.*;
|
|
||||||
import ${domain}.frame.base.BaseResponse;
|
|
||||||
import ${domain}.frame.base.ErrorType;
|
|
||||||
import ${domain}.frame.base.Token;
|
|
||||||
import ${domain}.frame.utils.*;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
public class ApiController {
|
|
||||||
//基本请求参数KEY
|
|
||||||
private static final String P_APP_KEY = "app_key";
|
|
||||||
private static final String P_TYPE = "type";
|
|
||||||
private static final String P_TARGET = "target";
|
|
||||||
private static final String P_TARGET_JSON = "target_json";
|
|
||||||
private static final String P_FILE_NAME = "file_name";
|
|
||||||
private static final String P_TIMESTAMP = "timestamp";
|
|
||||||
private static final String P_METHOD = "method";
|
|
||||||
private static final String P_SIGN = "sign";
|
|
||||||
private static final String P_ENHANCED = "enhanced";
|
|
||||||
//安全模式,签名或加密
|
|
||||||
private static final String MODE_SIGN = "sign";
|
|
||||||
private static final String MODE_ENCRYPTION = "encryption";
|
|
||||||
//参数类型
|
|
||||||
private static final String TYPE_JSON = "json";
|
|
||||||
private static final String TYPE_FILE = "file";
|
|
||||||
//签名方式
|
|
||||||
private static final String SIGN_METHOD_MD5 = "MD5";
|
|
||||||
private static final String SIGN_METHOD_RSA = "RSA";
|
|
||||||
//加密方式
|
|
||||||
private static final String ENCRYPTION_METHOD_MD5 = "MD5";
|
|
||||||
private static final String ENCRYPTION_METHOD_RSA = "RSA";
|
|
||||||
|
|
||||||
private static final String APP_SECRET = "1234567890123456";
|
|
||||||
|
|
||||||
<#list managerList as i>
|
|
||||||
@Autowired
|
|
||||||
private ${tool.abb2Abb(i)} ${tool.Abb2abb(i)};
|
|
||||||
</#list>
|
|
||||||
|
|
||||||
@RequestMapping("/api")
|
|
||||||
@ResponseBody
|
|
||||||
public String api(HttpServletRequest request) {
|
|
||||||
BaseResponse baseResponse = new BaseResponse();
|
|
||||||
//安全认证
|
|
||||||
validate(request, baseResponse);
|
|
||||||
|
|
||||||
//权限认证
|
|
||||||
if (!baseResponse.hasError()) {
|
|
||||||
authenticate(request, baseResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 业务处理
|
|
||||||
if (!baseResponse.hasError()) {
|
|
||||||
baseResponse = handle(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
return encrypt(request,baseResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String encrypt(HttpServletRequest request,BaseResponse baseResponse){
|
|
||||||
String enhanced = request.getParameter(P_ENHANCED);
|
|
||||||
boolean isEnhanced = !StringUtils.isEmpty(enhanced) && "true".equals(enhanced);
|
|
||||||
byte[] bytes = MapperUtil.toJson(baseResponse).getBytes();
|
|
||||||
if (isEnhanced){
|
|
||||||
return RSAUtil.encrypt2Base64(bytes);
|
|
||||||
}else {
|
|
||||||
return AESUtil.encrypt2Base64(bytes, APP_SECRET);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求处理器
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private BaseResponse handle(HttpServletRequest request) {
|
|
||||||
|
|
||||||
//File请求处理
|
|
||||||
if (TYPE_FILE.equals(request.getParameter(P_TYPE))) {
|
|
||||||
return handleFILE(request);
|
|
||||||
}
|
|
||||||
//JSON请求处理
|
|
||||||
if (TYPE_JSON.equals(request.getParameter(P_TYPE))) {
|
|
||||||
return handleJSON(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseResponse baseResponse = new BaseResponse();
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "请求未处理");
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件请求处理
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private BaseResponse handleFILE(HttpServletRequest request) {
|
|
||||||
BaseResponse baseResponse = new BaseResponse();
|
|
||||||
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
|
|
||||||
|
|
||||||
String fileName = multipartHttpServletRequest.getParameter(P_FILE_NAME);
|
|
||||||
byte[] data = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
MultipartFile target = multipartHttpServletRequest.getFile(P_TARGET);
|
|
||||||
if (target == null) {
|
|
||||||
String base64 = multipartHttpServletRequest.getParameter(P_TARGET);
|
|
||||||
data = Base64Util.decode(base64);
|
|
||||||
} else {
|
|
||||||
data = target.getBytes();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "文件获取失败!");
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
//========
|
|
||||||
//处理文件
|
|
||||||
//========
|
|
||||||
|
|
||||||
if (data != null) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "文件上传成功,但未处理文件[" + fileName + "]!");
|
|
||||||
}else {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "文件上传失败!");
|
|
||||||
}
|
|
||||||
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BaseResponse handleJSON(HttpServletRequest request){
|
|
||||||
BaseResponse baseResponse = new BaseResponse();
|
|
||||||
String method = null;
|
|
||||||
String targetJson = null;
|
|
||||||
try {
|
|
||||||
method = request.getParameter(P_METHOD);
|
|
||||||
targetJson = (String) request.getAttribute(P_TARGET_JSON);
|
|
||||||
if (method == null) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "请求方法不能为空!");
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
if (targetJson == null) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "请求目标不能为空!");
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (method) {
|
|
||||||
<#list methodList as m >
|
|
||||||
case "${m.stringMethod}":
|
|
||||||
baseResponse = ${m.target}${tool.abb2Abb(m.method)}(targetJson, LocalData.getToken());
|
|
||||||
break;
|
|
||||||
</#list>
|
|
||||||
default:
|
|
||||||
baseResponse.addError(ErrorType.INVALID_PARAMETER, Message.NOT_EXIST_METHOD);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
baseResponse.addError(ErrorType.SYSTEM_ERROR, Message.ERROR_500);
|
|
||||||
LogUtil.dumpException(ex);
|
|
||||||
} finally {
|
|
||||||
if (baseResponse.hasError()) {
|
|
||||||
LogUtil.e("请求方法:" + method + ", 请求目标:" + targetJson);
|
|
||||||
LogUtil.e("错误原因:" + MapperUtil.toJson(baseResponse.getErrors()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return baseResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 安全认证
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private void validate(HttpServletRequest request, BaseResponse baseResponse) {
|
|
||||||
String type = request.getParameter(P_TYPE);
|
|
||||||
String timestamp = request.getParameter(P_TIMESTAMP);
|
|
||||||
String sign = request.getParameter(P_SIGN);
|
|
||||||
String enhanced = request.getParameter(P_ENHANCED);
|
|
||||||
boolean isEnhanced = !StringUtils.isEmpty(enhanced) && "true".equals(enhanced);
|
|
||||||
|
|
||||||
if(type == null || timestamp == null || sign == null){
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR,"无效参数");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TYPE_JSON.equals(type)) {
|
|
||||||
String target = request.getParameter(P_TARGET);
|
|
||||||
String jsonString = null;
|
|
||||||
try {
|
|
||||||
if (isEnhanced) {
|
|
||||||
jsonString = RSAUtil.decrypt2String(target);
|
|
||||||
} else {
|
|
||||||
jsonString = AESUtil.decrypt2String(target, APP_SECRET);
|
|
||||||
}
|
|
||||||
}catch (Exception e){
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR,"Target解码错误,请确认编码是否正确!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String sign_ = MD5Util.encode(APP_SECRET + jsonString + timestamp);
|
|
||||||
if (!sign_.equals(sign)) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "签名验证失败");
|
|
||||||
}
|
|
||||||
request.setAttribute(P_TARGET_JSON,jsonString);
|
|
||||||
} else if (TYPE_FILE.equals(type)) {
|
|
||||||
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
|
|
||||||
MultipartFile file = multipartHttpServletRequest.getFile(P_TARGET);
|
|
||||||
String base64 = multipartHttpServletRequest.getParameter(P_TARGET);
|
|
||||||
|
|
||||||
try {
|
|
||||||
String sign_ = MD5Util.encode(APP_SECRET + MD5Util.encode(file != null ? file.getBytes() : Base64Util.decode(base64)) + timestamp);
|
|
||||||
|
|
||||||
if (!sign_.equals(sign)) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "签名验证失败");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "签名验证失败");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!baseResponse.hasError()){//时效性验证
|
|
||||||
long timestamp_ = Long.parseLong(timestamp);
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
if (currentTime - timestamp_ > 2 * 60 * 1000) {
|
|
||||||
baseResponse.addError(ErrorType.BUSINESS_ERROR, "请求过期, 或本地时间错误.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void authenticate(HttpServletRequest request, BaseResponse baseResponse){
|
|
||||||
Token token = new Token();
|
|
||||||
token.setId(0L);
|
|
||||||
token.setUserId(0L);
|
|
||||||
token.setUserName("admin");
|
|
||||||
LocalData.setToken(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
<#list methodList as m>
|
|
||||||
private BaseResponse ${m.target}${tool.abb2Abb(m.method)}(String targetJson, Token token) {
|
|
||||||
${m.request} request = MapperUtil.toJava(targetJson, ${m.request}.class);
|
|
||||||
return ${m.manager}.${m.method}(request, token);
|
|
||||||
}
|
|
||||||
</#list>
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package ${domain}.${module}.enums;
|
|
||||||
|
|
||||||
<#list annotation as i>
|
|
||||||
${i}
|
|
||||||
</#list>
|
|
||||||
public enum ${className} {
|
|
||||||
<#list body as i>
|
|
||||||
${i}
|
|
||||||
</#list>
|
|
||||||
}
|
|
Loading…
Reference in new issue