代码实现根据官网提供的example https://github.com/netty/nett...
以及netty官网的api文档 https://netty.io/4.1/api/inde...
项目地址 https://github.com/1433365571...
package server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.util.SelfSignedCertificate; public final class HttpUploadServer { static final boolean SSL = System.getProperty("ssl") != null; static final int PORT = Integer.parseInt(System.getProperty("port", SSL ? "8443" : "8080")); public static void main(String[] args) throws Exception { // Configure SSL. final SslContext sslCtx; if (SSL) { SelfSignedCertificate ssc = new SelfSignedCertificate(); sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build(); } else { sslCtx = null; } EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup); b.channel(NioServerSocketChannel.class); b.handler(new LoggingHandler(LogLevel.INFO)); b.childHandler(new HttpUploadServerInitializer(sslCtx)); Channel ch = b.bind(PORT).sync().channel(); System.err.println("Open your web browser and navigate to " + (SSL ? "https" : "http") + "://127.0.0.1:" + PORT + '/'); ch.closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package server; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpContentCompressor; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.ssl.SslContext; public class HttpUploadServerInitializer extends ChannelInitializer<SocketChannel> { private final SslContext sslCtx; public HttpUploadServerInitializer(SslContext sslCtx) { this.sslCtx = sslCtx; } @Override public void initChannel(SocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); if (sslCtx != null) { pipeline.addLast(sslCtx.newHandler(ch.alloc())); } pipeline.addLast(new HttpRequestDecoder()); pipeline.addLast(new HttpResponseEncoder()); // Remove the following line if you don't want automatic content compression. pipeline.addLast(new HttpContentCompressor()); // pipeline.addLast("http-aggregator", // new HttpObjectAggregator(65536));// 目的是将多个消息转换为单一的request或者response对象 pipeline.addLast(new HttpUploadServerHandler()); } }
package server; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.multipart.*; import io.netty.util.CharsetUtil; import java.io.File; import java.io.IOException; import java.net.URI; public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObject> { private HttpRequest request; private static final String uploadUrl = "/up"; private static final String fromFileUrl = "/post_multipart"; private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk if size exceed private HttpPostRequestDecoder decoder; static { DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file // on exit (in normal // exit) DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on // exit (in normal exit) DiskAttribute.baseDirectory = null; // system temp directory } @Override public void channelInactive(ChannelHandlerContext ctx) { if (decoder != null) { decoder.cleanFiles(); } } protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpRequest) { this.request = (HttpRequest) msg; URI uri = new URI(request.uri()); System.out.println(uri); urlRoute(ctx, uri.getPath()); } if (decoder != null) { if (msg instanceof HttpContent) { // 接收一个新的请求体 decoder.offer((HttpContent) msg); // 将内存中的数据序列化本地 readHttpDataChunkByChunk(); } if (msg instanceof LastHttpContent) { System.out.println("LastHttpContent"); reset(); writeResponse(ctx, "<h1>上传成功</h1>"); } } } // url路由 private void urlRoute(ChannelHandlerContext ctx, String uri) { StringBuilder urlResponse = new StringBuilder(); // 访问文件上传页面 if (uri.startsWith(uploadUrl)) { urlResponse.append(getUploadResponse()); } else if (uri.startsWith(fromFileUrl)) { decoder = new HttpPostRequestDecoder(factory, request); return; } else { urlResponse.append(getHomeResponse()); } writeResponse(ctx, urlResponse.toString()); } private void writeResponse(ChannelHandlerContext ctx, String context) { ByteBuf buf = Unpooled.copiedBuffer(context, CharsetUtil.UTF_8); FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=utf-8"); ctx.channel().writeAndFlush(response); } private String getHomeResponse() { return " <h1> welcome home </h1> "; } private String getUploadResponse() { return "<!DOCTYPE html>/n" + "<html lang=/"en/">/n" + "<head>/n" + " <meta charset=/"UTF-8/">/n" + " <title>Title</title>/n" + "</head>/n" + "<body>/n" + "/n" + "<form action=/"http://127.0.0.1:8080/post_multipart/" enctype=/"multipart/form-data/" method=/"POST/">/n" + "/n" + "/n" + " <input type=/"file/" name=" + " " + "" + "/"YOU_KEY/">/n" + "/n" + " <input type=/"submit/" name=/"send/">/n" + "/n" + "</form>/n" + "/n" + "</body>/n" + "</html>"; } private void readHttpDataChunkByChunk() throws IOException { while (decoder.hasNext()) { InterfaceHttpData data = decoder.next(); if (data != null) { if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) { FileUpload fileUpload = (FileUpload) data; if (fileUpload.isCompleted()) { fileUpload.isInMemory();// tells if the file is in Memory // or on File fileUpload.renameTo(new File(PathUtil.getFileBasePath() + fileUpload.getFilename())); // enable to move into another // File dest decoder.removeHttpDataFromClean(fileUpload); //remove } } } } } private void reset() { request = null; // destroy the decoder to release all resources decoder.destroy(); decoder = null; } }
package server; import java.io.File; public class PathUtil { private static final ClassLoader classLoader = PathUtil.class.getClassLoader(); public static String getFileBasePath() { String os = System.getProperty("os.name"); String basePath; if (os.toLowerCase().startsWith("win")) { basePath = "D:/warehouse/"; } else { basePath = "/root/upload_source"; } basePath = basePath.replace("/", File.separator); return basePath; } public static String getSourcePath(String name) { return classLoader.getResource(name).getPath(); } }
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>nettyHttpUploadServer</groupId> <artifactId>http.upload</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/io.netty/netty-all --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.10.Final</version> </dependency> </dependencies> <!-- <build>--> <!-- <plugins>--> <!-- <plugin>--> <!-- <groupId>org.apache.maven.plugins</groupId>--> <!-- <artifactId>maven-jar-plugin</artifactId>--> <!-- <configuration>--> <!-- <archive>--> <!-- <manifest>--> <!-- <addClasspath>true</addClasspath>--> <!-- <mainClass>server.HttpUploadServer</mainClass>--> <!-- </manifest>--> <!-- </archive>--> <!-- </configuration>--> <!-- </plugin>--> <!-- </plugins>--> <!-- </build>--> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>3.0.0</version> <configuration> <archive> <manifest> <mainClass>server.HttpUploadServer</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>server.HttpUploadServer</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>com.jolira</groupId> <artifactId>onejar-maven-plugin</artifactId> <version>1.4.4</version> <executions> <execution> <goals> <goal>one-jar</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>