java访问Https服务的客户端示例

Wesley13
• 阅读 799

关于证书

1、每个人都可以使用一些证书生成工具为自己的https站点生成证书(比如JDK的keytool),大家称它为“自签名证书”,但是自己生成的证书是不被浏览器承认的,所以浏览器会报安全提示,要求你手动安装证书,提示风险,是否继续等。只有通过权威的CA机构付费获得的证书才能被浏览器承认。

2、证书(无客户端服务端之分)保存着IP信息、证书过期时间、证书所有者地址信息等。

双向认证

1、先决条件是有两个或两个以上的证书,一个是服务端证书,另一个或多个是客户端证书。

2、服务端保存着客户端的证书并信任该证书,客户端保存着服务端的证书并信任该证书。这样,在证书验证成功的情况下即可完成请求响应。

3、双向认证安全性更高。

单向认证

1、客户端保存着服务端的证书并信任该证书即可。

2、https一般是单向认证,这样可以让绝大部分人可以访问你的站点。

使用示例代码:

public interface PCIHttpClient {

    /** 请求头信息:Content-Type **/
    public static final String CONTENT_TYPE = "Content-Type";
    /** 请求头信息:User-Agent **/
    public static final String USER_AGENT = "User-Agent";
    /** 默认的内容类型 **/
    public static final String DEFAULT_CONTENTTYPE = "application/x-www-form-urlencoded;charset=UTF-8";
    /** 默认的用户代理(浏览器类型) **/
    public static final String DEFAULT_USERAGENT = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath.1; .NET CLR 1.1.4322; CIBA)";
    /** 默认的读取超时时间(单位毫秒) **/
    public static final int DEFAULT_TIMEOUT = 180000;
    /** 默认的连接超时时间(单位毫秒) **/
    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendGetAndResponseAsString(String url, 
            int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendGetAndResponseAsString(String url, 
            Map<String, String> headers, int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendGetAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendGetAndResponseAsByteArray(String url, 
            int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendGetAndResponseAsByteArray(String url, 
            Map<String, String> headers, int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendGetAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException;

    /**
     * 发送GET方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(输入流)
     * @throws IOException
     */
    public InputStream sendGetAndResponseAsStream(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException;

    /**
     * 发送GET方式请求
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @param output 响应内容(输出流)
     * @throws IOException
     */
    public void sendGet(String url, Map<String, String> headers, 
            Map<String, String> params, String charsetName, int timeout, 
            OutputStream output) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> params, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param timeout 超时时间(单位毫秒)
     * @param charsetName 字符编码
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            int timeout, String charsetName) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Object stringOrStream, 
            String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字符串)
     * @throws IOException
     */
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> params, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param timeout 超时时间(单位毫秒)
     * @param charsetName 字符编码
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            int timeout, String charsetName) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Object stringOrStream, 
            String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(字节数组)
     * @throws IOException
     */
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求数据,并接收响应数据
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return 响应内容(输入流)
     * @throws IOException
     */
    public InputStream sendPostAndResponseAsStream(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @param output 响应内容(输出流)
     * @throws IOException
     */
    public void sendPost(String url, Map<String, String> headers, 
            Map<String, String> params, Object stringOrStream, 
            String charsetName, int timeout, OutputStream output) throws IOException;

    /**
     * 发送GET方式请求
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return
     * @throws IOException
     * 
     * @since 2.0.0
     */
    public PCIHttpResponse sendGet(String url, Map<String, String> headers, 
            Map<String, String> params, String charsetName, int timeout) throws IOException;

    /**
     * 发送POST方式请求
     * 
     * @param url 请求地址
     * @param headers 请求头信息
     * @param params 请求参数
     * @param stringOrStream 请求体内容(字符串或者输入流)
     * @param charsetName 字符编码
     * @param timeout 超时时间(单位毫秒)
     * @return
     * @throws IOException
     * 
     * @since 2.0.0
     */
    public PCIHttpResponse sendPost(String url, Map<String, String> headers, 
            Map<String, String> params, Object stringOrStream, 
            String charsetName, int timeout) throws IOException;

}

public class CustomConstants {

    /** 字符编码:UTF-8 */
    public static final String CHARSET_UTF8 = "UTF-8";

}

public class CustomStringUtils {

    private static LogUtils logger = new LogUtils(CustomStringUtils.class);

    /**
     * 长度不足,左补字符
     * @param str
     * @param ch
     * @param len
     * @return
     */
    public static String leftFill(String str, char ch, int len) {
        if (str == null) {
            str = "";
        }
        while (str.length() < len) {
            str = ch + str;
        }
        return str;
    }

    /**
     * 长度不足,右补字符
     * @param str
     * @param ch
     * @param len
     * @return
     */
    public static String rightFill(String str, char ch, int len) {
        if (str == null) {
            str = "";
        }
        while (str.length() < len) {
            str = str + ch;
        }
        return str;
    }

    /**
     * 拼接字符串
     * @param objs
     * @return
     */
    public static String append(Object... objs) {
        if (objs == null || objs.length == 0) {
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (Object obj : objs) {
            buffer.append(obj);
        }
        return buffer.toString();
    }

    /**
     * 如果字符串为空,则返回空字符
     * @param str
     * @return
     */
    public static String nullToBlank(String str) {
        return str == null ? "" : str;
    }

    /**
     * 将map转化成字符串
     * @param map
     * @return 格式:key1=value1&key2=value2...
     */
    public static String convertMapToString(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        boolean first = true;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (first) {
                buffer.append(entry.getKey()).append("=").append(entry.getValue());
                first = false;
            } else {
                buffer.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
        }
        return buffer.toString();
    }

    /**
     * 将map转化成字符串,并对map.value进行URL编码
     * @param map
     * @param encoding
     * @return 格式:key1=value1&key2=value2...
     */
    public static String convertMapToString(Map<String, String> map, String encoding) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        boolean first = true;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (first) {
                buffer.append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding));
                first = false;
            } else {
                buffer.append("&").append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding));
            }
        }
        return buffer.toString();
    }

    /**
     * 将map转化成字符串(当参数值为null时,则忽略该参数)
     * @param map
     * @return 格式:key1=value1&key2=value2...
     */
    public static String convertMapToStringIgnoreNull(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        boolean first = true;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue() == null) {
                continue;
            }
            if (first) {
                buffer.append(entry.getKey()).append("=").append(entry.getValue());
                first = false;
            } else {
                buffer.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
        }
        return buffer.toString();
    }

    /**
     * 将map转化成字符串,并对map.value进行URL编码(当参数值为null时,则忽略该参数)
     * @param map
     * @param encoding
     * @return 格式:key1=value1&key2=value2...
     */
    public static String convertMapToStringIgnoreNull(Map<String, String> map, String encoding) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        StringBuffer buffer = new StringBuffer();
        boolean first = true;
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (entry.getValue() == null) {
                continue;
            }
            if (first) {
                buffer.append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding));
                first = false;
            } else {
                buffer.append("&").append(entry.getKey()).append("=").append(urlEncode(entry.getValue(), encoding));
            }
        }
        return buffer.toString();
    }

    /**
     * 对字符串进行URL编码
     * @param str
     * @param encoding
     * @return
     */
    public static String urlEncode(String str, String encoding) {
        if (str == null || "".equals(str)) {
            return str;
        }
        try {
            return URLEncoder.encode(str, encoding);
        } catch (UnsupportedEncodingException e) {
            logger.error(append("URL encode string error. str=", str, ", encoding=", encoding), e);
            return str;
        }
    }

    /**
     * 对字符串进行URL解码
     * @param str
     * @param encoding
     * @return
     */
    public static String urlDecode(String str, String encoding) {
        if (str == null || "".equals(str)) {
            return str;
        }
        try {
            return URLDecoder.decode(str, encoding);
        } catch (UnsupportedEncodingException e) {
            logger.error(append("URL decode string error. str=", str, ", encoding=", encoding), e);
            return str;
        }
    }

    /**
     * 字符串的字节长度是否超出边界值
     * @param str 字符串
     * @param bounds 边界值
     * @param charsetName 字符编码
     * @return
     */
    public static boolean bytesLengthOutOfBounds(
            String str, int bounds, String charsetName) {
        if (bounds < 0 || str == null || "".equals(str)) {
            return false;
        }
        try {
            int bytesLen = str.getBytes(charsetName).length;
            return bytesLen > bounds;
        } catch (UnsupportedEncodingException e) {
            logger.error(append("Check bytes length out of bounds error. str=", 
                    str, ", charsetName=", charsetName), e);
        }
        return false;
    }

    /**
     * @Title: generate 
     * @Description: 随机生成指定长度的16进制的字符串
     * @since: 0.0.1
     * @param len    字符串长度
     * @return
     */
    public static String generateRandomHex(int len){
        
        if (len < 1) {
            return null;
        }
        
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        
        for (int i = 0; i < len; i++) {
            sb.append(Integer.toHexString(random.nextInt(16)));
        }
        
        return sb.toString().toUpperCase();
    }
    
    /**
     * @Title: generateConformOddCheckHex 
     * @Description: 生成符合奇校验的字符串
     * @since: 0.0.1    
     * @param len    字节长度
     * @return
     */
    public static String generateConformOddCheckHex(int len) {
        
        byte[] bytes = new byte[len];
        for (int i = 0; i < len; i++) {
            Random random = new Random();
            int randomInt = random.nextInt(255);
            String binaryString = Integer.toBinaryString(randomInt);
            boolean oddCheck = isConformOddCheck(binaryString);
            if (!oddCheck) {
                randomInt ^= 1;
            }
//            System.err.println(Integer.toBinaryString(randomInt));
            byte b = (byte) randomInt;
            bytes[i] = b;
        } 
        String hexString = CommonUtils.byte2hexString(bytes);
        return hexString;
    }
    
    /**
     * @Title: oddCheck 
     * @Description: 检验是否符合奇校验
     * @since: 0.0.1
     * @param binaryString
     * @return
     */
    private static boolean isConformOddCheck(String binaryString) {
        int sum = 0;
        char[] charArray = binaryString.toCharArray();
        for(char c : charArray){
            if (c == '1') {
                sum ++;
            }
        }
        if (sum%2 == 1) {
            return true;
        }
        return false;
    }
    
}

