1. 实现文件的上传
1.1 文件上传入门案例
1.1.1 编辑上传页面
提前给大家准备了一个页面,在webapp下名字叫file.jsp的文件,访问local host:8091/file.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>实现文件长传</h1>
<!--enctype="开启多媒体标签" -->
<form action="http://localhost:8091/file" method="post"
enctype="multipart/form-data">
<input name="fileImage" type="file" />
<input type="submit" value="提交"/>
</form>
</body>
</html>
这里的请求方式(method)不采用get的方式,因为get请求他把0/1存到我们的浏览器中,以后以后缀的形式进行拼接
enctype="multipart/form-data"代表着开启多媒体标签,开启之后我们文件才能进行正常的上传,否则他上传的东西就对当作普通的文本进行操作
我们看一下请求路径,点击选择文件,选择一个图片,然后打开,提交,我们看一下url
1.1.2 编辑文件上传功能
请求参数类型这里我们可以采用流的方式进行处理,InputStream或者FileInput Stream,但是我们这里有个麻烦的问题,一方面我们对流的操作不熟悉,另一方面我们需要使用完之后关闭流,说白了要记得关闭,不关的话一方面占 用内存,另一方面别人再用的时候可能会出现异常,所以mvc针对文件上传的操作,提供了一个非常好用的接口,接口名叫MultipartFile,MultipartFile下有很多方法其中getOriginalFilename()获取文件真实的名字,transferTo是表示要操作文件上传
package com.hc.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@RestController//返回数据是一个json
public class FileController {
/**
* 业务说明:实现用户文件上传
* url地址:http://localhost:8091/file
* 请求参数:fileImage
* 返回值:表示上传成功的字符串
* 文件上传的容量:默认条件下是1M
*/
@RequestMapping("/file")
public String file(MultipartFile fileImage) throws IOException {
String dir="D:/JT-SOFT/images";
File dirFile=new File(dir);
if(!dirFile.exists()){
dirFile.mkdirs();//创建多级目录
}
//获取文件名称
String fileName=fileImage.getOriginalFilename();
//将文件封装为一个完整的路径
File imageFile=new File(dir+"/"+fileName);
fileImage.transferTo(imageFile);
return "文件上传成功";
}
}
我们的项目上传图片弹出的文本框是谁提供的呢?我们点击批量上传,发现,这个文本框是富文本编辑器给我们的
1.2 文件上传实现
1.2.1 页面参数分析
1.请求网址
2.请求参数
找到common.js找到
3.返回结果要求
打开华电资料,找到D:\华电新版本资料\华电新版本资料\课上资料-配-文件\3-文件上传-nginx负载均衡\1-富文本编辑器案例\图片回显的json格式,这里面就是上传文件要求我们返回的数据格式
{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
参数说明: 0代表是一张图片,如果是0,前台才可以解析并显示。1代表不是图片,
不显示如果不设置宽度和高度,则默认用图片原来的大小,所以不用设置
1.error=0文件上传成功 error=1 文件上传失败
2.url :图片上传之后的虚拟路径
3.width.height 是我们图片的特有的属性
所以说,我们富文本编辑器里面的key和value是一一对应的,key不变,但是value需要我们自己填写
1.2.2 封装ImageVO
package com.hc.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO implements Serializable {
/**
* 为了保证我们ImageVo对象传递的完整性和可传递性,我们实现下序列化
* SerialtionsUID 用来表明了类的不同版本间的兼容性
*/
// {"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
private Integer error; //0正常 1错误
private String url; //图片的虚拟路径
private Integer width; //宽度
private Integer height;//高度
public static ImageVO fail(){
return new ImageVO(1,null,null,null);
}
public static ImageVO success(String url,Integer width,Integer height){
return new ImageVO(0,url,width,height);
}
}
1.2.3 编辑FileController
/**
* 业务实现:文件上传实现
* url地址:http://localhost:8091/pic/upload?dir=image
* 参数 uploadFile
* 返回值: ImageVO
*/
@RequestMapping("/pic/upload")
public ImageVO uploadFile(MultipartFile uploadFile){
//return fileService.uploadFile(uploadFile);
String url="http://img30.360buyimg.com/jgsq-productsoa/jfs/t1/189927/28/12397/178759/60e80002E1313d54d/fc32d9a0b8eb47fb.jpg";
return ImageVO.success(url, 800, 800);
}
写完项目之后,看看效果,我们有一个小bug,就是上传多个图片的时候都一致
业务分析:
/**
- 文件上传策略:
- 1.图片类型进行校验 正则表达式
- 2.检验文件是否有木马 木马.exe.jpg 宽度和高度
- 3.将文件分目录存储 hash 时间
- 4.防止文件重名 uuid当名称
- @param uploadFile
- @return
*/
1.2.5 正则表达式
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
我们回到controller这里,因为我们要用正则表达式,所以不需要去取类型,将 String fileType=fileName.substring(fileName.lastIndexOf(".")+1);注释掉
public ImageVO uploadFile(MultipartFile uploadFile) {
//1.图片类型校验
//1.1 获取图片名称
String fileName=uploadFile.getOriginalFilename();
//1.2 文件类型判断
// String fileType=fileName.substring(fileName.lastIndexOf(".")+1);
// if(!fileType.equals("jpg")){
//
// }else if(fileType.equals("png")){
//
// }else if(fileType.equals("png")){
//
// }
// switch (){
// case:
// }
//上面的方法很显然是非常非常笨的,而且low
// if(!typeSet.contains(fileType)){
// return ImageVO.fail();
// }
//虽然这种方式也可以,但是我们可以做的更加简洁
//jpg png gif.... ABC.jpg java中\\代表\
if(!fileName.matches("^.+\\.(jpg|png|git)$")){
return ImageVO.fail();
}
System.out.println("文件类型校验成功");
return null;
}
重启服务器,访问下页面后
我们的程序有一个bug
package com.hc.service;
import com.hc.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService{
// private static Set<String> typeSet=new HashSet<>();
//静态代码块 为成员变量赋值
// static {
// typeSet.add("jpg");
// typeSet.add("png");
// typeSet.add("gif");
// }
private String localDirPath="D:/JT-SOFT/images"; //D:/xxxxx/
private String urlPath="http://image.jt.com";
/**
* 文件上传策略:
* 1.图片类型进行校验 正则表达式
* 2.检验文件是否有木马 木马.exe.jpg 宽度和高度
* 3.将文件分目录存储 hash 时间
* 4.防止文件重名 uuid当名称
* @param uploadFile
* @return
*/
@Override
public ImageVO uploadFile(MultipartFile uploadFile) {
//1.图片类型校验
//1.1 获取图片名称
String fileName=uploadFile.getOriginalFilename();
//1.2 文件类型判断
// String fileType=fileName.substring(fileName.lastIndexOf(".")+1);
// if(!fileType.equals("jpg")){
//
// }else if(fileType.equals("png")){
//
// }else if(fileType.equals("png")){
//
// }
// switch (){
// case:
// }
//上面的方法很显然是非常非常笨的,而且low
// if(!typeSet.contains(fileType)){
// return ImageVO.fail();
// }
//虽然这种方式也可以,但是我们可以做的更加简洁
//jpg png gif.... ABC.jpg java中\\代表\ QWE.JPG
//为了解决操作系统大小写问题 需要讲字符全部小写
fileName=fileName.toLowerCase();
if(!fileName.matches("^.+\\.(jpg|png|git)$")){
return ImageVO.fail();
}
//2.是否是恶意程序
//通过IO流读取文件信息,转化为图片类型
try {
BufferedImage bufferedImage=ImageIO.read(uploadFile.getInputStream());
int height=bufferedImage.getHeight();
int width=bufferedImage.getWidth();
if(height==0 || width==0){
//说明该文件是一个恶意程序
return ImageVO.fail();
}
/**
* 接下来我们对文件分目录存储,我们可以通过hash函数的方式,常规的hash函数是8个16进制数
* 我么可以按照截串的方式,2个一截,2个一截,形成4层文件目录 4级
*/
//3.根据时间动态生成文件目录
String dateDirPath=new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
//yyyy前面为什么加/ 为了实现路径的拼接
//3.1 实现本地用户路径的拼接 D:/JT-SOFT/images/2021/07/12/xxxxx.jpg
String localDir=localDirPath+dateDirPath;
//3.2 动态生成文件路径
File dirFile=new File(localDir);
if(!dirFile.exists()){//动态生成目录
dirFile.mkdirs();//创建多级目录
}
//4.动态的生成用户名称 fc32d9a0b8eb47fb.jpg
String uuid=UUID.randomUUID().toString().replace("-", "");
int index=fileName.lastIndexOf(".");
String fileType=fileName.substring(index);
String realFileName=uuid+fileType;
//5.实现文件上传 文件目录、文件名称
File imageFile=new File(localDir+realFileName);
uploadFile.transferTo(imageFile);
//6.虚拟路径拼接
String url=urlPath+dateDirPath+realFileName;
return ImageVO.success(url, width, height);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
}
}
1.2.4 编辑properties配置文件
说明:由于文件上传的路径和url地址可能发生改变,如果写死到代码里。不便于维护,所以将我们的配置文件信息写到pro里
在manage项目下,properties文件夹下创建一个新的file, image.properties
2. 代理机制
2.1 图片代理说明
2.2 反向代理机制
2.2.1 反向代理说明
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。
2.2.2 反向代理的特点
1.用户不知道访问的服务器到底是谁
2.反向代理是服务器代理(保护了后端服务器数据)
2.3 正向代理
2.3.1 正向代理介绍
正向代理,意思是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理。
2.3.2 正向代理特点
1.用户向代理发送请求,并指定目标服务器(用户清楚自己访问的是谁)
2.正向代理是客户端代理保护了用户的信息
3.正向代理一般是为了实现网络通信(保护了我们用户的信息)
问题:当我们访问jd.com的时候,我们是反向代理还是正向代理呢?
正向反向都经历了
2.3 Nginx
2.3.1 Nginx介绍
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
特点1:占用内存少 每个线程的启动不超过2M
特点2:并发能力强 5万/秒 2-3万/秒
2.3.2 Nginx的下载/安装
2.3.3 nginx相关命令
命令执行位置:要求在nginx的根目录下执行
如何看我们的nginx正常运行了吗?
2.3.4 关于进程项说明
主进程:主要是提供反向代理服务的
守护进程:防止主进程意外关闭
1.启动nginx start nginx
2.nginx重启 nginx -s reload -s任务树
3.nginx停止 nginx -s stop
2.4 反向代理入门案例
配置文件conf文件夹下有一个nginx.cof,打开
注意:nginx的所有配置必须在http协议之内完成,否则不生效
每一个server都是一个反向代理的服务