Base64方式上传文件

文章目录

          • 一、遇到的问题
          • 二、将jar导入maven仓库
          • 三、android客户端生成base64
          • 四、Java接口base64转文件

一、遇到的问题

1.Java中直接使用spring框架提供的工具包来实现,Web页面生成的Base64正常解码,但是Android客户端生成的Base64解码报错,错误信息为:Illegal base64 character a, data=null]。
spring 原生框架提供jar将base64转图片核心代码如下:

 byte[] bs = Base64Utils.decodeFromString(data);
	try{
    //使用apache提供的工具类操作流
	FileUtils.writeByteArrayToFile(new File("D:", tempFileName), bs);  
	}catch(Exception ee){
	  throw new Exception("上传失败,写入文件失败,"+ee.getMessage());
	}

2.Android客户端提交的Base64使用BASE64Decoder包生成的图片是破损的,原因是可能是没有拼接前缀data:image/jpeg;base64,或者是上传的过程中数据发生了改变。通过浏览器上http://imgbase64.duoshitong.com/,生成base64如下:
Base64方式上传文件_第1张图片
生成图片的base64可知,base6前拼接data:image/jpeg;base64,来标识这个base64应该生成什么类型的文件,所以客户端生成的base64也有拼上这段标识,而后台接口接收到数据时先要截取,根据标识去生成文件。

二、将jar导入maven仓库

找了半天找到BASE64Decoder真是太happy了,然而访问到生成图片的代码时却报classNotFoundException,找不到这个包的类,但包明明已经导入到里面去了,编译能通过,但是运行到对应的类就报错了。原因是:通过右键项目Build Path —>Configure Build Path… —>Add External JARS 这样导入的jar包 只存在工作环境当中,当项目部署到tomcat以后,webapp文件夹下的项目文件夹中并不会存在我们的jar包。解决这个问题的方式有两种方法:
1、在WEB-INF下建一个文件夹 lib,把jar包 copy 进去,这样在部署项目的时候就会将jar也部署进去了。
2、将jar导入maven中,生成对应的pom版本。
将jar导入maven的指令:

./mvn install:install-file -Dfile="/Users/linxz/Desktop/jar/sun.misc.BASE64Decoder.jar" -DgroupId=sun.misc.base64decoder -DartifactId=sun.misc.base64decoder -Dversion=1.0.0 -Dpackaging=jar

如果是windows系统,则不要前面的./。

/Users/linxz/Desktop/jar/sun.misc.BASE64Decoder.jar为jar包的位置,DgroupId为项目组ID,DartifactId为项目ID,我这里皆用包名命名,Dversion为当前生成的版本号。这里就有点像android里生成aar部署到Nexus Maven仓库。Nexus搭建Maven私服

执行指令结果如下则表示打包成功:

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /Users/linxz/Desktop/jar/sun.misc.BASE64Decoder.jar to /Users/linxz/java/localmaven/sun/misc/base64decoder/sun.misc.base64decoder/1.0.0/sun.misc.base64decoder-1.0.0.jar
[INFO] Installing /var/folders/q9/ysm4v_fx14110jhts8dcw5s00000gn/T/mvninstall3804221028910250225.pom to /Users/linxz/java/localmaven/sun/misc/base64decoder/sun.misc.base64decoder/1.0.0/sun.misc.base64decoder-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.290 s
[INFO] Finished at: 2019-10-12T08:38:08+08:00
[INFO] ------------------------------------------------------------------------
linxzdeMacBook-Pro:bin linxz$ 

Installing /Users/linxz/Desktop/jar/sun.misc.BASE64Decoder.jar to /Users/linxz/java/localmaven/sun/misc/base64decoder为生成的包在我本地maven的路径,可以去该路径下查看是否真的存在:
Base64方式上传文件_第2张图片这时候我们可以在代码中通过maven的方式导入:

<dependency>
    <groupId>sun.misc.base64decoder</groupId>
    <artifactId>sun.misc.base64decoder</artifactId>
    <version>1.0.0</version>
