首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

Apache 年度报告:Java 是项目开发使用最多的语言

Apache 2018 年年度报告显示,该生态系统今年生态系统活跃增长,甚至会有盈余。Apache 基金会拥有 300 多个项目和超过 6,700 个代码贡献者,现在是世界上最大的开源基金会。 项目领域涵盖从大数据到云计算再到内容管理的所有内容,最大的代码存储库用于处理 OpenOffice 的开源文档。 Apache 软件基金会总裁 Phil Steitz 表示,2018 年会是基金会发展很好的一年,他们会继续确保 Apache 软件基金会提供优质可靠的服务,并让 Apache Software Foundation 成为一个轻量级,轻度管理的组织。 最重要的是为确保可持续发展的基础奠定坚实的财政基础。 Apache 软件基金会基础设施副总裁 David Nalley 表示,去年提供的 GitBox 服务在今年得到了显着的扩展和改进,并希望所有使用 Git 的项目都将转向这个新的工作流程,计划明年放弃最初在内部使用的 Git 工具。 该报告揭示了基金会的持续增长: 在顶层项目中,194 个委员会共管理 319 个项目,其中 16 个是新项目,现在有 54 个项目处于孵化阶段 基于这上述项目,原始代码在过去一年中已被下载 900 万次。 共有 3,280 名提交者提交了 7100 万次代码。经换算,在 222,684 次提交中,贡献了超 6 亿美元的价值 从项目使用的代码语言的分布来看,Java 第一,占所有项目的 58%,第二位是 C,第三位是 Python,第四位和第五位是 C++ 和 Javascript,两者差距不大。

优秀的个人博客,低调大师

实战 Docker+Kubernetes 微服务容器化(三)-微服务开发

1 微服务业务分析 thrift 官网 安装 下载 boost 如果報錯error: Bison version 2.5 or higher must be installed on the system! 解決辦法:mac中默認安裝了bison 2.3版本,並配置了路徑在path中。安裝最新的版本3.0.5, 並將/usr/bin中的bison刪除,將bison 3.0.5 複製到/usr/bin中 cd /usr/bin brew install bison brew unlink bison source ~/.bash_profile 或者export PATH=/usr/local/Cellar/bison/3.0.5/bin:$PATH 新建 demo 文件 生成对应语言文件 生成众多的方法

优秀的个人博客,低调大师

25.Android Studio下Ndk开发(参数加密解决方案)

