最近项目上有个功能,需要在导入用户信息的时候将头像打包成zip压缩包上传到服务器解压缩存储,并将图片的URL地址存入到数据库。
分析功能点和流程:
上传压缩包解压缩到指定目录
拿到解压后的所有图片名字集合
根据传回来的值判断图片是以名字命名的还是手机号命名的
查询数据库名字集合或者手机号集合和图片集合比对
将图片集合中是数据库的人员的信息存入到数据库中
删除解压缩的目录和文件,删除上传的压缩包
废话不多说,直接上代码
控制层
/**
* todo 上传zip类型的压缩包到服务器
* @param file 定义文件名称
* @param isNameOrPhone 定义的参数:1姓名命名,2手机号命名
* @return 返回成功或失败消息
*/
@PostMapping(value = "/importImageZip")
public R importImageZip(@RequestParam("file") MultipartFile file,
Integer isNameOrPhone)
{
String fileName = fileService.importImageZip(file,isNameOrPhone);
if (fileName != null) {
return R.ok().message("图片压缩包上传成功");
} else {
return R.error().message("图片压缩包上传失败");
}
}
业务层
public String importImageZip(MultipartFile file, Integer isNameOrPhone)
{
String fileName;
File toFile = null;
try {
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
}
if(file.isEmpty()){
System.out.println("文件为空!");
return null;
}
String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
FileInputStream fileInputStream = new FileInputStream(toFile);
BufferedInputStream in = new BufferedInputStream(fileInputStream);
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
byte[] temp = new byte[1024];
int size = 0;
while ((size = in.read(temp)) != -1) {
out.write(temp, 0, size);
}
in.close();
byte[] content = out.toByteArray();
String zipName = IdUtil.simpleUUID();
String imageName = FileUpAndUncompress.sshSftp(content, zipName + fileSuffix);
FileUpAndUncompress.remoteZipToFile(imageName);
//找到解压后的图片文件夹路径并获取到所有的图片名字前缀
SysHuaWeiLinux linux = new SysHuaWeiLinux();
String remoteAddr = linux.getRemoteAddr();
String username = linux.getUsername();
String password = linux.getPassword();
String targetFolderFirst = linux.getTargetFolder();
String targetFolder = targetFolderFirst + file.getOriginalFilename().substring(0,file.getOriginalFilename().lastIndexOf("."));
String photoName;
String photoPrefix;
String photoSuffix;
String temporaryName;
List<String> repetitionName = new ArrayList<>();//存在名字重复时使用该字段
SFTPUtil sftp = new SFTPUtil(username, password, remoteAddr, "定义的端口号");
sftp.login();
List<String> photoList = sftp.listFiles(targetFolder);
//查询数据库所有人员名字或者手机号列表
List<String> userList = new ArrayList<>();
if (isNameOrPhone == 1) {
userList = personnelMapper.selectPerNames();
} else if (isNameOrPhone == 2){
userList = personnelMapper.selectPerPhones();
} else {
throw new JGException(CodeEnum.AN_UNEXPECTED_ERROR);
}
Map<String,String> photoNameMap = new HashMap<>();
List<String> photoNameList = new ArrayList<>();
//遍历图片集合拿到所有图片名字前缀
for (int i = 0; i < photoList.size(); i++) {
photoName = photoList.get(i);
photoPrefix = photoName.substring(0,photoName.lastIndexOf("."));
photoSuffix = photoName.substring(photoName.lastIndexOf("."));
photoNameMap.put(photoPrefix,photoSuffix);
photoNameList.add(photoPrefix);
}
//拿到图片前缀集合 和 人员姓名集合中相同的名字集合
if (isNameOrPhone == 1) {
for (int i = 0; i < photoNameList.size(); i++) {
boolean result = StringUtils.isNumber(photoNameList.get(i));
if (result) {
String repetition = photoNameList.get(i);
String first = "1";
int firstIndex = repetition.indexOf(first);
repetitionName.add(repetition.substring(firstIndex));
userList.add(photoNameList.get(i));
}
}
}
List<String> names = photoNameList.stream().filter(userList::contains)
.collect(Collectors.toList());
Connection connection = new Connection(服务器ip地址);// 创建一个连接实例
connection.connect();
boolean isAuthenticated = connection.authenticateWithPassword(服务器用户名, 密码);
if (isAuthenticated == false)throw new IOException("user and password error");
Session sess = connection.openSession();
sess.requestPTY("bash");
sess.startShell();
InputStream stdout = new StreamGobbler(sess.getStdout());
InputStream stderr = new StreamGobbler(sess.getStderr());
BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout));
BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr));
PrintWriter outPut = new PrintWriter(sess.getStdin());
for (int i = 0; i < names.size(); i++) {
boolean resultName = false;
String phone = null;
if (repetitionName.size() > 0) {
for (int j = 0; j < repetitionName.size(); j++) {
resultName = names.get(i).endsWith(repetitionName.get(j));
if (resultName) {
phone = repetitionName.get(j);
}
}
}
outPut.println("cd " + targetFolder);
temporaryName = IdUtil.simpleUUID();
outPut.println("mv " + names.get(i) + photoNameMap.get(names.get(i)) + " " + temporaryName + photoNameMap.get(names.get(i)));
outPut.println("mv " + temporaryName + photoNameMap.get(names.get(i)) + " " + "服务器存储图片的路径");
fileName = "Tomcat映射的url地址" + temporaryName + photoNameMap.get(names.get(i));
if (resultName) {
personnelMapper.saveRepetitionPerPhoto(phone,fileName);
continue;
}
personnelMapper.savePerPhoto(names.get(i),fileName);//存入到数据库
}
outPut.println("cd " + "服务器存储图片的路径");
outPut.println("rm -rf " + targetFolder);
outPut.println("rm -f " + imageName);
outPut.println("exit");
outPut.close();
sess.waitForCondition(ChannelCondition.CLOSED|ChannelCondition.EOF | ChannelCondition.EXIT_STATUS,30000);
System.out.println("下面是从stdout输出:");
while (true) {
String line = stdoutReader.readLine();
if (line == null)break;
System.out.println(line);
}
System.out.println("下面是从stderr输出:");
while (true) {
String line = stderrReader.readLine();
if (line == null)break;
System.out.println(line);
}
System.out.println("ExitCode: " + sess.getExitStatus());
sess.close();
connection.close();
fileName = names.get(0);
return fileName;
} catch (Exception e) {
log.error("捕获异常消息:" + e);
throw new JGException(CodeEnum.IMAGE_PACKAGE_ZIP_IMPORT_ERROR);
}
}
private static void inputStreamToFile(InputStream ins, File file)
{
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
log.info("MultipartFile transform to File completed!");
}catch(Exception e) {
e.printStackTrace();
}
}
工具类FileUpAndUncompress
@Slf4j
public class FileUpAndUncompress
{
/**
* 远程解压zip文件
*/
public static void remoteZipToFile(String imageName)
{
Date date = new Date();
long time = date.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String strTime = sdf.format(time);
try {
Connection connection = new Connection(服务器ip地址);
connection.connect();
boolean isAuthenticated = connection.authenticateWithPassword(用户名, 密码);
if (isAuthenticated == false)throw new IOException("user and password error");
Session sess = connection.openSession();
sess.requestPTY("bash");
sess.startShell();
InputStream stdout = new StreamGobbler(sess.getStdout());
InputStream stderr = new StreamGobbler(sess.getStderr());
BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout));
BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr));
PrintWriter out = new PrintWriter(sess.getStdin());
out.println("cd " + 存放图片的目录);
out.println("mkdir " + strTime);
out.println("unzip -o " + imageName + " -d " + 存放图片的目录 + strTime);
out.println("exit");
out.close();
sess.waitForCondition(ChannelCondition.CLOSED|ChannelCondition.EOF | ChannelCondition.EXIT_STATUS,30000);
System.out.println("下面是从stdout输出:");
while (true) {
String line = stdoutReader.readLine();
if (line == null)break;
System.out.println(line);
}
System.out.println("下面是从stderr输出:");
while (true) {
String line = stderrReader.readLine();
if (line == null)break;
System.out.println(line);
}
System.out.println("ExitCode: " + sess.getExitStatus());
sess.close();
connection.close();
} catch (IOException e) {
e.printStackTrace(System.err);
System.exit(2);
}
}
/**
*上传图片压缩包
* @param bytes 字节流
* @param fileName 返回的文件名
* @return 文件名
* @throws Exception 异常
*/
public static String sshSftp(byte[] bytes,String fileName) throws Exception
{
String ip = "服务器ip";
Integer port = 自定义;
String user = "用户名";
String password = "密码";
// 服务器保存路径
String filepath = "存储图片的路径";
com.jcraft.jsch.Session session = null;
Channel channel = null;
JSch jSch = new JSch();
if (port <= 0) {
session = jSch.getSession(user, ip);
} else {
session = jSch.getSession(user, ip, port);
}
if (session == null) {
throw new Exception("session is null");
}
session.setPassword(password);
//设置第一次登陆的时候提示,可选值:(ask | yes | no)
session.setConfig("userauth.gssapi-with-mic", "no");
session.setConfig("StrictHostKeyChecking", "no");
//设置登陆超时时间
session.connect(30000);
OutputStream outstream = null;
try {
channel = (Channel) session.openChannel("sftp");
channel.connect(1000);
ChannelSftp sftp = (ChannelSftp) channel;
sftp.cd(filepath);
outstream = sftp.put(fileName);
outstream.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outstream != null) {
outstream.flush();
outstream.close();
}
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
return fileName;
}
}
工具类SFTPUtil
@Data
public class SFTPUtil
{
private ChannelSftp sftp;
private Session session;
/**
* SFTP 登录用户名
*/
private String username;
private String password;
/**
* SFTP 服务器地址IP地址
*/
private String host;
private int port;
/**
* 连接sftp服务器
*/
public void login()
{
try {
JSch jsch = new JSch();
if (privateKey != null) {
jsch.addIdentity(privateKey);// 设置私钥
}
session = jsch.getSession(username, host, port);
if (password != null) {
session.setPassword(password);
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
} catch (JSchException e) {
e.printStackTrace();
}
}
/**
* 列出目录下.jpg .png .jpeg结尾的文件
* @param directory 要列出的目录
*/
public List<String> listFiles(String directory) throws SftpException
{
Vector<?> objects = sftp.ls(directory);
List<String> list = new ArrayList<>();
for (Object s : objects) {
String x = s.toString();
if (x.contains(".jpg") || x.contains(".jpeg") || x.contains(".png")) {
String[] s1 = x.split(" ");
list.add(s1[s1.length - 1]);
}
}
return list;
}
}
实体类SysHuaWeiLinux
@Data
public class SysHuaWeiLinux
{
private final String remoteAddr = ;//ip地址
private final String username = ;//登录用户名
private final String password = ;//登录密码
private String zipName;//上传的压缩包名字
Date newDate = new Date();
long time = newDate.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
private String date = sdf.format(time);//系统当天日期
private final String targetFolder = 图片存储目录 + date + "/";//要修改的目录(固定目录)
}