Skip to content

Commit 5b60e15

Browse files
committed
add upload file only picture
1 parent d1b3d6b commit 5b60e15

File tree

5 files changed

+136
-7
lines changed

5 files changed

+136
-7
lines changed

java-sec-code.iml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</configuration>
1313
</facet>
1414
</component>
15-
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6">
15+
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
1616
<output url="file://$MODULE_DIR$/target/classes" />
1717
<output-test url="file://$MODULE_DIR$/target/test-classes" />
1818
<content url="file://$MODULE_DIR$">
@@ -164,5 +164,6 @@
164164
<orderEntry type="library" name="Maven: com.thoughtworks.xstream:xstream:1.4.9" level="project" />
165165
<orderEntry type="library" name="Maven: xmlpull:xmlpull:1.1.3.1" level="project" />
166166
<orderEntry type="library" name="Maven: xpp3:xpp3_min:1.1.4c" level="project" />
167+
<orderEntry type="library" name="Maven: com.fasterxml.uuid:java-uuid-generator:3.1.4" level="project" />
167168
</component>
168169
</module>

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@
129129
<version>1.4.0.RELEASE</version>
130130
</dependency>
131131

132+
<!-- 生成uuid -->
133+
<dependency>
134+
<groupId>com.fasterxml.uuid</groupId>
135+
<artifactId>java-uuid-generator</artifactId>
136+
<version>3.1.4</version>
137+
</dependency>
138+
132139
</dependencies>
133140

134141
<dependencyManagement>

src/main/java/org/joychou/controller/FileUpload.java

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.joychou.controller;
22

3+
import com.fasterxml.uuid.Generators;
34
import org.springframework.stereotype.Controller;
45
import org.springframework.web.bind.annotation.GetMapping;
56
import org.springframework.web.bind.annotation.PostMapping;
@@ -8,10 +9,16 @@
89
import org.springframework.web.multipart.MultipartFile;
910
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
1011

12+
import java.io.File;
13+
import java.io.FileOutputStream;
1114
import java.io.IOException;
1215
import java.nio.file.Files;
1316
import java.nio.file.Path;
1417
import java.nio.file.Paths;
18+
import java.util.UUID;
19+
20+
import static org.joychou.utils.Security.isImage;
21+
1522

