基本原理:
用户使用支持FTP协议的客户端,连接到在远程主机上的FTP服务端程。用户通过客户端向服务端发出命令,服务端就会执行用户所发出的命令,然后将执行的结果返回到客户端。
端口:
通常默认使用TCP端口中的 20和21这两个端口
20传输数据,21传输控制信息
1.安装vsftpd
yum -y install vsftpd
2.关闭匿名访问
可以不关,不关就可以不输入用户名密码直接访问
vim /etc/vsftpd/vsftpd.conf
3.启动服务
systemctl start vsftpd.service
重启
systemctl restart vsftpd.service
4.查看服务状态
systemctl status vsftpd.service
5.关闭防火墙
systemctl disable firewalld
新建一个用户,用于操作FTP。并将文件保存在用户目录下
adduser ftpuser #创建账号
passwd ftpuser #设定密码
6.设置主目录
创建目录
mkdir -p /data/ftp
设置访问权限
chmod a-w /data/ftp && chmod 777 -R /data/ftp
设为用户的主目录
usermod -d /data/ftp ftpuser
通过本地文件夹 ftp://ip 进行访问
java实现链接ftp
添加对应的依赖
<!-- ftp上传-->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>
一:配置连接FTP静态方法,或者定义一个util
/**
* @param url FTP服务器hostname
* @param port FTP服务器端口
* @param username FTP登录账号
* @param password FTP登录密码
* @param path FTP服务器保存目录
* @param filename 文件名 6403_APP_YYYYMMDD_渠道标志_批次号.txt
* @param inputStream 输入流
* @return
*/
private static boolean uploadFileFTP(String url, int port, String username, String password,
String path, String filename, InputStream inputStream) {
boolean success;
FTPClient ftp = new FTPClient();
try {
int reply;
// 链接 FTP 服务器
// 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.setConnectTimeout(10000*10000);
ftp.connect(url);
// 登录
ftp.login(username, password);
// 返回链接码
reply = ftp.getReplyCode();
// 设置文件格式为二进制类型
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
log.info("FTP服务器 拒绝连接");
return false;
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.makeDirectory(path);
// 跳转到指定的目录路径
ftp.changeWorkingDirectory(path);
ftp.enterLocalPassiveMode();
// 存储文件
ftp.storeFile(filename, inputStream);
inputStream.close();
ftp.logout();
success = true;
} catch (IOException e) {
log.error("FTP服务器 文件上传失败 失败原因:{}", e.getMessage(), e);
return false;
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException e) {
log.error("FTP服务器 关闭失败 失败原因:{}", e.getMessage(), e);
}
}
}
return success;
}
二:创建接口进行上传图片
@RequestMapping("/addUser")
public Object addUser(@RequestParam("headPic")MultipartFile file) throws IOException {
InputStream inputStream = file.getInputStream(); //获取上传的文件流
String filename = file.getOriginalFilename();//获取上传的文件名
String suffix = filename.substring(filename.lastIndexOf("."));//获取后缀
String fileName = UUID.randomUUID().toString()+suffix; //定义一个不重复的名字
boolean b = uploadFileFTP("0.0.0.0", 21, "ftpuser", "ftpuser", "/root/tomcat/apache-tomcat-8.5.81/webapps/yuansheng", fileName, inputStream);
return b;
}
使用postman进行测试:
上传文件进行测试
一般都会存在用户目录下:
如果不是用户的目录下地址,则自动会存入用户下。(只会跑到用户目录下存储)
获取存入的图片或者文件
@RestController
public class FtpController {
@RequestMapping("/getImage")
@ResponseBody
public void getEventPicture(HttpServletRequest request, HttpServletResponse response) {
String imgPath = "a33e9bcc5137f7b49b8fbd5c9e1b3bb.png"; //传入图片名字
FTPClient ftp=null;
InputStream in = null;
OutputStream os = null;
try {
ftp= initFTP(ftp);
//下载文件 FTP协议里面,规定文件名编码为iso-8859-1,所以读取时要将文件名转码为iso-8859-1
//如果没有设置按照UTF-8读,获取的流是空值null
in = ftp.retrieveFileStream(new String(imgPath.getBytes("UTF-8"), "iso-8859-1"));
String picType = imgPath.split("\\.")[1];
BufferedImage bufImg = null;
bufImg = ImageIO.read(in);
os = response.getOutputStream();
ImageIO.write(bufImg, picType, os);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in!=null) {
try {
in.close();
destroy(ftp);
} catch (IOException e) {
}
}
}
}
//通过读取ftp.properties文件来初始化ftp的参数
private FTPClient initFTP(FTPClient ftp) throws IOException {
String addr="0.0.0.0"; //FTP服务器hostname
int port =21; //FTP服务器端口
String username ="ftpuser"; //FTP登录账号
String password ="ftpuser"; //FTP登录密码
String path="/home/ftpuser/files"; //FTP服务器保存目录
ftp = new FTPClient();
ftp.connect(addr,port);
ftp.login(username,password);
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.setControlEncoding("GBK");
ftp.setBufferSize(1024*1024*10); //设置缓冲区上传速度为10M,默认为1K
ftp.setFileType(FTP.BINARY_FILE_TYPE);//设置上传方式位字节
ftp.enterLocalPassiveMode();//Switch to passive mode
return ftp;
}
//关闭FTP客户端
private void destroy(FTPClient ftp) throws IOException {
if(ftp != null){
ftp.disconnect();
ftp = null;
}
}
}
前端js代码
//中文在ie浏览器上需要encodeURI()重新编码防止参数错误
var path="testimg.jpg";
var img="<image height='500px' width='600px' src='"+
"url/getImage.do?imgPath="+encodeURI(path)+"alt="+path+"/>";
//将图片添加到指定div
$('#divId').append(img);
postman测试
ftp删除图片
//ftp服务器ip地址
private static final String FTP_ADDRESS = "0.0.00.0";
//端口号
private static final int FTP_PORT = 21;
//用户名
private static final String FTP_USERNAME = "ftpuser";
//密码
private static final String FTP_PASSWORD = "ftpuser";
//图片路径
public static final String FTP_BASEPATH = "/www/wwwroot/ftpuser";
public static boolean deleteFile(String FileName) {
boolean success = false;
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("GBK");
try {
int reply;
ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return success;
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.makeDirectory(FTP_BASEPATH);
ftp.changeWorkingDirectory(FTP_BASEPATH);
success = ftp.deleteFile(FileName);
ftp.logout();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return success;
}
FTP获取音频文件
/**
* 获取影音文件 (response-header设置不同)
* @param response 。
* @param remote 文件名字
* @return void
**/
@RequestMapping(value = "/getImages",method = RequestMethod.GET)
@ResponseBody
@ApiOperation("获取音频文件")
public void downloadAudio(HttpServletResponse response, String remote) throws IOException {
// initFtpClient();
// ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// String fileName = remote.substring(remote.lastIndexOf(FILE_SEPARATOR) + 1);
// InputStream ins = ftpClient.retrieveFileStream(remote);
System.out.println("remote = " + remote);
FTPClient ftp=null;
InputStream in = null;
OutputStream os = null;
try {
ftp = initFTP(ftp);
//下载文件 FTP协议里面,规定文件名编码为iso-8859-1,所以读取时要将文件名转码为iso-8859-1
//如果没有设置按照UTF-8读,获取的流是空值null
in = ftp.retrieveFileStream(remote);
}catch (Exception e){
}
if (null == in) {
return;
}
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] buf = new byte[204800];
int bufsize = 0;
while ((bufsize = in.read(buf, 0, buf.length)) != -1) {
byteOut.write(buf, 0, bufsize);
}
byte[] return_arraybyte = byteOut.toByteArray();
response.reset();
//设置响应头
response.addHeader("Content-Disposition", "attachment;filename=" + new String(remote.getBytes("gb2312"), "ISO8859-1"));
response.setContentType("application/octet-stream");
response.addHeader("Accept-Ranges","bytes");
int length = return_arraybyte.length;
response.setContentLength(length);
byteOut.close();
in.close();
ServletOutputStream outputStream = response.getOutputStream();
BufferedOutputStream toClient = new BufferedOutputStream(outputStream);
toClient.write(return_arraybyte);
toClient.flush();
outputStream.close();
toClient.close();
}
前端使用
<audio src="地址.mp3" controls="controls"></audio> 标签进行使用
Ftp获取视频
@GetMapping("/getRmove")
@ApiOperation("获取视频文件")
public void getRmove(HttpServletResponse response,String remote) {
//创建FTPClient
FTPClient ftp = new FTPClient();
ftp.setControlEncoding("GBK");
try {
int reply;
ftp.connect("你的端口号", 21);// 连接FTP服务器
// 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
ftp.login("ftpxxxx", "ftpxxxx");// 登录
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
}
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.changeWorkingDirectory("/www/wwwroot/ftpuser");//切换到文件保存目录
ftp.enterLocalPassiveMode();
FTPFile[] ftpFiles = ftp.listFiles();//获取FTP服务器上的文件别表
InputStream in = null;
for (FTPFile file : ftpFiles) { //遍历文件列表
// 取得指定文件
if (file.getName().equals(remote)) {
if (file.isFile()) {
String fileName = file.getName();
//获取文件流
in = ftp.retrieveFileStream(new String(fileName.getBytes("gbk"), "ISO-8859-1"));
//创建ByteArrayOutputStream
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
int ch;
//循环将文件流写入ByteArrayOutputStream 中
while ((ch = in.read()) != -1) {
swapStream.write(ch);
}
//将ByteArrayOutputStream 转成byte[]
byte[] bytes = swapStream.toByteArray();
//通过输出流输出即可
response.addHeader("Access-Contro1-A11ow-0rigin", "*");
response.getOutputStream().write(bytes);
}
}
}
in.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
阿里OSS上传预览
阿里oss控制台:OSS管理控制台 (aliyun.com)
阿里ossAPI文档:Java (aliyun.com)
依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.0</version>
</dependency>
上传:
package com.ruoyi.web.jxxt.controller;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@Api(tags = "阿里云上传下载")
@RestController
@RequestMapping("/jx/oss")
public class AliyunOSSController {
@PostMapping("/png")
public List<String> png(@RequestBody MultipartFile[] files){
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号access Key和access Id
String accessKeyId = "LTAI5txxxxx";
String accessKeySecret = "Gc4EFvfAMxxxxx";
// 填写Bucket名称,桶的名称
String bucketName = "maixxxxx";
// ObjectMetadata meta = new ObjectMetadata();
// meta.setContentType("image/jpg");
ArrayList<String> strings = new ArrayList<>();
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
for (MultipartFile file:files){
// 文件名
String originalFilename = file.getOriginalFilename();
// 新的文件名 = 存储桶名称_时间戳.后缀名
String fileName = bucketName + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
System.out.println("fileName = " + fileName);
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, file.getInputStream());
// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
metadata.setObjectAcl(CannedAccessControlList.Private);
metadata.setContentType("image/jpg"); //不设置这个 使用地址会变成下载,这个格式是用来浏览的
putObjectRequest.setMetadata(metadata);
//上传
ossClient.putObject(putObjectRequest);
strings.add("http://maixuan88.oss-cn-hangzhou.aliyuncs.com/"+fileName);
}
} catch (OSSException oe) {
System.out.println("捕获了一个OSSException,这意味着你的请求使它到OSS,但由于某种原因错误响应被拒绝");
System.out.println("报错类型:" + oe.getErrorMessage());
System.out.println("报错原因:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("捕获了一个ClientException,这意味着客户端遇到了试图与OSS沟通时出现了严重的内部问题,例如不能访问网络。");
System.out.println("Error Message:" + ce.getMessage());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
return strings;
}
/**
* 下载OSS服务器的文件
*
* @param fileName
* @param response
*/
@RequestMapping(value = "/downOSSFile",method = RequestMethod.GET)
@ResponseBody
public void downOSSFile(String fileName, HttpServletResponse response) {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号access Key和access Id
String accessKeyId = "LTAxxxxxxxx";
String accessKeySecret = "Gc4xxxxxx";
// 填写Bucket名称,桶的名称
String bucketName = "xxxx";
BufferedInputStream input = null;
OutputStream outputStream = null;
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
OSSObject ossObject = ossClient.getObject(bucketName, fileName);
try {
response.reset();
response.setCharacterEncoding("utf-8");
response.setContentType("application/x-msdownload");
response.addHeader("Content-Disposition",
"attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1"));
input = new BufferedInputStream(ossObject.getObjectContent());
byte[] buffBytes = new byte[1024];
outputStream = response.getOutputStream();
int read = 0;
while ((read = input.read(buffBytes)) != -1) {
outputStream.write(buffBytes, 0, read);
}
outputStream.flush();
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
ossObject.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
ossClient.shutdown();
}
}
浏览:
视频的压缩
必要的依赖
<!-- 视频压缩 -->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-core</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 在windows上开发 开发机可实现压缩效果 window64位 -->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-win64</artifactId>
<version>3.0.0</version>
</dependency>
<!-- 在linux上部署 linux服务器需要这个才能生效 linux64位 -->
<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-nativebin-linux64</artifactId>
<version>3.0.0</version>
</dependency>
代码
//判断是否为视频文件
private static boolean IsVideo(String fileName) {
Boolean isVideo = false;
String[] formateList = {"avi","flv","mpg","mpeg","mpe","m1v","m2v","mpv2","mp2v","dat","ts","tp","tpr","pva","pss","mp4","m4v",
"m4p","m4b","3gp","3gpp","3g2","3gp2","ogg","mov","qt","amr","rm","ram","rmvb","rpm"};
for (String f : formateList){
if (fileName.split("\\.")[1].equals(f)) {
isVideo = true;
break;
}
}
return isVideo;
}
//判断是否为图片
public static Boolean isPicTure(String fileName){
boolean flag = false;
if (StringUtils.hasText(fileName)){
flag = false;
}
String[] imgArr = {".bmp",".jpg",".png",".tif",".gif",".pcx",".tga",".exif",".fpx",".svg",".psd",".cdr"};
for (String s : imgArr){
if (fileName.split("\\.")[1].equals(s)) {
flag = true;
break;
}
}
return flag;
}
压缩
/**
* 传视频File对象(这是一个具体的文件),返回压缩后File对象信息
* @param source
*/
public static File compressionVideo(File source,String picName) {
if(source == null){
return null;
}
String newPath = source.getAbsolutePath().substring(0, source.getAbsolutePath().lastIndexOf(File.separator)).concat(File.separator).concat(picName);
File target = new File(newPath);
try {
MultimediaObject object = new MultimediaObject(source);
AudioInfo audioInfo = object.getInfo().getAudio();
// 根据视频大小来判断是否需要进行压缩,
int maxSize = 5;
double mb = Math.ceil(source.length()/ 1048576);
int second = (int)object.getInfo().getDuration()/1000;
BigDecimal bd = new BigDecimal(String.format("%.4f", mb/second));
System.out.println("开始压缩视频了--> 视频每秒平均 "+ bd +" MB ");
// 视频 > 5MB, 或者每秒 > 0.5 MB 才做压缩, 不需要的话可以把判断去掉
boolean temp = mb > maxSize || bd.compareTo(new BigDecimal(0.5)) > 0;
// if(temp){
long time = System.currentTimeMillis();
//TODO 视频属性设置
int maxBitRate = 128000;
int maxSamplingRate = 44100;
int bitRate = 800000;
int maxFrameRate = 20;
int maxWidth = 1280;
AudioAttributes audio = new AudioAttributes();
// 设置通用编码格式10 audio.setCodec("aac");
// 设置最大值:比特率越高,清晰度/音质越好
// 设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 128000 = 182kb)
if(audioInfo.getBitRate() > maxBitRate){
audio.setBitRate(new Integer(maxBitRate));
}
// 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))。如果未设置任何声道值,则编码器将选择默认值 0。
audio.setChannels(audioInfo.getChannels());
// 采样率越高声音的还原度越好,文件越大
// 设置音频采样率,单位:赫兹 hz
// 设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
// audio.setVolume(256);
if(audioInfo.getSamplingRate() > maxSamplingRate){
audio.setSamplingRate(maxSamplingRate);
}
//TODO 视频编码属性配置
ws.schild.jave.info.VideoInfo videoInfo = object.getInfo().getVideo();
VideoAttributes video = new VideoAttributes();
video.setCodec("h264");
//设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 800000 = 800kb)
if(videoInfo.getBitRate() > bitRate){
video.setBitRate(bitRate);
}
// 视频帧率:15 f / s 帧率越低,效果越差
// 设置视频帧率(帧率越低,视频会出现断层,越高让人感觉越连续),视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。
if(videoInfo.getFrameRate() > maxFrameRate){
video.setFrameRate(maxFrameRate);
}
// 限制视频宽高
int width = videoInfo.getSize().getWidth();
int height = videoInfo.getSize().getHeight();
if(width > maxWidth){
float rat = (float) width / maxWidth;
video.setSize(new VideoSize(maxWidth,(int)(height/rat)));
}
EncodingAttributes attr = new EncodingAttributes();
// attr.setFormat("mp4");
attr.setAudioAttributes(audio);
attr.setVideoAttributes(video);
// 速度最快的压缩方式, 压缩速度 从快到慢: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow and placebo.
// attr.setPreset(PresetUtil.VERYFAST);
// attr.setCrf(27);
// // 设置线程数
// attr.setEncodingThreads(Runtime.getRuntime().availableProcessors()/2);
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(source), target, attr);
System.out.println("压缩总耗时:" + (System.currentTimeMillis() - time)/1000);
return target;
// }
} catch (Exception e) {
e.printStackTrace();
}finally {
if(target.length() > 0){
source.delete();
}
}
return source;
}