├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
├── java
└── com
│ └── imageServer
│ ├── config
│ └── FTPConnectAttr.java
│ ├── context
│ └── ShutdownResources.java
│ ├── controller
│ ├── FetchImagePathController.java
│ └── FtpServiceController.java
│ ├── factory
│ └── ExecutorFactory.java
│ ├── ftp
│ ├── DownloadThread.java
│ └── UploadThread.java
│ ├── interceptors
│ └── ImageSecurityInterceptor.java
│ ├── service
│ ├── FtpImageCacheService.java
│ ├── FtpService.java
│ └── impl
│ │ ├── FtpImageCacheServiceImp.java
│ │ └── FtpServiceImp.java
│ ├── util
│ ├── CustomerMath.java
│ ├── ExecuteThreadUtil.java
│ ├── FTPUtil.java
│ ├── FileUtil.java
│ ├── ImageCatchUtil.java
│ ├── ImageUtil.java
│ └── ObjectUtil.java
│ └── vo
│ └── ImageConvert.java
├── resources
├── log4j.properties
├── noimage.jpg
├── system.properties
├── tuijianBig.png
├── tuijianSmall.png
└── watermark.png
└── webapp
└── WEB-INF
├── applicationContext.xml
├── springMVC.xml
└── web.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | /imageServer.iml
3 | /src/main/resources/rebel.xml
4 | /src/main/webapp/home
5 | /target
6 | *.class
7 |
8 | # Mobile Tools for Java (J2ME)
9 | .mtj.tmp/
10 |
11 | # Package Files #
12 | *.jar
13 | *.war
14 | *.ear
15 |
16 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
17 | hs_err_pid*
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 项目简介
2 | 图片服务器,能够对源图片进行转换(指定高宽,等比缩放,添加水印,添加业务图标,改变透明度等),并且进行业务图片的缓存,提供业务图片的静态地址等
3 | (目前本项目还是第一版,还有很多不完善的地方,但是功能使用完全没有问题.后续会继续更进更新)
4 |
5 | # 配置说明
6 | - system.properties : 配置系统的参数,如FTP的访问配置等
7 | - noimage.jpg : 这个图片是图片服务器在未找到FTP上指定的图片的时候,或者图片处理出现异常时,返回的默认图片
8 | - tuijianBig.png : 偏大尺寸的推荐水印
9 | - tuijianSmall.png : 偏小尺寸的推荐水印
10 | - watermark.png : 版权水印
11 |
12 | # 项目使用说明
13 | 1. 需要配置一个FTP服务器,用于存放源图片.imageServer将会根据system.properties中配置的FTP信息进行访问
14 | 2. 如目前有一个FTP服务器上的图片:/image/user/demo.jpg :
15 | - 获取200 * 200 像素的业务图片的静态地址 :
16 | http://webRoot:8080/getImagePath?path=/image/user/demo.jpg&width=200&height=200
17 | - 直接获取显示200 * 200 像素的业务图片 :
18 | http://webRoot:8080/image?path=/image/user/demo.jpg&width=200&height=200
19 | - 具体的param参数的说明请查看Controller的方法注释
20 |
21 | # 联系我
22 | - email :642321251@qq.com
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | com.ql.web
5 | imageServer
6 | war
7 | 1.0-SNAPSHOT
8 | imageServer Maven Webapp
9 | http://maven.apache.org
10 |
11 |
12 | 4.0.0.RELEASE
13 | 4.0.0.RELEASE
14 |
15 |
16 |
17 |
18 |
19 | org.springframework
20 | spring-core
21 | ${springframework.version}
22 |
23 |
24 |
25 | org.springframework
26 | spring-web
27 | ${springframework.version}
28 |
29 |
30 |
31 | org.springframework
32 | spring-webmvc
33 | ${springframework.version}
34 |
35 |
36 |
37 | org.springframework
38 | spring-orm
39 | ${springframework.version}
40 |
41 |
42 |
43 | org.springframework
44 | spring-oxm
45 | ${springframework.version}
46 |
47 |
48 |
49 | org.springframework
50 | spring-context
51 | ${springframework.version}
52 |
53 |
54 |
55 | org.springframework.security
56 | spring-security-core
57 | ${springframework.version}
58 |
59 |
60 |
61 | org.springframework.security
62 | spring-security-web
63 | ${springframework.version}
64 |
65 |
66 |
67 | org.springframework
68 | spring-aop
69 | ${springframework.version}
70 |
71 |
72 |
73 | org.springframework
74 | spring-tx
75 | ${springframework.version}
76 |
77 |
78 |
79 | org.springframework
80 | spring-aspects
81 | ${springframework.version}
82 |
83 |
84 |
85 | org.springframework
86 | spring-expression
87 | ${springframework.version}
88 |
89 |
90 |
91 | org.springframework
92 | spring-test
93 | ${springframework.version}
94 |
95 |
96 |
97 | org.springframework
98 | spring-webmvc-portlet
99 | ${springframework.version}
100 |
101 |
102 |
103 | org.springframework
104 | spring-jms
105 | ${springframework.version}
106 |
107 |
108 |
109 |
110 |
111 | javax.servlet
112 | javax.servlet-api
113 | 3.0.1
114 | provided
115 |
116 |
117 |
118 | junit
119 | junit
120 | 4.7
121 | test
122 |
123 |
124 |
125 | org.slf4j
126 | slf4j-api
127 | 1.7.5
128 |
129 |
130 |
131 | org.slf4j
132 | slf4j-log4j12
133 | 1.7.5
134 |
135 |
136 |
137 | log4j
138 | log4j
139 | 1.2.12
140 |
141 |
142 |
143 | dom4j
144 | dom4j
145 | 1.6.1
146 |
147 |
148 |
149 | dwr
150 | dwr
151 | 1.1.3
152 |
153 |
154 |
155 |
156 | mysql
157 | mysql-connector-java
158 | 5.1.31
159 |
160 |
161 |
162 | org.codehaus.jackson
163 | jackson-core-asl
164 | 1.9.13
165 |
166 |
167 | org.codehaus.jackson
168 | jackson-mapper-asl
169 | 1.9.13
170 |
171 |
172 | org.aspectj
173 | aspectjrt
174 | 1.8.2
175 |
176 |
177 | org.aspectj
178 | aspectjweaver
179 | 1.8.2
180 |
181 |
182 | net.sf.json-lib
183 | json-lib-ext-spring
184 | 1.0.2
185 |
186 |
187 | net.sf.json-lib
188 | json-lib
189 | 2.4
190 | pom
191 |
192 |
193 |
194 | commons-net
195 | commons-net
196 | 3.1
197 |
198 |
199 |
200 | org.apache.poi
201 | poi
202 | 3.9
203 |
204 |
205 |
206 | com.thoughtworks.xstream
207 | xstream
208 | 1.3.1
209 |
210 |
211 |
212 |
213 | net.coobird
214 | thumbnailator
215 | 0.4.8
216 |
217 |
218 |
219 |
220 |
221 | driftBottleService
222 |
223 |
224 |
225 |
226 | org.apache.maven.plugins
227 | maven-compiler-plugin
228 |
229 | 1.8
230 | 1.8
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/config/FTPConnectAttr.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.config;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 16/2/27.
4 | */
5 |
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * FTP连接的帐号属性
11 | * Copyright 2015-2016 the original ql
12 | * Created by QianLong on 16/2/27.
13 | */
14 | @Component
15 | public class FTPConnectAttr {
16 | @Value("${ftp.address}")
17 | public String address;
18 | @Value("${ftp.userName}")
19 | public String userName;
20 | @Value("${ftp.password}")
21 | public String password;
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/context/ShutdownResources.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.context;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/8/29 0029.
4 | */
5 |
6 | import com.imageServer.factory.ExecutorFactory;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import javax.servlet.ServletContextEvent;
11 | import javax.servlet.ServletContextListener;
12 |
13 | /**
14 | * 关闭资源监听处理器
15 | * Copyright 2014-2015 the original ql
16 | * Created by QianLong on 2014/8/29 0029.
17 | */
18 | public class ShutdownResources implements ServletContextListener {
19 |
20 | private static final Logger log = LoggerFactory.getLogger(ShutdownResources.class);
21 |
22 | @Override
23 | public void contextInitialized(ServletContextEvent servletContextEvent) {
24 |
25 | }
26 |
27 | @Override
28 | public void contextDestroyed(ServletContextEvent servletContextEvent) {
29 | log.info("监听处理处理web容器关闭事件");
30 |
31 | log.info("关闭线程池");
32 | ExecutorFactory.EXECUTE.getExecutor().shutdown();
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/controller/FetchImagePathController.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.controller;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/7/9 0009.
4 | */
5 |
6 | import com.imageServer.service.FtpImageCacheService;
7 | import com.imageServer.util.ImageCatchUtil;
8 | import com.imageServer.util.ImageUtil;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.beans.factory.annotation.Value;
13 | import org.springframework.stereotype.Controller;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RequestMethod;
16 | import org.springframework.web.bind.annotation.ResponseBody;
17 |
18 | import javax.servlet.http.HttpServletRequest;
19 | import javax.servlet.http.HttpServletResponse;
20 | import java.io.File;
21 | import java.io.IOException;
22 | import java.io.PrintWriter;
23 |
24 | /**
25 | * 获取图片的地址控制器
26 | * Copyright 2014-2015 the original ql
27 | * Created by QianLong on 2014/7/9 0009.
28 | */
29 | @Controller
30 | public class FetchImagePathController {
31 |
32 | Logger log = LoggerFactory.getLogger(FetchImagePathController.class);
33 |
34 | @Autowired
35 | private FtpImageCacheService ftpImageCacheService;
36 | @Value("${sys.webUrl}")
37 | private String webUrl;
38 |
39 | /**
40 | * 获取图片静态资源的hashUrl网址
41 | * @param request
42 | * @param response
43 | */
44 | @RequestMapping(value = "getImagePath",method = RequestMethod.GET)
45 | @ResponseBody
46 | public void getImagepath(HttpServletRequest request,HttpServletResponse response){
47 | log.info(request.getRemoteAddr() + "获取图片的静态资源路径");
48 | response.setCharacterEncoding("UTF-8");
49 | PrintWriter out;
50 | try {
51 | out = response.getWriter();
52 | } catch (IOException e) {
53 | return;
54 | }
55 |
56 | String path = request.getParameter("path"),
57 | scale_str = request.getParameter("scale"),
58 | width_str = request.getParameter("width"),
59 | height_str = request.getParameter("height"),
60 | sign_str = request.getParameter("sign"),
61 | signAlpha_str = request.getParameter("signAlpha"),
62 | alpha_str = request.getParameter("alpha"),
63 | recommentSign_str = request.getParameter("recommentSign"),
64 | update = request.getParameter("update");
65 |
66 | float signAlpha = (float) 1;
67 | float alpha = (float) 1;
68 |
69 | boolean sign = true;
70 | boolean recomment = false;
71 | try {
72 | sign = !sign_str.equals("false");
73 |
74 | } catch (Exception ignored) { }
75 | try {
76 | recomment = recommentSign_str.equals("true");
77 | } catch (Exception ignored) {
78 | }
79 | try {
80 | if(signAlpha_str != null && !signAlpha_str.equals("")){
81 | signAlpha = Float.parseFloat(signAlpha_str);
82 | }else {
83 | signAlpha = 1;
84 | }
85 | } catch (NumberFormatException ignored) {
86 | }
87 | try {
88 | if(alpha_str != null && !alpha_str.equals("")){
89 | alpha = Float.parseFloat(alpha_str);
90 | }else {
91 | alpha = 1;
92 | }
93 | } catch (NumberFormatException ignored) {}
94 |
95 | log.info("图片系统对外的网站地址:" + webUrl);
96 | // 错误提示图片地址
97 | String errorImgPath = webUrl + "/" + "image?" + request.getQueryString();
98 |
99 | String cacheFileName = "";
100 | if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1){
101 |
102 | cacheFileName = ImageCatchUtil.getImageCachePathByFtpPath(path, sign, recomment, height_str, width_str, scale_str, signAlpha, alpha);
103 | log.info("获取图片静态资源的hash相对路径:" + cacheFileName);
104 | String cacheFileName1 = cacheFileName;
105 |
106 | //对平台的路径分隔符进行判断
107 | if(File.separator.equals("\\")){
108 | cacheFileName = cacheFileName.replace("/", "\\");
109 | }
110 |
111 | String webPath = ImageUtil.getWebPath(request);
112 |
113 | log.info("根据hash路径生成缓存文件绝对路径:" + webPath + cacheFileName);
114 | File cacheFile = new File(webPath + cacheFileName);
115 |
116 | String reUrl = webUrl + "/" + cacheFileName1;
117 |
118 | String cacheDir = (webPath + path.substring(1,path.lastIndexOf("/")+1))
119 | .replace("/",File.separator);
120 |
121 |
122 | if(update != null && update.equals("true")){//进行缓存文件的更新操作
123 | log.info("进行缓存文件更新操作,待更新的缓存文件:" + cacheFileName1);
124 | if(ftpImageCacheService.imageToCache(request)){
125 | log.info("缓存文件更新成功,返回静态资源网址:" + reUrl);
126 | out.write(reUrl);
127 | }else {
128 | File f = new File(cacheDir + cacheFileName);
129 | if(f.exists()){
130 | if(f.length() > 0){
131 | log.info("缓存文件更新失败,返回原来的静态资源网址:" + reUrl);
132 | out.write(reUrl);
133 | }else {
134 | log.warn("缓存文件更新失败,返回动态图片请求链接:" + errorImgPath);
135 | out.write(errorImgPath);
136 | }
137 | }else {
138 | log.warn("缓存文件更新失败,返回动态图片请求链接:" + errorImgPath);
139 | out.write(errorImgPath);
140 | }
141 | }
142 | }else {
143 | if(cacheFile.exists()){
144 | log.info("缓存文件已生成,返回已存在的静态资源网址:" + reUrl);
145 | out.write(reUrl);
146 | }else {
147 | log.info("缓存文件不存在,正在生成缓存文件");
148 | if(ftpImageCacheService.imageToCache(request)){
149 | log.info("缓存文件生成成功,返回静态资源网址:" + reUrl);
150 | out.write(reUrl);
151 | }else {
152 | log.warn("缓存文件生成失败,返回动态图片请求链接:" + errorImgPath);
153 | out.write(errorImgPath);
154 | }
155 | }
156 | }
157 |
158 | }else {
159 | out.write(errorImgPath);
160 | log.warn("传入的path无效,返回动态图片请求链接:" + errorImgPath);
161 | }
162 |
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/controller/FtpServiceController.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.controller;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/4/29 0029.
4 | */
5 |
6 | import com.imageServer.service.FtpImageCacheService;
7 | import com.imageServer.util.ImageUtil;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RequestMethod;
14 |
15 | import javax.imageio.ImageIO;
16 | import javax.servlet.http.HttpServletRequest;
17 | import javax.servlet.http.HttpServletResponse;
18 | import java.io.File;
19 | import java.io.IOException;
20 |
21 | /**
22 | * FTP控制器层的服务类
23 | * Copyright 2014-2015 the original ql
24 | * Created by QianLong on 2014/4/29 0029.
25 | */
26 | @Controller("imageFtpController")
27 | public class FtpServiceController {
28 |
29 | private Logger log = LoggerFactory.getLogger(FtpServiceController.class);
30 |
31 | @Autowired
32 | private FtpImageCacheService ftpImageCacheService;
33 |
34 | /**
35 | * 获取FTP文件服务器上的图像
36 | * 以response方式写出
37 | * 以下情况会返回 图片获取失败 的提示图像:
38 | * 1、远程的图片文件获取失败
39 | * 2、没有传入图片的path参数
40 | * 以下情况或返回 图片参数错误 的提示图像:
41 | * 1、scale参数非法
42 | * 2、width和height参数非法
43 | *
44 | * @param request 参数说明:
45 | * path :String 待获取的图像文件在FTP服务器上的全路径
46 | * alpha : 图片的透明度(0.0到1.0之间的float值,默认1.0)
47 | * scale : int 对图像进行缩放处理,小于100为缩小,大于100为放大
48 | * width : int 指定图像的输出宽度
49 | * height : int 指定图像的输出高度
50 | * sign : false:不添加版权水印 默认true (小于100 * 50 的不加水印)
51 | * signAlpha : 水印的透明度(0.0到1.0之间的float值,默认1.0)
52 | * 注意:
53 | * 1、width与height成对出现才会生效
54 | * 2、如果指定了width和height,那么scale参数将会失效
55 | * @param response 写出图像
56 | */
57 | @RequestMapping(value = "image", method = RequestMethod.GET)
58 | public void getImage(HttpServletRequest request, HttpServletResponse response) {
59 | String path = request.getParameter("path"),
60 | update = request.getParameter("update");
61 |
62 | response.setContentType("image/jpeg");
63 | response.setHeader("ragma", "No-cache");
64 | response.setHeader("Cache-Control", "no-cache");
65 | response.setDateHeader("Expires", 0);
66 |
67 | try {
68 | log.info("判断是否已经有请求文件的缓存图片");
69 | String cacheFileName = "";
70 | if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1){
71 | cacheFileName = ftpImageCacheService.getCacheFileHashName(request);
72 | if(File.separator.equals("\\")){
73 | cacheFileName = cacheFileName.replace("/",File.separator);
74 | }
75 | //存放缓存文件的绝对路径
76 | String cacheFilePath = ftpImageCacheService.getCacheFileAbsPath(request);
77 | File cacheFile = new File(cacheFilePath);
78 | log.info("计算缓存文件绝对路径:" + cacheFilePath);
79 |
80 | if(!"true".equals(update)){
81 | if(cacheFile.exists() && cacheFile.length() > 0){
82 | log.info("已有缓存文件,直接返回缓存文件流:" + cacheFile.getAbsolutePath());
83 | ImageUtil.getInstance().writeImage(cacheFileName.substring(cacheFileName.lastIndexOf(".")),ImageIO.read(cacheFile),response.getOutputStream());
84 | return;
85 | }
86 | }
87 |
88 | if("true".equals(update)){
89 | log.info("进行图片更新操作");
90 | if(ftpImageCacheService.imageToCache(request)){
91 | log.info("更新成功,写出图片流");
92 | ImageUtil.getInstance().writeImage(cacheFileName.substring(cacheFileName.lastIndexOf(".")),ImageIO.read(cacheFile),response.getOutputStream());
93 | }else{
94 | log.info("图片更新失败,写出默认图片");
95 | ImageUtil.getInstance().writeImage(".jpg",ImageUtil.getInstance().getNoImage(),response.getOutputStream());
96 | }
97 | }else {
98 | if(ftpImageCacheService.imageToCache(request)){
99 | log.info("处理成功,写出图片流");
100 | ImageUtil.getInstance().writeImage(cacheFileName.substring(cacheFileName.lastIndexOf(".")),ImageIO.read(cacheFile),response.getOutputStream());
101 | }else{
102 | log.info("图片处理失败,写出默认图片");
103 | ImageUtil.getInstance().writeImage(".jpg",ImageUtil.getInstance().getNoImage(),response.getOutputStream());
104 | }
105 | }
106 |
107 | }
108 | } catch (IOException e) {
109 | log.warn("返回缓存文件流时发生异常",e);
110 | }
111 |
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/factory/ExecutorFactory.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.factory;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 15-1-23.
4 | */
5 |
6 | import java.util.concurrent.ExecutorService;
7 | import java.util.concurrent.SynchronousQueue;
8 | import java.util.concurrent.ThreadPoolExecutor;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | /**
12 | * 并发线程执行对象工厂方法
13 | * 单例
14 | * Copyright 2014-2015 the original ql
15 | * Created by QianLong on 15-1-23.
16 | */
17 | public enum ExecutorFactory {
18 |
19 | EXECUTE;
20 |
21 | private static ExecutorService executorService;
22 |
23 | static {
24 | final int maxPoolSize = 200;
25 | //定义并发执行服务
26 | executorService = new ThreadPoolExecutor(5,maxPoolSize,0L, TimeUnit.MILLISECONDS,
27 | new SynchronousQueue<>(),
28 | r -> {
29 | Thread t=new Thread(r);
30 | t.setName("imageServerThreadPool");
31 | return t;
32 | }
33 | );
34 | }
35 | /**
36 | * 获取执行类
37 | * @return
38 | */
39 | public ExecutorService getExecutor(){
40 | return executorService;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/ftp/DownloadThread.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.ftp;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/8/2 0002.
4 | */
5 |
6 | import com.imageServer.config.FTPConnectAttr;
7 | import com.imageServer.util.FTPUtil;
8 | import org.apache.commons.net.ftp.FTPClient;
9 | import org.apache.commons.net.ftp.FTPFile;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.io.*;
14 |
15 | /**
16 | * FTP下载线程
17 | * Copyright 2014-2015 the original ql
18 | * Created by QianLong on 2014/8/2 0002.
19 | */
20 | public class DownloadThread implements Runnable{
21 |
22 | private static final Logger log = LoggerFactory.getLogger(DownloadThread.class);
23 |
24 | private File file;
25 | private String path;
26 | private PipedOutputStream pipedOutputStream;
27 | private FTPConnectAttr ftpConnectAttr;
28 |
29 | /**
30 | * 通道写出 0 : 下载失败
31 | * 通道写出1 : 下载成功
32 | * @param file
33 | * 下载文件的存放对象
34 | * @param path
35 | * 需要下载的文件在FTP服务器上的全路径
36 | * @param pipedOutputStream
37 | * 下载结果通信通道
38 | * @param ftpConnectAttr FTP连接配置
39 | */
40 | public DownloadThread(File file, String path, PipedOutputStream pipedOutputStream,FTPConnectAttr ftpConnectAttr) {
41 | this.file = file;
42 | this.path = path;
43 | this.pipedOutputStream = pipedOutputStream;
44 | this.ftpConnectAttr = ftpConnectAttr;
45 | log.info("download线程初始化完成,开始进行下载操作");
46 | }
47 |
48 | @Override
49 | public void run() {
50 | try {
51 | FTPClient ftpClient = FTPUtil.getFTPClient(ftpConnectAttr);
52 | if(ftpClient != null){
53 | //设置被动模式
54 | ftpClient.enterLocalPassiveMode();
55 | //设置以二进制方式传输
56 | ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
57 |
58 | //检查远程文件是否存在
59 | FTPFile[] files = ftpClient.listFiles(new String(path.getBytes("GBK"), "iso-8859-1"));
60 | if (files.length != 1) {
61 | log.warn("远程文件不存在:" + new String(path.getBytes("GBK"), "iso-8859-1"));
62 | pipedOutputStream.write(0);
63 | return;
64 | }
65 |
66 | long lRemoteSize = files[0].getSize();
67 | //本地存在文件,进行断点下载
68 | if (file.exists()) {
69 | long localSize = file.length();
70 | //判断本地文件大小是否大于远程文件大小
71 | if (localSize >= lRemoteSize) {
72 | log.warn("本地文件大于远程文件,下载中止");
73 | pipedOutputStream.write(0);
74 | return;
75 | }
76 |
77 | //进行断点续传,并记录状态
78 | FileOutputStream out = new FileOutputStream(file, true);
79 | ftpClient.setRestartOffset(localSize);
80 | InputStream in = ftpClient.retrieveFileStream(new String(path.getBytes("GBK"), "iso-8859-1"));
81 | byte[] bytes = new byte[1024];
82 | long step = lRemoteSize / 100;
83 | long process = localSize / step;
84 | int c;
85 | while ((c = in.read(bytes)) != -1) {
86 | out.write(bytes, 0, c);
87 | localSize += c;
88 | long nowProcess = localSize / step;
89 | if (nowProcess > process) {
90 | process = nowProcess;
91 | if (process % 10 == 0)
92 | log.info("下载进度:" + process);
93 | }
94 | }
95 | in.close();
96 | out.close();
97 | boolean isDo = ftpClient.completePendingCommand();
98 | if (isDo) {
99 | log.info("已下载,文件大小:" + file.length());
100 | pipedOutputStream.write(1);
101 | } else {
102 | log.error("下载失败");
103 | pipedOutputStream.write(0);
104 | }
105 | } else {
106 | OutputStream out = new FileOutputStream(file);
107 | InputStream in = ftpClient.retrieveFileStream(new String(path.getBytes("GBK"), "iso-8859-1"));
108 | byte[] bytes = new byte[1024];
109 | long step = lRemoteSize / 100;
110 | long process = 0;
111 | long localSize = 0L;
112 | int c;
113 | while ((c = in.read(bytes)) != -1) {
114 | out.write(bytes, 0, c);
115 | localSize += c;
116 | long nowProcess = localSize / step;
117 | if (nowProcess > process) {
118 | process = nowProcess;
119 | if (process % 10 == 0)
120 | log.info("下载进度:" + process);
121 | }
122 | }
123 | in.close();
124 | out.close();
125 | boolean upNewStatus = ftpClient.completePendingCommand();
126 | if (upNewStatus) {
127 | log.info("已下载,文件大小:" + file.length());
128 | pipedOutputStream.write(1);
129 | } else {
130 | log.error("下载失败");
131 | pipedOutputStream.write(0);
132 | }
133 | }
134 | if (ftpClient.isConnected()) {
135 | ftpClient.disconnect();
136 | }
137 | }
138 | } catch (IOException e) {
139 | log.error("下载失败IOException",e);
140 | e.printStackTrace();
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/ftp/UploadThread.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.ftp;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/8/2 0002.
4 | */
5 |
6 | import com.imageServer.config.FTPConnectAttr;
7 | import com.imageServer.util.FTPUtil;
8 | import com.imageServer.util.FileUtil;
9 | import org.apache.commons.net.ftp.FTPClient;
10 | import org.apache.commons.net.ftp.FTPFile;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.io.*;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.UUID;
18 |
19 | /**
20 | * FTP上传线程
21 | * Copyright 2014-2015 the original ql
22 | * Created by QianLong on 2014/8/2 0002.
23 | */
24 | public class UploadThread implements Runnable{
25 |
26 | private static final Logger log = LoggerFactory.getLogger(UploadThread.class);
27 |
28 | private InputStream inputStream;
29 | private String directory;
30 | private String fileName;
31 | private PipedOutputStream pipedOutputStream;
32 | private boolean export;
33 | private FTPConnectAttr ftpConnectAttr;
34 |
35 | /**
36 | * 注:此构造方法
37 | * 通道写出 0 : 上传失败
38 | * 通道写出1 : 上传成功
39 | *
40 | * @param inputStream 装载上传文件的输入流
41 | * @param directory 上传到远程FTP服务器的目录
42 | * @param fileName 存放在远程FTP服务器上的文件名
43 | * @param pipedOutputStream 上传结果通信通道
44 | * @param ftpConnectAttr FTP连接配置
45 | */
46 | public UploadThread(InputStream inputStream, String directory, String fileName, PipedOutputStream pipedOutputStream,FTPConnectAttr ftpConnectAttr) {
47 | this.inputStream = inputStream;
48 | this.directory = directory;
49 | this.fileName = fileName;
50 | this.pipedOutputStream = pipedOutputStream;
51 | this.export = false;
52 | this.ftpConnectAttr = ftpConnectAttr;
53 | log.info("upload线程初始化完成,开始进行FTP线程上传操作");
54 | }
55 |
56 | /**
57 | * 注:此构造方法
58 | * 通道写出上传进度百分比数值(int)
59 | *
60 | * @param pipedOutputStream
61 | * 输出的连接管道流
62 | * @param inputStream
63 | * 装载上传文件的输入流
64 | * @param directory
65 | * 上传到远程FTP服务器的目录
66 | * @param fileName
67 | * 存放在远程FTP服务器上的文件名
68 | */
69 | public UploadThread(PipedOutputStream pipedOutputStream,InputStream inputStream, String directory, String fileName) {
70 | this.inputStream = inputStream;
71 | this.directory = directory;
72 | this.fileName = fileName;
73 | this.pipedOutputStream = pipedOutputStream;
74 | this.export = true;
75 | log.info("upload线程初始化完成,开始进行FTP线程上传操作");
76 | }
77 |
78 | @Override
79 | public void run() {
80 | File tempFile = null;
81 | FTPClient ftpClient = null;
82 | try {
83 | ftpClient = FTPUtil.getFTPClient(ftpConnectAttr);
84 | if(ftpClient == null){
85 | log.error("FTPClient获取失败,上传失败");
86 | pipedOutputStream.write(0);
87 | return;
88 | }
89 |
90 | //设置上传目录,并自动创建目录
91 | if(!ftpClient.changeWorkingDirectory(directory)){
92 | log.info("上传目录不存在,开始自动创建目录");
93 | String[] dirs = directory.split("/");
94 | List dirList = new ArrayList<>();
95 | for (String dir : dirs) {
96 | if(!dir.equals("")){
97 | if(dirList.size() == 0){
98 | dirList.add("/" + dir);
99 | }else{
100 | dirList.add(dirList.get(dirList.size()-1) + "/" + dir);
101 | }
102 | }
103 | }
104 | for (String s : dirList) {
105 | if(!ftpClient.changeWorkingDirectory(s)){
106 | if(!ftpClient.makeDirectory(s)){
107 | log.error("目录创建失败,上传失败");
108 | pipedOutputStream.write(0);
109 | return;
110 | }
111 | }
112 | }
113 | if(ftpClient.changeWorkingDirectory(directory)){
114 | log.info("目录创建成功,目标路径更改成功:" + directory);
115 | }
116 | }
117 | log.info("目标路径更改成功:" + directory);
118 |
119 | //设置PassiveMode传输
120 | ftpClient.enterLocalPassiveMode();
121 | //设置以二进制流的方式传输
122 | ftpClient.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
123 | ftpClient.setControlEncoding("GBK");
124 | if(directory.lastIndexOf("/") == -1){
125 | directory = directory + "/";
126 | }
127 | String remoteFileName = directory + "/" + fileName;
128 | boolean result;
129 | //检查远程是否存在文件
130 | FTPFile[] files = ftpClient.listFiles(new String(remoteFileName.getBytes("GBK"), "iso-8859-1"));
131 | /* 创建临时文件 */
132 | tempFile = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID().toString() + fileName);
133 | if(!FileUtil.inputStreamToFile(inputStream, tempFile)){
134 | log.error("上传的文件流临时文件创建失败,上传失败");
135 | pipedOutputStream.write(0);
136 | return ;
137 | }
138 | if (files.length == 1) {
139 | long remoteSize = files[0].getSize();
140 | long localSize = tempFile.length();
141 | if (remoteSize == localSize) {
142 | log.warn("文件已存在");
143 | pipedOutputStream.write(1);
144 | return ;
145 | } else if (remoteSize > localSize) {
146 | log.warn("远程文件大于本地文件");
147 | pipedOutputStream.write(0);
148 | return ;
149 | }
150 |
151 | //尝试移动文件内读取指针,实现断点续传
152 | if(export){
153 | result = uploadFile(pipedOutputStream,remoteFileName, tempFile, ftpClient, remoteSize);
154 | }else {
155 | result = uploadFile(remoteFileName, tempFile, ftpClient, remoteSize);
156 | }
157 |
158 | //如果断点续传没有成功,则删除服务器上文件,重新上传
159 | if (!result) {
160 | if (!ftpClient.deleteFile(remoteFileName)) {
161 | log.warn("断点续传没有成功,删除服务器上文件,进行重新上传");
162 | }
163 | log.info("重新上传文件");
164 | if(export){
165 | result = uploadFile(pipedOutputStream,remoteFileName, tempFile, ftpClient, 0);
166 | }else {
167 | result = uploadFile(remoteFileName, tempFile, ftpClient, 0);
168 | }
169 | }
170 | } else {
171 | if(export){
172 | result = uploadFile(pipedOutputStream,remoteFileName, tempFile, ftpClient, 0);
173 | }else {
174 | result = uploadFile(remoteFileName, tempFile, ftpClient, 0);
175 | }
176 | }
177 |
178 | if(result){
179 | log.info("上传成功");
180 | if(!export){
181 | pipedOutputStream.write(1);
182 | }
183 |
184 | }else {
185 | log.error("上传失败");
186 | pipedOutputStream.write(0);
187 | }
188 | } catch (Exception e) {
189 | log.error("上传失败IOException", e);
190 | }finally {
191 | /* 删除本地的临时缓存文件 */
192 | if(tempFile != null && tempFile.exists()){
193 | tempFile.delete();
194 | }
195 | if(ftpClient != null && ftpClient.isConnected()){
196 | try {
197 | ftpClient.disconnect();
198 | } catch (IOException ignored) {
199 | }
200 | }
201 | }
202 |
203 | /* 非断点上传 */
204 | /*try {
205 | FTPClient ftpClient = FTPUtil.getFTPClient(ftpConnectAttr);
206 | if(ftpClient == null){
207 | log.error("FTPClient获取失败,上传失败");
208 | pipedOutputStream.write(0);
209 | return;
210 | }
211 |
212 | //设置上传目录,并自动创建目录
213 | if(!ftpClient.changeWorkingDirectory(directory)){
214 | log.info("上传目录不存在,开始自动创建目录");
215 | String[] dirs = directory.split("/");
216 | List dirList = new ArrayList<>();
217 | for (String dir : dirs) {
218 | if(!dir.equals("")){
219 | if(dirList.size() == 0){
220 | dirList.add("/" + dir);
221 | }else{
222 | dirList.add(dirList.get(dirList.size()-1) + "/" + dir);
223 | }
224 | }
225 | }
226 | for (String s : dirList) {
227 | if(!ftpClient.changeWorkingDirectory(s)){
228 | if(!ftpClient.makeDirectory(s)){
229 | log.error("目录创建失败,上传失败");
230 | pipedOutputStream.write(0);
231 | return;
232 | }
233 | }
234 | }
235 | if(ftpClient.changeWorkingDirectory(directory)){
236 | log.info("目录创建成功,目标路径更改成功:" + directory);
237 | }
238 | }
239 | log.info("目标路径更改成功:" + directory);
240 | ftpClient.setBufferSize(1024);
241 | ftpClient.setControlEncoding("UTF-8");
242 | //设置文件类型(二进制)
243 | ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
244 | log.info("上传文件到ftp服务器,位置:" + directory + fileName);
245 | boolean result = ftpClient.storeFile(fileName, inputStream);
246 | inputStream.close();
247 | ftpClient.disconnect();
248 | if(result){
249 | log.info("上传成功");
250 | pipedOutputStream.write(1);
251 | }
252 | else{
253 | log.info("上传失败");
254 | pipedOutputStream.write(0);
255 | }
256 | } catch (IOException e) {
257 | log.error("上传失败IOException");
258 | e.printStackTrace();
259 | }*/
260 | }
261 |
262 |
263 | /**
264 | * 上传文件到服务器,新上传和断点续传
265 | *
266 | * @param remoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变
267 | * @param localFile 本地文件 File句柄,绝对路径
268 | * @param ftpClient FTPClient 引用
269 | * @param remoteSize 远程已上传的文件大小
270 | * @return
271 | * @throws IOException
272 | */
273 | private boolean uploadFile(String remoteFile, File localFile, FTPClient ftpClient, long remoteSize) throws IOException {
274 | //显示进度的上传
275 | long step = localFile.length() / 100;
276 | long process = 0;
277 | long localreadbytes = 0L;
278 | RandomAccessFile raf = new RandomAccessFile(localFile, "r");
279 | OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"), "iso-8859-1"));
280 | //断点续传
281 | if (remoteSize > 0) {
282 | ftpClient.setRestartOffset(remoteSize);
283 | process = remoteSize / step;
284 | raf.seek(remoteSize);
285 | localreadbytes = remoteSize;
286 | }
287 | /* 每一次上传的数据量 */
288 | byte[] bytes = new byte[1024*10];
289 | int c;
290 | while ((c = raf.read(bytes)) != -1) {
291 | out.write(bytes, 0, c);
292 | localreadbytes += c;
293 | if (localreadbytes / step != process) {
294 | process = localreadbytes / step;
295 | log.info("上传进度:" + process);
296 | }
297 | }
298 | out.flush();
299 | raf.close();
300 | out.close();
301 | return ftpClient.completePendingCommand();
302 | }
303 |
304 | /**
305 | * 上传文件到服务器,新上传和断点续传
306 | *
307 | * @param pipedOutputStream 输出的连接管道流
308 | * @param remoteFile 远程文件名,在上传之前已经将服务器工作目录做了改变
309 | * @param localFile 本地文件 File句柄,绝对路径
310 | * @param ftpClient FTPClient 引用
311 | * @param remoteSize 远程已上传的文件大小
312 | * @return
313 | * @throws IOException
314 | */
315 | private boolean uploadFile(PipedOutputStream pipedOutputStream,String remoteFile, File localFile, FTPClient ftpClient, long remoteSize) throws IOException {
316 | //显示进度的上传
317 | long step = localFile.length() / 100;
318 | long process = 0;
319 | long localreadbytes = 0L;
320 | RandomAccessFile raf = new RandomAccessFile(localFile, "r");
321 | OutputStream out = ftpClient.appendFileStream(new String(remoteFile.getBytes("GBK"), "iso-8859-1"));
322 | //断点续传
323 | if (remoteSize > 0) {
324 | ftpClient.setRestartOffset(remoteSize);
325 | process = remoteSize / step;
326 | raf.seek(remoteSize);
327 | localreadbytes = remoteSize;
328 | }
329 | /* 每一次上传的数据量 */
330 | byte[] bytes = new byte[1024*10];
331 | int c;
332 | while ((c = raf.read(bytes)) != -1) {
333 | out.write(bytes, 0, c);
334 | localreadbytes += c;
335 | if (localreadbytes / step != process) {
336 | process = localreadbytes / step;
337 | pipedOutputStream.write(Integer.valueOf(process+""));
338 | pipedOutputStream.flush();
339 | log.info("上传进度:" + process);
340 | }
341 | }
342 | out.flush();
343 | out.close();
344 | raf.close();
345 | return ftpClient.completePendingCommand();
346 | }
347 |
348 | }
349 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/interceptors/ImageSecurityInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.interceptors;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.stereotype.Repository;
6 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 | import javax.servlet.http.HttpServletResponse;
10 |
11 | @Repository
12 | public class ImageSecurityInterceptor extends HandlerInterceptorAdapter {
13 |
14 | private Logger log = LoggerFactory.getLogger(ImageSecurityInterceptor.class);
15 |
16 | @Override
17 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
18 | Object arg2) throws Exception {
19 | response.setCharacterEncoding("UTF-8");
20 | response.setContentType("text/html;charset=UTF-8");
21 | String url = request.getRequestURI();
22 | String root = request.getContextPath();
23 | url = url.replaceAll(root, "");
24 | // if(url.equals("/") || url.equals("\\")){
25 | // return true;
26 | // }
27 | log.info("接受请求:" + request.getRemoteAddr() + ":" + request.getRequestURI());
28 | return true;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/service/FtpImageCacheService.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.service;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/7/9 0009.
4 | */
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 |
8 | /**
9 | * FTP服务器上的图片进行缓存服务
10 | * Copyright 2014-2015 the original ql
11 | * Created by QianLong on 2014/7/9 0009.
12 | */
13 | public interface FtpImageCacheService {
14 |
15 | boolean imageToCache(HttpServletRequest request);
16 |
17 | /**
18 | * 计算获取缓存文件的hash文件名
19 | * @param request
20 | * @return
21 | */
22 | String getCacheFileHashName(HttpServletRequest request);
23 |
24 | /**
25 | * 计算获取缓存文件的绝对路径位置
26 | * @param request
27 | * @return
28 | */
29 | String getCacheFileAbsPath(HttpServletRequest request);
30 |
31 | /**
32 | * 计算获取缓存文件的目录绝对路径位置
33 | * @param request
34 | * @return
35 | */
36 | String getCacheFileDirPath(HttpServletRequest request);
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/service/FtpService.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.service;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/4/18 0018.
4 | */
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | /**
11 | * FTP服务类
12 | * Copyright 2014-2015 the original ql
13 | * Created by QianLong on 2014/4/18 0018.
14 | */
15 | public interface FtpService {
16 |
17 | /**
18 | * 上传文件到FTP服务器
19 | * 自动关闭输入流
20 | * @param inputStream 装载上传文件的输入流
21 | * @param directory 上传到远程FTP服务器的目录
22 | * @param fileName 存放在远程FTP服务器上的文件名
23 | * @return true : 上传成功
24 | * @throws IOException 上传失败
25 | */
26 | public boolean upload(InputStream inputStream, String directory, String fileName) throws IOException;
27 |
28 | /**
29 | * 从FTP服务器下载文件
30 | * @param file
31 | * 下载文件的存放对象
32 | * @param path
33 | * 需要下载的文件在FTP服务器上的全路径
34 | * @return
35 | * true:下载成功
36 | * @throws IOException
37 | * 下载失败
38 | */
39 | public boolean download(File file, String path)throws IOException;
40 |
41 | /**
42 | * 删除FTP服务器上的指定文件
43 | * @param directory
44 | * 文件目录
45 | * @param fileName
46 | * 文件名
47 | * @return
48 | * true : 删除成功
49 | * @throws IOException
50 | * 删除失败
51 | */
52 | public boolean deleteFile(String directory, String fileName)throws IOException;
53 |
54 | /**
55 | * 删除FTP服务器上的指定文件
56 | * @param filePath
57 | * 被删除文件在FTP服务器上的全路径
58 | * @return
59 | * true : 删除成功
60 | * @throws IOException
61 | * 删除失败
62 | */
63 | public boolean deleteFile(String filePath) throws IOException;
64 |
65 | /**
66 | * 替换FTP服务器上的文件
67 | * 自动识别上传文件与删除文件是同一全路径的情况
68 | * @param upload 需要上传的文件
69 | * @param delFilePath FTP服务器上需要被删除的文件的全路径
70 | * @param directory 上传的目录
71 | * @param fileName 存放的文件名
72 | * @return true : 替换成功
73 | * @throws IOException
74 | */
75 | public boolean replaceFile(InputStream upload, String delFilePath, String directory, String fileName)throws IOException;
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/service/impl/FtpImageCacheServiceImp.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.service.impl;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/7/9 0009.
4 | */
5 |
6 | import com.imageServer.service.FtpImageCacheService;
7 | import com.imageServer.service.FtpService;
8 | import com.imageServer.util.ImageCatchUtil;
9 | import com.imageServer.util.ImageUtil;
10 | import com.imageServer.util.ObjectUtil;
11 | import com.imageServer.vo.ImageConvert;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.springframework.beans.factory.annotation.Autowired;
15 | import org.springframework.stereotype.Service;
16 |
17 | import javax.imageio.ImageIO;
18 | import javax.servlet.http.HttpServletRequest;
19 | import java.awt.image.BufferedImage;
20 | import java.io.File;
21 | import java.io.IOException;
22 |
23 | /**
24 | * FTP服务器上的图片进行缓存服务
25 | * Copyright 2014-2015 the original ql
26 | * Created by QianLong on 2014/7/9 0009.
27 | */
28 | @Service("ftpImageCacheService")
29 | public class FtpImageCacheServiceImp implements FtpImageCacheService {
30 |
31 | Logger log = LoggerFactory.getLogger(FtpImageCacheServiceImp.class);
32 |
33 | @Autowired
34 | private FtpService ftpService;
35 | private float signAlpha = (float) 1;
36 | private float alpha = (float) 1;
37 |
38 | /**
39 | * 根据请求条件,将原图进行转换,并生成缓存文件
40 | * @param request
41 | * @return
42 | */
43 | @Override
44 | public boolean imageToCache(HttpServletRequest request) {
45 | String path = request.getParameter("path"),
46 | scale_str = request.getParameter("scale"),
47 | width_str = request.getParameter("width"),
48 | height_str = request.getParameter("height"),
49 | sign_str = request.getParameter("sign"),
50 | signAlpha_str = request.getParameter("signAlpha"),
51 | alpha_str = request.getParameter("alpha"),
52 | recommentSign_str = request.getParameter("recommentSign");
53 |
54 | boolean sign = true;
55 | boolean recomment = false;
56 | try {
57 | sign = !sign_str.equals("false");
58 | } catch (Exception ignored) { }
59 | try {
60 | recomment = recommentSign_str.equals("true");
61 | } catch (Exception ignored) {
62 | }
63 | try {
64 | if(signAlpha_str != null && !signAlpha_str.equals("")){
65 | signAlpha = Float.parseFloat(signAlpha_str);
66 | }else {
67 | signAlpha = 1;
68 | }
69 | } catch (NumberFormatException ignored) {
70 | }
71 | try {
72 | if(alpha_str != null && !alpha_str.equals("")){
73 | alpha = Float.parseFloat(alpha_str);
74 | }else {
75 | alpha = 1;
76 | }
77 | } catch (NumberFormatException ignored) {}
78 |
79 | String cacheFileName;
80 | if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1){
81 | cacheFileName = getCacheFileHashName(request);
82 | log.info("获取图片静态资源的hash相对路径:" + cacheFileName);
83 | if(File.separator.equals("\\")){
84 | cacheFileName = cacheFileName.replace("/",File.separator);
85 | }
86 |
87 | }else {
88 | log.warn("ftp文件资源路径错误,返回false");
89 | return false;
90 | }
91 |
92 | File cacheFile = null;
93 | File temp = null;
94 | try {
95 | if(path.equals("")){
96 | return false;
97 | }
98 |
99 | String cacheDir = getCacheFileDirPath(request);
100 | log.info("计算待生成的缓存图片的绝对路径目录:" + cacheDir);
101 | String fileType;
102 | try {
103 | fileType = path.substring(path.lastIndexOf("."));
104 | } catch (Exception e) {
105 | return false;
106 | }
107 | log.info("原图片的文件类型:" + fileType);
108 | cacheFile = new File(getCacheFileAbsPath(request));
109 | log.info("计算待生成图片的绝对路径:" + cacheFile.getAbsolutePath());
110 | if(!cacheFile.exists()){
111 | log.info("待生成缓存文件的目录不存在,正在进行自动创建目录:" + cacheDir);
112 | File cacheFileDir = new File(cacheDir);
113 | cacheFileDir.mkdirs();
114 | }
115 |
116 | //若缓存文件已存在,用临时文件保存已有的缓存文件,原缓存文件进行重新保存下载的文件
117 |
118 | if(cacheFile.exists() && cacheFile.length() > 0){
119 | temp = new File(cacheFile.getPath() + ".temp");
120 | cacheFile.renameTo(temp);
121 | cacheFile.delete();
122 | }
123 |
124 | log.info("从ftp服务器下载path对应的图片资源:" + path);
125 | log.info("保存到文件:" + cacheFile.getAbsolutePath());
126 | ftpService.download(cacheFile, path);
127 |
128 | BufferedImage image = null;
129 | try {
130 | if(cacheFile.exists()){
131 | image = ImageIO.read(cacheFile);
132 | }else{
133 | log.warn("获取下载的图片资源失败,返回false");
134 | return false;
135 | }
136 | } catch (Exception e) {
137 | log.warn("图片文件读取异常",e);
138 | }
139 | if (image == null) {//输出提示错误图像
140 | log.info("图像下载错误,返回false");
141 | return false;
142 | } else {
143 | log.info("图像下载成功,进行图像转换操作");
144 | ImageConvert convert =ImageUtil.imageConvert(image,height_str,width_str,sign,recomment,signAlpha,scale_str,alpha);
145 | image = convert.getBufferedImage();
146 | if(convert.isSucess()){
147 | log.info("保存转换后的图片为缓存文件写入磁盘:" + cacheFile.getAbsolutePath());
148 | ImageUtil.getInstance().writeImage(fileType,image,cacheFile);
149 | if(cacheFile.exists()){
150 | log.info("缓存文件生成成功");
151 | //删除缓存文件
152 | if (temp != null) {
153 | temp.delete();
154 | }
155 | return true;
156 | }else {
157 | log.warn("缓存文件生成失败");
158 | //将缓存文件还原
159 | if (temp != null) {
160 | temp.renameTo(cacheFile);
161 | }
162 | return false;
163 | }
164 | }else {
165 | log.warn("图像转换失败,返回错误提示");
166 | return false;
167 | }
168 | }
169 | } catch (IOException e) {
170 | if(cacheFile.exists()){
171 | if(temp != null && temp.exists()){
172 | temp.delete();
173 | }
174 | }else {
175 | if(temp != null && temp.exists()){
176 | temp.renameTo(cacheFile);
177 | }
178 | }
179 | log.error("保存request中的图片信息到缓存文件中发生异常",e);
180 | return false;
181 | }
182 | }
183 |
184 | /**
185 | * 计算获取缓存文件的hash文件名
186 | *
187 | * @param request
188 | * @return
189 | */
190 | @Override
191 | public String getCacheFileHashName(HttpServletRequest request) {
192 | String path = request.getParameter("path"),
193 | scale_str = request.getParameter("scale"),
194 | width_str = request.getParameter("width"),
195 | height_str = request.getParameter("height"),
196 | sign_str = request.getParameter("sign"),
197 | signAlpha_str = request.getParameter("signAlpha"),
198 | alpha_str = request.getParameter("alpha"),
199 | recommentSign_str = request.getParameter("recommentSign");
200 |
201 | boolean sign = true;
202 | boolean recomment = false;
203 | try {
204 | sign = !sign_str.equals("false");
205 | } catch (Exception ignored) { }
206 | try {
207 | recomment = recommentSign_str.equals("true");
208 | } catch (Exception ignored) {
209 | }
210 | try {
211 | if(signAlpha_str != null && !signAlpha_str.equals("")){
212 | signAlpha = Float.parseFloat(signAlpha_str);
213 | }else {
214 | signAlpha = 1;
215 | }
216 | } catch (NumberFormatException ignored) {
217 | }
218 | try {
219 | if(alpha_str != null && !alpha_str.equals("")){
220 | alpha = Float.parseFloat(alpha_str);
221 | }else {
222 | alpha = 1;
223 | }
224 | } catch (NumberFormatException ignored) {}
225 |
226 | return ImageCatchUtil.getImageCachePathByFtpPath(path, sign, recomment, height_str, width_str, scale_str, signAlpha, alpha);
227 | }
228 |
229 | /**
230 | * 计算获取缓存文件的绝对路径位置
231 | *
232 | * @param request
233 | * @return
234 | */
235 | @Override
236 | public String getCacheFileAbsPath(HttpServletRequest request) {
237 |
238 | return ImageUtil.getWebPath(request) + getCacheFileHashName(request);
239 | }
240 |
241 | /**
242 | * 计算获取缓存文件的目录绝对路径位置
243 | *
244 | * @param request
245 | * @return
246 | */
247 | @Override
248 | public String getCacheFileDirPath(HttpServletRequest request) {
249 | String path = request.getParameter("path");
250 |
251 | if(ObjectUtil.isNull(path)){
252 | log.error("请求路径不能为空");
253 | return "";
254 | }
255 |
256 | String webPath = ImageUtil.getWebPath(request);
257 |
258 | return (webPath + path.substring(1,path.lastIndexOf("/")+1))
259 | .replace("/",File.separator);
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/service/impl/FtpServiceImp.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.service.impl;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/4/18 0018.
4 | */
5 |
6 | import com.imageServer.config.FTPConnectAttr;
7 | import com.imageServer.ftp.DownloadThread;
8 | import com.imageServer.ftp.UploadThread;
9 | import com.imageServer.service.FtpService;
10 | import com.imageServer.util.ExecuteThreadUtil;
11 | import com.imageServer.util.FTPUtil;
12 | import org.apache.commons.net.ftp.FTPClient;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.stereotype.Service;
17 |
18 | import java.io.*;
19 |
20 | /**
21 | * 图片服务器类
22 | * Copyright 2014-2015 the original ql
23 | * Created by QianLong on 2014/4/18 0018.
24 | */
25 | @Service("ftpService")
26 | public class FtpServiceImp implements FtpService {
27 |
28 | private Logger log = LoggerFactory.getLogger(FtpServiceImp.class);
29 | @Autowired
30 | private FTPConnectAttr ftpConnectAttr;
31 |
32 | /**
33 | * 上传文件到FTP服务器
34 | * 自动关闭输入流
35 | * @param inputStream 装载上传文件的输入流
36 | * @param directory 上传到远程FTP服务器的目录
37 | * @param fileName 存放在远程FTP服务器上的文件名
38 | * @return true : 上传成功
39 | * @throws IOException 上传失败
40 | */
41 | @Override
42 | public boolean upload(InputStream inputStream, String directory, String fileName) throws IOException {
43 | log.info("进行FTP上传:" );
44 | log.info("目录:" + directory);
45 | log.info("文件名:" + fileName);
46 | PipedOutputStream pipedOutputStream = new PipedOutputStream();
47 | PipedInputStream pipedInputStream = new PipedInputStream();
48 | pipedInputStream.connect(pipedOutputStream);
49 | ExecuteThreadUtil.execute(new UploadThread(inputStream, directory, fileName, pipedOutputStream,ftpConnectAttr));
50 | try {
51 | return pipedInputStream.read() == 1;
52 | } catch (IOException e) {
53 | return false;
54 | }
55 | }
56 |
57 | /**
58 | * 从FTP服务器下载文件
59 | * @param file
60 | * 下载文件的存放对象
61 | * @param path
62 | * 需要下载的文件在FTP服务器上的全路径
63 | * @return
64 | * true:下载成功
65 | * @throws IOException
66 | * 下载失败
67 | */
68 | @Override
69 | public boolean download(File file, String path) throws IOException {
70 | log.info("进行FTP文件下载");
71 | log.info("下载文件:" + path);
72 | PipedOutputStream pipedOutputStream = new PipedOutputStream();
73 | PipedInputStream pipedInputStream = new PipedInputStream();
74 | pipedInputStream.connect(pipedOutputStream);
75 | ExecuteThreadUtil.execute(new DownloadThread(file, path, pipedOutputStream,ftpConnectAttr));
76 | try {
77 | return pipedInputStream.read() == 1;
78 | } catch (IOException e) {
79 | return false;
80 | }
81 | }
82 |
83 |
84 | /**
85 | * 删除FTP服务器上的指定文件
86 | *
87 | * @param directory 文件目录
88 | * @param fileName 文件名
89 | * @return true : 删除成功
90 | * @throws IOException 删除失败
91 | */
92 | synchronized public boolean deleteFile(String directory, String fileName) throws IOException {
93 | log.info("删除FTP文件");
94 | log.info("被删除的文件目录:" + directory);
95 | log.info("被删除的文件:" + fileName);
96 | FTPClient ftpClient = FTPUtil.getFTPClient(ftpConnectAttr);
97 | boolean result = ftpClient != null && ftpClient.deleteFile(directory + "/" + fileName);
98 | if(result && ftpClient.isConnected())
99 | ftpClient.disconnect();
100 | return result;
101 | }
102 |
103 | /**
104 | * 删除FTP服务器上的指定文件
105 | *
106 | * @param filePath 被删除文件在FTP服务器上的全路径
107 | * @return true : 删除成功
108 | * @throws IOException 删除失败
109 | */
110 | @Override
111 | synchronized public boolean deleteFile(String filePath) throws IOException {
112 | FTPClient ftpClient = FTPUtil.getFTPClient(ftpConnectAttr);
113 | boolean result = ftpClient != null && ftpClient.deleteFile(filePath);
114 | if(result && ftpClient.isConnected())
115 | ftpClient.disconnect();
116 | return result;
117 | }
118 |
119 | /**
120 | * 替换FTP服务器上的文件
121 | * 自动识别上传文件与删除文件是同一全路径的情况
122 | * @param upload 需要上传的文件
123 | * @param delFilePath FTP服务器上需要被删除的文件的全路径
124 | * @param directory 上传的目录
125 | * @param fileName 存放的文件名
126 | * @return true : 替换成功
127 | * @throws IOException
128 | */
129 | @Override
130 | public boolean replaceFile(InputStream upload, String delFilePath, String directory, String fileName) throws IOException {
131 | PipedInputStream pipedInputStream = new PipedInputStream();
132 | PipedOutputStream pipedOutputStream = new PipedOutputStream();
133 | pipedInputStream.connect(pipedOutputStream);
134 | ExecuteThreadUtil.execute(new UploadThread(upload, directory, fileName, pipedOutputStream,ftpConnectAttr));
135 | boolean result = pipedInputStream.read() == 1;
136 | if(delFilePath.equals(directory + "/" + fileName)){
137 | return result;
138 | }
139 | if(result)
140 | deleteFile(delFilePath);
141 | return result;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/CustomerMath.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;
2 |
3 | import java.math.BigDecimal;
4 |
5 | /**
6 | * Copyright 2014-2015 the original ql
7 | * 用于金钱计算的工具类
8 | * @author QianLong
9 | * @createDate 2014-3-8
10 | */
11 | public class CustomerMath {
12 |
13 | /**
14 | * 转换数字为可显示格式,避免出现科学计数法形式
15 | * 自动保留2位小数
16 | * @param num
17 | * @return
18 | */
19 | public static String numFormat(Number num){
20 | return String.format("%.2f",num);
21 | }
22 |
23 | // 默认除法运算精度
24 | private static final int DEF_DIV_SCALE = 10;
25 |
26 | // 这个类不能实例化
27 | private CustomerMath() {
28 | ;
29 | }
30 |
31 | /**
32 | * 提供精确的加法运算。
33 | *
34 | * @param v1
35 | * 被加数
36 | * @param v2
37 | * 加数
38 | * @return 两个参数的和
39 | */
40 | public static double add(double v1, double v2) {
41 | BigDecimal b1 = new BigDecimal(Double.toString(v1));
42 | BigDecimal b2 = new BigDecimal(Double.toString(v2));
43 | return b1.add(b2).doubleValue();
44 | }
45 |
46 | /**
47 | * 提供精确的减法运算。
48 | *
49 | * @param v1
50 | * 被减数
51 | * @param v2
52 | * 减数
53 | * @return 两个参数的差
54 | */
55 | public static double sub(double v1, double v2) {
56 | BigDecimal b1 = new BigDecimal(Double.toString(v1));
57 | BigDecimal b2 = new BigDecimal(Double.toString(v2));
58 | return b1.subtract(b2).doubleValue();
59 | }
60 |
61 | /**
62 | * 提供精确的乘法运算。
63 | *
64 | * @param v1
65 | * 被乘数
66 | * @param v2
67 | * 乘数
68 | * @return 两个参数的积
69 | */
70 | public static double mul(double v1, double v2) {
71 | BigDecimal b1 = new BigDecimal(Double.toString(v1));
72 | BigDecimal b2 = new BigDecimal(Double.toString(v2));
73 | return b1.multiply(b2).doubleValue();
74 | }
75 |
76 | /**
77 | * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
78 | *
79 | * @param v1
80 | * 被除数
81 | * @param v2
82 | * 除数
83 | * @return 两个参数的商
84 | */
85 | public static double div(double v1, double v2) {
86 | return div(v1, v2, DEF_DIV_SCALE);
87 | }
88 |
89 | /**
90 | * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
91 | *
92 | * @param v1
93 | * 被除数
94 | * @param v2
95 | * 除数
96 | * @param scale
97 | * 表示表示需要精确到小数点以后几位。
98 | * @return 两个参数的商
99 | */
100 | public static double div(double v1, double v2, int scale) {
101 | if (scale < 0) {
102 | throw new IllegalArgumentException(
103 | "The scale must be a positive integer or zero");
104 | }
105 | BigDecimal b1 = new BigDecimal(Double.toString(v1));
106 | BigDecimal b2 = new BigDecimal(Double.toString(v2));
107 | return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
108 | }
109 |
110 | /**
111 | * 提供精确的小数位四舍五入处理。
112 | *
113 | * @param v
114 | * 需要四舍五入的数字
115 | * @param scale
116 | * 小数点后保留几位
117 | * @return 四舍五入后的结果
118 | */
119 | public static double round(double v, int scale) {
120 | if (scale < 0) {
121 | throw new IllegalArgumentException(
122 | "The scale must be a positive integer or zero");
123 | }
124 | BigDecimal b = new BigDecimal(Double.toString(v));
125 | BigDecimal one = new BigDecimal("1");
126 | return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/ExecuteThreadUtil.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 15-1-23.
4 | */
5 |
6 | import com.imageServer.factory.ExecutorFactory;
7 | import org.apache.poi.ss.formula.functions.T;
8 |
9 | import java.util.concurrent.*;
10 |
11 | /**
12 | * 并发线程执行辅助工具类
13 | * Copyright 2014-2015 the original ql
14 | * Created by QianLong on 15-1-23.
15 | */
16 | public class ExecuteThreadUtil {
17 |
18 | private static ExecutorService executorService = ExecutorFactory.EXECUTE.getExecutor();
19 |
20 | /**
21 | * 执行一个无返回值的线程任务
22 | * 注:若执行的线程任务是长时间运行的线程,
23 | * 请不要用此线程池进行线程任务的创建,会有死锁的隐患
24 | * @param task
25 | */
26 | public static void execute(Runnable task){
27 | executorService.submit(task);
28 | }
29 |
30 | /**
31 | * 执行有返回值的线程任务
32 | * 超时100秒
33 | * 注:若执行的线程任务是长时间运行的线程,
34 | * 请不要用此线程池进行线程任务的创建,会有死锁的隐患
35 | * @param task
36 | * @return
37 | * @throws InterruptedException
38 | * @throws ExecutionException
39 | * @throws TimeoutException
40 | */
41 | public static T execute(Callable task) throws InterruptedException, ExecutionException, TimeoutException {
42 | Future result = executorService.submit(task);
43 | return result.get(100, TimeUnit.SECONDS);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/FTPUtil.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/4/24 0024.
4 | */
5 |
6 | import com.imageServer.config.FTPConnectAttr;
7 | import org.apache.commons.net.ftp.FTPClient;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.io.IOException;
12 |
13 | /**
14 | * FTP工具类
15 | * 单例
16 | * Copyright 2014-2015 the original ql
17 | * Created by QianLong on 2014/4/24 0024.
18 | */
19 | public class FTPUtil {
20 |
21 | private static final Logger log = LoggerFactory.getLogger(FTPUtil.class);
22 |
23 | private FTPUtil(){
24 |
25 | }
26 |
27 | /**
28 | * 获取FTP连接对象
29 | * @param ftpConnectAttr
30 | * FTP的连接配置
31 | * @return
32 | * 获取异常失败则返回null
33 | */
34 | public static FTPClient getFTPClient(FTPConnectAttr ftpConnectAttr){
35 | if(ftpConnectAttr == null){
36 | log.error("FTP的连接配置不能为Null");
37 | return null;
38 | }
39 | if(ObjectUtil.isNull(ftpConnectAttr.address) || ObjectUtil.isNull(ftpConnectAttr.userName)){
40 | log.error("连接地址或连接的用户名不能为空");
41 | return null;
42 | }
43 | FTPClient ftpClient = new FTPClient();
44 | try {
45 | String url = ftpConnectAttr.address;
46 | log.info("设置ftp地址:" + url);
47 | if(url.split(":").length == 2){
48 | String[] us = url.split(":");
49 | int port = Integer.valueOf(us[1]);
50 | ftpClient.connect(us[0],port);
51 | }else {
52 | ftpClient.connect(url);
53 | }
54 | ftpClient.setDataTimeout(120000); //设置传输超时时间为120秒
55 | ftpClient.setConnectTimeout(120000); //连接超时为120秒
56 | ftpClient.setControlEncoding("GBK");
57 | log.info("设置登陆账号:" + ftpConnectAttr.userName + ":" + ftpConnectAttr.password);
58 | ftpClient.login(ftpConnectAttr.userName, ftpConnectAttr.password);
59 | int reply = ftpClient.getReplyCode();
60 | if(String.valueOf(reply).indexOf("2") != 0){
61 | log.error("ftp连接失败,返回值:" + reply);
62 | if(ftpClient.isConnected()){
63 | ftpClient.disconnect();
64 | return null;
65 | }
66 | }
67 | log.info("ftp连接成功,返回值:" + reply);
68 | } catch (IOException e) {
69 | log.error("获取FTPClient发生错误,返回null",e);
70 | if(ftpClient.isConnected()){
71 | try {
72 | ftpClient.disconnect();
73 | } catch (IOException ignored) {
74 | }
75 | }
76 | return null;
77 | }
78 | return ftpClient;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.*;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * Copyright 2014-2015 the original ql
12 | * 文件操作工具类
13 | *
14 | * @author qianlong
15 | *
16 | */
17 | public class FileUtil {
18 |
19 | private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
20 |
21 | /**
22 | * 获取文本文件的文本内容 若没有此文件,则创建一个新文件,返回空串
23 | *
24 | * @param fileName
25 | * @return
26 | * @throws IOException
27 | */
28 | public static String getTextFileContent(String fileName){
29 | StringBuilder text = new StringBuilder();
30 | File f = new File(fileName);
31 | if (!f.exists()) {
32 | try {
33 | if(!f.createNewFile()){
34 | log.warn("文件已存在");
35 | }
36 | } catch (IOException e) {
37 | log.error("文件读取失败,请检查是否有文件读取权限,或指定文件是否损坏等");
38 | }
39 | }
40 | try {
41 | FileInputStream fis = new FileInputStream(f);
42 | InputStreamReader read = new InputStreamReader(fis,"UTF-8");
43 | BufferedReader reader = new BufferedReader(read);
44 | String line = "";
45 | while((line = reader.readLine()) != null){
46 | text.append(line);
47 | }
48 | reader.close();
49 | } catch (Exception e) {
50 | log.error("文件读取失败,请检查是否有文件读取权限,或指定文件是否损坏等",e);
51 | }
52 | return text.toString();
53 | }
54 |
55 | /**
56 | * 获取制定路径下的所有文件中的文本
57 | * 如果不存在则创建传入的路径
58 | * @param path
59 | * @return
60 | * @throws Exception
61 | */
62 | public static List getAllFileTextFromDir(String path){
63 | List filesText = new ArrayList();
64 | File f = new File(path);
65 | if (!f.exists()) {
66 | if(!f.mkdirs()){
67 | log.warn("目录创建失败");
68 | }
69 | }
70 | File[] fs = f.listFiles();
71 | if(fs == null){
72 | return new ArrayList<>();
73 | }
74 | try {
75 | for (File file : fs) {
76 | StringBuilder text = new StringBuilder();
77 | FileInputStream fis = new FileInputStream(file);
78 | InputStreamReader read = new InputStreamReader(fis,"UTF-8");
79 | BufferedReader reader = new BufferedReader(read);
80 | String line = "";
81 | while((line = reader.readLine()) != null){
82 | text.append(line);
83 | }
84 | filesText.add(text.toString());
85 | reader.close();
86 | }
87 | } catch (Exception e) {
88 | return new ArrayList<>();
89 | }
90 | return filesText;
91 | }
92 |
93 | /**
94 | * 获取传入的路径下的文件的文件内容
95 | * 如果文件不存在,将自动根据路径及文件名创建一个新的,返回空串
96 | * @param path
97 | * @param fileName
98 | * @return
99 | * @throws Exception
100 | */
101 | public static String getFileTextFromDirFile(String path, String fileName){
102 | StringBuilder text = new StringBuilder();
103 | File f = new File(path);
104 | if (!f.exists()) {
105 | if(!f.mkdirs()){
106 | log.warn("目录创建失败");
107 | }
108 | }
109 | f = new File(path + File.separator + fileName);
110 | if(!f.exists()){
111 | try {
112 | if(!f.createNewFile()){
113 | log.warn("文件已存在");
114 | }
115 | } catch (IOException e) {
116 | log.error("文件读取失败,请检查是否有文件读取权限,或指定文件是否损坏等",e);
117 | }
118 | }
119 | try {
120 | FileInputStream fis = new FileInputStream(f);
121 | InputStreamReader read = new InputStreamReader(fis,"UTF-8");
122 | BufferedReader reader = new BufferedReader(read);
123 | String line = "";
124 | while((line = reader.readLine()) != null){
125 | text.append(line);
126 | }
127 | reader.close();
128 | } catch (Exception e) {
129 | return "文件读取失败,请检查是否有文件读取权限,或指定文件是否损坏等";
130 | }
131 | return text.toString();
132 | }
133 |
134 | /**
135 | * 将制定的字符串写入指定路径下的指定文件中
136 | * 如果路径及文件不存在,将自动创建
137 | * @param text
138 | * @param path
139 | * @param fileName
140 | * @param append : true为在文件后追加内容
141 | * @return
142 | */
143 | public static boolean writeTextToTextFile(String text,String path, String fileName,boolean append) {
144 | File f = new File(path);
145 | if(!f.exists()){
146 | if(!f.mkdirs()){
147 | log.warn("目录创建失败");
148 | }
149 | }
150 | f = new File(path + File.separator + fileName);
151 | if(!f.exists()){
152 | try {
153 | if(!f.createNewFile()){
154 | log.warn("文件创建失败");
155 | return false;
156 | }
157 | } catch (IOException e) {
158 | log.error("文件创建异常",e);
159 | return false;
160 | }
161 | }
162 | FileOutputStream fos;
163 | try {
164 | fos = new FileOutputStream(f, append);
165 | OutputStreamWriter write = new OutputStreamWriter(fos,"UTF-8");
166 | BufferedWriter writer = new BufferedWriter(write);
167 | writer.write(text);
168 | writer.close();
169 | return true;
170 | } catch (Exception e) {
171 | return false;
172 | }
173 | }
174 |
175 | /**
176 | * 将制定的字符串写入指定路径下的指定文件中
177 | * 如果文件不存在,返回false
178 | * @param text
179 | * @param file
180 | * @param append : true为在文件后追加内容
181 | * @return
182 | */
183 | public static boolean writeTextToTextFile(String text,File file,boolean append) {
184 | if(!file.exists()){
185 | return false;
186 | }
187 | FileOutputStream fos;
188 | try {
189 | fos = new FileOutputStream(file, append);
190 | OutputStreamWriter write = new OutputStreamWriter(fos,"UTF-8");
191 | BufferedWriter writer = new BufferedWriter(write);
192 | writer.write(text);
193 | writer.close();
194 | return true;
195 | } catch (Exception e) {
196 | return false;
197 | }
198 | }
199 |
200 | /**
201 | * InputStream输入流转换为File
202 | * @param ins
203 | * @param file
204 | */
205 | public static boolean inputStreamToFile(InputStream ins,File file) {
206 | try {
207 | OutputStream os = new FileOutputStream(file);
208 | int bytesRead = 0;
209 | byte[] buffer = new byte[8192];
210 | while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
211 | os.write(buffer, 0, bytesRead);
212 | }
213 | os.close();
214 | ins.close();
215 | return true;
216 | } catch (Exception e) {
217 | return false;
218 | }
219 | }
220 |
221 | /**
222 | * 遍历获取指定路径下的所有文件绝对路径
223 | * 如果不存在则创建传入的路径
224 | * @param path
225 | * @return
226 | * @throws Exception
227 | */
228 | public static List getAllFileNamesFromDir(String path){
229 | List fileNames = new ArrayList<>();
230 | File dir = new File(path);
231 | if (!dir.exists()) {
232 | if(!dir.mkdirs()){
233 | log.warn("目录创建失败");
234 | }
235 | }
236 | File[] fs = dir.listFiles();
237 | if(fs == null){
238 | return new ArrayList<>();
239 | }
240 | try {
241 | for (File file : fs) {
242 | appendFileNames(file.getPath(),fileNames);
243 | }
244 | } catch (Exception e) {
245 | log.error("获取文件名时发生异常",e);
246 | return new ArrayList<>();
247 | }
248 | return fileNames;
249 | }
250 |
251 | private static void appendFileNames(String dir,List fileNames){
252 | File file = new File(dir);
253 | if(file.isFile()){
254 | fileNames.add(file.getPath());
255 | }else {
256 | File[] fs = file.listFiles();
257 | if(fs != null){
258 | for (File f : fs) {
259 | if(f.isDirectory()){
260 | appendFileNames(f.getPath(),fileNames);
261 | }else if(f.isFile()){
262 | fileNames.add(f.getPath());
263 | }else {
264 | log.warn("发现一文件即非目录也非文件:" + f.getPath());
265 | }
266 | }
267 | }
268 | }
269 | }
270 |
271 | }
272 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/ImageCatchUtil.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/7/9 0009.
4 | */
5 |
6 | /**
7 | * 图片缓存机制工具类
8 | * Copyright 2014-2015 the original ql
9 | * Created by QianLong on 2014/7/9 0009.
10 | */
11 | public class ImageCatchUtil {
12 |
13 | /**
14 | * 组建文件hash路径名
15 | * 如:images/paintings/1/xxxx.png
16 | * @param path
17 | * @param sign
18 | * @param recomment
19 | * @param height_str
20 | * @param width_str
21 | * @param scale_str
22 | * @param signAlpha
23 | * @param alpha
24 | * @return
25 | */
26 | public static String getImageCachePathByFtpPath(String path,boolean sign,boolean recomment,String height_str,
27 | String width_str,String scale_str,float signAlpha,float alpha){
28 | String cacheFileName = "";
29 | if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1 && path.lastIndexOf("/") < path.length()-1) {
30 |
31 | //控制缓存文件的后缀名
32 | String cacheFileType = ".jpg";
33 | if (path.substring(path.lastIndexOf(".")).equals(".gif")) {
34 | cacheFileType = ".gif";
35 | }
36 |
37 | //获取ftp服务器path上的文件名
38 | String fileName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf("."));
39 |
40 | //文件名的hash算法
41 | if (sign) {
42 | fileName = "sign" + fileName;
43 | }
44 | if (recomment) {
45 | fileName = "reco" + fileName;
46 | }
47 | if (height_str != null && width_str != null) {
48 | fileName = height_str + width_str + fileName;
49 | } else if (scale_str != null) {
50 | fileName = "scale" + scale_str + fileName;
51 | }
52 | if (signAlpha != 1) {
53 | fileName = "signAlpha" + (signAlpha * 10) + fileName;
54 | }
55 | if (alpha != 1) {
56 | fileName = "alpha" + (alpha * 10) + fileName;
57 | }
58 |
59 | //组建最后的文件相对路径 如 : images/paintings/1/xxxx.png
60 | if(path.indexOf("/") == 0 || path.indexOf("\\") == 0){
61 | cacheFileName = path.substring(1, path.lastIndexOf("/") + 1) + fileName + cacheFileType;
62 | }else {
63 | cacheFileName = path.substring(0, path.lastIndexOf("/") + 1) + fileName + cacheFileType;
64 | }
65 |
66 | }
67 | return cacheFileName;
68 | }
69 |
70 |
71 | // /**
72 | // * 保存缓存文件的信息
73 | // * dir/info.xml
74 | // * dir:缓存文件的目录
75 | // * @param file
76 | // * 缓存的文件
77 | // * @param requestUrl
78 | // * 生成该缓存文件时,请求的url
79 | // */
80 | // public static void saveCatchImageInfo(File file,String requestUrl){
81 | // String dir = file.getParent();
82 | // File infoFile = new File(dir + "info.xml");
83 | //
84 | //
85 | //
86 | // }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/ImageUtil.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.util;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/7/9 0009.
4 | */
5 |
6 | import com.imageServer.vo.ImageConvert;
7 | import net.coobird.thumbnailator.Thumbnails;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.web.context.request.RequestContextHolder;
11 | import org.springframework.web.context.request.ServletRequestAttributes;
12 |
13 | import javax.imageio.ImageIO;
14 | import javax.servlet.ServletOutputStream;
15 | import javax.servlet.http.HttpServletRequest;
16 | import java.awt.*;
17 | import java.awt.image.BufferedImage;
18 | import java.awt.image.CropImageFilter;
19 | import java.awt.image.FilteredImageSource;
20 | import java.awt.image.ImageFilter;
21 | import java.io.File;
22 | import java.io.IOException;
23 |
24 | /**
25 | * 图片处理工具类
26 | * 单例模式
27 | * Copyright 2014-2015 the original ql
28 | * Created by QianLong on 2014/7/9 0009.
29 | */
30 | public class ImageUtil {
31 |
32 | private static final Logger log = LoggerFactory.getLogger(ImageUtil.class);
33 |
34 | private static ImageUtil imageUtil = null;
35 |
36 | private ImageUtil() {
37 | }
38 |
39 | /**
40 | * 获取网站的根目录
41 | * @param request
42 | * @return
43 | */
44 | public static String getWebPath(HttpServletRequest request){
45 | String webPath = request.getSession().getServletContext().getRealPath("/");
46 | if(webPath.lastIndexOf(File.separator) != webPath.length()-1){
47 | webPath = webPath + File.separator;
48 | }
49 | return webPath;
50 | }
51 |
52 | public static ImageUtil getInstance() {
53 | if (imageUtil == null) {
54 | imageUtil = new ImageUtil();
55 | }
56 | return imageUtil;
57 | }
58 |
59 | /**
60 | * 图片转换操作
61 | * 注意:
62 | * 1、width与height成对出现才会生效
63 | * 2、如果指定了width和height,那么scale参数将会失效
64 | * @param image
65 | * 待转换的图像
66 | * @param height_str
67 | * 指定图像的输出高度
68 | * @param width_str
69 | * 指定图像的输出宽度
70 | * @param sign
71 | * false:不添加版权水印 默认true (小于100 * 50 的不加水印)
72 | * @param recomment
73 | * true:添加重点推荐水印,默认false
74 | * @param signAlpha
75 | * 水印的透明度(0.0到1.0之间的float值,默认1.0)
76 | * @param scale_str
77 | * 对图像进行缩放处理,小于100为缩小,大于100为放大
78 | * @param alpha
79 | * 图片的透明度(0.0到1.0之间的float值,默认1.0)
80 | * @return
81 | */
82 | public static ImageConvert imageConvert(BufferedImage image,String height_str,String width_str
83 | ,boolean sign,boolean recomment,float signAlpha,String scale_str,float alpha){
84 | ImageConvert convert = new ImageConvert();
85 | if(height_str != null && width_str != null){//转换图像到指定高宽
86 | int width = 0,height = 0;
87 | try {
88 | width = Integer.parseInt(width_str);
89 | height = Integer.parseInt(height_str);
90 | image = ImageUtil.getInstance().turnImageToWH(width,height,image,sign,recomment,signAlpha);
91 | convert.setSucess(true);
92 | } catch (NumberFormatException e) {//输出提示错误图像
93 | log.error("图像输出错误", e);
94 | image = ImageUtil.getInstance().getNoImageByConvert(height_str,width_str,sign,recomment,signAlpha,scale_str,alpha);
95 | convert.setSucess(false);
96 | }
97 | }else if (scale_str != null) {//转换图像的等比缩放
98 | int scale = 100;
99 | try {
100 | scale = Integer.parseInt(scale_str);
101 | image = ImageUtil.getInstance().scale(scale,image,sign,recomment,signAlpha);
102 | convert.setSucess(true);
103 | } catch (NumberFormatException e) {//输出提示错误图像
104 | log.error("图像输出错误", e);
105 | image = ImageUtil.getInstance().getNoImageByConvert(height_str, width_str, sign, recomment, signAlpha, scale_str, alpha);
106 | convert.setSucess(false);
107 | }
108 | }else{
109 | if(sign){
110 | image = ImageUtil.getInstance().addSign(image,signAlpha);
111 | }
112 | convert.setSucess(true);
113 | }
114 |
115 | //调整图像透明度
116 | ImageUtil.getInstance().getImageAlpha(image, alpha);
117 |
118 | convert.setBufferedImage(image);
119 |
120 | return convert;
121 | }
122 |
123 | /**
124 | * 调整图像透明度
125 | *
126 | * @param image
127 | * @param alpha
128 | */
129 | public void getImageAlpha(BufferedImage image, float alpha) {
130 | if(alpha != 1){
131 | BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image.getHeight(),
132 | BufferedImage.TYPE_INT_RGB);
133 | Graphics2D g2 = bufferedImage.createGraphics();
134 | bufferedImage = g2.getDeviceConfiguration().createCompatibleImage(image.getWidth(), image.getHeight(), Transparency.TRANSLUCENT);
135 | g2.dispose();
136 | g2 = bufferedImage.createGraphics();
137 | g2.setComposite(AlphaComposite.SrcOver.derive(alpha));
138 | g2.drawImage(
139 | image.getScaledInstance(image.getWidth(), image.getHeight(), Image.SCALE_SMOOTH),
140 | 0, 0, null);
141 |
142 | g2.dispose();
143 | }
144 | }
145 |
146 | /**
147 | * response写出图片
148 | *
149 | * 若发生异常则写出默认图片
150 | *
151 | * @param fileType .jpg .gif .png
152 | * @param image
153 | * @param servletOutputStream
154 | * @throws IOException
155 | */
156 | public void writeImage(String fileType, BufferedImage image, ServletOutputStream servletOutputStream) throws IOException {
157 | try {
158 | imageWrite(fileType,image,servletOutputStream);
159 | } catch (Exception e) {
160 | ImageIO.write(getNoImage(), "JPEP", servletOutputStream);
161 | } finally {
162 | servletOutputStream.close();
163 | }
164 | }
165 |
166 | /**
167 | * response写出图片
168 | *
169 | * 若发生异常则写出默认图片
170 | *
171 | * @param fileType .jpg .gif .png
172 | * @param imagePath
173 | * @param servletOutputStream
174 | * @throws IOException
175 | */
176 | public void writeImage(String fileType, String imagePath, ServletOutputStream servletOutputStream) throws IOException {
177 | try {
178 | BufferedImage image = ImageIO.read(new File(imagePath));
179 | imageWrite(fileType,image,servletOutputStream);
180 | } catch (Exception e) {
181 | ImageIO.write(getNoImage(), "JPEP", servletOutputStream);
182 | } finally {
183 | servletOutputStream.close();
184 | }
185 | }
186 |
187 | /**
188 | * response写出图片,同时保存请求图片的缓存文件
189 | *
190 | * 若发生异常则写出默认图片
191 | *
192 | * @param fileType .jpg .gif .png
193 | * @param image
194 | * @param servletOutputStream
195 | * @param cacheFile
196 | * @throws IOException
197 | */
198 | public void writeImage(String fileType, BufferedImage image, ServletOutputStream servletOutputStream, File cacheFile) throws IOException {
199 | try {
200 | imageWrite(fileType,image,servletOutputStream);
201 | } catch (Exception e) {
202 | ImageIO.write(getNoImage(), "JPEP", servletOutputStream);
203 | //若缓存文件保存失败,则删除缓存文件
204 | if (cacheFile.exists()) {
205 | cacheFile.delete();
206 | }
207 | } finally {
208 | servletOutputStream.close();
209 | }
210 | }
211 |
212 | /**
213 | * 图片写出流方法
214 | * @param fileType .jpg .gif .png
215 | * @param image
216 | * @param servletOutputStream
217 | * @throws IOException
218 | */
219 | private void imageWrite(String fileType,BufferedImage image,ServletOutputStream servletOutputStream) throws IOException {
220 | switch (fileType) {
221 | case ".jpg":{
222 | Thumbnails.Builder builder = Thumbnails.of(image).scale(1f)
223 | // .outputQuality(0.38f)
224 | .outputFormat("jpg");
225 | builder.toOutputStream(servletOutputStream);
226 |
227 | // ImageIO.write(image, "PNG", servletOutputStream);
228 | break;
229 | }
230 | case ".gif":{
231 | ImageIO.write(image, "GIF", servletOutputStream);
232 | break;
233 | }
234 | case ".png":{
235 | Thumbnails.Builder builder = Thumbnails.of(image).scale(1f)
236 | // .outputQuality(0.38f)
237 | .outputFormat("jpg");
238 | builder.toOutputStream(servletOutputStream);
239 |
240 | // ImageIO.write(image, "PNG", servletOutputStream);
241 | break;
242 | }
243 | }
244 | }
245 |
246 | /**
247 | * 保存请求图片的缓存文件
248 | *
249 | * @param fileType .jpg .gif .png
250 | * @param image
251 | * @param cacheFile
252 | * @throws IOException
253 | */
254 | public void writeImage(String fileType, BufferedImage image, File cacheFile) throws IOException {
255 | try {
256 | switch (fileType) {
257 | case ".jpg":{
258 | Thumbnails.Builder builder = Thumbnails.of(image).scale(1f)
259 | // .outputQuality(0.38f)
260 | .outputFormat("jpg");
261 | builder.toFile(cacheFile);
262 |
263 | // ImageIO.write(image, "PNG", cacheFile);
264 | break;
265 | }
266 | case ".gif":{
267 | ImageIO.write(image, "GIF", cacheFile);
268 | break;
269 | }
270 | case ".png":{
271 | Thumbnails.Builder builder = Thumbnails.of(image).scale(1f)
272 | // .outputQuality(0.38f)
273 | .outputFormat("jpg");
274 | builder.toFile(cacheFile);
275 |
276 | // ImageIO.write(image, "PNG", cacheFile);
277 | break;
278 | }
279 | }
280 | } catch (IndexOutOfBoundsException e) {
281 | //若缓存文件保存失败,则删除缓存文件
282 | if (cacheFile.exists()) {
283 | cacheFile.delete();
284 | }
285 | }
286 | }
287 |
288 |
289 | /**
290 | * 返回指定高宽的图片
291 | * 按照中间的位置自动裁剪图片
292 | * @param width
293 | * 指定的宽
294 | * @param height
295 | * 指定的高
296 | * @param image
297 | * 需要进行处理的源图片
298 | * @param sign
299 | * 是否添加版权水印
300 | * @param recomment
301 | * 是否添加推荐水印
302 | * @param signAlpha
303 | * 水印透明度
304 | * @return
305 | */
306 | public BufferedImage turnImageToWH(int width, int height, BufferedImage image, boolean sign, boolean recomment, float signAlpha) {
307 |
308 | /**
309 | * 转换图像(高宽至少有目标高宽的最大值)
310 | */
311 | double z;
312 | if (image.getWidth() == image.getHeight()) {
313 | int s = width > height ? width : height;
314 | z = CustomerMath.div(s, image.getHeight(), 2);
315 | } else if (width > height) {
316 | if (image.getHeight() > image.getWidth()) {
317 | z = CustomerMath.div(width, image.getWidth(), 2);
318 | } else {
319 | z = CustomerMath.div(height, image.getHeight(), 2);
320 | }
321 | } else if (width < height) {
322 | if (image.getHeight() > image.getWidth()) {
323 | z = CustomerMath.div(width, image.getWidth(), 2);
324 | } else {
325 | z = CustomerMath.div(height, image.getHeight(), 2);
326 | }
327 | } else {
328 | int cut = image.getWidth() <= image.getHeight() ? image.getWidth() : image.getHeight();
329 | z = CustomerMath.div(width, cut, 2);
330 | }
331 |
332 | double tw = CustomerMath.mul(z,image.getWidth());
333 | double th = CustomerMath.mul(z,image.getHeight());
334 | while (tw < width || th < height){
335 | z = z + 0.01;
336 | tw = CustomerMath.mul(z,image.getWidth());
337 | th = CustomerMath.mul(z,image.getHeight());
338 | }
339 |
340 | int z1 = (int) CustomerMath.mul(z, 100);
341 |
342 | // 将图像等比缩放至至合适指定高宽的大小
343 | BufferedImage image1 = scale(z1, image, false, false, signAlpha);
344 |
345 | // 计算裁剪的中间位置开始坐标
346 | int x = 0,y = 0;
347 | if (image1.getWidth() > width) {
348 | x = (int) (CustomerMath.div(image1.getWidth(), 2) - CustomerMath.div(width, 2));
349 | }
350 | if (image1.getHeight() > height) {
351 | y = (int) (CustomerMath.div(image1.getHeight(), 2) - CustomerMath.div(height, 2));
352 | }
353 |
354 | // 从缩放的图像中间位置进行裁剪,成为指定的高宽的图像
355 | BufferedImage result = cut(image1,x,y,width,height);
356 |
357 | // 是否添加版权水印
358 | if(sign)
359 | result = addSign(result,signAlpha);
360 |
361 | // 是否添加推荐水印
362 | if(recomment)
363 | result = addRecommentSign(result);
364 |
365 | return result;
366 | }
367 |
368 | /**
369 | * 图像切割(指定切片的宽度和高度)
370 | * @param bi 原图像
371 | * @param x 裁剪原图像起点坐标X
372 | * @param y 裁剪原图像起点坐标Y
373 | * @param width 目标切片宽度
374 | * @param height 目标切片高度
375 | * @return
376 | */
377 | public static BufferedImage cut(BufferedImage bi,int x, int y, int width, int height) {
378 |
379 | BufferedImage tag = new BufferedImage(width, height,
380 | BufferedImage.TYPE_INT_RGB);
381 | Graphics2D g2 = tag.createGraphics();
382 | tag = g2.getDeviceConfiguration().createCompatibleImage(width, height,
383 | Transparency.TRANSLUCENT);
384 | g2.dispose();
385 | g2 = tag.createGraphics();
386 |
387 | int srcWidth = bi.getHeight(); // 源图宽度
388 | int srcHeight = bi.getWidth(); // 源图高度
389 | if (srcWidth > 0 && srcHeight > 0) {
390 | ImageFilter cropFilter = new CropImageFilter(x, y, width, height);
391 | Image img = Toolkit.getDefaultToolkit().createImage(
392 | new FilteredImageSource(bi.getSource(),cropFilter));
393 | g2.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图
394 | g2.dispose();
395 | }
396 | return tag;
397 | }
398 |
399 | /**
400 | * 等比缩放
401 | *
402 | * @param scale
403 | * @param scaleImage
404 | * @param sign
405 | * @return
406 | */
407 | public BufferedImage scale(int scale, BufferedImage scaleImage, boolean sign, boolean recomment, float signAlpha) {
408 | if(scale != 100){
409 | int width = (int) (scaleImage.getWidth(null) * scale / 100.0);
410 | int height = (int) (scaleImage.getHeight(null) * scale / 100.0);
411 |
412 | BufferedImage bufferedImage = new BufferedImage(width, height,
413 | BufferedImage.TYPE_INT_RGB);
414 | Graphics2D g2 = bufferedImage.createGraphics();
415 | bufferedImage = g2.getDeviceConfiguration().createCompatibleImage(width, height,
416 | Transparency.TRANSLUCENT);
417 | g2.dispose();
418 | g2 = bufferedImage.createGraphics();
419 |
420 | g2.drawImage(
421 | scaleImage.getScaledInstance(width, height, Image.SCALE_SMOOTH),
422 | 0, 0, null);
423 |
424 | try {
425 | bufferedImage = Thumbnails.of(bufferedImage).scale(1f)
426 | .outputQuality(0.38f)
427 | .asBufferedImage();
428 | } catch (IOException e) {
429 | log.error("更改图片质量失败",e);
430 | }
431 |
432 | if (sign) {
433 | bufferedImage = addSign(bufferedImage, signAlpha);
434 | }
435 | if (recomment) {
436 | bufferedImage = addRecommentSign(bufferedImage);
437 | }
438 | return bufferedImage;
439 | }else {
440 | try {
441 | BufferedImage bufferedImage = scaleImage;
442 | if(!sign && !recomment){
443 | bufferedImage = Thumbnails.of(scaleImage).scale(1f)
444 | .outputQuality(0.40f)
445 | .asBufferedImage();
446 | }
447 | if (sign) {
448 | bufferedImage = addSign(bufferedImage, signAlpha);
449 | }
450 | if (recomment) {
451 | bufferedImage = addRecommentSign(bufferedImage);
452 | }
453 | return bufferedImage;
454 | } catch (IOException e) {
455 | log.error("降低图片质量失败",e);
456 | return scaleImage;
457 | }
458 | }
459 | }
460 |
461 | /**
462 | * 获取图片未找到的提示图片
463 | *
464 | * @return
465 | */
466 | public BufferedImage getNoImage() {
467 | String markImgPath = this.getClass().getClassLoader().getResource("noimage.jpg").getPath();
468 | File file = new File(markImgPath);
469 | BufferedImage image;
470 | try {
471 | image = ImageIO.read(file);
472 | } catch (IOException e) {
473 | image = new BufferedImage(100, 35,
474 | BufferedImage.TYPE_INT_RGB);
475 | Graphics g = image.getGraphics();
476 | g.setFont(new Font("宋体", Font.BOLD, 15));
477 | g.setColor(Color.CYAN);
478 | g.drawString("图片获取失败", 0, 25);
479 | g.dispose();
480 | }
481 | return image;
482 | }
483 |
484 | /**
485 | * 获取图片未找到的提示图片
486 | * 并进行图片转换
487 | * @param height_str
488 | * @param width_str
489 | * @param sign
490 | * @param recomment
491 | * @param signAlpha
492 | * @param scale_str
493 | * @param alpha
494 | * @return
495 | */
496 | public BufferedImage getNoImageByConvert(String height_str,String width_str
497 | ,boolean sign,boolean recomment,float signAlpha,String scale_str,float alpha){
498 |
499 | String path = this.getClass().getClassLoader().getResource("noimage.jpg").getPath();
500 |
501 | HttpServletRequest request = null;
502 | try {
503 | request = ((ServletRequestAttributes) RequestContextHolder
504 | .getRequestAttributes()).getRequest();
505 | } catch (Exception ignored) {
506 | }
507 |
508 | String cacheFileName = "";
509 | if(request != null){
510 | cacheFileName = ImageCatchUtil.getImageCachePathByFtpPath(path,sign,recomment,height_str,width_str,scale_str,signAlpha,alpha);
511 | if(File.separator.equals("\\")){
512 | cacheFileName = cacheFileName.replace("/",File.separator);
513 | }
514 | File cacheFile = new File(request.getSession().getServletContext().getRealPath("/") + "/" + cacheFileName);
515 | if(cacheFile.exists() && cacheFile.length() > 0){
516 | try {
517 | log.info("返回已缓存的错误图片" + cacheFile.getPath());
518 | return ImageIO.read(cacheFile);
519 | } catch (IOException ignored) {
520 | }
521 | }
522 | }
523 |
524 | BufferedImage image = getNoImage();
525 | if(height_str != null && width_str != null){//转换图像到指定高宽
526 | int width = 0,height = 0;
527 | try {
528 | width = Integer.parseInt(width_str);
529 | height = Integer.parseInt(height_str);
530 | image = ImageUtil.getInstance().turnImageToWH(width,height,image,false,false,signAlpha);
531 | } catch (NumberFormatException e) {//输出提示错误图像
532 | log.error("图像输出错误", e);
533 | image = ImageUtil.getInstance().getNoImage();
534 | }
535 | }else if (scale_str != null) {//转换图像的等比缩放
536 | int scale = 100;
537 | try {
538 | scale = Integer.parseInt(scale_str);
539 | image = ImageUtil.getInstance().scale(scale,image,false,false,signAlpha);
540 | } catch (NumberFormatException e) {//输出提示错误图像
541 | log.error("图像输出错误", e);
542 | image = ImageUtil.getInstance().getNoImage();
543 | }
544 | }else{
545 | if(sign){
546 | image = ImageUtil.getInstance().addSign(image,signAlpha);
547 | }
548 | }
549 |
550 | //调整图像透明度
551 | ImageUtil.getInstance().getImageAlpha(image,alpha);
552 |
553 | try {
554 | log.info("将指定格式的错误图片的缓存文件保存");
555 | String webPath = ImageUtil.getWebPath(request);
556 | String cacheDir = (webPath + path.substring(1,path.lastIndexOf("/")+1))
557 | .replace("/",File.separator);
558 | String fileType = path.substring(path.lastIndexOf("."));
559 | log.info("计算获取文件后缀名:" + fileType);
560 |
561 | File cacheFile = new File(webPath + cacheFileName);
562 | File dir = new File(webPath + File.separator + "error");
563 | if(!dir.exists()){
564 | dir.mkdirs();
565 | }
566 | writeImage(fileType,image,cacheFile);
567 | } catch (Exception e) {
568 | log.error("错误图片的缓存文件保存失败",e);
569 | }
570 |
571 | return image;
572 | }
573 |
574 | /**
575 | * 添加版权水印
576 | * 宽度小于250,高度小于250的不添加水印
577 | * @param image
578 | * @return
579 | */
580 | public BufferedImage addSign(BufferedImage image, float signAlpha) {
581 | if(image.getHeight() < 250 || image.getWidth() < 250){
582 | return image;
583 | }
584 | Graphics g = image.getGraphics();
585 | g.setFont(new Font("宋体", Font.BOLD, 15));
586 | g.setColor(Color.GRAY);
587 | Graphics2D g2 = image.createGraphics();
588 | g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, signAlpha));
589 |
590 | try {
591 | String markImgPath = this.getClass().getClassLoader().getResource("watermark.png").getPath();
592 | File file = new File(markImgPath);
593 | BufferedImage markImg = ImageIO.read(file);
594 | g2.drawImage(markImg, image.getWidth() - markImg.getWidth() - 9, image.getHeight() - markImg.getHeight() - 9, null);
595 | } catch (IOException e) {
596 | g2.drawString("盛世文化", image.getWidth() - 80, image.getHeight() - 25);
597 | g2.drawString("版权所有", image.getWidth() - 80, image.getHeight() - 10);
598 | }
599 | g.dispose();
600 | return image;
601 | }
602 |
603 | /**
604 | * 添加推荐水印
605 | *
606 | * @param image
607 | * @return
608 | */
609 | public BufferedImage addRecommentSign(BufferedImage image) {
610 | int offset = 3;//设置偏移量
611 | String markImgPath = this.getClass().getClassLoader().getResource("tuijianBig.png").getPath();
612 | if(image.getWidth() <= 80 ){
613 | markImgPath = this.getClass().getClassLoader().getResource("tuijianSmall.png").getPath();
614 | offset = 2;
615 | }
616 |
617 | // 创建透明背景图
618 | BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image.getHeight(),
619 | BufferedImage.TYPE_INT_RGB);
620 | Graphics2D g2 = bufferedImage.createGraphics();
621 | bufferedImage = g2.getDeviceConfiguration().createCompatibleImage(image.getWidth(), image.getHeight(),
622 | Transparency.TRANSLUCENT);
623 | g2.dispose();
624 | g2 = bufferedImage.createGraphics();
625 |
626 | // 在背景图中画上原图像
627 | g2.drawImage(
628 | image.getScaledInstance(image.getWidth(), image.getHeight(), Image.SCALE_SMOOTH),
629 | offset, offset, null);
630 |
631 | // 画上推荐水印
632 | try {
633 | File file = new File(markImgPath);
634 | BufferedImage markImg = ImageIO.read(file);
635 | g2.drawImage(markImg, 0, 0, null);
636 | } catch (IOException ignored) {
637 |
638 | }
639 | g2.dispose();
640 | return bufferedImage;
641 | }
642 |
643 | }
644 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/util/ObjectUtil.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | package com.imageServer.util;
4 |
5 | public class ObjectUtil {
6 | /**
7 | * 判断字符串是否为空
8 | *
9 | * @param str
10 | * 字符串
11 | * @return 是否为空
12 | */
13 | public static boolean isNull(String str) {
14 | return (str == null || "".equals(str.trim()) || "null".equals(str.trim()) || "undefined".equals(str.trim()));
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/imageServer/vo/ImageConvert.java:
--------------------------------------------------------------------------------
1 | package com.imageServer.vo;/**
2 | * Copyright 2014-2015 the original ql
3 | * Created by QianLong on 2014/8/14 0014.
4 | */
5 |
6 | import java.awt.image.BufferedImage;
7 |
8 | /**
9 | * 图像转换结果实体
10 | * Copyright 2014-2015 the original ql
11 | * Created by QianLong on 2014/8/14 0014.
12 | */
13 | public class ImageConvert {
14 |
15 | private BufferedImage bufferedImage;
16 | private boolean sucess;
17 |
18 | public BufferedImage getBufferedImage() {
19 | return bufferedImage;
20 | }
21 |
22 | public void setBufferedImage(BufferedImage bufferedImage) {
23 | this.bufferedImage = bufferedImage;
24 | }
25 |
26 | public boolean isSucess() {
27 | return sucess;
28 | }
29 |
30 | public void setSucess(boolean sucess) {
31 | this.sucess = sucess;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Output pattern : date [thread] priority category - message FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7
2 | log4j.rootLogger=INFO, Console, RollingFile
3 |
4 | #Console
5 | log4j.appender.Console=org.apache.log4j.ConsoleAppender
6 | log4j.appender.Console.layout=org.apache.log4j.PatternLayout
7 | log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
8 |
9 | #RollingFile
10 | #log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
11 | #log4j.appender.RollingFile.File=${catalina.base}/logs/experian.log
12 | #log4j.appender.RollingFile.File=/home/platform/application/log/app/experian.log
13 | #log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
14 | log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
15 |
16 | #Springframework level
17 | #log4j.logger.org.springframework=ERROR
18 |
19 | #Hibernate level
20 | #log4j.logger.org.hibernate=ERROR
21 | log4j.logger.org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory=ERROR
22 | log4j.logger.org.hibernate.search.impl.ConfigContext=ERROR
23 | log4j.logger.net.sf.ehcache.config.CacheConfiguration=ERROR
24 |
25 | #mybatis
26 | log4j.logger.com.ibatis=DEBUG
27 | log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
28 | log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
29 | log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
30 | log4j.logger.java.sql.Connection=DEBUG
31 | log4j.logger.java.sql.PreparedStatement=DEBUG
32 | log4j.logger.java.sql.ResultSet=DEBUG
33 |
--------------------------------------------------------------------------------
/src/main/resources/noimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QianLongGit/imageServer/dc3a7d2c5798d9ae2301425ccc6946363361a1f0/src/main/resources/noimage.jpg
--------------------------------------------------------------------------------
/src/main/resources/system.properties:
--------------------------------------------------------------------------------
1 | # FTP 设置
2 | ftp.address = 172.16.189.134
3 | ftp.userName = qianlong
4 | ftp.password = qianlong
5 |
6 | # 本系统对外的网站地址
7 | sys.webUrl = http://127.0.0.1:8080
--------------------------------------------------------------------------------
/src/main/resources/tuijianBig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QianLongGit/imageServer/dc3a7d2c5798d9ae2301425ccc6946363361a1f0/src/main/resources/tuijianBig.png
--------------------------------------------------------------------------------
/src/main/resources/tuijianSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QianLongGit/imageServer/dc3a7d2c5798d9ae2301425ccc6946363361a1f0/src/main/resources/tuijianSmall.png
--------------------------------------------------------------------------------
/src/main/resources/watermark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QianLongGit/imageServer/dc3a7d2c5798d9ae2301425ccc6946363361a1f0/src/main/resources/watermark.png
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/applicationContext.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 | classpath:system.properties
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/springMVC.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | text/plain;charset=UTF-8
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Archetype Created Web Application
4 |
5 |
6 | contextConfigLocation
7 | /WEB-INF/applicationContext.xml
8 |
9 |
10 |
11 | org.springframework.web.context.ContextLoaderListener
12 |
13 |
14 |
15 | com.imageServer.context.ShutdownResources
16 |
17 |
18 |
19 |
20 | org.springframework.web.context.request.RequestContextListener
21 |
22 |
23 |
24 |
25 | SetCharacterEncoding
26 | org.springframework.web.filter.CharacterEncodingFilter
27 |
28 | encoding
29 | UTF-8
30 |
31 |
32 | forceEncoding
33 | true
34 |
35 |
36 |
37 |
38 | SetCharacterEncoding
39 | /*
40 |
41 |
42 |
43 | 404
44 | /
45 |
46 |
47 |
48 | 400
49 | /
50 |
51 |
52 |
53 | springMVC
54 | org.springframework.web.servlet.DispatcherServlet
55 |
56 | contextConfigLocation
57 | /WEB-INF/springMVC.xml
58 |
59 | 1
60 |
61 |
62 |
63 | springMVC
64 | /
65 |
66 |
67 |
68 | default
69 | *.css
70 |
71 |
72 |
73 | default
74 | *.gif
75 |
76 |
77 |
78 | default
79 | *.jpg
80 |
81 |
82 |
83 | default
84 | *.js
85 |
86 |
87 |
88 | default
89 | *.svg
90 |
91 |
92 |
93 | default
94 | *.png
95 |
96 |
97 |
98 | default
99 | *.eot
100 |
101 |
102 |
103 | default
104 | *.ttf
105 |
106 |
107 |
108 | default
109 | *.woff
110 |
111 |
112 |
113 | default
114 | *.txt
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------