public class IOUtils {

    private static LogUtils logger = new LogUtils(IOUtils.class);
    
    /** 默认的缓冲区大小 **/
    private static final int DEFAULT_BUFFER_SIZE = 4096;

    /**
     * 将字节输入流转换成字节数组
     * @param input
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            copy(input, output);
            return output.toByteArray();
        } finally {
            closeQuietly(output);
        }
    }

    /**
     * 将字符输入流转换成字节数组
     * @param reader
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(Reader reader) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            copy(reader, output);
            return output.toByteArray();
        } finally {
            closeQuietly(output);
        }
    }

    /**
     * 将字符输入流转换成字节数组
     * @param reader
     * @param encoding
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(Reader reader, String encoding) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            copy(reader, output, encoding);
            return output.toByteArray();
        } finally {
            closeQuietly(output);
        }
    }

    /**
     * 将字节输入流转换成字符串
     * @param input
     * @return
     * @throws IOException
     */
    public static String toString(InputStream input) throws IOException {
        StringWriter writer = null;
        try {
            writer = new StringWriter();
            copy(input, writer);
            return writer.toString();
        } finally {
            closeQuietly(writer);
        }
    }

    /**
     * 将字节输入流转换成字符串
     * @param input
     * @param encoding
     * @return
     * @throws IOException
     */
    public static String toString(InputStream input, String encoding) throws IOException {
        StringWriter writer = null;
        try {
            writer = new StringWriter();
            copy(input, writer, encoding);
            return writer.toString();
        } finally {
            closeQuietly(writer);
        }
    }

