示例环境:JDK8+MAVEN3+SSM(Spring+SpringMVC+MyBatis Plus或者MyBatis)
现在比较流行的除了分布式或微服务就是动静分离。
动静分离,以nginx集群为例,nginx通常加载静态资源(js,img,css等)效率相对tomcat等应用服务器效率是非常高的,由其专门处理静态资源,而动态资源,通常由tomcat等应用服务器来处理,应用服务器处理动态资源的效率比nginx处理静态资源效率又要高很多很多。就将它们做一个分工。利于静态资源处理就使用nginx,利于动态资源处理使用tomcat或者其他应用服务器等。这样分离的好处,各自发挥其优势,即利于资源充分利用,又利于系统性能。
传统的图片服务器ftp,就现在而言已经没几个人在用了,当然了,wordpress相关的插件安装和主题下载就用到ftp。
当然了,还有不少企业将上传文件(包含图片等)放入线上tomcat某个文件夹下或者项目里面,这样的弊端使项目会越来越庞大,之前庞大是因为不断增长的需求,代码不得不越多,因此也会扩充容量。
不过目前很多企业通常采用比如腾讯云、阿里云、七牛云等对象存储,作为图片存储。
一、导入依赖
<!-- 腾讯云 --> <dependency> <groupId>com.qcloud</groupId> <artifactId>cos_api</artifactId> <version>5.2.4</version> </dependency>
二、编写工具类
package com.custome; import com.qcloud.cos.COSClient; import com.qcloud.cos.ClientConfig; import com.qcloud.cos.auth.BasicCOSCredentials; import com.qcloud.cos.auth.COSCredentials; import com.qcloud.cos.model.ObjectMetadata; import com.qcloud.cos.model.PutObjectResult; import com.qcloud.cos.region.Region; import org.springframework.web.multipart.MultipartFile; import java.io.*; import java.net.URL; import java.util.Date; import java.util.Random; public class COSClientUtil { //todo 这些变量信息自行到 腾讯云对象存储控制台 获取 private COSClient cOSClient; private static final String ENDPOINT = "test.com"; //用户可以指定域名,不指定则为默认生成的域名 //secretId private static final String secretId = "AKIDCJ"; // secretKey private static final String secretKey = "CD7"; // 存储通名称 private static final String bucketName = "test";//公有读私有写 // 1 初始化用户身份信息(secretId, secretKey) private static COSCredentials cred = new BasicCOSCredentials(secretId, secretKey); // 2 设置bucket的区域, COS地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 private static ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing-1")); // 3 生成cos客户端 private static COSClient cosclient = new COSClient(cred, clientConfig); public COSClientUtil() { cOSClient = new COSClient(cred, clientConfig); } /** * 销毁 */ public void destory() { cOSClient.shutdown(); } /** * 上传图片 * * @param url */ public void uploadImg2Cos(String url) throws Exception { File fileOnServer = new File(url); FileInputStream fin; try { fin = new FileInputStream(fileOnServer); String[] split = url.split("/"); this.uploadFile2Cos(fin, split[split.length - 1]); } catch (FileNotFoundException e) { throw new Exception("图片上传失败"); } } public String uploadFile2Cos(MultipartFile file) throws Exception { if (file.getSize() > 10 * 1024 * 1024) { throw new Exception("上传图片大小不能超过10M!"); } //图片名称 String originalFilename = file.getOriginalFilename(); System.out.println("originalFilename = " + originalFilename); //图片后缀 String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase(); System.out.println("substring = " + substring); Random random = new Random(); //生成新的图片名称(随机数0-9999+系统当前时间+上传图片名) String name = random.nextInt(10000) + System.currentTimeMillis() + "_" + substring; try { InputStream inputStream = file.getInputStream(); this.uploadFile2Cos(inputStream, name); return name; } catch (Exception e) { throw new Exception("图片上传失败"); } } /** * 获得图片路径 * * @param fileUrl * @return */ public String getImgUrl(String fileUrl) { return getUrl(fileUrl); } /** * 获得url链接 * * @param key * @return */ public String getUrl(String key) { // 设置URL过期时间为10年 3600l* 1000*24*365*10 Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10); // 生成URL URL url = cOSClient.generatePresignedUrl(bucketName, key, expiration); if (url != null) { return url.toString(); } return null; } /** * 上传到COS服务器 如果同名文件会覆盖服务器上的 * * @param instream * 文件流 * @param fileName * 文件名称 包括后缀名 * @return 出错返回"" ,唯一MD5数字签名 */ public String uploadFile2Cos(InputStream instream, String fileName) { String ret = ""; try { // 创建上传Object的Metadata ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(instream.available()); objectMetadata.setCacheControl("no-cache"); objectMetadata.setHeader("Pragma", "no-cache"); objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf(".")))); objectMetadata.setContentDisposition("inline;filename=" + fileName); // 上传文件 PutObjectResult putResult = cOSClient.putObject(bucketName, fileName, instream, objectMetadata); ret = putResult.getETag(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (instream != null) { instream.close(); } } catch (IOException e) { e.printStackTrace(); } } return ret; } /** * Description: 判断Cos服务文件上传时文件的contentType * * @param filenameExtension 文件后缀 * @return String */ public static String getcontentType(String filenameExtension) { if (filenameExtension.equalsIgnoreCase("bmp")) { return "image/bmp"; } if (filenameExtension.equalsIgnoreCase("gif")) { return "image/gif"; } if (filenameExtension.equalsIgnoreCase("jpeg") || filenameExtension.equalsIgnoreCase("jpg") || filenameExtension.equalsIgnoreCase("png")) { return "image/jpeg"; } if (filenameExtension.equalsIgnoreCase("html")) { return "text/html"; } if (filenameExtension.equalsIgnoreCase("txt")) { return "text/plain"; } if (filenameExtension.equalsIgnoreCase("vsd")) { return "application/vnd.visio"; } if (filenameExtension.equalsIgnoreCase("pptx") || filenameExtension.equalsIgnoreCase("ppt")) { return "application/vnd.ms-powerpoint"; } if (filenameExtension.equalsIgnoreCase("docx") || filenameExtension.equalsIgnoreCase("doc")) { return "application/msword"; } if (filenameExtension.equalsIgnoreCase("xml")) { return "text/xml"; } return "image/jpeg"; } }
三、编写Controller方法
@PostMapping(value="/uploadPicture",produces="application/json;charset=utf-8") public JSONObject upModify(HttpServletRequest request, MultipartFile file) { JSONObject json = new JSONObject(); try { COSClientUtil cosClientUtil = new COSClientUtil(); //获取Cookie String cookie = CookieUtils.getCookie(request,"userCode"); //解密后的userCode String decodeStr = Base64.decodeStr(cookie); if(!file.isEmpty()) { String name = cosClientUtil.uploadFile2Cos(file); //图片名称 System.out.println("name = " + name); //上传到腾讯云 String img_url = cosClientUtil.getImgUrl(name); System.out.println("img_url = " + img_url); //数据库保存图片地址 String db_img_url = img_url.substring(0,img_url.indexOf("?")); System.out.println("db_img_url = " + db_img_url); SysUser user = new SysUser(); user.setUserCode(decodeStr); user.setAvatar(db_img_url); //调用修改逻辑 boolean isModifyUser = userService.updateById(user); if(isModifyUser) { json.put("returnCode", "000000"); json.put("returnMsg", "上传文件成功"); }else { json.put("returnCode", "111111"); json.put("returnMsg", "上传文件失败"); } }else { json.put("returnCode", "222222"); json.put("returnMsg", "参数异常"); } } catch (Exception e) { e.printStackTrace(); json.put("returnCode", "333333"); json.put("returnMsg", "特殊异常"); } return json; }
四、编写简单html测试
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>上传图片测试</title> <script type="text/javascript" src="../js/jquery-1.8.0.min.js"></script> <script type="text/javascript"> function setImg(obj){//用于进行图片上传,返回地址 var f = $(obj).val(); if(f == null || f == undefined || f == ''){ return false; } if(!/.(?:png|jpg|bmp|gif|PNG|JPG|BMP|GIF)$/.test(f)) { alertLayel("类型必须是图片(.png|jpg|bmp|gif|PNG|JPG|BMP|GIF)"); $(obj).val(''); return false; } var data = new FormData(); $.each($(obj)[0].files,function(i,file){ data.append('file', file); }); var upload_img = $("#uploadinput")[0].files[0]; var url = window.URL.createObjectURL(upload_img); $.ajax({ type: "POST", url: "uploadPicture", data: data, cache: false, contentType: false, //必须false才会自动加上正确的Content-Type processData: false, //必须false才会自动加上正确的Content-Type dataType:"json", success: function(data) { alert(data.returnMsg) }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert(XMLHttpRequest.status); // 状态 alert(XMLHttpRequest.readyState); // 错误信息 alert(textStatus); } }); } </script> </head> <body> <input type="file" id="uploadinput" name="file" onchange="setImg(this)"/> </body> </html>