</dependency>
三、android客户端生成base64
 public static String getBase64FromFilePath(String path){
        InputStream inputStream = null;
        byte[] data = null;
        try {
            inputStream = new FileInputStream(path);
            data = new byte[inputStream.available()];
            inputStream.read(data);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 加密
        BASE64Encoder encoder = new BASE64Encoder();
        String base64=encoder.encode(data);
        base64="data:image/jpeg;base64,"+base64;
        return base64;
    }
四、Java接口base64转文件

核心代码;

public static boolean base64ToImage(String imgStr,String imgFilePath) {
		if (StringUtils.isEmpty(imgStr)) 
			return false;
		File file =new File(imgFilePath);
		File fileParent=file.getParentFile();
		if(!fileParent.exists()) {
			fileParent.mkdirs();
		}
		BASE64Decoder decoder = new BASE64Decoder();
		try {
			byte[] b = decoder.decodeBuffer(imgStr);
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0) {
					// 调整异常数据
					b[i] += 256;
				}
			}
			OutputStream out = new FileOutputStream(imgFilePath);
			out.write(b);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

将传输过程中发生改变的字符替换回来:

base64=base64.replaceAll(" ","+");
base64=base64.replaceAll("[\\s*\t\n\r]", "");

文件路径不存在则创建对应文件夹:

File file =new File(imgFilePath);
File fileParent=file.getParentFile();
if(!fileParent.exists()) {
	fileParent.mkdirs();
}

我项目中的业务处理方式:验证base64非空->验证用户token->验证当前用户状态时候可用->将传输过程中被修改的base64替换回来->根据拼接的前缀判断当前base64属于什么类型文件->判断生成文件的地址路径是否存在不存在则生成对应的路径文件夹->base64开始转文件。

@Override
	public LinxzResult upLoadImg(FileParams fileParams) {
		try {
			if (StringUtils.isEmpty(fileParams.getBase64())) {
				return LinxzResult.build(ResponseCodeUtils.CODE_PARAMS_EMPTY, "长传失败,上传图片不能为空");
			}
			//校验用户
			String token = fileParams.getToken();
			if(StringUtils.isEmpty(token)){
				return LinxzResult.build(ResponseCodeUtils.CODE_PERMISSION_ERRO, "token错误");
			}
			String userId=TokenUtils.getUserId(token);
			BaseUser user=baseUserMapper.selectByUserId(userId);
			if(user==null || !token.equals(user.getToken())){
				return LinxzResult.build(ResponseCodeUtils.CODE_PERMISSION_ERRO, "token错误");
			}
			if(!UserConfig.USER_STATUS_NORMAL.equals(user.getStattus())){
				return LinxzResult.build(ResponseCodeUtils.CODE_PERMISSION_ERRO, "用户异常");
			}
			String base64=fileParams.getBase64();
			base64=base64.replaceAll(" ","+");
			base64=base64.replaceAll("[\\s*\t\n\r]", "");
			System.out.println("上传文件的数据:" + base64);
			String dataPrix = "";
			String data = "";
			String[] d = base64.split("base64,");
			if (d != null && d.length == 2) {
				dataPrix = d[0];
				data = d[1];
			} else {
				 return LinxzResult.build(ResponseCodeUtils.CODE_UNKNOWED_ERRO, "上传失败,数据不合法");
			}
			String suffix = "";
			if ("data:image/jpeg;".equalsIgnoreCase(dataPrix)) {
				// data:image/jpeg;base64,base64编码的jpeg图片数据
				suffix = ".jpg";
			} else if ("data:image/x-icon;".equalsIgnoreCase(dataPrix)) {
				// data:image/x-icon;base64,base64编码的icon图片数据
				suffix = ".ico";
			} else if ("data:image/gif;".equalsIgnoreCase(dataPrix)) {
				// data:image/gif;base64,base64编码的gif图片数据
				suffix = ".gif";
			} else if ("data:image/png;".equalsIgnoreCase(dataPrix)) {
				// data:image/png;base64,base64编码的png图片数据
				suffix = ".png";
			} else {
				 return LinxzResult.build(ResponseCodeUtils.CODE_UNKNOWED_ERRO, "上传图片格式不合法");
			}
			String tempFileName = getRandomFileName() + suffix;
			String homePath = "/Users/linxz/Pictures/streamlet/";
			String folderName="";
			if (!StringUtils.isEmpty(fileParams.getFolderName())) {
				folderName = fileParams.getFolderName();
			}
			homePath = homePath+folderName+"/"+user.getUserId()+"/"+tempFileName;
			boolean success=Base64Util.base64ToImage(data, homePath);
			if(success) {
				System.out.println("生成文件名为:" + homePath);
				return LinxzResult.build(ResponseCodeUtils.CODE_SUCCESS, "长传成功", folderName + "/" + user.getUserId()+"/"+tempFileName);
			}else {
				 return LinxzResult.build(ResponseCodeUtils.CODE_UNKNOWED_ERRO, "上传失败,写入文件失败");
			}
		} catch (Exception e) {
			return LinxzResult.build(ResponseCodeUtils.CODE_UNKNOWED_ERRO, "长传失败" + e.getMessage());
		}
	}

之前一直觉得,开发接口之后postman请求没问题就证明接口是可用的,剩下的就是客户端的问题,这个图片上传使用Srping的包,postman请求网页生成的base64没问题,可是android原生bas4工具类生成的base64就是死活解码失败,改变了我接口对接的一些看法。

你可能感兴趣的:(Android开发,java开发)