    /**
     * 将字符输入流转换成字符串
     * @param reader
     * @return
     * @throws IOException
     */
    public static String toString(Reader reader) throws IOException {
        StringWriter writer = null;
        try {
            writer = new StringWriter();
            copy(reader, writer);
            return writer.toString();
        } finally {
            closeQuietly(writer);
        }
    }

    /**
     * 按行读取字节输入流
     * @param input
     * @return
     * @throws IOException
     */
    public static List<String> readLines(InputStream input) throws IOException {
//        InputStreamReader reader = new InputStreamReader(input);
//        return readLines(reader);
        InputStreamReader reader = null;
        try {
            reader = new InputStreamReader(input);
            return readLines(reader);
        } finally {
            closeQuietly(reader);
        }
    }

    /**
     * 按行读取字节输入流
     * @param input
     * @param encoding
     * @return
     * @throws IOException
     */
    public static List<String> readLines(InputStream input, String encoding) throws IOException {
//        if (encoding == null) {
//            return readLines(input);
//        }
//        InputStreamReader reader = new InputStreamReader(input, encoding);
//        return readLines(reader);
        if (encoding == null) {
            return readLines(input);
        }
        InputStreamReader reader = null;
        try {
            reader = new InputStreamReader(input, encoding);
            return readLines(reader);
        } finally {
            closeQuietly(reader);
        }
    }

    /**
     * 按行读取字符输入流
     * @param reader
     * @return
     * @throws IOException
     */
    public static List<String> readLines(Reader reader) throws IOException {
//        BufferedReader br = new BufferedReader(reader);
//        List<String> lines = new ArrayList<String>();
//        String line = br.readLine();
//        while (line != null) {
//            lines.add(line);
//            line = br.readLine();
//        }
//        return lines;
        BufferedReader br = null;
        try {
            br = new BufferedReader(reader);
            List<String> lines = new ArrayList<String>();
            String line = br.readLine();
            while (line != null) {
                lines.add(line);
                line = br.readLine();
            }
            return lines;
        } finally {
            closeQuietly(br);
        }
    }

