mirror of https://github.com/longtai-cn/hippo4j
commit
9c59d84b43
@ -0,0 +1,121 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 适配SpringBoot1x
|
||||
|
||||
目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
Nacos SpringBoot 配置如下:
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
cloud:
|
||||
nacos:
|
||||
config:
|
||||
ext-config:
|
||||
- data-id: hippo4j-nacos.yaml
|
||||
group: DEFAULT_GROUP
|
||||
refresh: true
|
||||
server-addr: 127.0.0.1:8848
|
||||
dynamic:
|
||||
thread-pool:
|
||||
config-file-type: yml
|
||||
nacos:
|
||||
data-id: hippo4j-nacos.yaml
|
||||
group: DEFAULT_GROUP
|
||||
```
|
||||
|
||||
Apollo SpringBoot 配置如下:
|
||||
|
||||
```yaml
|
||||
apollo:
|
||||
autoUpdateInjectedSpringProperties: true
|
||||
bootstrap:
|
||||
eagerLoad:
|
||||
enabled: true
|
||||
enabled: true
|
||||
namespaces: application
|
||||
meta: http://127.0.0.1:8080
|
||||
app:
|
||||
id: dynamic-threadpool-example
|
||||
spring:
|
||||
dynamic:
|
||||
thread-pool:
|
||||
apollo:
|
||||
namespace: application
|
||||
```
|
||||
|
||||
动态线程池通用配置如下:
|
||||
|
||||
```yaml
|
||||
management:
|
||||
context-path: /actuator
|
||||
security:
|
||||
enabled: false
|
||||
server:
|
||||
port: 8091
|
||||
servlet:
|
||||
context-path: /example
|
||||
spring:
|
||||
application:
|
||||
name: dynamic-threadpool-example
|
||||
dynamic:
|
||||
thread-pool:
|
||||
banner: true
|
||||
check-state-interval: 5
|
||||
collect-type: micrometer
|
||||
config-file-type: properties
|
||||
enable: true
|
||||
executors:
|
||||
- active-alarm: 80
|
||||
alarm: true
|
||||
allow-core-thread-time-out: true
|
||||
blocking-queue: LinkedBlockingQueue
|
||||
capacity-alarm: 80
|
||||
core-pool-size: 1
|
||||
execute-time-out: 1000
|
||||
keep-alive-time: 6691
|
||||
maximum-pool-size: 1
|
||||
notify:
|
||||
interval: 8
|
||||
receives: chen.ma
|
||||
queue-capacity: 1
|
||||
rejected-handler: AbortPolicy
|
||||
thread-name-prefix: message-consume
|
||||
thread-pool-id: message-consume
|
||||
- active-alarm: 80
|
||||
alarm: true
|
||||
allow-core-thread-time-out: true
|
||||
blocking-queue: LinkedBlockingQueue
|
||||
capacity-alarm: 80
|
||||
core-pool-size: 1
|
||||
execute-time-out: 1000
|
||||
keep-alive-time: 6691
|
||||
maximum-pool-size: 1
|
||||
notify:
|
||||
interval: 8
|
||||
receives: chen.ma
|
||||
queue-capacity: 1
|
||||
rejected-handler: AbortPolicy
|
||||
thread-name-prefix: message-produce
|
||||
thread-pool-id: message-produce
|
||||
notify-platforms:
|
||||
- platform: WECHAT
|
||||
token: ac0426a5-c712-474c-9bff-72b8b8f5caff
|
||||
profiles:
|
||||
active: dev
|
||||
```
|
||||
|
||||
具体 Demo 运行请参考以下示例模块,已验证对应线程池动态变更、报警以及运行时监控功能。
|
||||
|
||||
- `/hippo4j-config-nacos-spring-boot-1x-starter-example`
|
||||
- `hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example`
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.auth.config;
|
||||
|
||||
import cn.hippo4j.auth.filter.RewriteUserInfoApiFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterConfig {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<RewriteUserInfoApiFilter> userInfoApiFilterRegistrationBean() {
|
||||
FilterRegistrationBean<RewriteUserInfoApiFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new RewriteUserInfoApiFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
return registration;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.auth.filter;
|
||||
|
||||
import cn.hippo4j.auth.toolkit.AuthUtil;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* When anonymous login is enabled, an error will be reported when viewing the current user information.
|
||||
* Modify the URI to query the default administrator information.
|
||||
*
|
||||
* before:hippo4j/v1/cs/auth/users/info or hippo4j/v1/cs/auth/users/info/xxx
|
||||
* after:hippo4j/v1/cs/auth/users/info/admin
|
||||
*/
|
||||
public class RewriteUserInfoApiFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
boolean enableAuthentication = AuthUtil.enableAuthentication;
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
|
||||
String path = httpRequest.getRequestURI();
|
||||
if (!enableAuthentication && path.contains("users/info")) {
|
||||
httpRequest.getRequestDispatcher("/hippo4j/v1/cs/auth/users/info/admin").forward(servletRequest, servletResponse);
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.auth.toolkit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AuthUtil {
|
||||
|
||||
public static boolean enableAuthentication;
|
||||
|
||||
@Value("${hippo4j.core.auth.enabled:true}")
|
||||
public void setEnableAuthentication(boolean enabled) {
|
||||
AuthUtil.enableAuthentication = enabled;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.constant;
|
||||
|
||||
/**
|
||||
* Http header constants.
|
||||
*/
|
||||
public interface HttpHeaderConstants {
|
||||
|
||||
String CLIENT_VERSION_HEADER = "Client-Version";
|
||||
|
||||
String USER_AGENT_HEADER = "User-Agent";
|
||||
|
||||
String REQUEST_SOURCE_HEADER = "Request-Source";
|
||||
|
||||
String CONTENT_TYPE = "Content-Type";
|
||||
|
||||
String CONTENT_LENGTH = "Content-Length";
|
||||
|
||||
String ACCEPT_CHARSET = "Accept-Charset";
|
||||
|
||||
String ACCEPT_ENCODING = "Accept-Encoding";
|
||||
|
||||
String CONTENT_ENCODING = "Content-Encoding";
|
||||
|
||||
String CONNECTION = "Requester";
|
||||
|
||||
String REQUEST_ID = "RequestId";
|
||||
|
||||
String REQUEST_MODULE = "Request-Module";
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.constant;
|
||||
|
||||
import cn.hippo4j.common.toolkit.StringUtil;
|
||||
|
||||
/**
|
||||
* Http media type.
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
public final class HttpMediaType {
|
||||
|
||||
public static final String APPLICATION_ATOM_XML = "application/atom+xml";
|
||||
|
||||
public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded;charset=UTF-8";
|
||||
|
||||
public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
|
||||
|
||||
public static final String APPLICATION_SVG_XML = "application/svg+xml";
|
||||
|
||||
public static final String APPLICATION_XHTML_XML = "application/xhtml+xml";
|
||||
|
||||
public static final String APPLICATION_XML = "application/xml;charset=UTF-8";
|
||||
|
||||
public static final String APPLICATION_JSON = "application/json;charset=UTF-8";
|
||||
|
||||
public static final String MULTIPART_FORM_DATA = "multipart/form-data;charset=UTF-8";
|
||||
|
||||
public static final String TEXT_HTML = "text/html;charset=UTF-8";
|
||||
|
||||
public static final String TEXT_PLAIN = "text/plain;charset=UTF-8";
|
||||
|
||||
private HttpMediaType(String type, String charset) {
|
||||
this.type = type;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* content type.
|
||||
*/
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* content type charset.
|
||||
*/
|
||||
private final String charset;
|
||||
|
||||
/**
|
||||
* Parse the given String contentType into a {@code MediaType} object.
|
||||
*
|
||||
* @param contentType mediaType
|
||||
* @return MediaType
|
||||
*/
|
||||
public static HttpMediaType valueOf(String contentType) {
|
||||
if (StringUtil.isEmpty(contentType)) {
|
||||
throw new IllegalArgumentException("MediaType must not be empty");
|
||||
}
|
||||
String[] values = contentType.split(";");
|
||||
String charset = Constants.ENCODE;
|
||||
for (String value : values) {
|
||||
if (value.startsWith("charset=")) {
|
||||
charset = value.substring("charset=".length());
|
||||
}
|
||||
}
|
||||
return new HttpMediaType(values[0], charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given contentType and charset to assemble into a {@code MediaType} object.
|
||||
*
|
||||
* @param contentType contentType
|
||||
* @param charset charset
|
||||
* @return MediaType
|
||||
*/
|
||||
public static HttpMediaType valueOf(String contentType, String charset) {
|
||||
if (StringUtil.isEmpty(contentType)) {
|
||||
throw new IllegalArgumentException("MediaType must not be empty");
|
||||
}
|
||||
String[] values = contentType.split(";");
|
||||
return new HttpMediaType(values[0], StringUtil.isEmpty(charset) ? Constants.ENCODE : charset);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getCharset() {
|
||||
return charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + ";charset=" + charset;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.constant;
|
||||
|
||||
/**
|
||||
* Http method constants.
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
public class HttpMethod {
|
||||
|
||||
public static final String GET = "GET";
|
||||
|
||||
public static final String HEAD = "HEAD";
|
||||
|
||||
public static final String POST = "POST";
|
||||
|
||||
public static final String PUT = "PUT";
|
||||
|
||||
public static final String PATCH = "PATCH";
|
||||
|
||||
public static final String DELETE = "DELETE";
|
||||
|
||||
public static final String OPTIONS = "OPTIONS";
|
||||
|
||||
public static final String TRACE = "TRACE";
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.constant;
|
||||
|
||||
/**
|
||||
* Http response code.
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
public interface HttpResponseCode {
|
||||
|
||||
int SC_CONTINUE = 100;
|
||||
|
||||
int SC_SWITCHING_PROTOCOLS = 101;
|
||||
|
||||
int SC_OK = 200;
|
||||
|
||||
int SC_CREATED = 201;
|
||||
|
||||
int SC_ACCEPTED = 202;
|
||||
|
||||
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||
|
||||
int SC_NO_CONTENT = 204;
|
||||
|
||||
int SC_RESET_CONTENT = 205;
|
||||
|
||||
int SC_PARTIAL_CONTENT = 206;
|
||||
|
||||
int SC_MULTIPLE_CHOICES = 300;
|
||||
|
||||
int SC_MOVED_PERMANENTLY = 301;
|
||||
|
||||
int SC_MOVED_TEMPORARILY = 302;
|
||||
|
||||
int SC_FOUND = 302;
|
||||
|
||||
int SC_SEE_OTHER = 303;
|
||||
|
||||
int SC_NOT_MODIFIED = 304;
|
||||
|
||||
int SC_USE_PROXY = 305;
|
||||
|
||||
int SC_TEMPORARY_REDIRECT = 307;
|
||||
|
||||
int SC_BAD_REQUEST = 400;
|
||||
|
||||
int SC_UNAUTHORIZED = 401;
|
||||
|
||||
int SC_PAYMENT_REQUIRED = 402;
|
||||
|
||||
int SC_FORBIDDEN = 403;
|
||||
|
||||
int SC_NOT_FOUND = 404;
|
||||
|
||||
int SC_METHOD_NOT_ALLOWED = 405;
|
||||
|
||||
int SC_NOT_ACCEPTABLE = 406;
|
||||
|
||||
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||
|
||||
int SC_REQUEST_TIMEOUT = 408;
|
||||
|
||||
int SC_CONFLICT = 409;
|
||||
|
||||
int SC_GONE = 410;
|
||||
|
||||
int SC_LENGTH_REQUIRED = 411;
|
||||
|
||||
int SC_PRECONDITION_FAILED = 412;
|
||||
|
||||
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
|
||||
|
||||
int SC_REQUEST_URI_TOO_LONG = 414;
|
||||
|
||||
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||
|
||||
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
|
||||
|
||||
int SC_EXPECTATION_FAILED = 417;
|
||||
|
||||
int SC_INTERNAL_SERVER_ERROR = 500;
|
||||
|
||||
int SC_NOT_IMPLEMENTED = 501;
|
||||
|
||||
int SC_BAD_GATEWAY = 502;
|
||||
|
||||
int SC_SERVICE_UNAVAILABLE = 503;
|
||||
|
||||
int SC_GATEWAY_TIMEOUT = 504;
|
||||
|
||||
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
|
||||
}
|
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit;
|
||||
|
||||
import cn.hippo4j.common.constant.Constants;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
* IO related tool methods.
|
||||
*
|
||||
* @author nacos
|
||||
*/
|
||||
public class IoUtil {
|
||||
|
||||
/**
|
||||
* Try decompress by GZIP from stream.
|
||||
*
|
||||
* @param raw compress stream
|
||||
* @return byte array after decompress
|
||||
*/
|
||||
public static byte[] tryDecompress(InputStream raw) throws IOException {
|
||||
try (
|
||||
GZIPInputStream gis = new GZIPInputStream(raw);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
copy(gis, out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try decompress by GZIP from byte array.
|
||||
*
|
||||
* @param raw compressed byte array
|
||||
* @return byte array after decompress
|
||||
* @throws Exception exception
|
||||
*/
|
||||
public static byte[] tryDecompress(byte[] raw) throws Exception {
|
||||
if (!isGzipStream(raw)) {
|
||||
return raw;
|
||||
}
|
||||
try (
|
||||
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(raw));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
copy(gis, out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try compress by GZIP for string.
|
||||
*
|
||||
* @param str strings to be compressed.
|
||||
* @param encoding encoding.
|
||||
* @return byte[]
|
||||
*/
|
||||
public static byte[] tryCompress(String str, String encoding) {
|
||||
if (str == null || str.length() == 0) {
|
||||
return new byte[0];
|
||||
}
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
|
||||
gzip.write(str.getBytes(encoding));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
private static BufferedReader toBufferedReader(Reader reader) {
|
||||
return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write string to a file.
|
||||
*
|
||||
* @param file file
|
||||
* @param data string
|
||||
* @param encoding encoding of string
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static void writeStringToFile(File file, String data, String encoding) throws IOException {
|
||||
try (OutputStream os = new FileOutputStream(file)) {
|
||||
os.write(data.getBytes(encoding));
|
||||
os.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read lines.
|
||||
*
|
||||
* @param input reader
|
||||
* @return list of line
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static List<String> readLines(Reader input) throws IOException {
|
||||
BufferedReader reader = toBufferedReader(input);
|
||||
List<String> list = new ArrayList<>();
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (null != line) {
|
||||
if (StringUtil.isNotEmpty(line)) {
|
||||
list.add(line.trim());
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* To string from stream.
|
||||
*
|
||||
* @param input stream
|
||||
* @param encoding charset of stream
|
||||
* @return string
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static String toString(InputStream input, String encoding) {
|
||||
if (input == null) {
|
||||
return StringUtil.EMPTY;
|
||||
}
|
||||
return (null == encoding) ? toString(new InputStreamReader(input, Constants.ENCODE))
|
||||
: toString(new InputStreamReader(input, encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
* To string from reader.
|
||||
*
|
||||
* @param reader reader
|
||||
* @return string
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static String toString(Reader reader) throws IOException {
|
||||
CharArrayWriter sw = new CharArrayWriter();
|
||||
copy(reader, sw);
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy data.
|
||||
*
|
||||
* @param input source
|
||||
* @param output target
|
||||
* @return copy size
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static long copy(Reader input, Writer output) throws IOException {
|
||||
char[] buffer = new char[1 << 12];
|
||||
long count = 0;
|
||||
for (int n = 0; (n = input.read(buffer)) >= 0;) {
|
||||
output.write(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy data.
|
||||
*
|
||||
* @param input source
|
||||
* @param output target
|
||||
* @return copy size
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static long copy(InputStream input, OutputStream output) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
int totalBytes = 0;
|
||||
while ((bytesRead = input.read(buffer)) != -1) {
|
||||
output.write(buffer, 0, bytesRead);
|
||||
|
||||
totalBytes += bytesRead;
|
||||
}
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete file or dir.
|
||||
*
|
||||
* <p>If is dir, clean directory, do not delete dir.
|
||||
*
|
||||
* <p>If is file, delete file.
|
||||
*
|
||||
* @param fileOrDir file or dir
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static void delete(File fileOrDir) throws IOException {
|
||||
if (fileOrDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileOrDir.isDirectory()) {
|
||||
cleanDirectory(fileOrDir);
|
||||
} else {
|
||||
if (fileOrDir.exists()) {
|
||||
boolean isDeleteOk = fileOrDir.delete();
|
||||
if (!isDeleteOk) {
|
||||
throw new IOException("delete fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理目录下的内容. Clean content under directory.
|
||||
*
|
||||
* @param directory directory
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static void cleanDirectory(File directory) throws IOException {
|
||||
if (!directory.exists()) {
|
||||
String message = directory + " does not exist";
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
if (!directory.isDirectory()) {
|
||||
String message = directory + " is not a directory";
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
|
||||
File[] files = directory.listFiles();
|
||||
// null if security restricted
|
||||
if (files == null) {
|
||||
throw new IOException("Failed to list contents of " + directory);
|
||||
}
|
||||
|
||||
IOException exception = null;
|
||||
for (File file : files) {
|
||||
try {
|
||||
delete(file);
|
||||
} catch (IOException ioe) {
|
||||
exception = ioe;
|
||||
}
|
||||
}
|
||||
|
||||
if (null != exception) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy File.
|
||||
*
|
||||
* @param source source file path
|
||||
* @param target target file path
|
||||
* @throws IOException io exception
|
||||
*/
|
||||
public static void copyFile(String source, String target) throws IOException {
|
||||
File sf = new File(source);
|
||||
if (!sf.exists()) {
|
||||
throw new IllegalArgumentException("source file does not exist.");
|
||||
}
|
||||
File tf = new File(target);
|
||||
if (!tf.getParentFile().mkdirs()) {
|
||||
throw new RuntimeException("failed to create parent directory.");
|
||||
}
|
||||
if (!tf.exists() && !tf.createNewFile()) {
|
||||
throw new RuntimeException("failed to create target file.");
|
||||
}
|
||||
try (
|
||||
FileChannel sc = new FileInputStream(sf).getChannel();
|
||||
FileChannel tc = new FileOutputStream(tf).getChannel()) {
|
||||
sc.transferTo(0, sc.size(), tc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Judge whether is Gzip stream.
|
||||
*
|
||||
* @param bytes byte array
|
||||
* @return true if is gzip, otherwise false
|
||||
*/
|
||||
public static boolean isGzipStream(byte[] bytes) {
|
||||
|
||||
int minByteArraySize = 2;
|
||||
if (bytes == null || bytes.length < minByteArraySize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GZIPInputStream.GZIP_MAGIC == ((bytes[1] << 8 | bytes[0]) & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close http connection quietly.
|
||||
*
|
||||
* @param connection http connection
|
||||
*/
|
||||
public static void closeQuietly(HttpURLConnection connection) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
closeQuietly(connection.getInputStream());
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close closable object quietly.
|
||||
*
|
||||
* @param closeable http connection
|
||||
*/
|
||||
public static void closeQuietly(Closeable closeable) {
|
||||
try {
|
||||
if (closeable != null) {
|
||||
closeable.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeQuietly(Closeable... closeable) {
|
||||
Arrays.stream(closeable).forEach(IoUtil::closeQuietly);
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Map util.
|
||||
*/
|
||||
public class MapUtil {
|
||||
|
||||
/**
|
||||
* Null-safe check if the specified Dictionary is empty.
|
||||
*
|
||||
* <p>Null returns true.
|
||||
*
|
||||
* @param map the collection to check, may be null
|
||||
* @return true if empty or null
|
||||
*/
|
||||
public static boolean isEmpty(Map map) {
|
||||
return (map == null || map.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe check if the specified Dictionary is empty.
|
||||
*
|
||||
* <p>Null returns true.
|
||||
*
|
||||
* @param coll the collection to check, may be null
|
||||
* @return true if empty or null
|
||||
*/
|
||||
public static boolean isEmpty(Dictionary coll) {
|
||||
return (coll == null || coll.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe check if the specified Dictionary is not empty.
|
||||
*
|
||||
* <p>Null returns false.
|
||||
*
|
||||
* @param map the collection to check, may be null
|
||||
* @return true if non-null and non-empty
|
||||
*/
|
||||
public static boolean isNotEmpty(Map map) {
|
||||
return !isEmpty(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe check if the specified Dictionary is not empty.
|
||||
*
|
||||
* <p>Null returns false.
|
||||
*
|
||||
* @param coll the collection to check, may be null
|
||||
* @return true if non-null and non-empty
|
||||
*/
|
||||
public static boolean isNotEmpty(Dictionary coll) {
|
||||
return !isEmpty(coll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put into map if value is not null.
|
||||
*
|
||||
* @param target target map
|
||||
* @param key key
|
||||
* @param value value
|
||||
*/
|
||||
public static void putIfValNoNull(Map target, Object key, Object value) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
if (value != null) {
|
||||
target.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put into map if value is not empty.
|
||||
*
|
||||
* @param target target map
|
||||
* @param key key
|
||||
* @param value value
|
||||
*/
|
||||
public static void putIfValNoEmpty(Map target, Object key, Object value) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
if (value instanceof String) {
|
||||
if (StringUtil.isNotEmpty((String) value)) {
|
||||
target.put(key, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
if (CollectionUtil.isNotEmpty((Collection) value)) {
|
||||
target.put(key, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
if (isNotEmpty((Map) value)) {
|
||||
target.put(key, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (value instanceof Dictionary) {
|
||||
if (isNotEmpty((Dictionary) value)) {
|
||||
target.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ComputeIfAbsent lazy load.
|
||||
*
|
||||
* @param target target Map data.
|
||||
* @param key map key.
|
||||
* @param mappingFunction function which is need to be executed.
|
||||
* @param param1 function's parameter value1.
|
||||
* @param param2 function's parameter value1.
|
||||
* @return
|
||||
*/
|
||||
public static <K, C, V, T> V computeIfAbsent(Map<K, V> target, K key, BiFunction<C, T, V> mappingFunction, C param1,
|
||||
T param2) {
|
||||
Objects.requireNonNull(target, "target");
|
||||
Objects.requireNonNull(key, "key");
|
||||
Objects.requireNonNull(mappingFunction, "mappingFunction");
|
||||
Objects.requireNonNull(param1, "param1");
|
||||
Objects.requireNonNull(param2, "param2");
|
||||
V val = target.get(key);
|
||||
if (val == null) {
|
||||
V ret = mappingFunction.apply(param1, param2);
|
||||
target.put(key, ret);
|
||||
return ret;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove value, Thread safety depends on whether the Map is a thread-safe Map.
|
||||
*
|
||||
* @param map map
|
||||
* @param key key
|
||||
* @param removeJudge judge this key can be remove
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
* @return value
|
||||
*/
|
||||
public static <K, V> V removeKey(Map<K, V> map, K key, Predicate<V> removeJudge) {
|
||||
return map.computeIfPresent(key, (k, v) -> removeJudge.test(v) ? null : v);
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.http;
|
||||
|
||||
import cn.hippo4j.common.constant.Constants;
|
||||
import cn.hippo4j.common.constant.HttpHeaderConstants;
|
||||
import cn.hippo4j.common.constant.HttpMediaType;
|
||||
import cn.hippo4j.common.toolkit.MapUtil;
|
||||
import cn.hippo4j.common.toolkit.StringUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Http header.
|
||||
*
|
||||
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
|
||||
*/
|
||||
public class Header {
|
||||
|
||||
public static final Header EMPTY = Header.newInstance();
|
||||
|
||||
private final Map<String, String> header;
|
||||
|
||||
private final Map<String, List<String>> originalResponseHeader;
|
||||
|
||||
private static final String DEFAULT_CHARSET = "UTF-8";
|
||||
|
||||
private static final String DEFAULT_ENCODING = "gzip";
|
||||
|
||||
private Header() {
|
||||
header = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
originalResponseHeader = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
addParam(HttpHeaderConstants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
|
||||
addParam(HttpHeaderConstants.ACCEPT_CHARSET, DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
public static Header newInstance() {
|
||||
return new Header();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the key and value to the header.
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return header
|
||||
*/
|
||||
public Header addParam(String key, String value) {
|
||||
if (StringUtil.isNotEmpty(key)) {
|
||||
header.put(key, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Header setContentType(String contentType) {
|
||||
if (contentType == null) {
|
||||
contentType = HttpMediaType.APPLICATION_JSON;
|
||||
}
|
||||
return addParam(HttpHeaderConstants.CONTENT_TYPE, contentType);
|
||||
}
|
||||
|
||||
public Header build() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getValue(String key) {
|
||||
return header.get(key);
|
||||
}
|
||||
|
||||
public Map<String, String> getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return header.entrySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer to KV part list. The odd index is key and the even index is value.
|
||||
*
|
||||
* @return KV string list
|
||||
*/
|
||||
public List<String> toList() {
|
||||
List<String> list = new ArrayList<>(header.size() * 2);
|
||||
Iterator<Map.Entry<String, String>> iterator = iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, String> entry = iterator.next();
|
||||
list.add(entry.getKey());
|
||||
list.add(entry.getValue());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all KV list to header. The odd index is key and the even index is value.
|
||||
*
|
||||
* @param list KV list
|
||||
* @return header
|
||||
*/
|
||||
public Header addAll(List<String> list) {
|
||||
if ((list.size() & 1) != 0) {
|
||||
throw new IllegalArgumentException("list size must be a multiple of 2");
|
||||
}
|
||||
for (int i = 0; i < list.size();) {
|
||||
String key = list.get(i++);
|
||||
if (StringUtil.isNotEmpty(key)) {
|
||||
header.put(key, list.get(i++));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all parameters to header.
|
||||
*
|
||||
* @param params parameters
|
||||
*/
|
||||
public void addAll(Map<String, String> params) {
|
||||
if (MapUtil.isNotEmpty(params)) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
addParam(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set original format response header.
|
||||
*
|
||||
* <p>Currently only corresponds to the response header of JDK.
|
||||
*
|
||||
* @param key original response header key
|
||||
* @param values original response header values
|
||||
*/
|
||||
public void addOriginalResponseHeader(String key, List<String> values) {
|
||||
if (StringUtil.isNotEmpty(key)) {
|
||||
this.originalResponseHeader.put(key, values);
|
||||
addParam(key, values.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get original format response header.
|
||||
*
|
||||
* <p>Currently only corresponds to the response header of JDK.
|
||||
*
|
||||
* @return Map original response header
|
||||
*/
|
||||
public Map<String, List<String>> getOriginalResponseHeader() {
|
||||
return this.originalResponseHeader;
|
||||
}
|
||||
|
||||
public String getCharset() {
|
||||
String acceptCharset = getValue(HttpHeaderConstants.ACCEPT_CHARSET);
|
||||
if (acceptCharset == null) {
|
||||
String contentType = getValue(HttpHeaderConstants.CONTENT_TYPE);
|
||||
acceptCharset = StringUtil.isNotBlank(contentType) ? analysisCharset(contentType) : Constants.ENCODE;
|
||||
}
|
||||
return acceptCharset;
|
||||
}
|
||||
|
||||
private String analysisCharset(String contentType) {
|
||||
String[] values = contentType.split(";");
|
||||
String charset = Constants.ENCODE;
|
||||
if (values.length == 0) {
|
||||
return charset;
|
||||
}
|
||||
for (String value : values) {
|
||||
if (value.startsWith("charset=")) {
|
||||
charset = value.substring("charset=".length());
|
||||
}
|
||||
}
|
||||
return charset;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
header.clear();
|
||||
originalResponseHeader.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Header{" + "headerToMap=" + header + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.http;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Represents a client-side HTTP response.
|
||||
*
|
||||
* @author mai.jh
|
||||
*/
|
||||
public interface HttpClientResponse extends Closeable {
|
||||
|
||||
/**
|
||||
* Return the headers of this message.
|
||||
*
|
||||
* @return a corresponding HttpHeaders object (never {@code null})
|
||||
*/
|
||||
Header getHeaders();
|
||||
|
||||
/**
|
||||
* Return the body of the message as an input stream.
|
||||
*
|
||||
* @return String response body
|
||||
*/
|
||||
InputStream getBody();
|
||||
|
||||
/**
|
||||
* Return the HTTP status code.
|
||||
*
|
||||
* @return the HTTP status as an integer
|
||||
*/
|
||||
int getStatusCode();
|
||||
|
||||
/**
|
||||
* Return the HTTP status text of the response.
|
||||
*
|
||||
* @return the HTTP status text
|
||||
*/
|
||||
String getStatusText();
|
||||
|
||||
/**
|
||||
* Return the body As string.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getBodyString();
|
||||
|
||||
/**
|
||||
* close response InputStream.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
}
|
@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.http;
|
||||
|
||||
import cn.hippo4j.common.constant.Constants;
|
||||
import cn.hippo4j.common.constant.HttpMediaType;
|
||||
import cn.hippo4j.common.constant.HttpMethod;
|
||||
import cn.hippo4j.common.constant.HttpResponseCode;
|
||||
import cn.hippo4j.common.toolkit.CollectionUtil;
|
||||
import cn.hippo4j.common.toolkit.IoUtil;
|
||||
import cn.hippo4j.common.toolkit.JSONUtil;
|
||||
import cn.hippo4j.common.toolkit.StringUtil;
|
||||
import cn.hippo4j.common.toolkit.logtracing.LogMessage;
|
||||
import cn.hippo4j.common.web.exception.ServiceException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static cn.hippo4j.common.constant.HttpHeaderConstants.CONTENT_LENGTH;
|
||||
|
||||
/**
|
||||
* Http request utilities.
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class HttpUtil {
|
||||
|
||||
/**
|
||||
* Default connect timeout
|
||||
*/
|
||||
private static final int DEFAULT_CONNECT_TIMEOUT = 10000;
|
||||
|
||||
/**
|
||||
* Default read timeout
|
||||
*/
|
||||
private static final int DEFAULT_READ_TIMEOUT = 30000;
|
||||
|
||||
/**
|
||||
* Send a get network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param headers headers
|
||||
* @param params form data
|
||||
* @param timeout request timeout
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T get(String url, Map<String, String> headers, Map<String, String> params, long timeout, Class<T> clazz) {
|
||||
return execute(buildUrl(url, params), HttpMethod.GET, null, headers, timeout, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a get network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param params form data
|
||||
* @return
|
||||
*/
|
||||
public static String get(String url, Map<String, String> params) {
|
||||
return execute(buildUrl(url, params), HttpMethod.GET, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a get network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @return
|
||||
*/
|
||||
public static String get(String url) {
|
||||
return execute(url, HttpMethod.GET, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a get network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T get(String url, Class<T> clazz) {
|
||||
return JSONUtil.parseObject(get(url), clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T post(String url, Object body, Class<T> clazz) {
|
||||
String result = post(url, body);
|
||||
return JSONUtil.parseObject(result, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @param timeout request timeout
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T post(String url, Object body, long timeout, Class<T> clazz) {
|
||||
String result = post(url, body, timeout);
|
||||
return JSONUtil.parseObject(result, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param headers headers
|
||||
* @param params form data
|
||||
* @param timeout request timeout
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T post(String url, Map<String, String> headers, Map<String, String> params, long timeout, Class<T> clazz) {
|
||||
return execute(buildUrl(url, params), HttpMethod.POST, null, headers, timeout, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param headers headers
|
||||
* @param body request body
|
||||
* @param timeout request timeout
|
||||
* @param clazz return the target data type
|
||||
* @param <T> return the target data type
|
||||
* @return
|
||||
*/
|
||||
public static <T> T post(String url, Map<String, String> headers, Object body, long timeout, Class<T> clazz) {
|
||||
return execute(url, HttpMethod.POST, body, headers, timeout, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @return
|
||||
*/
|
||||
public static String post(String url, Object body) {
|
||||
return execute(url, HttpMethod.POST, body, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @param timeout request timeout
|
||||
* @return
|
||||
*/
|
||||
public static String post(String url, Object body, long timeout) {
|
||||
return execute(url, HttpMethod.POST, body, null, timeout, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a post network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param json json data
|
||||
* @return
|
||||
*/
|
||||
public static String postJson(String url, String json) {
|
||||
return executeJson(url, HttpMethod.POST, json, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a put network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @return
|
||||
*/
|
||||
public static String put(String url, Object body) {
|
||||
return execute(url, HttpMethod.PUT, body, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a put network request.
|
||||
*
|
||||
* @param url target url
|
||||
* @param body request body
|
||||
* @param headers headers
|
||||
* @return
|
||||
*/
|
||||
public static String put(String url, Object body, Map<String, String> headers) {
|
||||
return execute(url, HttpMethod.PUT, body, headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a complete Url from the query string.
|
||||
*
|
||||
* @param url target url
|
||||
* @param queryParams query params
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows
|
||||
public static String buildUrl(String url, Map<String, String> queryParams) {
|
||||
if (CollectionUtil.isEmpty(queryParams)) {
|
||||
return url;
|
||||
}
|
||||
boolean isFirst = true;
|
||||
StringBuilder builder = new StringBuilder(url);
|
||||
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key != null && entry.getValue() != null) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
builder.append("?");
|
||||
} else {
|
||||
builder.append("&");
|
||||
}
|
||||
String value = URLEncoder.encode(queryParams.get(key), Constants.ENCODE)
|
||||
.replaceAll("\\+", "%20");
|
||||
builder.append(key)
|
||||
.append("=")
|
||||
.append(value);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String executeJson(String url, String method, String json, Map<String, String> headers) {
|
||||
if (!JSONUtil.isJson(json)) {
|
||||
log.error(LogMessage.getInstance().setMsg("Http Call error.")
|
||||
.kv("url", url)
|
||||
.kv("method", method)
|
||||
.kv("json", json)
|
||||
.kv2String("headers", JSONUtil.toJSONString(headers)));
|
||||
throw new ServiceException("Invalid http json body, please check it again.");
|
||||
}
|
||||
return execute(url, method, json, headers);
|
||||
}
|
||||
|
||||
private static String execute(String url, String method, Object param, Map<String, String> headers) {
|
||||
HttpURLConnection connection = createConnection(url, method);
|
||||
HttpClientResponse response = null;
|
||||
try {
|
||||
response = doExecute(connection, param, headers);
|
||||
return response.getBodyString();
|
||||
} finally {
|
||||
Optional.ofNullable(response).ifPresent(each -> each.close());
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T execute(String url, String method, Object body, Map<String, String> headers, long timeout, Class<T> clazz) {
|
||||
HttpURLConnection connection = createConnection(url, method, timeout);
|
||||
HttpClientResponse response = null;
|
||||
try {
|
||||
response = doExecute(connection, body, headers);
|
||||
if (clazz == String.class) {
|
||||
return (T) response.getBodyString();
|
||||
}
|
||||
return JSONUtil.parseObject(response.getBodyString(), clazz);
|
||||
} finally {
|
||||
Optional.ofNullable(response).ifPresent(each -> each.close());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static HttpClientResponse doExecute(HttpURLConnection connection, Object body, Map<String, String> headers) {
|
||||
try {
|
||||
if (headers != null && headers.size() > 0) {
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
connection.setRequestProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
String bodyString;
|
||||
if (body instanceof String) {
|
||||
bodyString = (String) body;
|
||||
} else {
|
||||
bodyString = JSONUtil.toJSONString(body);
|
||||
}
|
||||
if (!StringUtil.isEmpty(bodyString)) {
|
||||
connection.setDoOutput(true);
|
||||
byte[] b = bodyString.getBytes();
|
||||
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(b.length));
|
||||
OutputStream outputStream = connection.getOutputStream();
|
||||
outputStream.write(b, 0, b.length);
|
||||
outputStream.flush();
|
||||
IoUtil.closeQuietly(outputStream);
|
||||
}
|
||||
connection.connect();
|
||||
JdkHttpClientResponse response = new JdkHttpClientResponse(connection);
|
||||
if (HttpResponseCode.SC_OK != response.getStatusCode()) {
|
||||
String msg = String.format("HttpPost response code error. [code] %s [url] %s [body] %s", response.getStatusCode(), connection.getURL(), response.getBodyString());
|
||||
throw new ServiceException(msg);
|
||||
}
|
||||
return response;
|
||||
} catch (Throwable ex) {
|
||||
log.error(LogMessage.getInstance().setMsg("Http call error. ")
|
||||
.kv("url", connection.getURL())
|
||||
.kv("method", connection.getRequestMethod())
|
||||
.kv("body", JSONUtil.toJSONString(body))
|
||||
.kv2String("headers", JSONUtil.toJSONString(headers)), ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static HttpURLConnection createConnection(String url, String method) {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
|
||||
connection.setReadTimeout(DEFAULT_READ_TIMEOUT);
|
||||
connection.setRequestMethod(method);
|
||||
connection.setRequestProperty(Constants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static HttpURLConnection createConnection(String url, String method, long timeout) {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(Integer.parseInt(String.valueOf(timeout)));
|
||||
connection.setReadTimeout(Integer.parseInt(String.valueOf(timeout)));
|
||||
connection.setRequestMethod(method);
|
||||
connection.setRequestProperty(Constants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
|
||||
return connection;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.http;
|
||||
|
||||
import cn.hippo4j.common.constant.Constants;
|
||||
import cn.hippo4j.common.constant.HttpHeaderConstants;
|
||||
import cn.hippo4j.common.toolkit.IoUtil;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a client-side HTTP response with JDK implementation
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
public class JdkHttpClientResponse implements HttpClientResponse {
|
||||
|
||||
private final HttpURLConnection conn;
|
||||
|
||||
private InputStream responseStream;
|
||||
|
||||
private Header responseHeader;
|
||||
|
||||
private static final String CONTENT_ENCODING = "gzip";
|
||||
|
||||
public JdkHttpClientResponse(HttpURLConnection conn) {
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Header getHeaders() {
|
||||
if (this.responseHeader == null) {
|
||||
this.responseHeader = Header.newInstance();
|
||||
}
|
||||
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
|
||||
this.responseHeader.addOriginalResponseHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return this.responseHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public InputStream getBody() {
|
||||
Header headers = getHeaders();
|
||||
InputStream errorStream = this.conn.getErrorStream();
|
||||
this.responseStream = (errorStream != null ? errorStream : this.conn.getInputStream());
|
||||
String contentEncoding = headers.getValue(HttpHeaderConstants.CONTENT_ENCODING);
|
||||
// Used to process http content_encoding, when content_encoding is GZIP, use GZIPInputStream
|
||||
if (CONTENT_ENCODING.equals(contentEncoding)) {
|
||||
byte[] bytes = IoUtil.tryDecompress(this.responseStream);
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
return this.responseStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public int getStatusCode() {
|
||||
return this.conn.getResponseCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String getStatusText() {
|
||||
return this.conn.getResponseMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBodyString() {
|
||||
return IoUtil.toString(this.getBody(), Constants.ENCODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
IoUtil.closeQuietly(this.responseStream);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.logtracing;
|
||||
|
||||
import cn.hippo4j.common.toolkit.StringUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Log message.
|
||||
*
|
||||
* @author Rongzhen Yan
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class LogMessage {
|
||||
|
||||
private Map<String, Object> kvs = new ConcurrentHashMap<>();
|
||||
|
||||
private String msg = "";
|
||||
|
||||
public static LogMessage getInstance() {
|
||||
return new LogMessage();
|
||||
}
|
||||
|
||||
public LogMessage setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String msg(String msg, Object... args) {
|
||||
LogMessage l = new LogMessage();
|
||||
l.kvs = this.kvs;
|
||||
return l.setMsgString(msg, args);
|
||||
}
|
||||
|
||||
public LogMessage setMsg(String msg, Object... args) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, args);
|
||||
this.msg = ft.getThrowable() == null ? ft.getMessage() : ft.getMessage() + "||_fmt_throw=" + ft.getThrowable();
|
||||
return this;
|
||||
}
|
||||
|
||||
public String setMsgString(String msg, Object... args) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, args);
|
||||
this.msg = ft.getThrowable() == null ? ft.getMessage() : ft.getMessage() + "||_fmt_throw=" + ft.getThrowable();
|
||||
return toString();
|
||||
}
|
||||
|
||||
public LogMessage kv(String k, Object v) {
|
||||
this.kvs.put(k, v == null ? "" : v);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String kv2String(String k, Object v) {
|
||||
this.kvs.put(k, v == null ? "" : v);
|
||||
return toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (StringUtil.isNotEmpty(msg)) {
|
||||
sb.append(msg);
|
||||
}
|
||||
int tempCount = 0;
|
||||
for (Map.Entry<String, Object> kv : kvs.entrySet()) {
|
||||
tempCount++;
|
||||
Object value = kv.getValue();
|
||||
if (value != null) {
|
||||
if (value instanceof String && StringUtil.isEmpty((String) value)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(kv.getKey() + "=").append(kv.getValue());
|
||||
if (tempCount != kvs.size()) {
|
||||
sb.append("||");
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.common.toolkit.http;
|
||||
|
||||
import cn.hippo4j.common.toolkit.JSONUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpUtilsTest {
|
||||
|
||||
/**
|
||||
* test post url
|
||||
*/
|
||||
static String postUrl = "http://console.hippo4j.cn/hippo4j/v1/cs/";
|
||||
|
||||
/**
|
||||
* test get url
|
||||
*/
|
||||
static String getUrl = "https://hippo4j.cn/";
|
||||
|
||||
@Test
|
||||
public void get() {
|
||||
String s = HttpUtil.get(getUrl);
|
||||
Assert.assertNotNull(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void restApiPost() {
|
||||
String loginUrl = postUrl + "auth/login";
|
||||
LoginInfo loginInfo = new LoginInfo();
|
||||
loginInfo.setPassword("hippo4j");
|
||||
loginInfo.setUsername("hippo4j");
|
||||
loginInfo.setRememberMe(1);
|
||||
String s = HttpUtil.post(loginUrl, loginInfo);
|
||||
Result result = JSONUtil.parseObject(s, Result.class);
|
||||
Assert.assertNotNull(result);
|
||||
String data = result.getData().getData();
|
||||
Assert.assertNotNull(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestApiPost() {
|
||||
String loginUrl = postUrl + "auth/login";
|
||||
LoginInfo loginInfo = new LoginInfo();
|
||||
loginInfo.setPassword("hippo4j");
|
||||
loginInfo.setUsername("hippo4j");
|
||||
loginInfo.setRememberMe(1);
|
||||
Result result = HttpUtil.post(loginUrl, loginInfo, Result.class);
|
||||
Assert.assertNotNull(result);
|
||||
String data = result.getData().getData();
|
||||
Assert.assertNotNull(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestApiPostTimeout() {
|
||||
String loginUrl = postUrl + "auth/login";
|
||||
LoginInfo loginInfo = new LoginInfo();
|
||||
loginInfo.setPassword("hippo4j");
|
||||
loginInfo.setUsername("hippo4j");
|
||||
loginInfo.setRememberMe(1);
|
||||
Assert.assertThrows(SocketTimeoutException.class, () -> HttpUtil.post(loginUrl, loginInfo, 1, Result.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildUrl() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("password", "hippo4j");
|
||||
map.put("username", "hippo4j");
|
||||
String s = HttpUtil.buildUrl(getUrl, map);
|
||||
Assert.assertEquals(getUrl + "?password=hippo4j&username=hippo4j", s);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static class LoginInfo {
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private Integer rememberMe;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static class Result {
|
||||
|
||||
private String code;
|
||||
|
||||
private ResultData data;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private static class ResultData {
|
||||
|
||||
private String data;
|
||||
|
||||
private String[] roles;
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}
|
@ -1 +1 @@
|
||||
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-3efc76dc]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-3efc76dc]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-3efc76dc]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-3efc76dc]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-3efc76dc]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-3efc76dc]{position:relative}.login-container .title-container .title[data-v-3efc76dc]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-3efc76dc]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-3efc76dc]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-3efc76dc]{display:none}}
|
||||
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-13dcd441]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-13dcd441]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-13dcd441]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-13dcd441]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-13dcd441]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-13dcd441]{position:relative}.login-container .title-container .title[data-v-13dcd441]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-13dcd441]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-13dcd441]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-13dcd441]{display:none}}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-example</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>hippo4j-config-apollo-spring-boot-1x-starter-example</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<spring-boot.version>1.5.22.RELEASE</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-example-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ctrip.framework.apollo</groupId>
|
||||
<artifactId>apollo-client</artifactId>
|
||||
<version>${apollo.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<version>1.3.6.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-spring-legacy</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cn.hippo4j.example.config.apollo;
|
||||
|
||||
import cn.hippo4j.core.enable.EnableDynamicThreadPool;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@EnableDynamicThreadPool
|
||||
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.core")
|
||||
public class ConfigApolloSpringBoot1xExampleApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ConfigApolloSpringBoot1xExampleApplication.class, args);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
server.port=8091
|
||||
server.servlet.context-path=/example
|
||||
|
||||
app.id=dynamic-threadpool-example
|
||||
apollo.meta=http://127.0.0.1:8080
|
||||
apollo.autoUpdateInjectedSpringProperties=true
|
||||
apollo.bootstrap.enabled=true
|
||||
apollo.bootstrap.namespaces=application
|
||||
apollo.bootstrap.eagerLoad.enabled=true
|
||||
|
||||
spring.profiles.active=dev
|
||||
spring.application.name=dynamic-threadpool-example
|
||||
|
||||
management.security.enabled=false
|
||||
management.context-path=/actuator
|
||||
|
||||
spring.dynamic.thread-pool.enable=true
|
||||
spring.dynamic.thread-pool.banner=true
|
||||
spring.dynamic.thread-pool.check-state-interval=5
|
||||
spring.dynamic.thread-pool.collect-type=micrometer
|
||||
|
||||
spring.dynamic.thread-pool.notify-platforms[0].platform=WECHAT
|
||||
spring.dynamic.thread-pool.notify-platforms[0].token=ac0426a5-c712-474c-9bff-72b8b8f5caff
|
||||
|
||||
spring.dynamic.thread-pool.apollo.namespace=application
|
||||
spring.dynamic.thread-pool.config-file-type=properties
|
||||
|
||||
spring.dynamic.thread-pool.executors[0].active-alarm = 80
|
||||
spring.dynamic.thread-pool.executors[0].alarm = true
|
||||
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out = true
|
||||
spring.dynamic.thread-pool.executors[0].blocking-queue = LinkedBlockingQueue
|
||||
spring.dynamic.thread-pool.executors[0].capacity-alarm = 80
|
||||
spring.dynamic.thread-pool.executors[0].core-pool-size = 1
|
||||
spring.dynamic.thread-pool.executors[0].execute-time-out = 1000
|
||||
spring.dynamic.thread-pool.executors[0].keep-alive-time = 6691
|
||||
spring.dynamic.thread-pool.executors[0].maximum-pool-size = 1
|
||||
spring.dynamic.thread-pool.executors[0].notify.interval = 8
|
||||
spring.dynamic.thread-pool.executors[0].notify.receives = chen.ma
|
||||
spring.dynamic.thread-pool.executors[0].queue-capacity = 1
|
||||
spring.dynamic.thread-pool.executors[0].rejected-handler = AbortPolicy
|
||||
spring.dynamic.thread-pool.executors[0].thread-name-prefix = message-consume
|
||||
spring.dynamic.thread-pool.executors[0].thread-pool-id = message-consume
|
||||
spring.dynamic.thread-pool.executors[1].active-alarm = 80
|
||||
spring.dynamic.thread-pool.executors[1].alarm = true
|
||||
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
|
||||
spring.dynamic.thread-pool.executors[1].blocking-queue = LinkedBlockingQueue
|
||||
spring.dynamic.thread-pool.executors[1].capacity-alarm = 80
|
||||
spring.dynamic.thread-pool.executors[1].core-pool-size = 1
|
||||
spring.dynamic.thread-pool.executors[1].execute-time-out = 1000
|
||||
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
|
||||
spring.dynamic.thread-pool.executors[1].maximum-pool-size = 1
|
||||
spring.dynamic.thread-pool.executors[1].notify.interval = 8
|
||||
spring.dynamic.thread-pool.executors[1].notify.receives = chen.ma
|
||||
spring.dynamic.thread-pool.executors[1].queue-capacity = 1
|
||||
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
|
||||
spring.dynamic.thread-pool.executors[1].thread-name-prefix = message-produce
|
||||
spring.dynamic.thread-pool.executors[1].thread-pool-id = message-produce
|
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-example</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>hippo4j-config-nacos-spring-boot-1x-starter-example</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<spring-boot.version>1.5.22.RELEASE</spring-boot.version>
|
||||
<nacos-client.version>1.1.4</nacos-client.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
<version>1.5.1.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-example-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hippo4j</groupId>
|
||||
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-registry-prometheus</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-spring-legacy</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue