一、静态资源服务与动态资源服务的区别
首先动静分离非前后端分离,关于两者的介绍如下:
- 动静分离:动态资源(jsp、ftl)与静态资源(js、img、css)分开
- 前后端分离:接口与视图分开独立开发部署
二、为什么静态资源需要实现CDN内容加速
在一个网站中,请求是比较占宽带资源的。
其主要加载内容为静态资源,如: css、js、img
我们知道,一个1兆带宽服务器 = 128kb/s,如果存在一个 512/kb 的静态资源需要请求 4s 左右,而动态资源(json)占带宽很小(几十B),几乎可以忽略不计。
既然带宽影响网站访问速度,那就加带宽好了?
但是!带宽价格不是贵的一点点…
所以市场上出现了一些静态资源服务器平台(对象文件存储) 。
比如七牛云、阿里云(oss)、腾讯云(内置CDN内容分发)。
什么是CDN内容分发?
CDN内容分发,就是将静态资源服务器会部署全国各个服务器节点,用户访问的时候,遵循就近原则。比如你的所在地在济南,那么你在访问资源文件时,会分配给你距离济南最近的CDN网点。
三、七牛云创建静态资源存储空间
官方地址:https://developer.qiniu.com/
注册之后就可以去创建对象存储空间了,详细步骤建议看官方文档。
创建好空间后需要绑定一个自己的域名,如果不绑定则使用默认提供的域名,提供的域名有默认的使用时长:
如下是我的存储空间域名绑定截图:
如下是我之前涂涂影院存放的一些静态资源:
四、动静分离架构系统缺点
使用CDN内容分发确实提高了网站的访问速度,但是动静分离架构模式有什么缺点呢?
跨域问题
比如域名访问的是:www.sscai.club
而静态资源访问的则是:cdn.sscai.club
如何解决跨域问题?
nginx转发
将 www.sscai.club 转发到 cdn.sscai.club
五、代码中实现七牛云文件上传
引入pom依赖
<!-- 七牛云SDK -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.2.0, 7.2.99]</version>
</dependency>
主要代码:
@RequestMapping(value = "/file", method = RequestMethod.POST)
@ApiOperation(value = "文件上传")
public Result<Object> upload(
@RequestParam(required = false) MultipartFile file,
@RequestParam(required = false) String base64,
HttpServletRequest request) {
// 判断上传类型 */
if(StrUtil.isNotBlank(base64)){
// base64上传 */
file = Base64DecodeMultipartFile.base64Convert(base64);
}
String result = "";
String fKey = renamePic(file.getOriginalFilename());
File f = new File();
try {
// 获取文件流
InputStream inputStream = file.getInputStream();
/* 上传至第三方云服务——七牛云 */
result = qiniuInputStreamUpload(inputStream, fKey);
f.setLocation(CommonConstant.OSS_QINIU);
/* 保存数据信息至数据库 */
f.setName(file.getOriginalFilename());
f.setSize(file.getSize());
f.setType(file.getContentType());
f.setFKey(fKey);
f.setUrl(result);
fileService.save(f);
} catch (Exception e) {
log.error(e.toString());
return new ResultUtil<Object>().setErrorMsg(e.toString());
}
if(used.equals(SettingConstant.LOCAL_OSS)){
OssSetting os = fileUtil.getOssSetting();
result = os.getHttp() + os.getEndpoint() + "/" + f.getId();
}
return new ResultUtil<Object>().setData(result);
}
public static String renamePic(String fileName) {
String extName = fileName.substring(fileName.lastIndexOf("."));
return UUID.randomUUID().toString().replace("-", "") + extName;
}
/**
* 文件流上传
* @param inputStream
* @param key 文件名
* @return
*/
public String qiniuInputStreamUpload(InputStream inputStream, String key) {
OssSetting os = getOssSetting();
Auth auth = Auth.create(os.getAccessKey(), os.getSecretKey());
String upToken = auth.uploadToken(os.getBucket());
try {
Response response = getUploadManager(getConfiguration(os.getZone())).put(inputStream, key, upToken, null, null);
/* 解析上传成功的结果 */
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
return os.getHttp() + os.getEndpoint() + "/" + putRet.key;
} catch (QiniuException ex) {
Response r = ex.response;
throw new XbootException("上传文件出错,请检查七牛云配置," + r.toString());
}
}
@Data
public class OssSetting implements Serializable{
@ApiModelProperty(value = "服务商")
private String serviceName;
@ApiModelProperty(value = "ak")
private String accessKey;
@ApiModelProperty(value = "sk")
private String secretKey;
@ApiModelProperty(value = "endpoint域名")
private String endpoint;
@ApiModelProperty(value = "bucket空间")
private String bucket;
@ApiModelProperty(value = "http")
private String http;
@ApiModelProperty(value = "zone存储区域")
private Integer zone;
@ApiModelProperty(value = "bucket存储区域")
private String bucketRegion;
@ApiModelProperty(value = "本地存储路径")
private String filePath;
@ApiModelProperty(value = "是否改变secrectKey")
private Boolean changed;
}
Base64转为MultipartFile工具类:
/**
* base64转为multipartFile工具类
* @author nikou
*/
public class Base64DecodeMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public Base64DecodeMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
return System.currentTimeMillis() + (int)Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
public static MultipartFile base64Convert(String base64) {
String[] baseStrs = base64.split(",");
BASE64Decoder decoder = new BASE64Decoder();
byte[] b = new byte[0];
try {
b = decoder.decodeBuffer(baseStrs[1]);
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new Base64DecodeMultipartFile(b, baseStrs[0]);
}
}
我创建了一个java相关的公众号,用来记录自己的学习之路,感兴趣的小伙伴可以关注一下微信公众号哈:niceyoo