    /**
     * 阻塞地读取字节输入流
     * @param input
     * @param buffer
     * @param off
     * @param length
     * @throws IOException
     */
    public static void read(InputStream input, 
            byte[] buffer, int off, int length) throws IOException {
        while (off < length) {
            off = off + input.read(buffer, off, length - off);
            if (off < 0) {
                throw new IOException("读取时出错[readLen=" + off + "]");
            }
        }
    }

    /**
     * 将字节输入流拷贝到字符输出流
     * @param input
     * @param writer
     * @throws IOException
     */
    public static void copy(InputStream input, Writer writer) throws IOException {
//        InputStreamReader reader = new InputStreamReader(input);
//        copy(reader, writer);
        InputStreamReader reader = null;
        try {
            reader = new InputStreamReader(input);
            copy(reader, writer);
        } finally {
            closeQuietly(reader);
        }
    }

    /**
     * 将字节输入流拷贝到字符输出流
     * @param input
     * @param writer
     * @param encoding
     * @throws IOException
     */
    public static void copy(InputStream input, Writer writer, String encoding) throws IOException {
//        if (encoding == null) {
//            copy(input, writer);
//        } else {
//            InputStreamReader reader = new InputStreamReader(input, encoding);
//            copy(reader, writer);
//        }
        if (encoding == null) {
            copy(input, writer);
        } else {
            InputStreamReader reader = null;
            try {
                reader = new InputStreamReader(input, encoding);
                copy(reader, writer);
            } finally {
                closeQuietly(reader);
            }
        }
    }

    /**
     * 将字节输入流拷贝到字节输出流
     * @param input
     * @param output
     * @return 字节数
     * @throws IOException
     */
    public static int copy(InputStream input, OutputStream output) throws IOException {
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int count = 0;
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
            count += n;
        }
        output.flush();
        return count;
    }

    /**
     * 将字符输入流拷贝到字节输出流
     * @param reader
     * @param output
     * @throws IOException
     */
    public static void copy(Reader reader, OutputStream output) throws IOException {
//        OutputStreamWriter writer = new OutputStreamWriter(output);
//        copy(reader, writer);
        OutputStreamWriter writer = null;
        try {
            writer = new OutputStreamWriter(output);
            copy(reader, writer);
        } finally {
            closeQuietly(writer);
        }
    }

    /**
     * 将字符输入流拷贝到字节输出流
     * @param reader
     * @param output
     * @param encoding
     * @throws IOException
     */
    public static void copy(Reader reader, OutputStream output, String encoding)
            throws IOException {
//        if (encoding == null) {
//            copy(reader, output);
//        } else {
//            OutputStreamWriter writer = new OutputStreamWriter(output, encoding);
//            copy(reader, writer);
//        }
        if (encoding == null) {
            copy(reader, output);
        } else {
            OutputStreamWriter writer = null;
            try {
                writer = new OutputStreamWriter(output, encoding);
                copy(reader, writer);
            } finally {
                closeQuietly(writer);
            }
        }
    }

    /**
     * 将字符输入流拷贝到字符输出流
     * @param reader
     * @param writer
     * @return 字符数
     * @throws IOException
     */
    public static int copy(Reader reader, Writer writer) throws IOException {
        char[] buffer = new char[DEFAULT_BUFFER_SIZE];
        int count = 0;
        int n = 0;
        while (-1 != (n = reader.read(buffer))) {
            writer.write(buffer, 0, n);
            count += n;
        }
        writer.flush();
        return count;
    }

    /**
     * 关闭IO流
     * @param close
     */
    public static void closeQuietly(Closeable close) {
        closeQuietly(close, "关闭IO流出错!");
    }

    /**
     * 关闭IO流
     * @param close
     * @param errorMsg
     */
    public static void closeQuietly(Closeable close, String errorMsg) {
        if (close != null) {
            try {
                close.close();
            } catch (IOException e) {
                logger.error(errorMsg, e);
            }
        }
    }

public class PCIHttpClientImpl4 implements PCIHttpClient {

    private static LogUtils logger = new LogUtils(PCIHttpClientImpl4.class);
    
    private SSLConnectionSocketFactory sslSocketFactory = null;

    /**
     * 构造方法
     * 
     * <p>允许信任任何证书策略和允许任何域名验证</p>
     */
    public PCIHttpClientImpl4() {
        this(false, false, true, true, null, null, null);
    }

