java 在Netty中处理multipart/form-data类型的请求并获取文件

一、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();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值