Java文件上傳實(shí)例并解決跨域問(wèn)題
目在Web應(yīng)用系統(tǒng)開(kāi)發(fā)中,文件上傳和下載功能是非常常用的功能,今天來(lái)講一下JavaWeb中的文件上傳功能的實(shí)現(xiàn)。
了解MultipartFile接口
我們實(shí)現(xiàn)文件的上傳用到了Spring-web框架中的 MultipartFile接口,MultipartFile接口的源碼注釋中說(shuō)“MultipartFile接口是 在大部分請(qǐng)求中接收的上載文件的表示形式。”
A representation of an uploaded file received in a multipart request.
The file contents are either stored in memory or temporarily on disk. In either case, the user is responsible for copying file contents to a session-level or persistent store as and if desired. The temporary storage will be cleared at the end of request processing.
常用方法如下表
Method Summary | ||
---|---|---|
byte[] |
獲取文件的字節(jié)數(shù)組 |
getBytes() Return the contents of the file as an array of bytes. |
String |
獲取文件的類型 |
getContentType() Return the content type of the file. |
InputStream |
獲取文件的輸入流 |
getInputStream() Return an InputStream to read the contents of the file from. |
String |
獲取文件名 |
getName() Return the name of the parameter in the multipart form. |
String |
獲取原始文件名(防止篡改文件類型) |
getOriginalFilename() Return the original filename in the client's filesystem. |
long |
獲取文件的大小,以字節(jié)的形式) |
getSize() Return the size of the file in bytes. |
boolean |
判斷文件是否為空 |
isEmpty() Return whether the uploaded file is empty, that is, either no file has been chosen in the multipart form or the chosen file has no content. |
void |
將接收到的文件傳輸?shù)浇o定的目標(biāo)文件。 |
transferTo(File dest) Transfer the received file to the given destination file. |
文件上傳業(yè)務(wù)代碼
Controller類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/** * @Author: 小小張自由 * @Date: 2021/7/6 - 20:56 * @Description: 文件上傳 * @version: 1.0 */ @Controller @RequestMapping ( "upload" ) public class UploadController { @Autowired private UploadService uploadService; @PostMapping ( "image" ) public ResponseEntity<String> uploadImage( @RequestParam ( "file" ) MultipartFile file){ String url= this .uploadService.uploadImage(file); if (StringUtils.isBlank(url)){ return ResponseEntity.badRequest().build(); } return ResponseEntity.status(HttpStatus.CREATED).body(url); } } |
Service類
寫了具體的業(yè)務(wù)邏輯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
/** * @Author: 小小張自由 * @Date: 2021/7/6 - 21:01 * @Description: 文件上傳 * @version: 1.0 */ @Service public class UploadService { //用于判斷文件的類型,暫時(shí)只判斷了“image/gif","image/jpeg” private static final List<String> CONTENT_TYPES= Arrays.asList( "image/gif" , "image/jpeg" ); private static final Logger LOGGER= LoggerFactory.getLogger(UploadService. class ); /** * 業(yè)務(wù)邏輯代碼 * @param file 文件的存儲(chǔ)的url * @return */ public String uploadImage(MultipartFile file) { String originalFilename = file.getOriginalFilename(); //校驗(yàn)文件類型 //方法一:截取字符串 String afterLast = StringUtils.substringAfterLast( "." , originalFilename); //方法二:使用getContentType方法 String contentType = file.getContentType(); if (!CONTENT_TYPES.contains(contentType)){ LOGGER.info( "文件類型不合法:" +originalFilename); return null ; } //校驗(yàn)文件內(nèi)容 try { //獲取文件流 BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); if (bufferedImage== null ){ LOGGER.info( "文件內(nèi)容不合法:{}" ,originalFilename); return null ; } //保存到服務(wù)器 E:\Leyou\image //將接收到的文件傳輸?shù)浇o定的目標(biāo)文件。 file.transferTo( new File( "E:\\Leyou\\Image\\" +originalFilename)); //返回URL,進(jìn)行回顯 //可以使用Nginx-圖片服務(wù)器 return "http://image.leyou.com/" +originalFilename; } catch (Exception e) { LOGGER.info( "服務(wù)器內(nèi)部錯(cuò)誤:" +originalFilename); e.printStackTrace(); } return null ; } } |
修改nginx配置
將文件存儲(chǔ)到文件服務(wù)器中
修改Nginx的配置文件nginx.conf,監(jiān)聽(tīng)80端口,設(shè)置root的值為:E盤
- 圖片不能保存在服務(wù)器內(nèi)部,這樣會(huì)對(duì)服務(wù)器產(chǎn)生額外的加載負(fù)擔(dān)
一般靜態(tài)資源都應(yīng)該使用獨(dú)立域名,這樣訪問(wèn)靜態(tài)資源時(shí)不會(huì)攜帶一些不必要的cookie,減小請(qǐng)求的數(shù)據(jù)量
1
2
3
4
5
6
7
8
9
10
11
12
|
server { listen 80 ; server_name image.leyou.com; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { root E:\\Leyou\\image; } } |
如何繞過(guò)網(wǎng)關(guān)
每次上傳文件都會(huì)經(jīng)過(guò)網(wǎng)關(guān),必然會(huì)給網(wǎng)關(guān)帶來(lái)很大的壓力,那我們?nèi)绾卫@過(guò)網(wǎng)關(guān)呢?
1.在網(wǎng)關(guān)中配置白名單
在網(wǎng)關(guān)中配置白名單,這樣也會(huì)走網(wǎng)關(guān),只是壓力少了一點(diǎn)點(diǎn)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
@Slf4j public class AuthorizeFilter implements GlobalFilter, Ordered { //白名單:存放放行的URL private List<String> allowPaths; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //獲取請(qǐng)求的url路徑 String path = request.getURI().getPath(); boolean flag=isAllowPath(path); if (flag) { log.info( "請(qǐng)求在白名單中,leyou.filter: {}" ,path); //放行 return chain.filter(exchange); } else { //寫其他的業(yè)務(wù)邏輯 ~~~~ } } private boolean isAllowPath(String path) { //判斷是否允許放行 if (allowPaths.contains(path)){ return true ; } return false ; } |
2.在nginx做轉(zhuǎn)發(fā)
在nginx做轉(zhuǎn)發(fā),當(dāng)請(qǐng)求文件上傳時(shí),直接轉(zhuǎn)到相應(yīng)的服務(wù)
本實(shí)例使用了方法二,需要增加配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
server { listen 80 ; server_name api.leyou.com; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 新增加的配置,用于文件上傳 location /api/upload { proxy_pass http: //127.0.0.1:8082; proxy_connect_timeout 600 ; proxy_read_timeout 600 ; rewrite "^/api/(.*)$" /$ 1 break ; } # 網(wǎng)關(guān)的配置 location / { proxy_pass http: //127.0.0.1:10010; proxy_connect_timeout 600 ; proxy_read_timeout 600 ; } } |
當(dāng)這樣配置之后,文件上傳就不會(huì)過(guò)網(wǎng)關(guān),減少了網(wǎng)關(guān)的壓力。但是有引來(lái)了一個(gè)新問(wèn)題那就是跨域。
解決上傳文件出現(xiàn)跨域問(wèn)題
由于Nginx將文件上傳的請(qǐng)求直接轉(zhuǎn)發(fā)到了具體服務(wù)中,不再走gateway,所以gateway中的跨域配置,不再生效了。 需要在文件上傳這個(gè)服務(wù)中單獨(dú)配置跨域。
寫配置類CorsFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/** * @Author: 小小張自由 * @Date: 2021/6/15 - 11:12 * @Description: 解決 跨域問(wèn)題 * @version: 1.0 */ @Configuration public class LeyouCorsConfiguration { @Bean public CorsFilter corsFilter(){ //初始化配置對(duì)象 CorsConfiguration configuration = new CorsConfiguration(); //允許跨域訪問(wèn)的域名 configuration.addAllowedOrigin( "*" ); // configuration.setAllowCredentials(true); //運(yùn)行攜帶cookie configuration.addAllowedMethod( "*" ); //代表所有請(qǐng)求方法 configuration.addAllowedHeader( "*" ); //允許攜帶任何頭信息 //初始化cors配置源對(duì)象 UrlBasedCorsConfigurationSource configurationSource= new UrlBasedCorsConfigurationSource(); configurationSource.registerCorsConfiguration( "/**" ,configuration); //返回CorSfilter實(shí)例,參數(shù) return new CorsFilter(configurationSource); } } |
到此應(yīng)該就可以上傳了,但是還是報(bào)跨域,我已經(jīng)配置好了啊,為什么還是報(bào)跨域呢?
在nginx配置中配置請(qǐng)求實(shí)體大小
我就想是不是Nginx的問(wèn)題,然后我就一行一行的讀配置,最后發(fā)現(xiàn)
nginx配置中沒(méi)有配置請(qǐng)求實(shí)體大小
加上這行配置就好了
1
|
client_max_body_size 1024m; |
到此這篇關(guān)于Java實(shí)例講解文件上傳與跨域問(wèn)題的文章就介紹到這了,更多相關(guān)Java文件上傳跨域內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/promsing/article/details/120089365