本文参考《Netty权威指南》

NettyApplication
package com.xh.netty;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class NettyApplication { public static void main(String[] args) { SpringApplication.run(NettyApplication.class, args); String[] argList =args;
System.out.println("+++++++++++++Simple Netty HttpFileServer+++++++++++++++");
System.out.println("+ VERSION 1.0.1 +");
System.out.println("+ AUTHER:XH +");
System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++");
if (args.length==0){
System.out.println("Usage: java -var thisPackageName.jar [-options][args...]");
System.out.println("Use -h for more infomation");
System.out.println("default port is 8080 , webRoot is /root ");
}else {
for (int i=0;i<argList.length;i++){
if (argList[i].equalsIgnoreCase("-h")){
System.out.println("-p your Listern port");
System.out.println("-f your webRoot path");
System.out.println("Example:java -jar netty-0.0.1-SNAPSHOT.jar -p 80 -f /root");
return;
}else {
if (argList[i].equalsIgnoreCase("-p")){
try{
HttpFileServer.PORT=Integer.valueOf(argList[i+1]);
}catch (NumberFormatException e){
System.out.println("wrong number for you port");
System.out.println("Use -h for more infomation");
e.printStackTrace();
return;
}
}
if (argList[i].equalsIgnoreCase("-f")){
try{
HttpFileServer.WEBROOT=argList[i+1];
}catch (Exception e){
System.out.println("wrong path for you webRoot");
System.out.println("Use -h for more infomation");
e.printStackTrace();
return;
}
}
}
}
} try {
HttpFileServer.main();
} catch (InterruptedException e) {
e.printStackTrace();
} }
}
HttpFileServer
package com.xh.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler; /**
* Created by root on 8/14/17.
*/
public class HttpFileServer { public static String WEBROOT = "/root";
public static int PORT = 8080; public void run(final int port , final String url) throws InterruptedException {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();
try{
ServerBootstrap bootstrap=new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast("http-decoder",new HttpRequestDecoder());
socketChannel.pipeline().addLast("http-aggregator",new HttpObjectAggregator(65536));
socketChannel.pipeline().addLast("http-encoder",new HttpResponseEncoder());
socketChannel.pipeline().addLast("http-chunked",new ChunkedWriteHandler());
socketChannel.pipeline().addLast("fileServerHandler",new HttpFileServerHandler(url)); }
});
ChannelFuture future = bootstrap.bind("127.0.0.1",port).sync();
System.out.println("服务器已启动>>网址:"+"127.0.0.1:"+port+url);
future.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
} } public static void main() throws InterruptedException { new HttpFileServer().run(PORT,WEBROOT);
}
}
HttpFileServerHandler
package com.xh.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil; import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.net.URLDecoder;
import java.util.regex.Pattern; import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpHeaderUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpHeaderUtil.setContentLength;
import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; /**
* Created by root on 8/14/17.
*/
public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{ private final String url;
String WEBROOT = HttpFileServer.WEBROOT;
public HttpFileServerHandler(String url) {
this.url = url;
} protected void messageReceived(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception {
if (!fullHttpRequest.decoderResult().isSuccess()){
sendError(channelHandlerContext, HttpResponseStatus.BAD_REQUEST);
return;
} if (fullHttpRequest.method()!= HttpMethod.GET){
sendError(channelHandlerContext,HttpResponseStatus.METHOD_NOT_ALLOWED);
return;
} String uri=fullHttpRequest.uri();
if (uri==null||uri.trim().equalsIgnoreCase("")){
uri="/";
}
if (uri.trim().equalsIgnoreCase("/")){
uri= WEBROOT;
}
if(!uri.startsWith(WEBROOT)){
uri= WEBROOT +uri;
}
final String path=sanitizeUri(uri);
if (path==null){
sendError(channelHandlerContext,HttpResponseStatus.FORBIDDEN);
return;
} File file=new File(path);
if (file.isHidden()||!file.exists()){
sendError(channelHandlerContext,HttpResponseStatus.NOT_FOUND);
return;
} if (file.isDirectory()){
if (uri.endsWith("/")){
senfListing(channelHandlerContext,file); }else {
sendRedirect(channelHandlerContext,uri+"/");
} return;
} if (!file.isFile()){
sendError(channelHandlerContext,HttpResponseStatus.FORBIDDEN);
return;
} RandomAccessFile randomAccessFile=null;
try{
randomAccessFile=new RandomAccessFile(file,"r");
}catch (FileNotFoundException e){
e.printStackTrace();
sendError(channelHandlerContext,HttpResponseStatus.NOT_FOUND);
return;
} Long fileLength=randomAccessFile.length();
HttpResponse httpResponse=new DefaultHttpResponse(HTTP_1_1,OK);
setContentLength(httpResponse,fileLength);
setContentTypeHeader(httpResponse,file); if (isKeepAlive(fullHttpRequest)){
httpResponse.headers().set(CONNECTION,KEEP_ALIVE);
} channelHandlerContext.writeAndFlush(httpResponse);
ChannelFuture sendFileFuture = channelHandlerContext.write(
new ChunkedFile(randomAccessFile,0,fileLength,8192),channelHandlerContext.newProgressivePromise()); sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total<0){
System.err.println("progress:"+progress);
}else {
System.err.println("progress:"+progress+"/"+total);
}
} public void operationComplete(ChannelProgressiveFuture future) {
System.err.println("complete");
}
}); ChannelFuture lastChannelFuture=channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (!isKeepAlive(fullHttpRequest)){
lastChannelFuture.addListener(ChannelFutureListener.CLOSE ); } } @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
if (ctx.channel().isActive()){
sendError(ctx,INTERNAL_SERVER_ERROR);
}
} private static final Pattern INSECURE_URI=Pattern.compile(".*[<>&\"].*"); public String sanitizeUri(String uri){
try{
uri= URLDecoder.decode(uri,"UTF-8");
}catch (Exception e){
try{
uri= URLDecoder.decode(uri,"ISO-8859-1");
}catch (Exception ew){
ew.printStackTrace();
}
} if (!uri.startsWith(url)){
return null; } if (!uri.startsWith("/")){
return null; } uri=uri.replace('/',File.separatorChar);
if (uri.contains(File.separator+'.')||uri.startsWith(".")||uri.endsWith(".")||INSECURE_URI.matcher(uri).matches()){
return null;
} return uri;//System.getProperty("user.dir")+uri } private static final Pattern ALLOWED_FILE_NAME=Pattern.compile("[a-zA-Z0-9\\.]*");
private void senfListing(ChannelHandlerContext channelHandlerContext, File dir) {
FullHttpResponse response=new DefaultFullHttpResponse(HTTP_1_1,OK);
response.headers().set(CONTENT_TYPE,"text/html;charset=UTF-8");
StringBuilder builder =new StringBuilder();
String dirPath=dir.getPath();
builder.append("<!DOCTYPE html> \r\n");
builder.append("<html><head><title>");
builder.append(dirPath);
builder.append("目录:");
builder.append("</title></head><body>\r\n");
builder.append("<h3>");
builder.append(dirPath).append("目录:");
builder.append("</h3>\r\n");
builder.append("<ul>");
builder.append("<li>链接:<a href=\"../\">..</a></li>\r\n");
for (File f:dir.listFiles()){
if (f.isHidden()||!f.canRead()){
continue;
}
String fname=f.getName();
if (!ALLOWED_FILE_NAME.matcher(fname).matches()){
continue;
}
builder.append("<li>链接:<a href=\" ");
builder.append(fname);
builder.append("\" >");
builder.append(fname);
builder.append("</a></li>\r\n");
}
builder.append("</ul></body></html>\r\n"); ByteBuf byteBuf= Unpooled.copiedBuffer(builder, CharsetUtil.UTF_8);
response.content().writeBytes(byteBuf);
byteBuf.release();
channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } private void sendRedirect(ChannelHandlerContext channelHandlerContext, String newUri) {
FullHttpResponse response=new DefaultFullHttpResponse(HTTP_1_1,FOUND);
response.headers().set(LOCATION,newUri);
channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
} private void sendError(ChannelHandlerContext channelHandlerContext, HttpResponseStatus status) {
FullHttpResponse response=new DefaultFullHttpResponse(
HTTP_1_1,status,Unpooled.copiedBuffer("Failure: "+status.toString()+"\r\n",
CharsetUtil.UTF_8));
response.headers().set(CONTENT_TYPE,"text/plain; charset=UTF-8");
channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } private void setContentTypeHeader(HttpResponse httpResponse, File file) { MimetypesFileTypeMap mimetypesFileTypeMap=new MimetypesFileTypeMap();
httpResponse.headers().set(CONTENT_TYPE,mimetypesFileTypeMap.getContentType(file.getPath()));
} }

