今天项目优化了一下上传头像的功能。
如果图片以文件的形式在前后端传输不是很方便
于是将图片转成 base64 加密的字符串,在前后端传输,自然上传头像也就涉及到了如何把加密的字符串转换成图片的问题。
首先呢在网上找到很多,都是使用的 sun.misc.Base64Encoder和sun.misc.Base64Decoder这个在 Java高版本用不了而且有缺陷
因此楼主采用的替代方案是使用 commons-codec是Apache下面的一个加解密开发包
pom
<!-- Base64编码转换 -->
<dependency>
<groupId>servlets.com</groupId>
<artifactId>cos</artifactId>
<version>05Nov2002</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
下面呢是一个工具类,等下我们上传图片到服务器的时候会用到
package com.dheaven.utils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.codec.binary.Base64;
public class BaseCodeToPicUtils {
/**
* @Description: 将base64编码字符串转换为图片
* @Author:
* @CreateTime:
* @param imgStr base64编码字符串
* @param path 图片路径-具体到文件
* @return
* @throws FileNotFoundException
*/
public static void generateImage(String imgStr, String path) throws Exception {
OutputStream out = null;
Base64 base64 = new Base64();
byte[] b = base64.decodeBase64(imgStr);
for (int i = 0; i < b.length; i++) {
if(b[i]<0) {
b[i]+=256;
}
}
out = new FileOutputStream(path);
out.write(b);
out.flush();
out.close();
}
/**
* @Description: 根据图片地址转换为base64编码字符串
* @Author:
* @CreateTime:
* @return
*/
public static String getImageStr(String imgFile) {
InputStream inputStream = null;
byte[] data = null;
try {
inputStream = new FileInputStream(imgFile);
data = new byte[inputStream.available()];
inputStream.read(data);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
// 加密
Base64 base64 = new Base64();
return base64.encodeToString(data);
}
/**
* 示例
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String strImg = getImageStr("C:\\Users\\Administrator\\Desktop\\Test\\126.jpg");
System.out.println("111111"+strImg);
generateImage(strImg, "C:\\Users\\Administrator\\Desktop\\Test\\132.png");
}
}
上面就是准备工作啦,都Ok啦,接下来我们写 comtroller
/**
* 用户上传头像
* @param request
* @param response
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value="/uploadPic", method = { RequestMethod.POST, RequestMethod.GET})
public ResponseData uploadPic(HttpServletRequest request,HttpServletResponse response,@RequestBody UploadPicRequest uploadPicRequest) throws Exception{
response.setHeader("Access-Control-Allow-Origin", "*");
Map<String, Object> map = new HashMap<String, Object>();
ResponseData resp = null;
String userName = uploadPicRequest.getUserName();
String imgStr = uploadPicRequest.getUploadPicStr();
if(StringUtils.isEmpty(userName)) {
resp = new ResponseData(ResponseEnum.ERROR, "userName为空");
}
if(StringUtils.isEmpty(imgStr)||imgStr.length()<7) {
resp = new ResponseData(ResponseEnum.ERROR, "图片编码有误");
}
String ID = userService.getIdByUserName(userName);
//这里是要截取前端传递过来的图片编码,图片加密的字符串前缀包含 data:image/jpeg;base64,
//我们要把这个处理去掉才能调用我们封装的工具类转成图片,不然图片会无法展示
int indexOf = imgStr.indexOf("base64,");
//处理过后的在用原来的字符串接受
imgStr=imgStr.substring(indexOf+7);
try {
if (null != imgStr) {
uploadPic(request, map, imgStr, ID);
} else {
resp = new ResponseData(ResponseEnum.ERROR, "上传头像为空");
}
} catch (Exception e) {
resp = new ResponseData(ResponseEnum.ERROR, "上传头像失败");
}
return resp;
}
private void uploadPic(HttpServletRequest request, Map<String, Object> map, String imgStr, String ID)
throws Exception {
ResponseData resp;
//项目服务器地址路径
String projectServerPath = request.getScheme() + "://" + request.getServerName() + ":"+ request.getServerPort() + "/uploadPic/imgs/headPortrait/";
logger.info("项目服务器地址路径 :"+projectServerPath);
//上传文件路径
String path = request.getSession().getServletContext().getRealPath("/").substring(0,request.getSession().getServletContext().getRealPath("/").indexOf(request.getContextPath().substring(1)))+"uploadPic/imgs/headPortrait/";
logger.info("上传文件路径 :"+path);
//新文件名称
String originalFilename = System.currentTimeMillis() + ".jpg";
//判断路径是否存在,如果不存在就创建一个
File file = new File(path+originalFilename);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//将64位编码转换成图片并且上传到服务器下
BaseCodeToPicUtils.generateImage(imgStr, path + originalFilename);
String serverFilePatn = projectServerPath + originalFilename;
logger.info("访问 服务器图片地址 : "+serverFilePatn);
map.put("id", ID);
map.put("headPortrait", serverFilePatn);
// 更新用户头像信息
userService.uploadPic(map);
resp = new ResponseData(ResponseEnum.SUCCESS, "上传头像成功 : ");
resp.setJson(serverFilePatn);
}
到上面我们的功能就做完啦
里面有service我是调用自己的
你要复制的可能会报错改成自己的即可
首先是要和前端约定好将图片转成加密字符串传输给后台
其次我们拿到字符串后通过解密将字符串转换成图片
之后将图片写入服务器的 webapp 下
将访问服务器上图片的地址保存到用户表
同时返回给前端展示
这里上传到 webapp/WEB-INF 下会有一个问题
当你重启 tomcat 之前上传的头像都会消失呢
网上解决方案很多,我的这个是 在 webapp 下创建啦同级的目录
我的在代码中 上传文件路径下的那一行代码后面添加了 /uploadPic/imgs/headPortrait/