020 文件(图片)上传功能---涉及switchhost和Nginx的使用
文件的上传并不只是在品牌管理中有需求,以后的其它服务也可能需要,因此我们创建一个独立的微服务,专门处理各种上传。
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>若类型符合
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)