说明:

(1) 为什么写这篇博客?:【SpringBoot电商项目用户模块使用MD5对密码进行保护】中,得到MD5的byte[]数组后后,为了便于最终的存储,我们使用Base64对其进行了转码;】→【然后,因为以前遇到过多次使用Base64转码的情况】→【所以,意识到了【好好总结下Base64转码】的必要性】;所以写了本篇博客;

(2) 可以参考下【Base64补充】这篇博客;


一:以前遇到过的【使用Base64转码】的情况;

(1)第一个地方;

前台系统二:需求分析与数据建模:创建数据工具类、分页工具类;Dao数据对象访问类;(分页模块的Model的Dao部分)】;

引入Common FileUpload组价】;

后台系统五:【修改】功能(然后,修改功能一般常用【隐藏域】(隐藏域挺简单……))】;

后台系统六:【删除】功能;】中都遇到过了;而且,上面四篇博客中介绍的,是同一种;


使用【前台系统二:需求分析与数据建模:创建数据工具类、分页工具类;Dao数据对象访问类;(分页模块的Model的Dao部分)】中的代码片段来说明:

 
   private static String dataFile;  // xml文件的地址;
     static {
             //程序运行编译后,src目录下得java文件会被编译为class文件,这些class文件会被放在classes目录下,而同样处于src目录下的painting.xml文件也会放在classes目录下;
             //XmlDataSource.class.getResoure()得到classes目录的根路径,然后在classes目录的根路径下找到painting.xml,然后getPath()获得painting.xml文件的完整的物理磁盘的地址;
             dataFile = XmlDataSource.class.getResource("/painting.xml").getPath();
             //System.out.println(dataFile);
             // 如painting.xml文件的地址是:c:\new style\painting.xml;可以发现,new和style之间有一个空格,这个空格是个特殊字符;
             //datFile得到painting.xml文件地址的时候,会进行base64转换,实际dataFile的值会是:c:\new%20style\painting.xml,即空格被转化成了%20;
             //但是如果在后续中,利用JavaIO对painting.xml文件按照“c:\new%20style\painting.xml”读取时,会提示路径找不到,因为%20不会被JavaIO解析;需要手动的将%20转换为空格;
             // URLDecoder的作用就是:将base64转回普通的字符串;
             URLDecoder decoder = new URLDecoder();
             try {
                     dataFile = decoder.decode(dataFile, "UTF-8");  //这个需要捕获“不支持的编码格式”异常
                     //System.out.println(dataFile);
                     SAXReader reader = new SAXReader();

通过上面的案例可以知道这个逻辑: 【我们通过【类.class.getResource(someFile).getPath()】获取类路径的时候,其采用的是Base64编码方式】→【但是,Base64编码方式,其中的如空格会被转成“%20”这种字符】→【而,我们读取文件时,因为路径中有“%20”,会导致文件找不到的】→【所以,我们这儿需要转化下路径的编码方式,即把Base64编码转成UTF-8编码】;


(2)第二个地方;

JDBC连接池简介】;

 
     //1.加载属性文件
             Properties properties = new Properties();
             //以前接触过,DruidSample.class.getResource(“某个文件”)获取当前类路径下对应文件的路径;
             String propertiesFile = DruidSample.class.getResource("/druid-config.properties").getPath();
             System.out.println("***"+propertiesFile+"***");
             try {
                 // 容纳错考虑:提取的配置文件路径:base64编码转成utf-8编码;(以前遇到过)
                 propertiesFile = new URLDecoder().decode(propertiesFile,"UTF-8");
                 properties.load(new FileInputStream(propertiesFile));
             } catch (UnsupportedEncodingException | FileNotFoundException e)
               {
                 e.printStackTrace();
             } catch (IOException e) {

这儿的逻辑,和【第一个地方】的逻辑,是一样的;


(3)第三个地方;

Java反射在项目中的应用】;

 
     public static void say(){
             Properties properties = new Properties();
             // 得到文件的路径
             String configPath = Application.class.getResource("/config.properties").getPath();
             try {
                 //处理下文件的路径,base64编码转为utf-8编码,防止空格等特殊编码
                 configPath = new URLDecoder().decode(configPath,"UTF-8"); //需要捕捉UnsupportedEncodingException异常,可以把这个异常扩大到Exception;
                 // 加载配置文件;properties对象就包含了"config.properties"配置文件的内容了;
                 properties.load(new FileInputStream(configPath));
                 //获取配置文件中,key为language的值
                 String language = properties.getProperty("language");

这儿的逻辑,和【第一个地方】、【第二个地方】的逻辑,是一样的;


二: 解决在【Spring Boot电商项目18:用户模块七:使用MD5,对密码进行保护;】中的疑问;

1.问题:为什么在【Spring Boot电商项目用户模块使用MD5对密码进行保护】中,我们要把MD5的byte[]数组转成Base64?

2.一个新问题?为什么非得把byte[]转成Base64编码的字符串;转成其他编码方式的String不香吗?

说明这个问题前,先看下在Java中,把byte[]转成String有哪些方式;

3.Java中,把byte[]转成String的方式;

这儿可以参考【Java字符串】;

4.发现,只有把【md5.digest()得到的byte[]】转成Base64编码方式的String,才可以;

但是,自己在实测的时候,发现了下面的情况:

5.所以,由此很自然就能想到,【MessageDigest.digest(ss.getBytes())】,在转MD5的时候;这个方法,背后的基础是不是就是Base64编码?(待写……)

因为知道,MD5本身是个哈希算法;那么哈希算法和Base64编码方式的关系是?

至此,感觉到,内容有点过多……暂时,hold不住;同时,目前暂时也没必要过于深究;为此,这个问题,就留着吧,以后有精力了或者需要了,再去研究;

似乎可以参考的博客有:

哈希加密 和 base64编码】,【Base64哈希散列函数Flags】……


三:Base64编码介绍;(照抄自Base64的百科)

这儿的内容,完全照抄自Base64的百科;

Base64 (基底64)是一种基于64个可打印字符来表示二进制数据的表示方法。由于log 2 64=6,所以每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母A-Za-z数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被称为Base64。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME电子邮件XML的一些复杂数据。

举例来说,一段引用自托马斯·霍布斯利维坦》的文句:

 
     Man is distinguished, not only by his reason, but by this singular
 passion from other animals, which is a lust of the mind, that by a
 perseverance of delight in the continued and indefatigable generation of
 knowledge, exceeds the short vehemence of any carnal pleasure.

经过Base64编码之后变成:

TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=

如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。也就是说,当最后剩余两个八位(待补足)字节(2个byte)时,最后一个6位的Base64字节块有四位是0值,最后附加上两个等号;如果最后剩余一个八位(待补足)字节(1个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 参考下表:

应用;

MIME

MIME格式的电子邮件中,Base64可以用来将binary的字节序列数据编码ASCII字符序列构成的文本。使用时,在传输编码方式中指定Base64。使用的字符包括大小写拉丁字母各26个、数字10个、加号+和斜杠/,共64个字符,等号=用来作为后缀用途。

完整的Base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。

转换的时候,将3字节的数据,先后放入一个24位的缓冲区中,先来的字节占高位。数据不足3字节的话,于缓冲器中剩下的比特用0补足。每次取出6比特,(因为2^6=64}),按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出,直到全部输入数据转换完成。

若原数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。

IRCu

IRCu等软件所使用的P10 IRC服务器间协议中,对客户与服务器的消息类型号(client/server numerics)和二进制IP地址采用了Base64编码。消息类型号的长度固定为3字节,故可直接编码为4个字节而不需要加填充。对IP地址进行编码时,则需要在地址前添加一些0比特,使之可以编码为整数个字节。这里所用的符号集与前述MIME的也有所不同,将+/改成了[]

UTF-7

UTF-7是一个修改版Base64( Modified Base64 )。主要是将UTF-16的数据,用Base64的方法编码为可打印的ASCII字符序列。目的是传输Unicode数据。主要的区别在于不用等号=补余,因为该字符通常需要大量的转译。

标准可见 RFC 2152,《A Mail-Safe Transformation Format of Unicode》。

URL(PS:这种方式,正式自己遇到过的Base64应用的情况)

Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的/+字符变为形如%XX的形式,而这些%号在存入数据库时还需要再进行转换,因为ANSI SQL中已将%号用作通配符。

为解决此问题,可采用一种 用于URL的改进Base64编码,它不在末尾填充=号,并将标准Base64中的+/分别改成了-_,这样就免去了在URL编解码和数据库存储时所要做的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。

另有一种 用于正则表达式的改进Base64变种,它将+/改成了!-,因为+*以及前面在IRCu中用到的[]正则表达式中都可能具有特殊含义。

此外还有一些变种,它们将+/改为_-._(用作编程语言中的标识符名称)或-(用于XML中的 Nmtoken )甚至_:(用于XML中的 Name )。

其他

垃圾消息传播者用Base64来避过反垃圾邮件工具,因为那些工具通常都不会翻译Base64的消息。 * 在LDIF文件,Base64用作编码字符串。