From 83b47a2be73dc7c4c7d5ac86cfc5ace0f8cc095b Mon Sep 17 00:00:00 2001 From: winLsy <18332763730@163.com> Date: Sat, 3 Feb 2018 16:14:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9F=BA=E4=BA=8Enetty?= =?UTF-8?q?=E7=9A=84nio=E5=AE=9E=E7=8E=B0=E7=9A=84websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/response/ServerResponse.java | 264 +++++++++--------- boot-starter/boot-starter-netty/README.md | 23 ++ boot-starter/boot-starter-netty/pom.xml | 39 +++ .../starter/netty/config/NettyConfig.java | 22 ++ .../fast/boot/starter/netty/package-info.java | 1 + .../websocket/WebSocketChannelHandler.java | 30 ++ .../netty/websocket/WebSocketHandler.java | 159 +++++++++++ .../netty/websocket/WebSocketMain.java | 33 +++ .../starter/netty/websocket/package-info.java | 1 + boot-starter/pom.xml | 1 + .../fast/gateway/filter/PreRequestFilter.java | 6 +- .../controller/RestfulEurekaController.java | 2 - 12 files changed, 444 insertions(+), 137 deletions(-) create mode 100644 boot-starter/boot-starter-netty/README.md create mode 100644 boot-starter/boot-starter-netty/pom.xml create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/config/NettyConfig.java create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/package-info.java create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketChannelHandler.java create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketHandler.java create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketMain.java create mode 100644 boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/package-info.java diff --git a/boot-starter/boot-starter-common/src/main/java/com/micro/fast/boot/starter/common/response/ServerResponse.java b/boot-starter/boot-starter-common/src/main/java/com/micro/fast/boot/starter/common/response/ServerResponse.java index eacfc46..0b7d32a 100644 --- a/boot-starter/boot-starter-common/src/main/java/com/micro/fast/boot/starter/common/response/ServerResponse.java +++ b/boot-starter/boot-starter-common/src/main/java/com/micro/fast/boot/starter/common/response/ServerResponse.java @@ -1,132 +1,132 @@ -package com.micro.fast.boot.starter.common.response; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; - -/** - * 统一服务响应类,方法返回值 - * 序列化中不包含为空值的字段 - * @author lishouyu 18332763730@163.com 2017/10/02 - * @version 1.0 - * @since 1.0 - */ -@JsonIgnoreProperties(ignoreUnknown = true) -@JsonInclude(JsonInclude.Include.NON_EMPTY) -public class ServerResponse { - /** - * 获取数据返回的提示数据字典码 - */ - private Integer code; - /** - * 获取数据成功或者失败的时候提示的消息 - */ - private String msg; - /** - * 返回的数据 - */ - T data; - - /** - * 所有的构造方法均为私有,不允许外部直接调用构造方法 - */ - public ServerResponse() { - - } - - private ServerResponse(Integer code) { - this(code, null, null); - } - - private ServerResponse(Integer code, String msg) { - this(code, msg, null); - } - - /** - * 为了避免T 为string的时候调用的是 上面的构造方法,需要对构造方法进行包装。构造方法设置为私有,不允许外部调用 - * - * @param code  响应代码 - * @param data  相应数据 - */ - private ServerResponse(Integer code, T data) { - this(code, null, data); - } - - private ServerResponse(Integer code, String msg, T data) { - this.code = code; - this.msg = msg; - this.data = data; - } - - public Integer getCode() { - return code; - } - - public void setCode(Integer code) { - this.code = code; - } - - public String getMsg() { - return msg; - } - - public void setMsg(String msg) { - this.msg = msg; - } - - public T getData() { - return data; - } - - public void setData(T data) { - this.data = data; - } - - /** - * 返回代码是小于等于0的时候表示请求数据失败,或者进行验证时失败 - * - * @return 是否成功 - */ - @JsonIgnore //使其不再json序列化结果之中 - public boolean isSuccess() { - return BaseConst.ServerResponseCode.SUCCESS.getCode().intValue() == this.code; - } - - //请求成功 - public static ServerResponse success() { - - return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode()); - } - - public static ServerResponse successMsg(String msg) { - - return new ServerResponse( - BaseConst.ServerResponseCode.SUCCESS.getCode(), - msg); - } - - public static ServerResponse successData(T data) { - - return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode(), - data); - } - - public static ServerResponse successMsgData(String msg, T data) { - - return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode(), - msg, data); - } - - //请求失败 - public static ServerResponse error() { - return new ServerResponse(BaseConst.ServerResponseCode.ERROR.getCode()); - } - - public static ServerResponse errorMsg(String msg) { - return new ServerResponse(BaseConst.ServerResponseCode.ERROR.getCode(), msg); - } - - public static ServerResponse errorCodeMsg(Integer code, String msg) { - return new ServerResponse(code, msg); - } -} +package com.micro.fast.boot.starter.common.response; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * 统一服务响应类,方法返回值 + * 序列化中不包含为空值的字段 + * @author lishouyu 18332763730@163.com 2017/10/02 + * @version 1.0 + * @since 1.0 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class ServerResponse { + /** + * 获取数据返回的提示数据字典码 + */ + private Integer code; + /** + * 获取数据成功或者失败的时候提示的消息 + */ + private String msg; + /** + * 返回的数据 + */ + T data; + + /** + * 所有的构造方法均为私有,不允许外部直接调用构造方法 + */ + public ServerResponse() { + + } + + private ServerResponse(Integer code) { + this(code, null, null); + } + + private ServerResponse(Integer code, String msg) { + this(code, msg, null); + } + + /** + * 为了避免T 为string的时候调用的是 上面的构造方法,需要对构造方法进行包装。构造方法设置为私有,不允许外部调用 + * + * @param code  响应代码 + * @param data  相应数据 + */ + private ServerResponse(Integer code, T data) { + this(code, null, data); + } + + private ServerResponse(Integer code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + /** + * 返回代码是小于等于0的时候表示请求数据失败,或者进行验证时失败 + * + * @return 是否成功 + */ + @JsonIgnore //使其不再json序列化结果之中 + public boolean isSuccess() { + return BaseConst.ServerResponseCode.SUCCESS.getCode().intValue() == this.code; + } + + //请求成功 + public static ServerResponse success() { + + return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode()); + } + + public static ServerResponse successMsg(String msg) { + + return new ServerResponse( + BaseConst.ServerResponseCode.SUCCESS.getCode(), + msg); + } + + public static ServerResponse successData(T data) { + + return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode(), + data); + } + + public static ServerResponse successMsgData(String msg, T data) { + + return new ServerResponse(BaseConst.ServerResponseCode.SUCCESS.getCode(), + msg, data); + } + + //请求失败 + public static ServerResponse error() { + return new ServerResponse(BaseConst.ServerResponseCode.ERROR.getCode()); + } + + public static ServerResponse errorMsg(String msg) { + return new ServerResponse(BaseConst.ServerResponseCode.ERROR.getCode(), msg); + } + + public static ServerResponse errorCodeMsg(Integer code, String msg) { + return new ServerResponse(code, msg); + } +} diff --git a/boot-starter/boot-starter-netty/README.md b/boot-starter/boot-starter-netty/README.md new file mode 100644 index 0000000..59bf57b --- /dev/null +++ b/boot-starter/boot-starter-netty/README.md @@ -0,0 +1,23 @@ +# boot-starter-netty项目说明 +## 几种io的对比 +io类型 | 通讯模型 | 描述 +---|------------|---- +bio | 阻塞同步通讯 | 使用一个线程处理一个请求 +伪nio |阻塞同步通讯 | 使用线程池,使用n个线程处理m个请求 +nio | 非阻塞同步通讯 | 使用一个线程处理多个请求,难度大,不方便调试 +aio | 非阻塞异步通讯 | 难度大,不方便调试 +## jdk自带的nio和netty的对比 +- jdk自带的nio的api繁杂、工作量和工作难度大、入门门槛高需要精通多线程、jdk的nio存在bug会出现selector空轮训导致cpu跑满 +- netty商用成功。可扩展性强、入门门槛低、成熟稳定、性能强 +## websocket简单介绍 +### websocket建立连接 +客户端发起握手请求,服务端响应请求,建立连接。 +### websocket的生命周期 +#### 打开事件 +#### 消息事件 +#### 错误事件 +- 能感知websocket所有方法的错误 +#### 关闭事件 +- 服务端端关闭底层tcp连接 +- 客户端发起TCP close +## 基于netty实现websocket协议 diff --git a/boot-starter/boot-starter-netty/pom.xml b/boot-starter/boot-starter-netty/pom.xml new file mode 100644 index 0000000..b61121f --- /dev/null +++ b/boot-starter/boot-starter-netty/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + boot-starter-netty + jar + + boot-starter-netty + Spring boot starter + + + com.micro.fast + boot-starter + 0.0.1-SNAPSHOT + + + + + + io.netty + netty-all + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + + boot-starter-netty + + diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/config/NettyConfig.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/config/NettyConfig.java new file mode 100644 index 0000000..354d805 --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/config/NettyConfig.java @@ -0,0 +1,22 @@ +package com.micro.fast.boot.starter.netty.config; + +import io.netty.channel.group.ChannelGroup; +import io.netty.channel.group.DefaultChannelGroup; +import io.netty.util.concurrent.GlobalEventExecutor; +import lombok.Getter; +import lombok.Setter; + +/** + * netty的全局配置类 + * @author lsy + */ +@Getter +@Setter +public class NettyConfig { + /** + * 存储每一个客户端接入进来的channel对象 + */ + public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); + + +} diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/package-info.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/package-info.java new file mode 100644 index 0000000..ad28071 --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/package-info.java @@ -0,0 +1 @@ +package com.micro.fast.boot.starter.netty; \ No newline at end of file diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketChannelHandler.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketChannelHandler.java new file mode 100644 index 0000000..d0ff3f4 --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketChannelHandler.java @@ -0,0 +1,30 @@ +package com.micro.fast.boot.starter.netty.websocket; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpObjectEncoder; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.stream.ChunkedWriteHandler; + + +/** + * 初始化连接时的各个组件 + * @author lsy + */ +public class WebSocketChannelHandler extends ChannelInitializer{ + + /** + * + * @param socketChannel + * @throws Exception + */ + @Override + protected void initChannel(SocketChannel socketChannel) throws Exception { + socketChannel.pipeline().addLast("http-codec",new HttpServerCodec()); + socketChannel.pipeline().addLast("aggregator", new HttpObjectAggregator(65536)); + socketChannel.pipeline().addLast("http-chunked",new ChunkedWriteHandler()); + socketChannel.pipeline().addLast("handler",new WebSocketChannelHandler()); + } +} diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketHandler.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketHandler.java new file mode 100644 index 0000000..27f2abd --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketHandler.java @@ -0,0 +1,159 @@ +package com.micro.fast.boot.starter.netty.websocket; + +import com.micro.fast.boot.starter.netty.config.NettyConfig; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.websocketx.*; + +import java.nio.charset.Charset; +import java.util.Date; + +/** + * 接收/处理/响应客户端websocket请求的核心业务处理类 + * @author lsy + */ +public class WebSocketHandler extends SimpleChannelInboundHandler{ + + private WebSocketServerHandshaker handshaker; + + private static final String webSocketUrl = "ws://localhost:8888/websocket"; + /** + * 客户端和服务端创建连接的时候调用 + * @param ctx + * @throws Exception + */ + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + NettyConfig.group.add(ctx.channel()); + } + + /** + * 客户端和服务端断开连接的时候调用 + * @param ctx + * @throws Exception + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + NettyConfig.group.remove(ctx.channel()); + } + + /** + * 服务端接收客户端数据完成时候调用 + * @param ctx + * @throws Exception + */ + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + ctx.flush(); + } + + /** + * 工程出现异常的时候调用 + * @param ctx + * @param cause + * @throws Exception + */ + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + ctx.close(); + } + + /** + * 服务端处理客户端webSocket请求的核心方法 + * @param channelHandlerContext + * @param msg + * @throws Exception + */ + @Override + protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception { + //处理客户端向服务端发起http握手请求的业务 + if (msg instanceof FullHttpRequest){ + handHttpRequestChannelHandler(channelHandlerContext,(FullHttpRequest)msg); + }else if(msg instanceof WebSocketFrame){ + //处理websocket连接请求的业务 + handWebSocketFrameChannelHandler(channelHandlerContext,(WebSocketFrame)msg); + } + } + + /** + * 处理http请求 + * @param ctx + * @param request + */ + private void handHttpRequestChannelHandler(ChannelHandlerContext ctx,FullHttpRequest request){ + if(request.getDecoderResult().isFailure() || "websocket".equals(request.headers().get("Upgrade"))){ + sendHttpResponse(ctx,request,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); + return; + }else{ + WebSocketServerHandshakerFactory webSocketServerHandshakerFactory = new WebSocketServerHandshakerFactory( + webSocketUrl,null,false); + //创建webSocket连接 + handshaker = webSocketServerHandshakerFactory.newHandshaker(request); + if (handshaker == null) { + WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); + }else { + handshaker.handshake(ctx.channel(),request); + } + } + } + + /** + * 服务端向客户端发送响应 + * @param ctx + * @param request + * @param response + */ + private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest request + , DefaultFullHttpResponse response){ + //判断请求是否成功 + if (response.getStatus().code()!= 200){ + // 返回请求 + ByteBuf byteBuf = Unpooled.copiedBuffer(response.getStatus().toString(), Charset.forName("UTF-8")); + response.content().writeBytes(byteBuf); + byteBuf.release(); + } + ChannelFuture channelFuture = ctx.channel().writeAndFlush(response); + if (response.getStatus().code()!=200){ + // 关闭连接 + channelFuture.addListener(ChannelFutureListener.CLOSE); + } + } + + /** + * 处理客户端和服务端之间的webSocket业务 + * @param ctx + * @param webSocketFrame + */ + private void handWebSocketFrameChannelHandler(ChannelHandlerContext ctx,WebSocketFrame webSocketFrame){ + // 判断是否是关闭websocket连接请求 + if (webSocketFrame instanceof CloseWebSocketFrame){ + handshaker.close(ctx.channel(),(CloseWebSocketFrame)webSocketFrame.retain()); + } + // 判断是否是pin消息 + if (webSocketFrame instanceof PingWebSocketFrame){ + ctx.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain())); + return; + } + // 判断是否是二进制消息,如果是二进制消息,抛出异常 + if (!(webSocketFrame instanceof TextWebSocketFrame)){ + throw new RuntimeException("不支持二进制消息的传递"); + } + // 返回消息 + TextWebSocketFrame textWebSocketFrame = (TextWebSocketFrame) (webSocketFrame); + //获取客户端向服务端发送的消息 + String text = textWebSocketFrame.text(); + TextWebSocketFrame textWebSocketFrame1 = new TextWebSocketFrame(new Date().toString()+":"+text); + + //服务端向每个连接上来的客户端群发消息 + NettyConfig.group.writeAndFlush(textWebSocketFrame1); + + } +} diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketMain.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketMain.java new file mode 100644 index 0000000..e5d0125 --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/WebSocketMain.java @@ -0,0 +1,33 @@ +package com.micro.fast.boot.starter.netty.websocket; + +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; + +/** + * webSocket启动的入口 + * @author lsy + */ +public class WebSocketMain { + public static void main(String[] args) { + EventLoopGroup bossGroup = new NioEventLoopGroup(); + NioEventLoopGroup workGroup = new NioEventLoopGroup(); + try { + ServerBootstrap serverBootstrap = new ServerBootstrap(); + serverBootstrap.group(bossGroup,workGroup); + serverBootstrap.channel(NioServerSocketChannel.class); + serverBootstrap.childHandler(new WebSocketChannelHandler()); + System.out.println("服务端开启等待客户端连接"); + Channel channel = serverBootstrap.bind(8888).sync().channel(); + channel.closeFuture().sync(); + }catch (Exception e){ + + }finally { + // 优雅的退出程序 + bossGroup.shutdownGracefully(); + workGroup.shutdownGracefully(); + } + } +} diff --git a/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/package-info.java b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/package-info.java new file mode 100644 index 0000000..a37d0a9 --- /dev/null +++ b/boot-starter/boot-starter-netty/src/main/java/com/micro/fast/boot/starter/netty/websocket/package-info.java @@ -0,0 +1 @@ +package com.micro.fast.boot.starter.netty.websocket; \ No newline at end of file diff --git a/boot-starter/pom.xml b/boot-starter/pom.xml index 5678fc1..75529cb 100644 --- a/boot-starter/pom.xml +++ b/boot-starter/pom.xml @@ -18,6 +18,7 @@ boot-starter-common boot-starter-util boot-starter-maven-plugin + boot-starter-netty boot-starter-fastdfs-client boot-starter-elasticsearch boot-starter-security-oauth diff --git a/ms/gateway/src/main/java/com/micro/fast/gateway/filter/PreRequestFilter.java b/ms/gateway/src/main/java/com/micro/fast/gateway/filter/PreRequestFilter.java index d654b83..99cfa4c 100644 --- a/ms/gateway/src/main/java/com/micro/fast/gateway/filter/PreRequestFilter.java +++ b/ms/gateway/src/main/java/com/micro/fast/gateway/filter/PreRequestFilter.java @@ -9,7 +9,6 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; /** * 对accessToken进行校验 @@ -42,10 +41,11 @@ public class PreRequestFilter extends ZuulFilter { HttpServletRequest request = requestContext.getRequest(); ServerResponse validate = ValidateJwtToken.validate(request, signingKey); if (validate.isSuccess()) { - //对请求进行后续处理 + //todo 对访问权限进行判断 + // 对请求进行后续处理 requestContext.setSendZuulResponse(true); }else { - //不进行后续操作,返回401状态码 + // 不进行后续操作,返回401状态码 requestContext.setSendZuulResponse(false); requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } diff --git a/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java b/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java index 5663e7f..28333fd 100644 --- a/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java +++ b/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java @@ -18,8 +18,6 @@ import com.netflix.eureka.util.StatusInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang.StringUtils; -import org.apache.http.HttpStatus; -import org.mortbay.jetty.Server; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*;