    /**
     * 构造方法
     * 
     * @param allowAnyTrustMaterial 是否允许信任任何证书策略
     * @param allowAnyHostnameVerifier 是否允许任何域名验证
     */
    public PCIHttpClientImpl4(boolean allowAnyTrustMaterial, boolean allowAnyHostnameVerifier) {
        this(false, false, allowAnyTrustMaterial, allowAnyHostnameVerifier, null, null, null);
    }

    /**
     * 构造方法
     * 
     * @param loadKeyMaterial 是否加载密钥
     * @param loadTrustMaterial 是否加载信任证书
     * @param keystoreFilePath 密钥库文件路径
     * @param storePassword 密钥库密码
     * @param keyPassword 私钥密码
     */
    public PCIHttpClientImpl4(boolean loadKeyMaterial, boolean loadTrustMaterial, 
            String keystoreFilePath, String storePassword, String keyPassword) {
        this(loadKeyMaterial, loadTrustMaterial, false, true, keystoreFilePath, storePassword, keyPassword);
    }

    /**
     * 构造方法
     * 
     * @param loadKeyMaterial 是否加载密钥
     * @param loadTrustMaterial 是否加载信任证书(若allowAnyTrustMaterial=true,则loadTrustMaterial无效)
     * @param allowAnyTrustMaterial 是否允许信任任何证书策略
     * @param allowAnyHostnameVerifier 是否允许任何域名验证
     * @param keystoreFilePath 密钥库文件路径
     * @param storePassword 密钥库密码
     * @param keyPassword 私钥密码
     */
    public PCIHttpClientImpl4(boolean loadKeyMaterial, boolean loadTrustMaterial, 
            boolean allowAnyTrustMaterial, boolean allowAnyHostnameVerifier, 
            String keystoreFilePath, String storePassword, String keyPassword) {
        try {
            // Create SSLContext
            SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
            if (loadKeyMaterial) {
                sslContextBuilder.loadKeyMaterial(
                        new File(keystoreFilePath), storePassword.toCharArray(), keyPassword.toCharArray());
            }
            if (allowAnyTrustMaterial) {
                sslContextBuilder.loadTrustMaterial(null, new AnyTrustStrategy());
            } else if (loadTrustMaterial) {
                sslContextBuilder.loadTrustMaterial(
                        new File(keystoreFilePath), storePassword.toCharArray(), new TrustSelfSignedStrategy());
            }
            SSLContext sslContext = sslContextBuilder.build();
            
            // Create SSLConnectionSocketFactory
            if (allowAnyHostnameVerifier) {
                sslSocketFactory = new SSLConnectionSocketFactory(sslContext, new AnyHostnameVerifier());
            } else {
                sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
            }
        } catch (NoSuchAlgorithmException e) {
            logger.error("Error occurred: NoSuchAlgorithmException", e);
        } catch (KeyStoreException e) {
            logger.error("Error occurred: KeyStoreException", e);
        } catch (UnrecoverableKeyException e) {
            logger.error("Error occurred: UnrecoverableKeyException", e);
        } catch (CertificateException e) {
            logger.error("Error occurred: CertificateException", e);
        } catch (IOException e) {
            logger.error("Error occurred: IOException", e);
        } catch (KeyManagementException e) {
            logger.error("Error occurred: KeyManagementException", e);
        }
    }

