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可知,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的路径,可以去该路径下查看是否真的存在:
这时候我们可以在代码中通过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开始转文件。
@Overridepublic 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就是死活解码失败,改变了我接口对接的一些看法。
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- 一句话锁定MySQL数据占用元凶
- android 模拟器手机如何添加文件到sd卡?
- error: Error parsing XML: unbound prefix 与 error: Invalid s
- Android(安卓)ListView动画(逐行显示动画效果)
- Android技术周报_W2_2017年01月15日
- Android(安卓)studio的那些坑- so文件添加的正确位置
- Android(安卓)ADB详细介绍及用法
- Android应用程序四大组件之使用AIDL如何实现跨进程调用Service