打包发布:

cd 到项目target同级目录

mvn clean package

然后 cd target/

java -jar netty-0.0.1-SNAPSHOT.jar -h运行

Netty+SpringBoot写一个基于Http协议的文件服务器的更多相关文章

  1. 教你如何使用Java手写一个基于链表的队列

    在上一篇博客[教你如何使用Java手写一个基于数组的队列]中已经介绍了队列,以及Java语言中对队列的实现,对队列不是很了解的可以我上一篇文章.那么,现在就直接进入主题吧. 这篇博客主要讲解的是如何使 ...

  2. 使用springboot写一个简单的测试用例

    使用springboot写一个简单的测试用例 目录结构 pom <?xml version="1.0" encoding="UTF-8"?> < ...

  3. 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发

    ''' 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发 ''' client import socket import time client = socket.socket() clie ...

  4. 闲来无事,写个基于UDP协议的Socket通讯Demo

    项目一期已经做完,二期需求还没定稿,所以最近比较闲. 上一篇写的是TCP协议,今天写一下UDP协议.TCP是有连接协议,所以发送和接收消息前客户端和服务端需要建立连接:UDP是无连接协议,所以发送消息 ...

  5. [PHP]用PHP自己写一个基于zoomeye的api(偷懒必备quq)

    0x01 起因 因为手速慢,漏洞刷不过别人,一个个手补确实慢,所以想自己写一个api,一键抓取zoomeye的20页,然后就可以打批量了 ovo(真是太妙了!) 0x02 动工       1.抓包做 ...

  6. 网络编程—【自己动手】用C语言写一个基于服务器和客户端(TCP)!

    如果想要自己写一个服务器和客户端,我们需要掌握一定的网络编程技术,个人认为,网络编程中最关键的就是这个东西--socket(套接字). socket(套接字):简单来讲,socket就是用于描述IP地 ...

  7. 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  8. 专题十一:实现一个基于FTP协议的程序——文件上传下载器

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  9. SpringBoot写一个登陆注册功能,和期间走的坑

    文章目录 前言 1. 首先介绍项目的相关技术和工具: 2. 首先创建项目 3. 项目的结构 3.1实体类: 3.2 Mapper.xml 3.3 mapper.inteface 3.4 Service ...

