当前位置: 首页 > news >正文

太阳能公司网站建设多少钱购物网站模板带后台

太阳能公司网站建设多少钱,购物网站模板带后台,ftp 网站管理,海口网站建设在线Java Cryptography API 使你能够在 Java 中加密和解密数据#xff0c;以及管理密钥、签名、验证消息、计算加密哈希等等。Cryptography 属于经常被简称为 crypto#xff0c;所以你有时候可能会看到 Java crypto 而不是 Java Cryptography#xff0c;这两个术语是同一个意思。…Java Cryptography API 使你能够在 Java 中加密和解密数据以及管理密钥、签名、验证消息、计算加密哈希等等。Cryptography 属于经常被简称为 crypto所以你有时候可能会看到 Java crypto 而不是 Java Cryptography这两个术语是同一个意思。 Java Cryptography API 由被称为 Java Cryptography Extension 提供Java Cryptography Extension 经常被引用通过它的缩写 JCE。Java Cryptography Extension 长期以来一直是 Java 平台的一部分。JCE 最初与 Java 是分开的因为美国对加密技术有一些出口限制。因此最强的加密算法并未包含在标准 Java 平台中。如果你是美国境内的公司你可以从 Java JCE 获得这些更强大的加密算法但世界其他地区不得不使用较弱的算法。到 2017 年的时候美国加密出口规则已经放宽了很多因此世界上大部分地区都可以通过 JCT 从国际加密标准中受益。 Java Cryptography ArchitectureJCA是 Java 加密 API 内部设计的名称。JCA 是围绕一些核心通用类和接口构建的。这些接口背后的真正功能是由 Providers 提供的。因此你可以使用一个 Cipher 类来加密和解密某些数据但具体的密码实现取决于所使用的具体 Provider。 Provider java.security.Provider 类是 Java cryptography API 中的核心类。为了使用 Java crypto API你需要一组 Provider。Java SDK 带有自己的 Provider。如果你没有显示设置 Provider则会使用 Java SDK 默认的 Provider。但是此 Provider 可能不支持你要使用的加密算法。因此你可能不得不设置自己的 Provider。 在 Java cryptography API 中最流行的 Provider 之一是 Bouncy Castle如下是一个设置 BouncyCastleProvider 的示例 import org.bouncycastle.jce.provider.BouncyCastleProvider;import java.security.Security;public class ProviderExample {public static void main(String[] args) {Security.addProvider(new BouncyCastleProvider());} }Cipher javax.crypto.Cipher 类表示一种加密算法Cipher 是在密码学领域中一个加密算法的标准术语这就是为什么 Java 类被叫做 Cipher 而不是 Encrypter/Decrypter 或者其他的原因。 你可以使用一个 Cipher 实例在 Java 中加密和解密数据。 创建 Cipher 在你使用 Cipher 之前需要先创建一个 Cipher 类的实例。你可以通过调用 Cipher 的 getInstance() 方法来创建一个 Cipher 实例该方法需要传入一个用来表明你想要使用的加密算法的参数实例如下 Cipher cipher Cipher.getInstance(AES);此示例创建了一个使用 AES 加密算法的 Cipher 实例。 Cipher 模式 一些加密算法可以在不同的模式下工作加密模式指定有关算法应如何加密数据的详细信息因此加密模式影响了部分加密算法。 加密模式有时可以与多种不同的加密算法一起使用 ---- 就像附加到核心加密算法的一门技术。这就是为什么这些模式被认为与加密算法本身是分开的而不是具体加密算法的 “附加组件”。以下是一些著名的 cipher 模式 ECB - Electronic CodebookCBC - Cipher Block ChainingCFB - Cipher FeedbackOFB - Output FeedbackCTR - Counter 初始化 Cipher 时你可以将其模式附加到加密算法的名称后面。例如要使用 Cipher Block ChainingCBC创建 AES Cipher 实例你可以使用以下代码 Cipher cipher Cipher.getInstance(AES/CBC/PKCS5Padding);由于密码块链接也需要 “填充方案”因此 “填充方案” 附加在加密算法名称字符串的末尾。 值得注意的是默认的 Java SDK Provider 并不包含所有的加密算法和模式你可能需要一个外部的 Provider 比如 Bouncy Castle 来使用你想要的模式和填充方案来实例化 Cipher。 初始化 Cipher 在使用 Cipher 实例之前你必须对其进行初始化。初始化一个 Cipher 是指调用它的 init() 方法init() 方法需要两个参数 加密/解密密码操作模式加密/解密密钥 下面是一个以加密方式初始化 Cipher 实例的例子 Key key ... // get / create symmetric encryption key cipher.init(Cipher.ENCRYPT_MODE, key);下面是一个以解密方式初始化 Cipher 实例的例子 Key key ... // get / create symmetric encryption key cipher.init(Cipher.DECRYPT_MODE, key);加密和解密数据 为了使用 Cipher 实例加密或解密数据你可以调用以下两个方法中的一个 update()doFinal() 这两个方法都有多个接受不同参数的重载版本我将在这里介绍最常用的版本。 如果你想要加密/解密单个数据块只需调用 doFinal() 并传入需要加密/解密的数据。如下是一个加密示例 byte[] plainText abcdefghijklmnopqrstuvwxyz.getBytes(UTF-8); byte[] cipherText cipher.doFinal(plainText);只需要在初始化 Cipher 的时候指定是加密模式还是解密模式就可以使用同一个方法 doFinal 来加密/解密数据。 如果你想要加密/解密多个数据块例如来自一个大文件的多个块你可以为每个数据块调用一次 update()并在最后一个数据块调用 doFinal()下面是一个加密多个数据块的例子 byte[] data1 abcdefghijklmnopqrstuvwxyz.getBytes(UTF-8); byte[] data2 zyxwvutsrqponmlkjihgfedcba.getBytes(UTF-8); byte[] data3 01234567890123456789012345.getBytes(UTF-8); byte[] cipherText1 cipher.update(data1); byte[] cipherText2 cipher.update(data2); byte[] cipherText3 cipher.doFinal(data3);最后一个数据块需要调用 doFinal() 的原因是一些加密算法需要填充数据以适应确定的密码块大小比如 8 byte 边界。但是我们不想填充中间的数据块因此中间数据块调用 update()最后一个数据块调用 doFinal()。 当解密多个数据块时也是一样的以下是使用 Cipher 实例解密多个数据块的示例 byte[] plainText1 cipher.update(cipherText1); byte[] plainText2 cipher.update(cipherText2); byte[] plainText3 cipher.doFinal(cipherText3);在这之前记得将 Cipher 实例初始化为解密模式。 加密/解密部分字节数组 Cipher 类的加解密方法能够加密/解密一个字节数组中的部分数据你只需要简单地将 offset 和 length 传递给 update() 或者 doFinal() 方法即可如下所示 int offset 10; int length 24; byte[] cipherText cipher.doFinal(data, offset, length);此示例加密从索引 8 开始的 24 个字节。 加密/解密到现有字节数组中 到目前为止本教程中展示的所有加密和解密示例都是通过返回一个新的字节数组然而你也可以将加密/解密后的数据填充到现有的字节数组中这对于减少创建的字节数组的数量很有用。 通过将目标字节数组作为参数传递给 update() 或 doFinal() 方法来可以实现这一点示例如下 int offset 10; int length 24; byte[] dest new byte[1024]; cipher.doFinal(data, offset, length, dest);此示例加密源字节数组中从索引 10 开始的 24 个字节并将加密后的数据从索引 0 开始填充到 dest 字节数组中如果你想要为 dest 字节数组设置不同的起始索引Cipher 类中有额外接收目标字节数组偏移量的版本的 update() 和 doFinal() 方法下面示例中给 doFinal() 方法传递了目标字节数组的偏移量 int offset 10; int length 24; byte[] dest new byte[1024]; int destOffset 12 cipher.doFinal(data, offset, length, dest, destOffset);重用 Cipher 实例 初始化 Cipher 实例是一项开销很大的操作。因此重用 Cipher 实例是个好主意。幸运的是Cipher 类在设计时考虑到了重用。 当你在 Cipher 实例上调用 doFinal() 方法时Cipher 实例将返回到初始化后的状态。Cipher 实例能够用来加密解密数据多次。 下面是一个重用 Cipher 实例的例子 Cipher cipher Cipher.getInstance(AES);Key key ... // get / create symmetric encryption key cipher.init(Cipher.ENCRYPT_MODE, key);byte[] data1 abcdefghijklmnopqrstuvwxyz.getBytes(UTF-8); byte[] data2 zyxwvutsrqponmlkjihgfedcba.getBytes(UTF-8);byte[] cipherText1 cipher.update(data1); byte[] cipherText2 cipher.doFinal(data2);byte[] data3 01234567890123456789012345.getBytes(UTF-8); byte[] cipherText3 cipher.doFinal(data3);MessageDigest Java MessageDigest 类表示一个加密散列算法它被用来从二进制数据中计算消息摘要。当你收到一些加密数据时你无法从数据本身看出它是否在传输过程中被修改消息摘要可以帮助解决该问题。 为了能够检测加密数据是否在传输过程中被修改发送方可以根据数据计算消息摘要并将其与数据一起发送。当你收到加密后的数据和消息摘要时你可以根据数据重新计算消息摘要并检查计算出的消息摘要是否与随数据接收的消息摘要相匹配。如果两个消息摘要匹配则有可能加密数据在传输过程中未被修改。 创建 MessageDigest 实例 要创建 MessageDigest 实例你可以调用 MessageDigest 类的静态方法 getInstance()。以下是创建 MessageDigest 实例的示例 MessageDigest messageDigest MessageDigest.getInstance(SHA-256);传递给 getInstance() 方法的文本参数是要使用的具体消息摘要算法的名称。 消息摘要算法 Java Cryptography API 支持以下消息摘要算法 MD2MD5SHA-1SHA-256SHA-384SHA-512 并非所有的这些消息摘要算法都同样安全建议使用 SHA-256 或更高版本以获得尽可能高的安全性。 计算 MessageDigest 一旦你创建了 MessageDigest 实例之后你就可以使用它来计算数据的消息摘要了如果你有单个数据块来计算消息摘要请使用 digest() 方法以下是从单个数据块计算消息摘要的方式 byte[] data1 0123456789.getBytes(UTF-8); MessageDigest messageDigest MessageDigest.getInstance(SHA-256); byte[] digest messageDigest.digest(data1);如果你有多个数据块要包含在同一个消息摘要中请先调用 update() 方法并在最后调用 digest() 方法以下是从多个数据块计算消息摘要的方式 byte[] data1 0123456789.getBytes(UTF-8); byte[] data2 abcdefghijklmnopqrstuvxyz.getBytes(UTF-8);MessageDigest messageDigest MessageDigest.getInstance(SHA-256); messageDigest.update(data1); messageDigest.update(data2);byte[] digest messageDigest.digest();Mac javax.crypto.Mac 类可以从二进制数据中创建 Message Authentication Code一个 Mac 是一个使用安全密钥加密之后的消息摘要只有当你有用密钥时才能验证 MAC。 创建 Mac 实例 在你使用 Mac 类之前你必须先创建 Mac 实例创建 Mac 实例可以使用 getInstance() 静态方法示例如下 Mac mac Mac.getInstance(HmacSHA256);传递给 getInstance() 方法的字符串参数包含了要使用的 MAC 算法的名字在这个例子中是 HmacSHA256。 初始化 Mac 在创建 Mac 实例之后你需要初始化初始化 Mac 实例是通过调用 init() 方法并传入安全密钥作为参数如下所示 byte[] keyBytes new byte[]{0,1,2,3,4,5,6,7,8 ,9,10,11,12,13,14,15}; String algorithm RawBytes; SecretKeySpec key new SecretKeySpec(keyBytes, algorithm);mac.init(key);init() 方法接受一个 Key 实例在这个例子中是 SecreKeySpec它是 Key 接口的实现类。 计算 Mac 初始化之后你就可以计算 Mac 的值了计算 Mac 的值你需要调用 update() 或者 doFinal() 方法如果你只有一个数据块需要计算你可以直接使用 doFinal() 方法如下所示 byte[] data abcdefghijklmnopqrstuvxyz.getBytes(UTF-8); byte[] macBytes mac.doFinal(data);如果你有多个数据块要计算那么你必须给每个数据块调用 update() 方法并在最后调用 doFinal() 方法示例如下 byte[] data abcdefghijklmnopqrstuvxyz.getBytes(UTF-8); byte[] data2 0123456789.getBytes(UTF-8);mac.update(data); mac.update(data2);byte[] macBytes mac.doFinal();Signature java.security.Signature 类可以为二进制数据创建数字签名数字签名是使用私钥/公钥对中的私钥加密后的消息摘要。任何拥有公钥的人都可以验证该数字签名。 创建 Signature 实例 在使用 Signature 类之前你必须创建一个 Signature 实例你可以通过调用静态方法 getInstance() 方法创建一个 Signature 实例下面是一个创建 Signature 实例的示例 Signature signature Signature.getInstance(SHA256WithDSA);作为参数传递给 getInstance() 方法的字符串是要使用的数字签名算法的名称。 初始化 Signature 实例 创建 Signature 实例后你需要先对其进行初始化然后才能使用它。你通过调用 Signature 实例的 init() 方法来初始化实例这是一个 Signature 初始化示例 SecureRandom secureRandom new SecureRandom(); KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(DSA); KeyPair keyPair keyPairGenerator.generateKeyPair();signature.initSign(keyPair.getPrivate(), secureRandom);如你所见Signature 实例是使用私钥/公钥对的私钥和一个 SecureRandom 实例初始化的。 创建数字签名 Signature 实例被初始化后你就可以使用它来创建数字签名。你可以通过调用一次或多次 update() 方法来创建数字签名并在最后调用 sign() 方法以下是为二进制数据块创建数字签名的示例 byte[] data abcdefghijklmnopqrstuvxyz.getBytes(UTF-8); signature.update(data);byte[] digitalSignature signature.sign();验证数字签名 如果要验证其他人创建的数字签名则必须将 Signature 实例初始化为验证模式而不是签名模式。以下是将 Signature 实例初始化为验证模式的方式 Signature signature Signature.getInstance(SHA256WithDSA);signature.initVerify(keyPair.getPublic());在上面的示例中Signature 实例被初始化为验证模式并将公钥/私钥对的公钥作为参数传递进去了。 一旦初始化为验证模式你就可以使用 Signature 实例来验证一个数字签名了如下示例展示了如何验证一个数字签名 byte[] data2 abcdefghijklmnopqrstuvxyz.getBytes(UTF-8); signature2.update(data2);boolean verified signature2.verify(digitalSignature);完整的签名和验证示例如下 SecureRandom secureRandom new SecureRandom(); KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(DSA); KeyPair keyPair keyPairGenerator.generateKeyPair();Signature signature Signature.getInstance(SHA256WithDSA);signature.initSign(keyPair.getPrivate(), secureRandom);byte[] data abcdefghijklmnopqrstuvxyz.getBytes(UTF-8); signature.update(data);byte[] digitalSignature signature.sign();Signature signature2 Signature.getInstance(SHA256WithDSA); signature2.initVerify(keyPair.getPublic());signature2.update(data);boolean verified signature2.verify(digitalSignature);System.out.println(verified verified);KeyGenerator javax.crypto.KeyGenerator 被用于生成对称加密密钥对称加密密钥是一种密钥对称加密算法可以使用它来加密和解密数据。 创建 KeyGenerator 实例 在使用 KeyGenerator 类之前你必须先创建一个 KeyGenerator 实例你可以通过调用静态方法 getInstance() 并传递创建密钥的加密算法的名称来做到这一点以下是创建 KeyGenerator 实例的示例 KeyGenerator keyGenerator KeyGenerator.getInstance(AES);此示例创建一个 KeyGenerator 实例该实例可以通过 AES 加密算法生成密钥。 初始化 KeyGenerator 创建 KeyGenerator 实例后你必须对其进行初始化初始化一个 KeyGenerator 实例是通过调用它的 init() 方法来完成的这是初始化 KeyGenerator 实例的示例 SecureRandom secureRandom new SecureRandom(); int keyBitSize 256;keyGenerator.init(keyBitSize, secureRandom);KeyGenerator 的 init() 方法接收两个参数要生成的密钥的 bit 位是多少以及一个 SecureRandom 实例。 生成密钥 初始化 KeyGenerator 实例后你可以使用它来生成密钥。生成密钥是通过调用 KeyGenerator.generateKey() 方法完成的。以下是生成对称密钥的示例 SecretKey secretKey keyGenerator.generateKey();KeyPair java.security.KeyPair 代表一个非对称密钥对换句话说就是一个公钥私钥对KeyPair 实例通常在执行非对称加密时使用例如对数据进行加密或者签名的时候。 获取 KeyPair 实例 你通常会从 Java KeyStore 或 Java KeyPairGenerator 获取一个 KeyPair 实例。 访问 KeyPair 中的 Public Key 你可以通过调用 KeyPair.getPublic() 方法来访问一个 PulicKey实例如下 PublicKey publicKey keyPair.getPublic();访问 KeyPair 中的 Private Key 你可以通过调用 KeyPair 的 getPrivate() 方法来访问 PrivateKey示例如下 PrivateKey privateKey keyPair.getPrivate();KeyPairGenerator java.security.KeyPairGenerator 类用于生成非对称加密/解密密钥对。非对称密钥对由两个密钥组成。第一个密钥通常用于加密数据第二个密钥用于解密第一个密钥加密的数据。 最广为人知的非对称密钥对类型是公钥、私钥类型的密钥对。私钥用于加密数据公钥用于解密数据。实际上你也可以使用公钥加密数据并使用私钥解密。 私钥通常是保密的公钥通常是公开的。 创建 KeyPairGenerator 实例 要使用 KeyPairGenerator你必须首先创建一个 KeyPairGenerator 实例创建 KeyPairGenerator 实例是通过调用 getInstance() 方法完成的以下是创建 KeyPairGenerator 实例的示例 KeyPairGenerator keyPairGenerator KeyPairGenerator.getInstance(RSA);getInstance() 方法通过接收加密算法的名称作为参数来生成 KeyPairGenerator在此例中我们使用 RSA 加密算法。 初始化 KeyPairGenerator 根据生成密钥对的算法你可能必须初始化 KeyPairGenerator 实例初始化 KeyPairGenerator 是通过调用它的 initialize() 方法来完成的下面是初始化一个 KeyPairGenerator 实例的例子 keyPairGenerator.initialize(2048);此示例初始化 KeyPairGenerator 以生成大小为 2048 位的密钥。 生成 KeyPair 要使用一个 KeyPairGenerator 生成一个 KeyPair你可以调用 generatorKeyPair() 方法下面是一个生成 KeyPair 的示例 KeyPair keyPair keyPairGenerator.generateKeyPair();KeyStore Java KeyStore 是一个可以存储密钥的数据库一个 Java KeyStore 在 Java 中的抽象是 java.security.KeyStore 类。一个 KeyStore 可以被写入磁盘并再次读取KeyStore 作为一个整体可以用密钥保护并且 KeyStore 中的每个 key entry 可以有自己的密码来保护自己。这使得 KeyStore 成为安全处理加密密钥的有用机制。 一个 KeyStore 可以持有以下类型的密钥 Private keysPublic keys certificatesSecret keys 私钥和公钥用于非对称加密公钥可以有关联的证书证书是一个用于验证持有公钥的个人、组织和设备身份的文档。证书通常由验证方进行数字签名作为证明。 安全密钥用于非对称加密在大部分场景中在一个安全连接被建立的时候会商定非对称密钥因此你可能使用 KeyStore 存储公钥和私钥的时间存储安全密钥的时间多。 创建 KeyStore 你可以通过调用 KeyStore.getInstance() 方法来创建 KeyStore以下是创建 KeyStore 的示例 KeyStore keyStore KeyStore.getInstance(KeyStore.getDefaultType());此示例创建默认类型的 KeyStore 实例也可以通过将不同的参数传递给 getInstance() 方法来创建其他类型的实例例如这是一个创建 PKCS12 类型的示例 KeyStore keyStore KeyStore.getInstance(PKCS12);加载 KeyStore 在 KeyStore 实例可以使用之前必须先加载它。KeyStore 实例通常被写入磁盘或其他类型的存储以备后用。这就是为什么 KeyStore 假定你必须先读入它的数据才能使用它的原因。但是可以初始化一个没有数据的空 KeyStore 实例。 从文件或其他存储中加载 KeyStore 数据是通过调用 KeyStore.load() 方法来完成的该方法有两个参数 加载数据的 InputStream包含 KeyStore 密码的 char[] 这是加载 KeyStore 的示例 char[] keyStorePassword 123abc.toCharArray(); try(InputStream keyStoreData new FileInputStream(keystore.ks)){ keyStore.load(keyStoreData, keyStorePassword); }此示例加载位于 keystore.ks 文件中的 KeyStore。 如果你不想将任何数据加载到 KeyStore 中只需给 InputStream 参数传递 null 即可下例示例加载一个空的 KeyStore keyStore3.load(null, keyStorePassword);你必须始终加载 KeyStore 实例无论是有数据的 KeyStore 还是空的 KeyStore否则 KeyStore 是未初始化的所有对其方法的调用都将抛出异常。 获取 Keys 你可以通过调用 getEntry() 方法来获取 KeyStore 中的密钥一个 KeyStore Entry 映射一个密钥的别名每个密钥被自己的密钥保护。因此要访问密钥你必须将密钥的别名和密钥的密码传递给 getEntry() 方法下面是访问 KeyStore 实例中的 key entry 的示例 char[] keyPassword 789xyz.toCharArray(); KeyStore.ProtectionParameter entryPassword new KeyStore.PasswordProtection(keyPassword); KeyStore.Entry keyEntry keyStore3.getEntry(keyAlias, entryPassword);如果你知道要访问的密钥是一个私钥则可以将 KeyStore.Entry 实例转换为 KeyStore.PrivateKeyEntry示例如下 KeyStore.PrivateKeyEntry privateKeyEntry (KeyStore.PrivateKeyEntry) keyStore3.getEntry(keyAlias, entryPassword);转换成 KeyStore.PrivateKeyEntry 之后通过以下方法你能够访问私钥证书和证书链。 getPrivateKey()getCertificate()getCertificateChain() 设置 Keys 你也可以给 KeyStore 实例设置密钥示例如下 SecretKey secretKey getSecretKey(); KeyStore.SecretKeyEntry secretKeyEntry new KeyStore.SecretKeyEntry(secretKey);keyStore3.setEntry(keyAlias2, secretKeyEntry, entryPassword);存储 KeyStore 有时你可能想要存储一个 KeyStore 到存储器中磁盘、数据库等用于在某个时间再次加载它。你可以通过 store() 方法存储一个 KeyStore示例如下 char[] keyStorePassword 123abc.toCharArray(); try (FileOutputStream keyStoreOutputStream new FileOutputStream(data/keystore.ks)) {keyStore3.store(keyStoreOutputStream, keyStorePassword); }参考 https://jenkov.com/tutorials/java-cryptography/index.html
http://www.huolong8.cn/news/111151/

