文件的上传并不只是在品牌管理中有需求,以后的其它服务也可能需要,因此我们创建一个独立的微服务,专门处理各种上传。
1.搭建模块
(1)创建模块




(2)依赖
我们需要EurekaClient和web依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leyou</artifactId>
<groupId>lucky.leyou.parent</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>lucky.leyou.upload</groupId>
<artifactId>leyou-upload</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
(3)编写配置
server:
port: 8082
spring:
application:
name: upload-service
servlet:
multipart:
max-file-size: 5MB # 限制文件上传的大小
# Eureka
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
instance:
lease-renewal-interval-in-seconds: 5 # 每隔5秒发送一次心跳
lease-expiration-duration-in-seconds: 10 # 10秒不发送就过期
(4)引导类
package lucky.leyou;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class LeyouUploadApplication {
public static void main(String[] args) {
SpringApplication.run(LeyouUploadApplication.class, args);
}
}
(5)模块初步结构图

2.编写上传功能
(1)Controller
package lucky.leyou.upload.controller;
import lucky.leyou.upload.service.IUploadService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping(path = "/upload")
public class UploadController {
@Autowired
IUploadService iUploadService;
@PostMapping(path = "/image")
public ResponseEntity<String> uploadImage(@RequestParam("file")MultipartFile file){
String url=this.iUploadService.uploadImage(file);
//若url为空,则返回400,上传失败
if(StringUtils.isBlank(url)){
return ResponseEntity.badRequest().build();
}
return ResponseEntity.status(HttpStatus.CREATED).body(url);
}
}
(2)service
接口
package lucky.leyou.upload.service;
import org.springframework.web.multipart.MultipartFile;
public interface IUploadService {
String uploadImage(MultipartFile file);
}
实现类
package lucky.leyou.upload.service.impl;
import lucky.leyou.upload.service.IUploadService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class UploadServiceImpl implements IUploadService {
private static final List<String> CONTENT_TYPES = Arrays.asList("image/jpeg", "image/gif");
private static final Logger LOGGER = LoggerFactory.getLogger(UploadServiceImpl.class);
@Override
public String uploadImage(MultipartFile file) {
String originalFilename = file.getOriginalFilename();
// 校验文件的类型
String contentType = file.getContentType();
//利用浏览器开发者模式下可见的content-type,判断文件类型
//Content-Type: application/x-www-form-urlencoded
if (!CONTENT_TYPES.contains(contentType)){
// 文件类型不合法,直接返回null
LOGGER.info("文件类型不合法:{}", originalFilename);
return null;
}
try {
// 校验文件的内容
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
if (bufferedImage == null){
LOGGER.info("文件内容不合法:{}", originalFilename);
return null;
}
// 保存到服务器
file.transferTo(new File("C:\\Users\\image\\" + originalFilename));
// 生成url地址,返回
return "http://image.leyou.com/" + originalFilename;
} catch (IOException e) {
LOGGER.info("服务器内部错误:{}", originalFilename);
e.printStackTrace();
}
return null;
}
}
(3)使用Nginx代理,实现域名访问
进入Nginx的安装路径E:\toolsoftware\nginx-1.14.0\nginx-1.14.0\conf,修改

添加一个server,如下配置
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 C:\\Users\\image;
}
}
重新加载Nginx

(4)修改host解析

(5)效果图

(6)修改Nginx配置文件
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;
}
location / {
proxy_pass http://127.0.0.1:10010;
proxy_connect_timeout 600;
proxy_read_timeout 600;
}
(7)重启nginx,再次上传,发现跟上次的状态码已经不一样了,但是依然报错


不过庆幸的是,这个错误已经不是第一次见了,跨域问题。

package lucky.leyou.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 利用cors解决跨域问题
*/
@Configuration
public class LeyouCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允许的域,不要写*,否则cookie就无法使用了
config.addAllowedOrigin("http://manage.leyou.com");
//2) 是否发送Cookie信息
config.setAllowCredentials(true);
//3) 允许的请求方式
config.addAllowedMethod("*");
// 4)允许的头信息
config.addAllowedHeader("*");
//2.添加映射路径,我们拦截一切请求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}
(8)最终效果
<1>若文件类型不符合

<2>若类型符合
