"embed-responsive embed-responsive-16by9"这个类就是用来限制待编辑图片加载后的宽度大小,值得注意的是,我在其内种,加了一个
pre-scrollable这个类,会让加载的图片不会因为太大而“变形”,因为我外层通过embed-responsive-16by9限制死了图片的宽高,图片本身又加了img-responsive这个添加响应式属性的类,为了防止图片缩放,导致截图障碍,所以就给内层加上pre-scrollable,这个会给图片这一层div加上滚动条,如果图片高度太高,超过了外层框,则会出现滚动条,而这不会影响图片截取,同时又保证了模态窗口不会“太长”,导致体验糟糕(尤其在移动端)。
底下四个隐藏域相信大家看他们的name值也就知道个大概,这个就是用于存放Jcrop截取时所产生的原点坐标和截取宽高的值。
JS
1 $(document).ready(function () {
2 new PageInit().init();
3 });
4
5
6 function PageInit() {
7 var api = null;
8 var _this = this;
9 this.init = function () {
10 $("[name='upload']").on('click', this.portraitUpload);
11 };
12
13 this.portraitUpload = function () {
14 var model = $.scojs_modal({
15 title: '头像上传',
16 content: template('portraitUpload'),
17 onClose: refresh
18 }
19 );
20 model.show();
21 var fileUp = new FileUpload();
22 var portrait = $('#fileUpload');
23 fileUp.portrait(portrait, '/upload/portrait', _this.getExtraData, $('#alert'));
24 portrait.on('change', _this.readURL);
25 };
26
27 this.readURL = function () {
28 var img = $('#cut-img');
29 var input = $('#fileUpload');
30 if (input[0].files && input[0].files[0]) {
31 var reader = new FileReader();
32 reader.readAsDataURL(input[0].files[0]);
33 reader.onload = function (e) {
34 img.removeAttr('src');
35 img.attr('src', e.target.result);
36 img.Jcrop({
37 setSelect: [20, 20, 200, 200],
38 handleSize: 10,
39 aspectRatio: 1,
40 onSelect: updateCords
41 }, function () {
42 api = this;
43 });
44 };
45 if (api != undefined) {
46 api.destroy();
47 }
48 }
49 function updateCords(obj) {
50 $("#x").val(obj.x);
51 $("#y").val(obj.y);
52 $("#w").val(obj.w);
53 $("#h").val(obj.h);
54 }
55 };
56
57 this.getExtraData = function () {
58 return {
59 sw: $('.jcrop-holder').css('width'),
60 sh: $('.jcrop-holder').css('height'),
61 x: $('#x').val(),
62 y: $('#y').val(),
63 w: $('#w').val(),
64 h: $('#h').val()
65 }
66 }
67 }
这个JS是上传页面的相关逻辑。会JS的人都看得懂它的意义,我就简单说一下几个事件的意义:
1 portrait.on('fileuploaderror', function (event, data, msg) {
2 alert.removeClass('hidden').html(msg);
3 fileUp.fileinput('disable');
4 });
这个事件,是用于bootstrap-fileinput插件在校验文件格式、文件大小等的时候,如果不符合我们的要求,则会对前面HTML代码中有一个
进行一些错误信息的显示操作。
1 portrait.on('fileclear', function (event) {
2 alert.addClass('hidden').html();
3 });
这部分代码,是当文件移除时,隐藏错误信息提示区,以及清空内容,当然这是符合我们的业务逻辑的。
1 portrait.on('fileloaded', function (event, file, previewId, index, reader) {
2 alert.addClass('hidden').html();
3 });
这部分代码是当选择文件时(此时还没进行文件校验),隐藏错误信息,清空错误内容,这么做是为了应对如果上一次文件校验时有错误,而重新选择文件时,肯定要清空上一次的错误信息,再显示本次的错误信息。
1 portrait.on('fileuploaded', function (event, data) {
2 if (!data.response.status) {
3 alert.html(data.response.message).removeClass('hidden');
4 }
5 })
这部分是当文件上传后,后端如果返回了错误信息,则需要进行相关的提示信息处理。
1 this.getExtraData = function () {
2 return {
3 sw: $('.jcrop-holder').css('width'),
4 sh: $('.jcrop-holder').css('height'),
5 x: $('#x').val(),
6 y: $('#y').val(),
7 w: $('#w').val(),
8 h: $('#h').val()
9 }
10 }
这部分代码是获取上传文件时,附带需要发往后端的参数,这里面可以看到,x、y自然是Jcrop截取时,选框的左上角原点坐标,w、h自然就是截取的宽高,但是刚才我说了,这个是经过缩放后的宽高,不是依据图片实际像素的宽高。而sw、sh代表的是scaleWidth、scaleHeight,就是缩放宽高的意思。这个.jcrop-holder的对象是当Jcrop插件启用后,加载的图片外层容器的对象,只需要获取这个对象的宽高,就是图片被压缩的宽高,但是因为我限制了图片的宽度和高度,宽度的比例是定死的(不是宽高定死,只是比例定死,bootstrap本身就是响应式框架,所以不能单纯的说宽高定死,宽高会随着使用终端的变化而变化),高度是根据宽度保持16:4,可是我又加了pre-scrollable这个类让图片过高时以滚动条的方式不破坏外层容器的高度,所以我们实际能拿来计算缩放比例的,是宽度,而不是高度,但是这里我一起传,万一以后有其他的使用场景,要以高度为准也说不定。
好了,然后我需要贴上bootstrap-fileinput插件的配置代码:
1 this.portrait = function (target, uploadUrl, data, alert) {
2 target.fileinput({
3 language: 'zh', //设置语言
4 maxFileSize: 2048,//文件最大容量
5 uploadExtraData: data,//上传时除了文件以外的其他额外数据
6 showPreview: false,//隐藏预览
7 uploadAsync: true,//ajax同步
8 dropZoneEnabled: false,//是否显示拖拽区域
9 uploadUrl: uploadUrl, //上传的地址
10 elErrorContainer: alert,//错误信息内容容器
11 allowedFileExtensions: ['jpg'],//接收的文件后缀
12 showUpload: true, //是否显示上传按钮
13 showCaption: true,//是否显示标题
14 browseClass: "btn btn-primary", //按钮样式
15 previewFileIcon: "",
16 ajaxSettings: {//这个是因为我使用了SpringSecurity框架,有csrf跨域提交防御,所需需要设置这个值
17 beforeSend: function (xhr) {
18 xhr.setRequestHeader(header, token);
19 }
20 }
21 });
22 this.alert(target, alert);
23 };
24 this.alert = function (target, alert) {
25 target.on('fileuploaderror', function (event, data, msg) {
26 alert.removeClass('hidden').html(msg);
27 _this.fileinput('disable');
28 });
29 target.on('fileclear', function (event) {
30 alert.addClass('hidden').html();
31 });
32 target.on('fileloaded', function (event, file, previewId, index, reader) {
33 alert.addClass('hidden').html();
34 });
35 target.on('fileuploaded', function (event, data) {
36 if (!data.response.status) {
37 alert.html(data.response.message).removeClass('hidden');
38 }
39 });
40 };
这个代码有写了注释,我就不多解释了。
唯一做一个补充,就是“elErrorContainer: alert,//错误信息内容容器”这个配置,这个是我后来再次研究这个插件得到的一个心得,这个插件自带错误信息显示的功能,但是吧,至少我还不知道如何能够让ajax后自定义的错误信息调用这个显示功能,于是我就只能自己定义一个alert的容器,用来存放错误信息来扩展这个插件,但是这样就会在某种情况下比如400错误时,导致出现两个错误信息提示,那解决的办法我是看到了这个参数,只需要将这个错误信息的容器从默认值修改为我自定义的容器就可以了。
关于Ajax同步,是因为我个人认为,上传文件这个还是做成同步比较好,等文件上传完成后,js代码才能继续执行下去。因为文件上传毕竟是一个耗时的工作,有的逻辑又确实需要当文件上传成功以后才执行,比如刷新页面,所以为了避免出现问题,还是做成同步的比较好。还有就是去掉预览,用过bootstrap-fileinput插件的都知道,这个插件的图片预览功能很强大,甚至可以单独依靠这个插件来制作相册管理。但是因为我们这次要结合Jcrop,所以要割掉这部分功能。
SpringMVC-Controller获取文件
1 @ResponseBody
2 @RequestMapping(value = "/portrait", method = {RequestMethod.POST})
3 public JsonResult upload(HttpServletRequest request) throws Exception {
4 Integer x = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("x"), "图片截取异常:X!"));
5 Integer y = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("y"), "图片截取异常:Y!"));
6 Integer w = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("w"), "图片截取异常:W!"));
7 Integer h = Integer.parseInt(MyStringTools.checkParameter(request.getParameter("h"), "图片截取异常:H!"));
8 String scaleWidthString = MyStringTools.checkParameter(request.getParameter("sw"), "图片截取异常:SW!");
9 int swIndex = scaleWidthString.indexOf("px");
10 Integer sw = Integer.parseInt(scaleWidthString.substring(0, swIndex));
11 String scaleHeightString = MyStringTools.checkParameter(request.getParameter("sh"), "图片截取异常:SH!");
12 int shIndex = scaleHeightString.indexOf("px");
13 Integer sh = Integer.parseInt(scaleHeightString.substring(0, shIndex));
14
15
16 //获取用户ID用于指向对应文件夹
17 SysUsers sysUsers = HttpTools.getSessionUser(request);
18 int userID = sysUsers.getUserId();
19 //获取文件路径
20 String filePath = FileTools.getPortraitPath(userID);
21
22 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
23 request.getSession().getServletContext());
24
25 String path;
26 //检查form中是否有enctype="multipart/form-data"
27 if (multipartResolver.isMultipart(request)) {
28 //将request变成多部分request
29 MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
30 //获取multiRequest 中所有的文件名
31 Iterator iterator = multiRequest.getFileNames();
32 while (iterator.hasNext()) {
33 //一次遍历所有文件
34 MultipartFile multipartFile = multiRequest.getFile(iterator.next().toString());
35 if (multipartFile != null) {
36 String[] allowSuffix = {".jpg",".JPG"};
37 if (!FileTools.checkSuffix(multipartFile.getOriginalFilename(), allowSuffix)) {
38 throw new BusinessException("文件后缀名不符合要求!");
39 }
40 path = filePath + FileTools.getPortraitFileName(multipartFile.getOriginalFilename());
41 //存入硬盘
42 multipartFile.transferTo(new File(path));
43 //图片截取
44 if (FileTools.imgCut(path, x, y, w, h, sw, sh)) {
45 CompressTools compressTools = new CompressTools();
46 if (compressTools.simpleCompress(new File(path))) {
47 return JsonResult.success(FileTools.filePathToSRC(path, FileTools.IMG));
48 } else {
49 return JsonResult.error("图片压缩失败!请重新上传!");
50 }
51 } else {
52 return JsonResult.error("图片截取失败!请重新上传!");
53 }
54 }
55 }
56 }
57 return JsonResult.error("图片获取失败!请重新上传!");
58 }
Image图片切割
1 /**
2 * 截图工具,根据截取的比例进行缩放裁剪
3 *
4 * @param path 图片路径
5 * @param zoomX 缩放后的X坐标
6 * @param zoomY 缩放后的Y坐标
7 * @param zoomW 缩放后的截取宽度
8 * @param zoomH 缩放后的截取高度
9 * @param scaleWidth 缩放后图片的宽度
10 * @param scaleHeight 缩放后的图片高度
11 * @return 是否成功
12 * @throws Exception 任何异常均抛出
13 */
14 public static boolean imgCut(String path, int zoomX, int zoomY, int zoomW,
15 int zoomH, int scaleWidth, int scaleHeight) throws Exception {
16 Image img;
17 ImageFilter cropFilter;
18 BufferedImage bi = ImageIO.read(new File(path));
19 int fileWidth = bi.getWidth();
20 int fileHeight = bi.getHeight();
21 double scale = (double) fileWidth / (double) scaleWidth;
22
23 double realX = zoomX * scale;
24 double realY = zoomY * scale;
25 double realW = zoomW * scale;
26 double realH = zoomH * scale;
27
28 if (fileWidth >= realW && fileHeight >= realH) {
29 Image image = bi.getScaledInstance(fileWidth, fileHeight, Image.SCALE_DEFAULT);
30 cropFilter = new CropImageFilter((int) realX, (int) realY, (int) realW, (int) realH);
31 img = Toolkit.getDefaultToolkit().createImage(
32 new FilteredImageSource(image.getSource(), cropFilter));
33 BufferedImage bufferedImage = new BufferedImage((int) realW, (int) realH, BufferedImage.TYPE_INT_RGB);
34 Graphics g = bufferedImage.getGraphics();
35 g.drawImage(img, 0, 0, null);
36 g.dispose();
37 //输出文件
38 return ImageIO.write(bufferedImage, "JPEG", new File(path));
39 } else {
40 return true;
41 }
42 }
缩放比例scale一定要用double,并且宽高也要转换成double后再相除,否则会变成求模运算,这样会降低精度,别小看这里的精度下降,最终的截图效果根据图片的缩放程度,误差可是有可能被放大的很离谱的。
图片压缩
1 package com.magic.rent.tools;
2
3 /**
4 * 知识产权声明:本文件自创建起,其内容的知识产权即归属于原作者,任何他人不可擅自复制或模仿.
5 * 创建者: wu 创建时间: 2016/12/15
6 * 类说明: 缩略图类(通用) 本java类能将jpg、bmp、png、gif图片文件,进行等比或非等比的大小转换。 具体使用方法
7 * 更新记录:
8 */
9
10 import com.magic.rent.exception.custom.BusinessException;
11 import com.sun.image.codec.jpeg.JPEGCodec;
12 import com.sun.image.codec.jpeg.JPEGImageEncoder;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import javax.imageio.ImageIO;
17 import java.awt.*;
18 import java.awt.image.BufferedImage;
19 import java.io.File;
20 import java.io.FileOutputStream;
21
22 public class CompressTools {
23 private File file; // 文件对象
24 private String inputDir; // 输入图路径
25 private String outputDir; // 输出图路径
26 private String inputFileName; // 输入图文件名
27 private String outputFileName; // 输出图文件名
28 private int outputWidth = 100; // 默认输出图片宽
29 private int outputHeight = 100; // 默认输出图片高
30 private boolean proportion = true; // 是否等比缩放标记(默认为等比缩放)
31 private static Logger logger = LoggerFactory.getLogger(CompressTools.class);
32
33
34 public CompressTools() {
35 }
36
37 public CompressTools(boolean proportion) {
38 this.proportion = proportion;
39 }
40
41 /**
42 * 设置输入参数
43 *
44 * @param inputDir
45 * @param inputFileName
46 * @return
47 */
48 public CompressTools setInputInfo(String inputDir, String inputFileName) {
49 this.inputDir = inputDir;
50 this.inputFileName = inputFileName;
51 return this;
52 }
53
54 /**
55 * 设置输出参数
56 *
57 * @param outputDir
58 * @param outputFileName
59 * @param outputHeight
60 * @param outputWidth
61 * @param proportion
62 * @return
63 */
64 public CompressTools setOutputInfo(String outputDir, String outputFileName, int outputHeight, int outputWidth, boolean proportion) {
65 this.outputDir = outputDir;
66 this.outputFileName = outputFileName;
67 this.outputWidth = outputWidth;
68 this.outputHeight = outputHeight;
69 this.proportion = proportion;
70 return this;
71 }
72
73
74 // 图片处理
75 public boolean compress() throws Exception {
76 //获得源文件
77 file = new File(inputDir);
78 if (!file.exists()) {
79 throw new BusinessException("文件不存在!");
80 }
81 Image img = ImageIO.read(file);
82 // 判断图片格式是否正确
83 if (img.getWidth(null) == -1) {
84 System.out.println(" can't read,retry!" + "
");
85 return false;
86 } else {
87 int newWidth;
88 int newHeight;
89 // 判断是否是等比缩放
90 if (this.proportion) {
91 // 为等比缩放计算输出的图片宽度及高度
92 double rate1 = ((double) img.getWidth(null)) / (double) outputWidth + 0.1;
93 double rate2 = ((double) img.getHeight(null)) / (double) outputHeight + 0.1;
94 // 根据缩放比率大的进行缩放控制
95 double rate = rate1 > rate2 ? rate1 : rate2;
96 newWidth = (int) (((double) img.getWidth(null)) / rate);
97 newHeight = (int) (((double) img.getHeight(null)) / rate);
98 } else {
99 newWidth = outputWidth; // 输出的图片宽度
100 newHeight = outputHeight; // 输出的图片高度
101 }
102 long start = System.currentTimeMillis();
103 BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
104 /*
105 * Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的
106 * 优先级比速度高 生成的图片质量比较好 但速度慢
107 */
108 tag.getGraphics().drawImage(img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
109 FileOutputStream out = new FileOutputStream(outputDir);
110
111 // JPEGImageEncoder可适用于其他图片类型的转换
112 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
113 encoder.encode(tag);
114 out.close();
115 long time = System.currentTimeMillis() - start;
116 logger.info("[输出路径]:" + outputDir + "\t[图片名称]:" + outputFileName + "\t[压缩前大小]:" + getPicSize() + "\t[耗时]:" + time + "毫秒");
117 return true;
118 }
119 }
120
121
122 /**
123 * 简单压缩方法,压缩后图片将直接覆盖源文件
124 *
125 * @param images
126 * @return
127 * @throws Exception
128 */
129 public boolean simpleCompress(File images) throws Exception {
130 setInputInfo(images.getPath(), images.getName());
131 setOutputInfo(images.getPath(), images.getName(), 300, 300, true);
132 return compress();
133 }
134
135 /**
136 * 获取图片大小,单位KB
137 *
138 * @return
139 */
140 private String getPicSize() {
141 return file.length() / 1024 + "KB";
142 }
143
144 public static void main(String[] args) throws Exception {
145 CompressTools compressTools = new CompressTools();
146 compressTools.setInputInfo("/Users/wu/Downloads/background.jpg", "background.jpg");
147 compressTools.setOutputInfo("/Users/wu/Downloads/background2.jpg", "background2.jpg", 633, 1920, false);
148 compressTools.compress();
149 }
150
151 }
我专门把图片压缩写成了一个类。
其中可以看到一些关于文件路径的方法,其实没有什么特别的,就是截取后缀获取路径之类的,我这边也贴出来吧,免得有些朋友看的云里雾里的。
1 package com.magic.rent.tools;
2
3 import com.magic.rent.exception.custom.BusinessException;
4
5 import javax.imageio.ImageIO;
6 import java.awt.*;
7 import java.awt.image.BufferedImage;
8 import java.awt.image.CropImageFilter;
9 import java.awt.image.FilteredImageSource;
10 import java.awt.image.ImageFilter;
11 import java.io.File;
12 import java.util.ArrayList;
13
14 /**
15 * 知识产权声明:本文件自创建起,其内容的知识产权即归属于原作者,任何他人不可擅自复制或模仿.
16 * 创建者: wu 创建时间: 2016/11/25
17 * 类说明:
18 * 更新记录:
19 */
20 public class FileTools {
21
22 public static final int IMG = 1;
23
24 /**
25 * 获取项目根目录
26 *
27 * @return 根目录
28 */
29 public static String getWebRootPath() {
30 return System.getProperty("web.root");
31 }
32
33 /**
34 * 获取头像目录,若不存在则直接创建一个
35 *
36 * @param userID 用户ID
37 * @return
38 */
39 public static String getPortraitPath(int userID) {
40 String realPath = getWebRootPath() + "img/portrait/" + userID + "/";
41 File file = new File(realPath);
42 //判断文件夹是否存在,不存在则创建一个
43 if (!file.exists() || !file.isDirectory()) {
44 if (!file.mkdirs()) {
45 throw new BusinessException("创建头像文件夹失败!");
46 }
47 }
48 return realPath;
49 }
50
51 /**
52 * 重命名头像文件
53 *
54 * @param fileName 文件名
55 * @return
56 */
57 public static String getPortraitFileName(String fileName) {
58 // 获取文件后缀
59 String suffix = getSuffix(fileName);
60 return "portrait" + suffix;
61 }
62
63 /**
64 * 判断文件后缀是否符合要求
65 *
66 * @param fileName 文件名
67 * @param allowSuffix 允许的后缀集合
68 * @return
69 * @throws Exception
70 */
71 public static boolean checkSuffix(String fileName, String[] allowSuffix) throws Exception {
72 String fileExtension = getSuffix(fileName);
73 boolean flag = false;
74 for (String extension : allowSuffix) {
75 if (fileExtension.equals(extension)) {
76 flag = true;
77 }
78 }
79 return flag;
80 }
81
82
83 public static String getSuffix(String fileName) {
84 return fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
85 }
86
87 /**
88 * 将文件地址转成链接地址
89 *
90 * @param filePath 文件路径
91 * @param fileType 文件类型
92 * @return
93 */
94 public static String filePathToSRC(String filePath, int fileType) {
95 String href = "";
96 if (null != filePath && !filePath.equals("")) {
97 switch (fileType) {
98 case IMG:
99 if (filePath.contains("/img/")) {
100 int index = filePath.indexOf("/img/");
101 href = filePath.substring(index);
102 } else {
103 href = "";
104 }
105 return href;
106 }
107 }
108 return href;
109 }
110
111 /**
112 * 获取指定文件或文件路径下的所有文件清单
113 *
114 * @param fileOrPath 文件或文件路径
115 * @return
116 */
117 public static ArrayList getListFiles(Object fileOrPath) {
118 File directory;
119 if (fileOrPath instanceof File) {
120 directory = (File) fileOrPath;
121 } else {
122 directory = new File(fileOrPath.toString());
123 }
124
125 ArrayList files = new ArrayList();
126
127 if (directory.isFile()) {
128 files.add(directory);
129 return files;
130 } else if (directory.isDirectory()) {
131 File[] fileArr = directory.listFiles();
132 if (null != fileArr && fileArr.length != 0) {
133 for (File fileOne : fileArr) {
134 files.addAll(getListFiles(fileOne));
135 }
136 }
137 }
138
139 return files;
140 }
141
142
143 /**
144 * 截图工具,根据截取的比例进行缩放裁剪
145 *
146 * @param path 图片路径
147 * @param zoomX 缩放后的X坐标
148 * @param zoomY 缩放后的Y坐标
149 * @param zoomW 缩放后的截取宽度
150 * @param zoomH 缩放后的截取高度
151 * @param scaleWidth 缩放后图片的宽度
152 * @param scaleHeight 缩放后的图片高度
153 * @return 是否成功
154 * @throws Exception 任何异常均抛出
155 */
156 public static boolean imgCut(String path, int zoomX, int zoomY, int zoomW,
157 int zoomH, int scaleWidth, int scaleHeight) throws Exception {
158 Image img;
159 ImageFilter cropFilter;
160 BufferedImage bi = ImageIO.read(new File(path));
161 int fileWidth = bi.getWidth();
162 int fileHeight = bi.getHeight();
163 double scale = (double) fileWidth / (double) scaleWidth;
164
165 double realX = zoomX * scale;
166 double realY = zoomY * scale;
167 double realW = zoomW * scale;
168 double realH = zoomH * scale;
169
170 if (fileWidth >= realW && fileHeight >= realH) {
171 Image image = bi.getScaledInstance(fileWidth, fileHeight, Image.SCALE_DEFAULT);
172 cropFilter = new CropImageFilter((int) realX, (int) realY, (int) realW, (int) realH);
173 img = Toolkit.getDefaultToolkit().createImage(
174 new FilteredImageSource(image.getSource(), cropFilter));
175 BufferedImage bufferedImage = new BufferedImage((int) realW, (int) realH, BufferedImage.TYPE_INT_RGB);
176 Graphics g = bufferedImage.getGraphics();
177 g.drawImage(img, 0, 0, null);
178 g.dispose();
179 //输出文件
180 return ImageIO.write(bufferedImage, "JPEG", new File(path));
181 } else {
182 return true;
183 }
184 }
185 }
顺便一提:getWebRootPath这个方法,要生效,必须在Web.xml中做一个配置:
1 <context-param>
2 <param-name>webAppRootKeyparam-name>
3 <param-value>web.rootparam-value>
4 context-param>
否则是无法动态获取项目的本地路径的。这个配置只要跟在Spring配置后面就行了,应该就不会有什么大碍,其实就是获取本地路径然后设置到系统参数当中。
好了,这就是整个插件的功能了。
附上Github地址:
https://github.com/wuxinzhe/Portrait.git 如果有帮助,希望给个Star