相关文章:

  • 温岭建设阳光网站宝安中心医院妇科
  • 遵义在线遵义晚报wordpress 主题 seo
  • 做旅游网站平台ppt婚纱外贸网站
  • 贵阳市住房和城乡建设厅网站网址升级访问
  • 代理网站在线跳转网站怎么做的
  • 制作网站首页分为哪几部分wordpress 到顶插件
  • 简单网站 快速建设新网站如何推广
  • 民宿网站建设问卷调查建设银行信用卡官网站首页
  • 网站怎么营销推广给wordpress写一个留言表单
  • 图片 网站开发公司网站改版方案
  • 长沙的网站制作公司wordpress m3u8
  • 做网站用框架广州 网站备案
  • 网站开发需求表模板做关于水果的网站
  • 苏州木渎做网站wpf可以做网站吗
  • 网页设计师常用网站诸城网站建设葛小燕
  • 网站制作 招聘青岛公司注册
  • 上海网站建站视频网站做视频节目赚钱吗
  • 公司网站建设具体实施方案表3-5企业网站建设可行性分析
  • 石家庄网站搭建公司惠州建设厅网站
  • discuz论坛建站教程广告联盟排行
  • 免费企业网站模板htmlwordpress编辑器视频
  • 朋友做网站网站挣了好多钱青岛找网站建设公司哪家好
  • 北京城市建设档案馆网站wordpress主题太臃肿
  • 外贸网站违反谷歌规则购物网站建设所需软件
  • 宁波个人网站建设营销型企业网站的提出
  • 普通人找工作哪个网站好wordpress一键分享微博
  • 兰州建设局网站公告长沙seo公司
  • 影视网站如何做做一个微信公众号商城多少钱
  • 网站建设类型有哪些界首网站优化公司
  • 怎么做阿里巴巴外贸网站软考培训机构哪家好一点