rush:js;">
$(document).ready(function () {
new PageInit().init();
});
function PageInit() {
var api = null;
var _this = this;
this.init = function () {
$("[name='upload']").on('click',this.portraitUpload)
};
this.portraitUpload = function () {
var model = $.scojs_modal({
title: '头像上传',content: template('portraitUpload'),onClose: refresh
}
);
model.show();
var fileUp = new FileUpload();
var portrait = $('#fileUpload');
var alert = $('#alert');
fileUp.portrait(portrait,'/file/portrait',_this.getExTradata);
portrait.on('change',_this.readURL);
portrait.on('fileuploaderror',function (event,data,msg) {
alert.removeClass('hidden').html(msg);
fileUp.fileinput('disable');
});
portrait.on('fileclear',function (event) {
alert.addClass('hidden').html();
});
portrait.on('fileloaded',file,previewId,index,reader) {
alert.addClass('hidden').html();
});
portrait.on('fileuploaded',data) {
if (!data.response.status) {
alert.html(data.response.message).removeClass('hidden');
}
})
};
this.readURL = function () {
var img = $('#cut-img');
var input = $('#fileUpload');
if (input[0].files && input[0].files[0]) {
var reader = new FileReader();
reader.readAsDataURL(input[0].files[0]);
reader.onload = function (e) {
img.removeAttr('src');
img.attr('src',e.target.result);
img.Jcrop({
setSelect: [20,20,200,200],handleSize: 10,aspectRatio: 1,onSelect: updateCords
},function () {
api = this;
});
};
if (api != undefined) {
api.destroy();
}
}
function updateCords(obj) {
$("#x").val(obj.x);
$("#y").val(obj.y);
$("#w").val(obj.w);
$("#h").val(obj.h);
}
};
this.getExTradata = function () {
return {
sw: $('.jcrop-holder').css('width'),sh: $('.jcrop-holder').css('height'),x: $('#x').val(),y: $('#y').val(),w: $('#w').val(),h: $('#h').val()
}
}
}
rush:xhtml;">
进行一些错误信息的显示操作。
rush:js;">
portrait.on('fileclear',function (event) {
alert.addClass('hidden').html();
});
这部分代码,是当文件移除时,隐藏错误信息提示区,以及清空内容,当然这是符合我们的业务逻辑的。
rush:js;">
portrait.on('fileloaded',reader) {
alert.addClass('hidden').html();
});
这部分代码是当选择文件时(此时还没进行文件校验),隐藏错误信息,清空错误内容,这么做是为了应对如果上一次文件校验时有错误,而重新选择文件时,肯定要清空上一次的错误信息,再显示本次的错误信息。
rush:js;">
portrait.on('fileuploaded',data) {
if (!data.response.status) {
alert.html(data.response.message).removeClass('hidden');
}
})
这部分是当文件上传后,后端如果返回了错误信息,则需要进行相关的提示信息处理。
rush:js;">
this.getEx
Tradata = function () {
return {
sw: $('.jcrop-holder').css('width'),h: $('#h').val()
}
}
这部分代码是获取上传文件时,附带需要发往后端的参数,这里面可以看到,x、y自然是Jcrop截取时,选框的左上角原点坐标,w、h自然就是截取的宽高,但是刚才我说了,这个是经过缩放后的宽高,不是依据图片实际像素的宽高。而sw、sh代表的是scaleWidth、scaleHeight,就是缩放宽高的意思。这个.jcrop-holder的对象是当Jcrop插件启用后,加载的图片外层容器的对象,只需要获取这个对象的宽高,就是图片被压缩的宽高,但是因为我限制了图片的宽度和高度,宽度的比例是定死的(不是宽高定死,只是比例定死,bootstrap本身就是响应式框架,所以不能单纯的说宽高定死,宽高会随着使用终端的变化而变化),高度是根据宽度保持16:4,可是我又加了pre-scrollable这个类让图片过高时以滚动条的方式不破坏外层容器的高度,所以我们实际能拿来计算缩放比例的,是宽度,而不是高度,但是这里我一起传,万一以后有其他的使用场景,要以高度为准也说不定。
好了,然后我需要贴上bootstrap-fileinput插件的配置代码:
rush:js;">
this.portrait = function (target,uploadUrl,data) {
target.fileinput({
language: 'zh',//设置语言
maxFileSize: 2048,//
文件最大容量
uploadEx
Tradata: data,//
上传时除了
文件以外的其他额外数据
showPreview: false,//隐藏预览
uploadAsync: true,//ajax同步
dropZoneEnabled: false,//是否
显示拖拽区域
uploadUrl: uploadUrl,//
上传的地址
allowedFileExtensions: ['jpg'],//接收的
文件后缀
showUpload: true,//是否
显示上传按钮
showCaption: true,//是否
显示标题
browseClass: "btn btn-primary",//按钮样式
previewFileIcon: "
",ajaxSettings: {//这个是因为我使用了SpringS
ecurity框架,有csrf跨域提交防御,所需需要设置这个值
beforeSend: function (xhr) {
xhr.setRequestHeader(header,token);
}
}
});
}
这个代码有写了注释,我就不多解释了。关于Ajax同步,是因为我个人认为,上传文件这个还是做成同步比较好,等文件上传完成后,js代码才能继续执行下去。因为文件上传毕竟是一个耗时的工作,有的逻辑又确实需要当文件上传成功以后才执行,比如刷新页面,所以为了避免出现问题,还是做成同步的比较好。还有就是去掉预览,用过bootstrap-fileinput插件的都知道,这个插件的图片预览功能很强大,甚至可以单独依靠这个插件来制作相册管理。但是因为我们这次要结合Jcrop,所以要割掉这部分功能。
SpringMVC-Controller获取文件
rush:java;">
@ResponseBody
@RequestMapping(value = "/portrait",method = {RequestMethod.POST})
public JsonResult upload(HttpServletRequest request) throws Exception {
Integer x = Integer.parseInt(MyStringTools.checkP
arameter(request.getP
arameter("x"),"
图片截取异常:X!"));
Integer y = Integer.parseInt(MyStringTools.checkP
arameter(request.getP
arameter("y"),"
图片截取异常:Y!"));
Integer w = Integer.parseInt(MyStringTools.checkP
arameter(request.getP
arameter("w"),"
图片截取异常:W!"));
Integer h = Integer.parseInt(MyStringTools.checkP
arameter(request.getP
arameter("h"),"
图片截取异常:H!"));
String scaleWidthString = MyStringTools.checkP
arameter(request.getP
arameter("sw"),"
图片截取异常:SW!");
int swIndex = scaleWidthString.indexOf("px");
Integer sw = Integer.parseInt(scaleWidthString.substring(0,swIndex));
String scaleHeightString = MyStringTools.checkP
arameter(request.getP
arameter("sh"),"
图片截取异常:SH!");
int shIndex = scaleHeightString.indexOf("px");
Integer sh = Integer.parseInt(scaleHeightString.substring(0,shIndex));
//<a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a><a href="https://www.jb51.cc/tag/yonghu/" target="_blank" class="keywords">用户</a>ID用于指向对应<a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>夹
SysUsers sysUsers = HttpTools.getSessionUser(request);
int userID = sysUsers.getUserId();
//<a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a><a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>路径
String filePath = Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.getPortraitPath(userID);
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
request.getSession().getServletContext());
String path;
//检查form中是否有enctype="multipart/form-data"
if (multipartResolver.isMultipart(request)) {
//将request变成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
//<a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a>multiRequest 中所有的<a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>名
I<a href="https://www.jb51.cc/tag/tera/" target="_blank" class="keywords">tera</a>tor i<a href="https://www.jb51.cc/tag/tera/" target="_blank" class="keywords">tera</a>tor = multiRequest.getFileNames();
while (i<a href="https://www.jb51.cc/tag/tera/" target="_blank" class="keywords">tera</a>tor.hasNext()) {
//一次遍历所有<a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>
<a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a> <a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a> = multiRequest.getFile(i<a href="https://www.jb51.cc/tag/tera/" target="_blank" class="keywords">tera</a>tor.next().toString());
if (<a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a> != null) {
String[] allowSuffix = {".jpg",".JPG"};
if (!Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.checkSuffix(<a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a>.g<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>riginalFilename(),allowSuffix)) {
throw new Busi<a href="https://www.jb51.cc/tag/nes/" target="_blank" class="keywords">nes</a>sException("<a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>后缀名不符合要求!");
}
path = filePath + Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.getPortraitFileName(<a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a>.g<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>riginalFilename());
//存入硬盘
<a href="https://www.jb51.cc/tag/multipartfile/" target="_blank" class="keywords">multipartfile</a>.transferTo(new File(path));
//<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a><a href="https://www.jb51.cc/tag/jiequ/" target="_blank" class="keywords">截取</a>
if (Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.imgCut(path,x,y,w,h,sw,sh)) {
Compre<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ools compre<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ools = new Compre<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ools();
if (compre<a href="https://www.jb51.cc/tag/sst/" target="_blank" class="keywords">sst</a>ools.simpleCompress(new File(path))) {
return JsonResult.success(Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.filePathToSRC(path,Fil<a href="https://www.jb51.cc/tag/eto/" target="_blank" class="keywords">eto</a>ols.IMG));
} else {
return JsonResult.error("<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a>压缩失败!请重新<a href="https://www.jb51.cc/tag/shangchuan/" target="_blank" class="keywords">上传</a>!");
}
} else {
return JsonResult.error("<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a><a href="https://www.jb51.cc/tag/jiequ/" target="_blank" class="keywords">截取</a>失败!请重新<a href="https://www.jb51.cc/tag/shangchuan/" target="_blank" class="keywords">上传</a>!");
}
}
}
}
return JsonResult.error("<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a><a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a>失败!请重新<a href="https://www.jb51.cc/tag/shangchuan/" target="_blank" class="keywords">上传</a>!");
}
Image图片切割
double realX = zoomX * scale;
double realY = zoomY * scale;
double realW = zoomW * scale;
double realH = zoomH * scale;
if (fileWidth >= realW && fileHeight >= realH) {
Image image = bi.getScaledInstance(fileWidth,fileHeight,Image.SCALE_DEFAULT);
cropFilter = new CropImageFilter((int) realX,(int) realY,(int) realW,(int) realH);
img = Toolkit.getDefaultToolkit().createImage(
new FilteredImageSource(image.getSource(),cropFilter));
BufferedImage bufferedImage = new BufferedImage((int) realW,(int) realH,BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(img,null);
g.<a href="https://www.jb51.cc/tag/dis/" target="_blank" class="keywords">dis</a>pose();
//<a href="https://www.jb51.cc/tag/shuchu/" target="_blank" class="keywords">输出</a><a href="https://www.jb51.cc/tag/wenjian/" target="_blank" class="keywords">文件</a>
return ImageIO.write(bufferedImage,"JPEG",new File(path));
} else {
return true;
}
}
缩放比例scale一定要用double,并且宽高也要转换成double后再相除,否则会变成求模运算,这样会降低精度,别小看这里的精度下降,最终的截图效果根据图片的缩放程度,误差可是有可能被放大的很离谱的。
rush:java;">
package com.magic.rent.tools;
/**
- 知识产权声明:本文件自创建起,其内容的知识产权即归属于原作者,任何他人不可擅自复制或模仿.
- 创建者: wu 创建时间: 2016/12/15
- 类说明: 缩略图类(通用) 本java类能将jpg、bmp、png、gif图片文件,进行等比或非等比的大小转换。 具体使用方法
- 更新记录:
*/
import com.magic.rent.exception.custom.BusinessException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
public class Compresstools {
private File file; // 文件对象
private String inputDir; // 输入图路径
private String outputDir; // 输出图路径
private String inputFileName; // 输入图文件名
private String outputFileName; // 输出图文件名
private int outputWidth = 100; // 默认输出图片宽
private int outputHeight = 100; // 默认输出图片高
private boolean proportion = true; // 是否等比缩放标记(默认为等比缩放)
private static Logger logger = LoggerFactory.getLogger(Compresstools.class);
public Compresstools() {
}
public Compresstools(boolean proportion) {
this.proportion = proportion;
}
/**
- 设置输入参数
-
- @param inputDir
- @param inputFileName
- @return
*/
public Compresstools setInputInfo(String inputDir,String inputFileName) {
this.inputDir = inputDir;
this.inputFileName = inputFileName;
return this;
}
/**
- 设置输出参数
-
- @param outputDir
- @param outputFileName
- @param outputHeight
- @param outputWidth
- @param proportion
- @return
*/
public Compresstools setoutputInfo(String outputDir,String outputFileName,int outputHeight,int outputWidth,boolean proportion) {
this.outputDir = outputDir;
this.outputFileName = outputFileName;
this.outputWidth = outputWidth;
this.outputHeight = outputHeight;
this.proportion = proportion;
return this;
}
// 图片处理
public boolean compress() throws Exception {
//获得源文件
file = new File(inputDir);
if (!file.exists()) {
throw new BusinessException("文件不存在!");
}
Image img = ImageIO.read(file);
// 判断图片格式是否正确
if (img.getWidth(null) == -1) {
System.out.println(" can't read,retry!" + "
");
return false;
} else {
int newWidth;
int newHeight;
// 判断是否是等比缩放
if (this.proportion) {
// 为等比缩放计算输出的图片宽度及高度
double rate1 = ((double) img.getWidth(null)) / (double) outputWidth + 0.1;
double rate2 = ((double) img.getHeight(null)) / (double) outputHeight + 0.1;
// 根据缩放比率大的进行缩放控制
double rate = rate1 > rate2 ? rate1 : rate2;
newWidth = (int) (((double) img.getWidth(null)) / rate);
newHeight = (int) (((double) img.getHeight(null)) / rate);
} else {
newWidth = outputWidth; // 输出的图片宽度
newHeight = outputHeight; // 输出的图片高度
}
long start = System.currentTimeMillis();
BufferedImage tag = new BufferedImage(newWidth,newHeight,BufferedImage.TYPE_INT_RGB);
/*
- Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的
- 优先级比速度高 生成的图片质量比较好 但速度慢
*/
tag.getGraphics().drawImage(img.getScaledInstance(newWidth,Image.SCALE_SMOOTH),null);
FileOutputStream out = new FileOutputStream(outputDir);
// JPEGImageEncoder可适用于其他<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a>类型的转换
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(tag);
out.close();
long time = Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.currentTimeMillis() - start;
logger.info("[<a href="https://www.jb51.cc/tag/shuchu/" target="_blank" class="keywords">输出</a>路径]:" + outputDir + "\t[<a href="https://www.jb51.cc/tag/tupian/" target="_blank" class="keywords">图片</a><a href="https://www.jb51.cc/tag/mingcheng/" target="_blank" class="keywords">名称</a>]:" + outputFileName + "\t[压缩前大小]:" + getPicSize() + "\t[耗时]:" + time + "毫秒");
return true;
}
}
/**
- 简单压缩方法,压缩后图片将直接覆盖源文件
-
- @param images
- @return
- @throws Exception
*/
public boolean simpleCompress(File images) throws Exception {
setInputInfo(images.getPath(),images.getName());
setoutputInfo(images.getPath(),images.getName(),300,true);
return compress();
}
/**
- 获取图片大小,单位KB
-
- @return
*/
private String getPicSize() {
return file.length() / 1024 + "KB";
}
public static void main(String[] args) throws Exception {
Compresstools compresstools = new Compresstools();
compresstools.setInputInfo("/Users/wu/Downloads/background.jpg","background.jpg");
compresstools.setoutputInfo("/Users/wu/Downloads/background2.jpg","background2.jpg",633,1920,false);
compresstools.compress();
}
}
我专门把图片压缩写成了一个类。
其中可以看到一些关于文件路径的方法,其实没有什么特别的,就是截取后缀获取路径之类的,我这边也贴出来吧,免得有些朋友看的云里雾里的。
rush:java;">
package com.magic.rent.tools;
import com.magic.rent.exception.custom.BusinessException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.util.ArrayList;
/**
- 知识产权声明:本文件自创建起,任何他人不可擅自复制或模仿.
- 创建者: wu 创建时间: 2016/11/25
- 类说明:
- 更新记录:
*/
public class Filetools {
public static final int IMG = 1;
/**
- 获取项目根目录
-
- @return 根目录
*/
public static String getWebrootPath() {
return System.getProperty("web.root");
}
/**
- 获取头像目录,若不存在则直接创建一个
-
- @param userID 用户ID
- @return
*/
public static String getPortraitPath(int userID) {
String realPath = getWebrootPath() + "img/portrait/" + userID + "/";
File file = new File(realPath);
//判断文件夹是否存在,不存在则创建一个
if (!file.exists() || !file.isDirectory()) {
if (!file.mkdirs()) {
throw new BusinessException("创建头像文件夹失败!");
}
}
return realPath;
}
/**
- 重命名头像文件
-
- @param fileName 文件名
- @return
*/
public static String getPortraitFileName(String fileName) {
// 获取文件后缀
String suffix = getSuffix(fileName);
return "portrait" + suffix;
}
/**
- 判断文件后缀是否符合要求
-
- @param fileName 文件名
- @param allowSuffix 允许的后缀集合
- @return
- @throws Exception
*/
public static boolean checkSuffix(String fileName,String[] allowSuffix) throws Exception {
String fileExtension = getSuffix(fileName);
boolean flag = false;
for (String extension : allowSuffix) {
if (fileExtension.equals(extension)) {
flag = true;
}
}
return flag;
}
public static String getSuffix(String fileName) {
return fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
}
/**
- 将文件地址转成链接地址
-
- @param filePath 文件路径
- @param fileType 文件类型
- @return
*/
public static String filePathToSRC(String filePath,int fileType) {
String href = "";
if (null != filePath && !filePath.equals("")) {
switch (fileType) {
case IMG:
if (filePath.contains("/img/")) {
int index = filePath.indexOf("/img/");
href = filePath.substring(index);
} else {
href = "";
}
return href;
}
}
return href;
}
/**
- 获取指定文件或文件路径下的所有文件清单
-
- @param fileOrPath 文件或文件路径
- @return
*/
public static ArrayList getListFiles(Object fileOrPath) {
File directory;
if (fileOrPath instanceof File) {
directory = (File) fileOrPath;
} else {
directory = new File(fileOrPath.toString());
}
ArrayList<File> files = new ArrayList<File>();
if (directory.isFile()) {
files.add(directory);
return files;
} else if (directory.isDirectory()) {
File[] fileArr = directory.listFiles();
if (null != fileArr && fileArr.length != 0) {
for (File fileOne : fileArr) {
files.addAll(getListFiles(fileOne));
}
}
}
return files;
}
/**
- 截图工具,根据截取的比例进行缩放裁剪
-
- @param path 图片路径
- @param zoomX 缩放后的X坐标
- @param zoomY 缩放后的Y坐标
- @param zoomW 缩放后的截取宽度
- @param zoomH 缩放后的截取高度
- @param scaleWidth 缩放后图片的宽度
- @param scaleHeight 缩放后的图片高度
- @return 是否成功
- @throws Exception 任何异常均抛出
*/
public static boolean imgCut(String path,new File(path));
} else {
return true;
}
}
}
顺便一提:getWebrootPath这个方法,要生效,必须在Web.xml中做一个配置:
rush:xml;">
webAppRootKey
web.root
否则是无法动态获取项目的本地路径的。这个配置只要跟在Spring配置后面就行了,应该就不会有什么大碍,其实就是获取本地路径然后设置到系统参数当中。
好了,这就是整个插件的功能了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。