随机推荐

  1. Hopcroft-Carp 算法模板 自用

    #include <iostream> #include <cstdio> #include <cstring> #include <queue> #d ...

  2. day26 单继承

    继承是创建新类的一种方式,目的就为了减少代码.表达了子类是父类的关系,比如狗是动物,教授是老师一个类可以多个类继承,所有语言都是这样的一个类可以继承多个父类 ,只有python支持多继承子类可以找到父 ...

  3. 【POI每日题解 #8】DYN-Dynamite

    你问蒟蒻为什么一天写两篇每日题解? 难道每日坚果你不能一天吃两包吗? 题目链接 哇…这道题第一反应就是二分答案[太明显了 枚举答案 就那个“关键节点到这些点中距离的最小值的最大值”[蒟蒻读了好几遍…… ...

  4. 【题解】 bzoj3956: Count (ST表+单调栈)

    题面 Solution 看了一点点题解,自己又刚了\(2h30min\),刚了出来qwq,我好菜啊qwq 貌似这道题是BZOJ 4826的弱化,弱化都不会qwq凉凉 Solution 首先你可以考虑, ...

  5. 自学Linux Shell12.2-test命令

    点击返回 自学Linux命令行与Shell脚本之路 12.2-test命令 if-then语句不能测试命令退出状态码之外的条件,test命令提供了在if-then语句中测试不同条件的途径. 如果tes ...

  6. 有标号的DAG计数(FFT)

    有标号的DAG计数系列 有标号的DAG计数I 题意 给定一正整数\(n\),对\(n\)个点有标号的有向无环图(可以不连通)进行计数,输出答案\(mod \ 10007\)的结果.\(n\le 500 ...

  7. 冬令营前的一些计划&记录

    冬令营前的一些计划&记录 计划 yyb发现自己很多以前学过的东西完完全全不记得了,所以在接下来的时间里可能会留下多篇复习向的博客,当然也可能因为觉得没有必要复习而到处乱做题. 现在先大概归类一 ...

  8. 洛谷 P4100 [HEOI2013]钙铁锌硒维生素 解题报告

    P4100 [HEOI2013]钙铁锌硒维生素 题目描述 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加 宇宙比赛的饮食. 众所周知,前往宇宙的某个星球,通常要花费好长好长的时间, ...

  9. 利用快排partition求前N小的元素

    求前k小的数,一般人的想法就是先排序,然后再遍历,但是题目只是求前N小,没有必要完全排序,所以可以想到部分排序,而能够部分排序的排序算法我能想到的就是堆排序和快排了. 第一种思路,局部堆排序. 首先, ...

  10. pymysql 在数据库中插入空值

    1. 先搞清 ''(空字符串)和 NULL的区别 (1)本质区别: 空字符串是个值 NULL 和Python中的NULL一样,是空值的意思 (2)查询语句的区别: SELECT * FROM test ...