网络请求通过http传递到后台,如果不对数据做加密处理的话,很容易会被抓包,此时,app就是很不安全的,被截取到接口地址和参数后容易被攻击。今天我要分享的就是如何提高网络接口安全性的解决方案。 之前做的项目是采取直接在java层对参数进行加密,加密方式也有很多,RSA加密,MD5加密,AES加密,DES加密,Base64加密等等,具体介绍可以参考这里 Android中的加密方法(http://www.cnblogs.com/whoislcj/p/5470095.html),这种方式在一定程度上可以提高数据的安全性,但是深入来看,我们的加密方式对外暴露出来,当app被反编译时,对方可以拿到我们的代码,可以看到我们加密的方式,这样一来,会更加容易让对方找到破解密文的方法,因为在目前所有加密方式中,既具备实用性又具备绝对安全性的方法是不存在的。所以我们是否可以做到加密方式也对外不可见呢,或者如果不能做到绝对不可见,是否可以大大的提高对方破解密文的难度。这就是今天要做的,通过jni将加密方法打包到so库中,防止被放编译,算是在这些加密算法的上面加一层壳,这里以md5加密为例。 so库破解的难度之大,远远超过破解混淆后的apk,所以jni是解决安全性隐患的一个切入点。 创建CMakeLists文件,配置相关的内容 #参数加密 cmake_minimum_required(VERSION 3.4.1) find_library( log-lib log ) add_library( encrypt SHARED src/main/cpp/encrypt.cpp src/main/cpp/md5.cpp) # 将预构建库与本地库相连 target_link_libraries( encrypt ${log-lib} ) EncryptUtils package com.app.rzm.utils; import android.content.Context; /** * ndk实现参数加密 */ public class EncryptUtils { static { System.loadLibrary("encrypt"); } public static String encrypt(Context context, String param){ checkSignature(context); return encryptNative(context,param); } /** * 对一个字符串进行加密 * @param context * @param param * @return */ private static native String encryptNative(Context context, String param); /** * 校验app签名 * @param context */ private static native void checkSignature(Context context); } 调用方式 public class TestParamsEncryptActivity extends AppCompatActivity { private TextView mText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_params_encrypt); mText = (TextView) findViewById(R.id.text); //拿到签名 try { PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); Signature[] signatures = packageInfo.signatures; LogUtils.d("signature:"+signatures[0].toCharsString()); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } //将网络请求中的http参数拼接成这样的字符串username=renzhenming&password=123456 //然后将这个参数字符串进行加密 String params = EncryptUtils.encrypt(this,"username=renzhenming&password=123456"); //作为参数给到服务器,服务器也生成同样的密文,然后将加密的字符串进行比较 mText.setText(params); } } 接下来是关键代码,在c++中实现md5加密, * 加密解密的过程: md5.h #ifndef MD5_H #define MD5_H typedef struct { unsigned int count[2]; unsigned int state[4]; unsigned char buffer[64]; }MD5_CTX; #define F(x,y,z) ((x & y) | (~x & z)) #define G(x,y,z) ((x & z) | (y & ~z)) #define H(x,y,z) (x^y^z) #define I(x,y,z) (y ^ (x | ~z)) #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) #define FF(a,b,c,d,x,s,ac) { \ a += F(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define GG(a,b,c,d,x,s,ac) { \ a += G(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define HH(a,b,c,d,x,s,ac) { \ a += H(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } #define II(a,b,c,d,x,s,ac) { \ a += I(b, c, d) + x + ac; \ a = ROTATE_LEFT(a, s); \ a += b; \ } void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); void MD5Final(MD5_CTX *context, unsigned char digest[16]); void MD5Transform(unsigned int state[4], unsigned char block[64]); void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); #endif md5.cpp #include "md5.h" #include "string" unsigned char PADDING[] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //在逆向代码的时候,需要关注下面的特征值 void MD5Init(MD5_CTX *context) { context->count[0] = 0; context->count[1] = 0; context->state[0] = 0x67452301; context->state[1] = 0xEFCDAB89; context->state[2] = 0x98BADCFE; context->state[3] = 0x10325476; } void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen) { unsigned int i = 0, index = 0, partlen = 0; index = (context->count[0] >> 3) & 0x3F; partlen = 64 - index; context->count[0] += inputlen << 3; if (context->count[0] < (inputlen << 3)) context->count[1]++; context->count[1] += inputlen >> 29; if (inputlen >= partlen) { memcpy(&context->buffer[index], input, partlen); MD5Transform(context->state, context->buffer); for (i = partlen; i + 64 <= inputlen; i += 64) MD5Transform(context->state, &input[i]); index = 0; } else { i = 0; } memcpy(&context->buffer[index], &input[i], inputlen - i); } void MD5Final(MD5_CTX *context, unsigned char digest[16]) { unsigned int index = 0, padlen = 0; unsigned char bits[8]; index = (context->count[0] >> 3) & 0x3F; padlen = (index < 56) ? (56 - index) : (120 - index); MD5Encode(bits, context->count, 8); MD5Update(context, PADDING, padlen); MD5Update(context, bits, 8); MD5Encode(digest, context->state, 16); } void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[j] = input[i] & 0xFF; output[j + 1] = (input[i] >> 8) & 0xFF; output[j + 2] = (input[i] >> 16) & 0xFF; output[j + 3] = (input[i] >> 24) & 0xFF; i++; j += 4; } } void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len) { unsigned int i = 0, j = 0; while (j < len) { output[i] = (input[j]) | (input[j + 1] << 8) | (input[j + 2] << 16) | (input[j + 3] << 24); i++; j += 4; } } void MD5Transform(unsigned int state[4], unsigned char block[64]) { unsigned int a = state[0]; unsigned int b = state[1]; unsigned int c = state[2]; unsigned int d = state[3]; unsigned int x[64]; MD5Decode(x, block, 64); FF(a, b, c, d, x[0], 7, 0xd76aa478); FF(d, a, b, c, x[1], 12, 0xe8c7b756); FF(c, d, a, b, x[2], 17, 0x242070db); FF(b, c, d, a, x[3], 22, 0xc1bdceee); FF(a, b, c, d, x[4], 7, 0xf57c0faf); FF(d, a, b, c, x[5], 12, 0x4787c62a); FF(c, d, a, b, x[6], 17, 0xa8304613); FF(b, c, d, a, x[7], 22, 0xfd469501); FF(a, b, c, d, x[8], 7, 0x698098d8); FF(d, a, b, c, x[9], 12, 0x8b44f7af); FF(c, d, a, b, x[10], 17, 0xffff5bb1); FF(b, c, d, a, x[11], 22, 0x895cd7be); FF(a, b, c, d, x[12], 7, 0x6b901122); FF(d, a, b, c, x[13], 12, 0xfd987193); FF(c, d, a, b, x[14], 17, 0xa679438e); FF(b, c, d, a, x[15], 22, 0x49b40821); GG(a, b, c, d, x[1], 5, 0xf61e2562); GG(d, a, b, c, x[6], 9, 0xc040b340); GG(c, d, a, b, x[11], 14, 0x265e5a51); GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); GG(a, b, c, d, x[5], 5, 0xd62f105d); GG(d, a, b, c, x[10], 9, 0x2441453); GG(c, d, a, b, x[15], 14, 0xd8a1e681); GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); GG(a, b, c, d, x[9], 5, 0x21e1cde6); GG(d, a, b, c, x[14], 9, 0xc33707d6); GG(c, d, a, b, x[3], 14, 0xf4d50d87); GG(b, c, d, a, x[8], 20, 0x455a14ed); GG(a, b, c, d, x[13], 5, 0xa9e3e905); GG(d, a, b, c, x[2], 9, 0xfcefa3f8); GG(c, d, a, b, x[7], 14, 0x676f02d9); GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); HH(a, b, c, d, x[5], 4, 0xfffa3942); HH(d, a, b, c, x[8], 11, 0x8771f681); HH(c, d, a, b, x[11], 16, 0x6d9d6122); HH(b, c, d, a, x[14], 23, 0xfde5380c); HH(a, b, c, d, x[1], 4, 0xa4beea44); HH(d, a, b, c, x[4], 11, 0x4bdecfa9); HH(c, d, a, b, x[7], 16, 0xf6bb4b60); HH(b, c, d, a, x[10], 23, 0xbebfbc70); HH(a, b, c, d, x[13], 4, 0x289b7ec6); HH(d, a, b, c, x[0], 11, 0xeaa127fa); HH(c, d, a, b, x[3], 16, 0xd4ef3085); HH(b, c, d, a, x[6], 23, 0x4881d05); HH(a, b, c, d, x[9], 4, 0xd9d4d039); HH(d, a, b, c, x[12], 11, 0xe6db99e5); HH(c, d, a, b, x[15], 16, 0x1fa27cf8); HH(b, c, d, a, x[2], 23, 0xc4ac5665); II(a, b, c, d, x[0], 6, 0xf4292244); II(d, a, b, c, x[7], 10, 0x432aff97); II(c, d, a, b, x[14], 15, 0xab9423a7); II(b, c, d, a, x[5], 21, 0xfc93a039); II(a, b, c, d, x[12], 6, 0x655b59c3); II(d, a, b, c, x[3], 10, 0x8f0ccc92); II(c, d, a, b, x[10], 15, 0xffeff47d); II(b, c, d, a, x[1], 21, 0x85845dd1); II(a, b, c, d, x[8], 6, 0x6fa87e4f); II(d, a, b, c, x[15], 10, 0xfe2ce6e0); II(c, d, a, b, x[6], 15, 0xa3014314); II(b, c, d, a, x[13], 21, 0x4e0811a1); II(a, b, c, d, x[4], 6, 0xf7537e82); II(d, a, b, c, x[11], 10, 0xbd3af235); II(c, d, a, b, x[2], 15, 0x2ad7d2bb); II(b, c, d, a, x[9], 21, 0xeb86d391); state[0] += a; state[1] += b; state[2] += c; state[3] += d; } 客户端通过定义的规则将参数加密后,将密文和铭文参数同时传递到服务器,服务器收到参数进行解析,使用同样的加密算法将参数加密,然后对比此次得到的密文和客户端传递的密文是否相同,如果相同说明数据安全,没有被篡改,如果不同,则表示数据改变,不再发送数据到客户端 将加密方法打包到so库中的好处就是可以防止对方反编译看到我们的加密条件,如果对方不知道我们是如何加密的,也就可以在一定程度上防止数据泄漏,但是只是单纯的这样做并不能保证绝对的安全,比如,我不需要知道你是怎么加密的,只需要反编译apk后得到几个信息1.你应用的包名,2.你的so库,3.你的native方法 的完整类名和方法名(native方法不能被混淆,混淆后无法使用,所以可以得到),只要得到这三个信息,我就可以创建包名相同方法名相同的一个应用,把so放进去,然后就可以绕过密钥检查,轻松的调用你的接口了。 解决这个问题的方法就是在so库中加入签名验证,当调用加密方法对操作参数的时候,验证此时应用签名是否是我们本应用的,如果不是,则表示当前应用是伪应用,直接返回, 防止上边那种恶意调用接口情况的出现。对签名做校验,也就是只允许指定的应用可以使用,类似在微信支付中,也有在官方管理后台申请和配置应用的的签名和包名,否则就禁止使用,签名和包名必须得要一致。 com_app_rzm_utils_EncryptUtils.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_app_rzm_utils_Encryptils */ #ifndef _Included_com_app_rzm_utils_EncryptUtils #define _Included_com_app_rzm_utils_EncryptUtils #ifdef __cplusplus extern "C" { #endif /* * Class: com_app_rzm_utils_Encryptils * Method: encryptNative * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_app_rzm_utils_EncryptUtils_encryptNative (JNIEnv *, jclass, jobject ,jstring); JNIEXPORT void JNICALL Java_com_app_rzm_utils_EncryptUtils_checkSignature (JNIEnv *, jclass, jobject); #ifdef __cplusplus } #endif #endif encrypt.cpp #include "com_app_rzm_utils_EncryptUtils.h" #include "md5.h" #include <string> #include <android/log.h> using namespace std; #define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"renzhenming",FORMAT,##__VA_ARGS__); #define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"renzhenming",FORMAT,##__VA_ARGS__); //我们加密的方式是对参数进行md5加密,在md5加密之前还有一层加密,就是对参数字符串进行改造 //在字符串前加上自定义的key值,然后去掉字符串后边两位字符串,这个规则按需定制,增加破解的难度 #define MD5_KEY "renzhenming" //签名校验是否通过,否返回-1 static int signature_verify = -1; //app包名 static char* PACKAGE_NAME = "com.app.rzm"; //app签名,在这里配置我们app的正式签名,在so库中,可以保证安全性 static char* APP_SIGNATURE = "308201dd30820146020101300d06092a864886f70d010105050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b3009060355040613025553301e170d3137303332333033323030305a170d3437303331363033323030305a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330819f300d06092a864886f70d010101050003818d00308189028181008658a9a532d1c5e8c5a1a78c61535636220f73deb9b36d0912e2b6b1c50f5ed7eccb5cd8e0e4b2fd192d983fa15aeef6be5e5258e809b3fbad538fb68d1c78ebbdd89080664d707e9731c706386a45242a1e3a9e4819789bf832206a2bb7a45b663b6deb9be153ca4fe77b26ca1c43d85cbc20465cc6046f1e1dc16bbc65fe310203010001300d06092a864886f70d010105050003818100213550aa14811a7a407e7eb148b9cb50709c2c84185340b4c52f22caff07fd2e4a79e2814dc5a16fbd7a4b3ec638574eb5ee6baf7537b69aed6529a594bf556f1e0f073884739271f3e2572c4c174031b547846212643ae57bb35e8157c65b3760e37fc3c74f4e24daf3d91086d6ddd7a3f1e54b69ad235a6eb6c5524ce24800"; /** * @param env * @param jclazz * @param jparam * @return */ JNIEXPORT jstring JNICALL Java_com_app_rzm_utils_EncryptUtils_encryptNative (JNIEnv *env, jclass jclazz,jobject context,jstring jparam){ if(signature_verify == -1){ return env->NewStringUTF("EncryptUtils--> signature check err"); } const char *param = env->GetStringUTFChars(jparam,NULL); //在参数头位置加上MD5_KEY,然后去掉后面两位字符串 string signature_str(param); //insert(int p0, const char *s);在p0位置插入字符串s signature_str.insert(0,MD5_KEY); signature_str = signature_str.substr(0,signature_str.length()-2); //md5加密 MD5_CTX *ctx = new MD5_CTX(); MD5Init(ctx); MD5Update(ctx,(unsigned char *)signature_str.c_str(),signature_str.length()); unsigned char digest[16]; MD5Final(ctx, digest); int i = 0; char szMd5[32] = {0}; for(i = 0;i< 16 ; i++){ LOGI("EncryptUtils--> szMd5[%d]:%s",i,szMd5); //最终生成32位,不足前面补一位0 //x 表示以十六进制形式输出 ,02 表示不足两位,前面补0输出;出过两位,不影响 sprintf(szMd5,"%s%02x",szMd5,digest[i]); } env->ReleaseStringUTFChars(jparam,param); return env->NewStringUTF(szMd5); } JNIEXPORT void JNICALL Java_com_app_rzm_utils_EncryptUtils_checkSignature (JNIEnv *env, jclass jclazz, jobject context){ //1.获取包名 通过Context的getPackageName方法获取 //获取Context对象的class jclass context_class = env->GetObjectClass(context); //获取getPackageName的方法id jmethodID context_method_id = env->GetMethodID(context_class,"getPackageName","()Ljava/lang/String;"); //调用getPackageName方法 jstring package_name = (jstring)env->CallObjectMethod(context,context_method_id); //转换为char* const char *c_package_name = (char *)env->GetStringUTFChars(package_name,NULL); LOGI("EncryptUtils--> package name:%s\n",c_package_name); //2.对比包名 if(strcmp(c_package_name,PACKAGE_NAME)){ LOGI("EncryptUtils--> package name check err"); return; } //3.获取签名(通过下边这种方式) //PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES); //Signature[] signatures = packageInfo.signatures; //LogUtils.d("signature:"+signatures[0].toCharsString()); //获取Context中的getPackageManager方法id jmethodID get_package_manager_method_id = env->GetMethodID(context_class,"getPackageManager","()Landroid/content/pm/PackageManager;"); //从Context中通过调用getPackageManager获取PackageManager对象 jobject package_manager = env->CallObjectMethod(context,get_package_manager_method_id); //获取PackageManager对象的class jclass package_manager_class = env->GetObjectClass(package_manager); //获取PackageManager对象中的getPackageInfo方法id jmethodID get_package_info_method_id = env->GetMethodID(package_manager_class,"getPackageInfo","(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;"); //调用PackageInfo中的getPackageInfo方法获取PackageInfo对象(PackageManager.GET_SIGNATURES=64) jobject package_manager_info = env->CallObjectMethod(package_manager,get_package_info_method_id,package_name,64); //获取PackageInfo的class,获取它的属性的时候要用到 jclass package_info_class = env->GetObjectClass(package_manager_info); //获取PackageInfo中的signatures属性的fieldid jfieldID signatures_field_id = env->GetFieldID(package_info_class,"signatures","[Landroid/content/pm/Signature;"); //获取PackageInfo中的signatures属性 jobjectArray signatures_arrary = (jobjectArray) env->GetObjectField(package_manager_info, signatures_field_id); //获取数组中[0]位置的元素 jobject signature = env->GetObjectArrayElement(signatures_arrary,0); //获取String的class jclass signature_class = env->GetObjectClass(signature); //获取String中的toCharsString方法的methodid jmethodID to_chars_string_method_id = env->GetMethodID(signature_class,"toCharsString","()Ljava/lang/String;"); //调用String的toCharsString jstring signature_string = (jstring) env->CallObjectMethod(signature, to_chars_string_method_id); //转换为char* const char * signature_char = env->GetStringUTFChars(signature_string,NULL); LOGI("EncryptUtils--> current app signature:%s\n",signature_char); LOGI("EncryptUtils--> real app signature:%s\n",APP_SIGNATURE); //4.对比签名 if(strcmp(signature_char,APP_SIGNATURE) == 0){ signature_verify = 1; LOGI("EncryptUtils--> signature_verify success:%d\n",signature_verify); }else{ signature_verify = -1; LOGI("EncryptUtils--> signature_verify check failed:%d\n",signature_verify); } } 总结一下: 我们通过使用纯c++代码实现md5加密,将加密实现方式打包成so库,提高反编译的难度,另外在md5加密之外我们还设置了另一层加密规则,对参数字符串头尾进行处理,双层加密,确保数据的安全性。在加密手段之外,再进行app包名和签名的校验,从而保证so库只能在我们自己的app中使用。三层保护,这样一来,相信即便是遇到逆向工程师,要破解我们的app也是有一定难度的。

优秀的个人博客,低调大师

最详细的JavaWeb开发基础之java环境搭建(Mac版)

阅读文本大概需要 5 分钟。 我之前分享过在 Windows 下面配置 Java 环境,这次给大家带来的是 Mac 下面安装配置 Java 环境。首先 Mac 系统已经带有默认的 Java,但是由于使用不方便,这里教大家一个比较方便的方法,并且管理方便。也方便我们后面配置 IDEA, Eclipse。 下面开始我们 Java 环境的安装配置。 1、打开 Java 官网 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 在这里你可以选择你要下载的 java 版本,这里我们以 java1.8 为例来讲解。在下载之前,我们需要先接受协议才能够去下载。 这里说明下,我为什么去选择 linux 版本的 JDK 去下载,而不是 Mac 版本的 JDK,这里主要是因为如果我们下载了 Mac 版本的 JDK 在安装的时候,我们是无法去选择安装目录的,也就是它默认安装之后,你还是要在接着去 Google Mac 下 JDK 默认的安装目录,这样岂不是多次一举。其次,因为 Mac 就是原生的 Unix 系统呀,更可以去选择对应的 Linux 版本,而且这样更便于我们去管理。通过上面的链接下载好之后,我们就可以在本地看到这个文件。 如果觉得上面的下载不够高大上,我们可以直接在命令中使用命令去下载,我们可以使用 wget 命令进行下载 JDK,下载地址如下: http://download.oracle.com/otn-pub/java/jdk/8u172-b11/a58eab1ec242421181065cdc37240b08/jdk-8u172-linux-x64.tar.gz 在命令行中执行如下,这样下载之后的结果跟我们上面都过浏览器下载是一样,喜欢哪一种就可以用哪一种方式去下载。 2、解压下载好的 JDK 文件 下载的文件是 tar.gz 格式的文件,这里我们可以通过 tar 命令进行解压,这个格式文件其实相当于 Windows 下面的 rar 文件,tar 可以对文件进行解压或者压缩,下载我们使用该命令进行解压下载好的 JDK 文件。这里我们先将下载好的 JDK 文件移动到我们的工具目录,方便我们下次使用和查找。上图我已经将 JDK 移动到 Tools 目录下面,所以这里就不需要在重新移动了,如果我们需要移动文件的话,可以通过 mv 命令进行移动。对文件进行解压。 解压完成之后,我们会得到如下的一个文件夹,我们可以进入该文件夹并查看下文件夹下的内容。 到这里我们的 java 安装算是完成一半了,其实说安装根本谈不上,我们之不过是下载了文件,并做了解压的工作。还剩下环境变量的设置,说到环境变量的设置,想必很多会认为一定很复杂,其实这是一种自我限制的思想,在 Mac 或者 Linux 系统下面进行环境变量设置其实很简单,下面你就会见到。 3、查看 JDK 的目录并配置环境变量 配置 java 环境变量之前,我们一定要知道我们的 java 根目录在哪里,在这里我们可以通过 pwd 命令,来查看我们当前 java 根目录是在那个目录下面。 这里我们就看到了我们的 java 所在的根目录了,这是我们将这个路径进行选择,其实相当于复制。下面就到我们最后的一步了进行配置环境变量,这里两行我们就可以搞定。相比于 Windows 下面要简单的多了。我们先回到当前用户的家目录,使用 cd 即可。然后编辑我们的 .bashrc 文件。加入以下两行即可。 至此,我们的 java 配置已经完成,接下来就是我们验证的时刻,在验证之前,我们还需要在执行一个命令,执行这个命令的原因是因为我们在刚才的文件中添加了两行命令,系统是否会自动生效的呢,答案是否定,所以这里我们需要手动去使我们刚才加入的那两行命令生效。 执行上面的命令之后,刚才加入的命令就生效了。下面我们来验证 java 是否配置成功,验证是否成功跟我们前面在 windows 下面的验证是一样的,输入 java -version 即可进行验证。 这样我们就完成了 java 的配置,接下来我们就可以在工具里面去配置使用了。 如果你有任何问题,都可以通过下面的方式,联系我。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册