一、multipartFile与file之间相互转换(了解)
// file 类型转换为 multipartFile
File file = new File("读取文件路径");
MultipartFile multipartFile;
try (FileInputStream input = new FileInputStream(file)) {
multipartFile = new MockMultipartFile(file.getName(), input);
} catch (IOException e) {
throw new RuntimeException();
}
System.out.println("F -> M 成功");
// multipartFile 类型转换为 file
try (InputStream ins = multipartFile.getInputStream();
FileOutputStream os = new FileOutputStream("输出文件路径")) {
int bytesRead;
int bytes = 1024;
byte[] buffer = new byte[bytes];
while ((bytesRead = ins.readNBytes(buffer, 0, bytes)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("M -> F 成功");
二、通过feign发送multipart/form-data类型文件请求
@Service
@FeignClient(name = "在nacos上请求的服务端名称")
public interface InsideApi {
@PostMapping(consumes = "multipart/form-data")
JsonResult<Object> send(@RequestPart("文件名") MultipartFile file);
}
三、使用FullHttpRequest对传送数据进行解析
import cn.hutool.core.util.CharsetUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpVersion;
import org.springframework.stereotype.Component;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
@Slf4j
@Component
@ChannelHandler.Sharable
public class BusiInHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("channel active............");
}
@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) {
// 检查是否为multipart请求
if (HttpPostRequestDecoder.isMultipart(fullHttpRequest)) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(fullHttpRequest);
decoder.offer(fullHttpRequest);
List<InterfaceHttpData> bodyHttpDatas = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : bodyHttpDatas) {
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
// 此处处理表单数据
log.info("==========Attribute处理==========");
Attribute attribute = (Attribute) data;
attribute.getName();
// ......
} else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
// 此处处理文件上传
log.info("==========FileUpload处理==========");
FileUpload fileUpload = (FileUpload) data;
try (FileOutputStream out = new FileOutputStream("文件保存路径" + fileUpload.getFilename())) {
// 获取文件内容
ByteBuf byteBuf = fileUpload.getByteBuf();
// 创建与文件内容长度一致的byte数组
byte[] byteArray = new byte[byteBuf.readableBytes()];
// 将文件内容读取到数组中
byteBuf.readBytes(byteArray);
out.write(byteArray);
// 释放byteBuf
ReferenceCountUtil.release(byteBuf);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 其他处理:
// 将发送内容转换为字符串 可在此处获取可用数据
fullHttpRequest.content().toString(io.netty.util.CharsetUtil.UTF_8);
// 请求头相关处理
fullHttpRequest.headers().get("请求头内容字段");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
log.info("channel read complete......");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error(cause.toString());
ctx.close();
}
public void doReturn(ChannelHandlerContext ctx, JsonResult resp) {
String respJsonStr = JSON.toJSONString(resp);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(respJsonStr, CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
log.info("response message send, remoteAddress:[{}], msg:[{}]", ctx.channel().remoteAddress(), respJsonStr);
}
}
四、netty编解码器部分
@Slf4j
@Service
public class BusiInServer extends Server {
@Autowired
private BusiInHandler busiHandler;
@Override
public void start(LocalServerProperties localServerParam) throws Exception {
log.info("HttpServer Configuration[{}]", localServerParam.toString());
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
// 设置循环线程组事例
bootstrap.group(boss, worker);
// 设置channel工厂
bootstrap.channel(NioServerSocketChannel.class);
// 设置管道
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel socketChannel) {
// 此处使用默认的http编解码器
socketChannel.pipeline().addLast(new HttpServerCodec());
// 自定义http解码器
// socketChannel.pipeline().addLast(new BusiInDecoder());
// socketChannel.pipeline().addLast(new HttpResponseEncoder());
// 消息聚合器,1024x1024为接收的最大报文长度
socketChannel.pipeline().addLast("httpAggregator", new HttpObjectAggregator(1024 * 1024));
socketChannel.pipeline().addLast(busiHandler);
}
});
ChannelFuture f = bootstrap.bind(localServerParam.getPort()).sync();
log.info("服务[{}][{}] 启动完成,监听端口 : [{}]", localServerParam.getLocalServerNo(),
localServerParam.getLocalServerDesc(), f.channel().localAddress());
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
} finally {
worker.shutdownGracefully();
boss.shutdownGracefully();
}
}
}