    /**
     * 信任任何证书策略
     */
    private static class AnyTrustStrategy implements TrustStrategy {
        @Override
        public boolean isTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            return true;
        }
    }

    /**
     * 允许任何域名验证
     */
    private static class AnyHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    @Override
    public String sendGetAndResponseAsString(String url, 
            int timeout) throws IOException {
        return sendGetAndResponseAsString(url, null, null, CustomConstants.CHARSET_UTF8, timeout);
    }

    @Override
    public String sendGetAndResponseAsString(String url, 
            Map<String, String> headers, int timeout) throws IOException {
        return sendGetAndResponseAsString(url, headers, null, CustomConstants.CHARSET_UTF8, timeout);
    }

    @Override
    public String sendGetAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException {
        byte[] buffer = sendGetAndResponseAsByteArray(url, headers, params, charsetName, timeout);
        if (buffer == null) {
            return null;
        }
        return new String(buffer, charsetName);
    }

    @Override
    public byte[] sendGetAndResponseAsByteArray(String url, 
            int timeout) throws IOException {
        return sendGetAndResponseAsByteArray(url, null, null, null, timeout);
    }

    @Override
    public byte[] sendGetAndResponseAsByteArray(String url, 
            Map<String, String> headers, int timeout) throws IOException {
        return sendGetAndResponseAsByteArray(url, headers, null, null, timeout);
    }

    @Override
    public byte[] sendGetAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            sendGet(url, headers, params, charsetName, timeout, output);
            return output.toByteArray();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    @Override
    public InputStream sendGetAndResponseAsStream(String url, 
            Map<String, String> headers, Map<String, String> params, 
            String charsetName, int timeout) throws IOException {
        byte[] buffer = sendGetAndResponseAsByteArray(url, headers, params, charsetName, timeout);
        if (buffer == null) {
            return null;
        }
        return new ByteArrayInputStream(buffer);
    }

    @Override
    public void sendGet(String url, Map<String, String> headers, 
            Map<String, String> params, String charsetName, int timeout, 
            OutputStream output) throws IOException {
        if (StringUtils.isEmpty(url)) {
            logger.error("The url can not be null.");
            throw new IllegalArgumentException("The url can not be null.");
        }
        sendAndResponseAsStream(new HttpGet(createURI(url, params, charsetName)), 
                headers, timeout, output);
    }

    @Override
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> params, String charsetName, int timeout) throws IOException {
        return sendPostAndResponseAsString(url, null, params, null, charsetName, timeout);
    }

    @Override
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            int timeout, String charsetName) throws IOException {
        return sendPostAndResponseAsString(url, headers, params, null, charsetName, timeout);
    }

    @Override
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Object stringOrStream, 
            String charsetName, int timeout) throws IOException {
        return sendPostAndResponseAsString(url, headers, null, stringOrStream, charsetName, timeout);
    }

    @Override
    public String sendPostAndResponseAsString(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException {
        byte[] buffer = sendPostAndResponseAsByteArray(
                url, headers, params, stringOrStream, charsetName, timeout);
        if (buffer == null) {
            return null;
        }
        return new String(buffer, charsetName);
    }

    @Override
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> params, String charsetName, int timeout) throws IOException {
        return sendPostAndResponseAsByteArray(url, null, params, null, charsetName, timeout);
    }

    @Override
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            int timeout, String charsetName) throws IOException {
        return sendPostAndResponseAsByteArray(url, headers, params, null, charsetName, timeout);
    }

    @Override
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Object stringOrStream, 
            String charsetName, int timeout) throws IOException {
        return sendPostAndResponseAsByteArray(url, headers, null, stringOrStream, charsetName, timeout);
    }

    @Override
    public byte[] sendPostAndResponseAsByteArray(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException {
        ByteArrayOutputStream output = null;
        try {
            output = new ByteArrayOutputStream();
            sendPost(url, headers, params, stringOrStream, charsetName, timeout, output);
            return output.toByteArray();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    @Override
    public InputStream sendPostAndResponseAsStream(String url, 
            Map<String, String> headers, Map<String, String> params, 
            Object stringOrStream, String charsetName, int timeout) throws IOException {
        byte[] buffer = sendPostAndResponseAsByteArray(
                url, headers, params, stringOrStream, charsetName, timeout);
        if (buffer == null) {
            return null;
        }
        return new ByteArrayInputStream(buffer);
    }

    @Override
    public void sendPost(String url, Map<String, String> headers, 
            Map<String, String> params, Object stringOrStream, 
            String charsetName, int timeout, OutputStream output) throws IOException {
        if (StringUtils.isEmpty(url)) {
            logger.error("The url can not be null.");
            throw new IllegalArgumentException("The url can not be null.");
        }
        
        // post请求方式
        HttpPost method = new HttpPost(createURI(url, params, charsetName));
        
        // 设置请求头信息
        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        if (!headers.containsKey(CONTENT_TYPE)) {
            headers.put(CONTENT_TYPE, DEFAULT_CONTENTTYPE);
        }
        
        // 设置请求体内容
        if (stringOrStream != null) {
            HttpEntity entity = null;
            if (stringOrStream instanceof InputStream) {
                entity = new InputStreamEntity((InputStream) stringOrStream);
            } else {
                entity = new StringEntity(stringOrStream.toString(), 
                        ContentType.create(CONTENT_TYPE, charsetName));
            }
            method.setEntity(entity);
        }
        
        // 发送请求数据,并接收响应数据
        sendAndResponseAsStream(method, headers, timeout, output);
    }

    /**
     * 发送请求数据,并接收响应数据
     * @param method 请求方式
     * @param headers 请求头信息
     * @param timeout 超时时间
     * @param output 响应内容(输出流)
     * @throws IOException
     */
    private void sendAndResponseAsStream(HttpRequestBase method, 
            Map<String, String> headers, int timeout, OutputStream output) throws IOException {
        // 设置请求配置信息
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT) //连接超时时间
                .setSocketTimeout(timeout) //读取超时时间
                .setCircularRedirectsAllowed(true) //设置是否允许循环重定向(重定向到相同路径)
                .build();
        method.setConfig(config);
        
        // 设置请求头信息
        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        if (!headers.containsKey(USER_AGENT)) {
            headers.put(USER_AGENT, DEFAULT_USERAGENT);
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            method.setHeader(entry.getKey(), entry.getValue());
        }
        
        // 发送请求
        CloseableHttpClient httpClient = createHttpClient(method.getURI());
        CloseableHttpResponse httpResponse = null;
        InputStream input = null;
        try {
            httpResponse = httpClient.execute(method);
            int status = httpResponse.getStatusLine().getStatusCode();
            if (status != HttpStatus.SC_OK) {
                String errorMsg = CustomStringUtils.append("The remote service[", 
                        method.getURI(), "] respose an error status:", status);
                logger.error(errorMsg);
                if (status >= 500 && status < 600) {
                    throw new IOException(errorMsg);
                }
            }
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity == null) {
                String errorMsg = CustomStringUtils.append("The remote service[", 
                        method.getURI(), "] respose entity is null. status:", status);
                logger.error(errorMsg);
                throw new IOException(errorMsg);
            }
            input = httpEntity.getContent();
            if (input == null) {
                String errorMsg = CustomStringUtils.append("The remote service[", 
                        method.getURI(), "] respose entity content is null. status:", status);
                logger.error(errorMsg);
                throw new IOException(errorMsg);
            }
            IOUtils.copy(input, output);
        } catch (IOException e) {
            logger.error("Access to the remote service[" + method.getURI() + "] error.", e);
            throw e;
        } finally {
            IOUtils.closeQuietly(input);
//            method.releaseConnection();
            IOUtils.closeQuietly(httpResponse);
            IOUtils.closeQuietly(httpClient);
        }
    }

    /**
     * 创建HttpClient对象
     * @param uri
     * @return
     */
    private CloseableHttpClient createHttpClient(URI uri) {
        if ("https".equalsIgnoreCase(uri.getScheme()) && sslSocketFactory != null) {
            return HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
        } else {
            return HttpClients.createDefault();
        }
    }

    /**
     * 创建请求URI
     * @param url
     * @param params
     * @param charsetName
     * @return
     * @throws IOException
     */
    private URI createURI(String url, 
            Map<String, String> params, String charsetName) throws IOException {
        if (params == null || params.isEmpty()) {
            return URI.create(url);
        }
        // 设置请求参数
        List<NameValuePair> parameters = new ArrayList<NameValuePair>(params.size());
        for (Map.Entry<String, String> entry : params.entrySet()) {
            parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        try {
            return new URIBuilder(url)
                .addParameters(parameters)
                .setCharset(Charset.forName(charsetName))
                .build();
        } catch (URISyntaxException e) {
            String errorMsg = "Build request URI error, the url is [" + url + "].";
            logger.error(errorMsg, e);
            throw new IOException(errorMsg, e);
        }
    }

    /** 
     * @see PCIHttpClient.com.bestpay.pgw.tools.http.PGWHttpClient#sendGet(java.lang.String, java.util.Map, java.util.Map, java.lang.String, int)
     */
    @Override
    public PCIHttpResponse sendGet(String url, Map<String, String> headers,
            Map<String, String> params, String charsetName, int timeout)
            throws IOException {
        if (StringUtils.isEmpty(url)) {
            logger.error("The url can not be null.");
            throw new IllegalArgumentException("The url can not be null.");
        }
        return sendAndResponseAsStream(
                new HttpGet(createURI(url, params, charsetName)), headers, timeout);
    }

    /** 
     * @see PCIHttpClient.com.bestpay.pgw.tools.http.PGWHttpClient#sendPost(java.lang.String, java.util.Map, java.util.Map, java.lang.Object, java.lang.String, int)
     */
    @Override
    public PCIHttpResponse sendPost(String url, Map<String, String> headers,
            Map<String, String> params, Object stringOrStream,
            String charsetName, int timeout) throws IOException {
        if (StringUtils.isEmpty(url)) {
            logger.error("The url can not be null.");
            throw new IllegalArgumentException("The url can not be null.");
        }
        
        // post请求方式
        HttpPost method = new HttpPost(createURI(url, params, charsetName));
        
        // 设置请求头信息
        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        if (!headers.containsKey(CONTENT_TYPE)) {
            headers.put(CONTENT_TYPE, DEFAULT_CONTENTTYPE);
        }
        
        // 设置请求体内容
        if (stringOrStream != null) {
            HttpEntity entity = null;
            if (stringOrStream instanceof InputStream) {
                entity = new InputStreamEntity((InputStream) stringOrStream);
            } else {
                entity = new StringEntity(stringOrStream.toString(), 
                        ContentType.create(CONTENT_TYPE, charsetName));
            }
            method.setEntity(entity);
        }
        
        // 发送请求数据,并接收响应数据
        return sendAndResponseAsStream(method, headers, timeout);
    }

    /**
     * 发送请求数据,并接收响应数据
     * 
     * @param method 请求方式
     * @param headers 请求头信息
     * @param timeout 超时时间
     * @return
     * @throws IOException
     * 
     * @since 2.0.0
     */
    private PCIHttpResponse sendAndResponseAsStream(HttpRequestBase method, 
            Map<String, String> headers, int timeout) throws IOException {
        // 设置请求配置信息
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT) //连接超时时间
                .setSocketTimeout(timeout) //读取超时时间
                .setCircularRedirectsAllowed(true) //设置是否允许循环重定向(重定向到相同路径)
                .build();
        method.setConfig(config);
        
        // 设置请求头信息
        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        if (!headers.containsKey(USER_AGENT)) {
            headers.put(USER_AGENT, DEFAULT_USERAGENT);
        }
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            method.setHeader(entry.getKey(), entry.getValue());
        }
        
        // 发送请求
        CloseableHttpClient httpClient = createHttpClient(method.getURI());
        CloseableHttpResponse httpResponse = null;
        InputStream responseBodyInputStream = null;
        ByteArrayOutputStream responseBodyOutputStream = null;
        try {
            httpResponse = httpClient.execute(method);
            int status = httpResponse.getStatusLine().getStatusCode();
            if (status != HttpStatus.SC_OK) {
                String errorMsg = CustomStringUtils.append("The remote service[", 
                        method.getURI(), "] respose an error status:", status);
                logger.error(errorMsg);
                if (status >= 500 && status < 600) {
                    throw new IOException(errorMsg);
                }
            }
            
            // 获取响应头
            Map<String, String> responseHeaders = null;
            Header[] httpHeaders = httpResponse.getAllHeaders();
            if (httpHeaders != null && httpHeaders.length > 0) {
                responseHeaders = new HashMap<String, String>(httpHeaders.length);
                for (Header header : httpHeaders) {
                    responseHeaders.put(header.getName(), header.getValue());
                }
            }
            
            // 获取响应体
            byte[] responseBody = null;
            HttpEntity httpEntity = httpResponse.getEntity();
            if (httpEntity != null) {
                responseBodyInputStream = httpEntity.getContent();
                if (responseBodyInputStream != null) {
                    responseBodyOutputStream = new ByteArrayOutputStream();
                    IOUtils.copy(responseBodyInputStream, responseBodyOutputStream);
                    responseBody = responseBodyOutputStream.toByteArray();
                } else {
                    logger.warn(CustomStringUtils.append("The remote service[", 
                            method.getURI(), "] respose entity content is null. status:", status));
                }
            } else {
                logger.warn(CustomStringUtils.append("The remote service[", 
                        method.getURI(), "] respose entity is null. status:", status));
            }
            
            return new PCIHttpResponse(responseHeaders, responseBody);
        } catch (IOException e) {
            logger.error("Access to the remote service[" + method.getURI() + "] error.", e);
            throw e;
        } finally {
            IOUtils.closeQuietly(responseBodyInputStream);
            IOUtils.closeQuietly(responseBodyOutputStream);
//            method.releaseConnection();
            IOUtils.closeQuietly(httpResponse);
            IOUtils.closeQuietly(httpClient);
        }
    }

}

单元测试示例(本示例为双向认证示例,单向认证则对应修改PCIHttpClientImpl4的构造参数即可):

    @Test
    public void testClock() throws Exception {
        String testUrl = "https://mail.xxxxxx.com:8440/service";
        Map<String, String> map = new HashMap<String, String>();
        
        map.put("messageType", "2058");
        map.put("accessUser", "gxecard_test_user_zhengchuan");
        map.put("terminalNo", "1");
        
        String parameter = JSON.toJSONString(map);
        String requestJson = "parameter=" + parameter;
        System.out.println("requestJson:" + requestJson);
        
//        httpClient = new PCIHttpClientImpl4(true, false, 
//                true, true, 
//                "D:\\keystore.jks", "123456", "123456");
            
    
                //证书可以是jks格式也可以是p12格式 
        httpClient = new PCIHttpClientImpl4(true, false, 
        true, true, 
        "D:\\keystore.p12", "123456", "123456");
        
        PCIHttpResponse httpResponse = null;
        httpResponse = httpClient.sendPost(testUrl, null, null, requestJson, "UTF-8", 55 * 1000);
        
        System.out.println(httpResponse.getBodyString());
    }
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
2个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
8个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这