1623
/**
1724
* @author: JoyChou ([email protected])
@@ -31,6 +38,11 @@ public String index() {
3138
return "upload"; // return upload.html page
3239
}
3340

41+
@GetMapping("/pic")
42+
public String uploadPic() {
43+
return "uploadPic"; // return uploadPic.html page
44+
}
45+
3446
@PostMapping("/upload")
3547
public String singleFileUpload(@RequestParam("file") MultipartFile file,
3648
RedirectAttributes redirectAttributes) {
@@ -52,15 +64,94 @@ public String singleFileUpload(@RequestParam("file") MultipartFile file,
5264
} catch (IOException e) {
5365
redirectAttributes.addFlashAttribute("message", "upload failed");
5466
e.printStackTrace();
55-
return "uploadStatus";
67+
return "redirect:/file/status";
5668
}
5769

5870
return "redirect:/file/status";
5971
}
6072

73+
// only upload picture
74+
@PostMapping("/upload/picture")
75+
public String uploadPicture(@RequestParam("file") MultipartFile multifile,
76+
RedirectAttributes redirectAttributes) throws Exception{
77+
if (multifile.isEmpty()) {
78+
// 赋值给uploadStatus.html里的动态参数message
79+
redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
80+
return "redirect:/file/status";
81+
}
82+
83+
// get suffix
84+
String fileName = multifile.getOriginalFilename();
85+
String Suffix = fileName.substring(fileName.lastIndexOf("."));
86+
87+
File excelFile = convert(multifile);
88+
89+
// security check
90+
String picSuffixList[] = {".jpg", ".png", ".jpeg", ".gif", ".bmp"};
91+
Boolean suffixFlag = false;
92+
for (String white_suffix : picSuffixList) {
93+
if (Suffix.toLowerCase().equals(white_suffix)) {
94+
suffixFlag = true;
95+
break;
96+
}
97+
}
98+
if ( !suffixFlag || !isImage(excelFile) ) {
99+
redirectAttributes.addFlashAttribute("message", "illeagl picture");
100+
deleteFile(excelFile);
101+
return "redirect:/file/status";
102+
}
103+
104+
105+
try {
106+
// Get the file and save it somewhere
107+
byte[] bytes = multifile.getBytes();
108+
Path path = Paths.get(UPLOADED_FOLDER + multifile.getOriginalFilename());
109+
Files.write(path, bytes);
110+
111+
redirectAttributes.addFlashAttribute("message",
112+
"You successfully uploaded '" + UPLOADED_FOLDER + multifile.getOriginalFilename() + "'");
113+
114+
} catch (IOException e) {
115+
redirectAttributes.addFlashAttribute("message", "upload failed");
116+
e.printStackTrace();
117+
deleteFile(excelFile);
118+
return "redirect:/file/status";
119+
}
120+
121+
deleteFile(excelFile);
122+
return "redirect:/file/status";
123+
}
124+
61125
@GetMapping("/status")
62126
public String uploadStatus() {
63127
return "uploadStatus";
64128
}
65129

130+
private void deleteFile(File... files) {
131+
for (File file : files) {
132+
if (file.exists()) {
133+
file.delete();
134+
}
135+
}
136+
}
137+
138+
/**
139+
* @desc 不建议使用transferTo,因为原始的MultipartFile会被覆盖
140+
* @url https://stackoverflow.com/questions/24339990/how-to-convert-a-multipart-file-to-file
141+
* @param multiFile
142+
* @return
143+
* @throws Exception
144+
*/
145+
private File convert(MultipartFile multiFile) throws Exception {
146+
String fileName = multiFile.getOriginalFilename();
147+
String suffix = fileName.substring(fileName.lastIndexOf("."));
148+
UUID uuid = Generators.timeBasedGenerator().generate();
149+
150+
File convFile = new File(UPLOADED_FOLDER + uuid + suffix);
151+
convFile.createNewFile();
152+
FileOutputStream fos = new FileOutputStream(convFile);
153+
fos.write(multiFile.getBytes());
154+
fos.close();
155+
return convFile;
156+
}
66157
}

src/main/java/org/joychou/utils/Security.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import com.google.common.net.InternetDomainName;
44

5+
import javax.imageio.ImageIO;
6+
import java.awt.image.BufferedImage;
7+
import java.io.File;
8+
import java.io.IOException;
59
import java.net.URI;
610
import java.net.URL;
711

@@ -10,8 +14,8 @@ public class Security {
1014
* @param url
1115
* @return 安全url返回true,危险url返回false
1216
*/
13-
public static Boolean checkSafeUrl(String url, String[] urlwhitelist){
14-
try{
17+
public static Boolean checkSafeUrl(String url, String[] urlwhitelist) {
18+
try {
1519
URL u = new URL(url);
1620
URI uri = new URI(url);
1721
// 判断是否是http(s)协议
@@ -25,18 +29,31 @@ public static Boolean checkSafeUrl(String url, String[] urlwhitelist){
2529
// 如果非顶级域名后缀会报错
2630
String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString();
2731

28-
for (String whiteurl: urlwhitelist){
32+
for (String whiteurl : urlwhitelist) {
2933
if (rootDomain.equals(whiteurl)) {
3034
return true;
3135
}
3236
}
3337

3438
System.out.println("Url is not safe.");
3539
return false;
36-
}catch (Exception e) {
40+
} catch (Exception e) {
3741
System.out.println(e.toString());
3842
e.printStackTrace();
3943
return false;
4044
}
4145
}
42-
}
46+
47+
48+
/**
49+
* @param file
50+
* @desc 判断文件内容是否是图片
51+
*/
52+
public static boolean isImage(File file) throws IOException {
53+
BufferedImage bi = ImageIO.read(file);
54+
if (bi == null) {
55+
return false;
56+
}
57+
return true;
58+
}
59+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html xmlns:th="http://www.thymeleaf.org">
3+
<body>
4+
5+
<h3>file upload only picture</h3>
6+
7+
<form method="POST" action="upload/picture" enctype="multipart/form-data">
8+
<input type="file" name="file" /><br/><br/>
9+
<input type="submit" value="Submit" />
10+
</form>
11+
12+
</body>
13+
</html>

0 commit comments

Comments
 (0)