一個SpringBoot框架搭建起來的項目發佈接口服務是這樣的java
SpringBoot搭建教程點擊這裏spring
@Controller
@RequestMapping("/v1/product")
public class DocController {
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@ResponseBody
public WebResult search(@PathVariable("id") Integer id) {
logger.debug("獲取指定產品接收產品id=>%d", id);
if (id == null || "".equals(id)) {
logger.debug("產品id不能爲空");
return WebResult.error(ERRORDetail.RC_0101001);
}
return WebResult.success(products.get(id));
}
}
複製代碼
我但願我使用Netty構建的Web服務器也能使用這樣便捷的註解方式去發佈個人接口服務json
public class HttpPipelineInitializer extends ChannelInitializer<Channel> {
//編解碼處理器名稱
public final static String CODEC = "codec";
//HTTP消息聚合處理器名稱
public final static String AGGEGATOR = "aggegator";
//HTTP消息壓縮處理器名稱
public final static String COMPRESSOR = "compressor";
@Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(CODEC, new HttpServerCodec());
pipeline.addLast(AGGEGATOR, new HttpObjectAggregator(512 * 1024));
pipeline.addLast(COMPRESSOR,new HttpContentCompressor());
pipeline.addLast(new AllocHandler());
}
}
複製代碼
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String[] value() default {};
}
複製代碼
public class CettyBootstrap {
private static final Logger logger = LoggerFactory.getLogger(CettyBootstrap.class);
private static final String DEFAULT_SPRING_XMLPATH = "classpath:applicantContext.xml";
private static final String DEFAULT_HTTP_SERVER_BEAN_NAME = "defaultHttpServer";
public static void create() {
create(DEFAULT_SPRING_XMLPATH);
}
public static void create(String springXmlpath) {
if (StringUtils.isEmpty(springXmlpath)) {
springXmlpath = DEFAULT_SPRING_XMLPATH;
}
logger.debug("spring框架配置文件地址爲{}", springXmlpath);
try {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
context.start();
logger.debug("spring框架啓動成功");
try {
context.getBean(DEFAULT_HTTP_SERVER_BEAN_NAME, DefaultHttpServer.class);
} catch (NoSuchBeanDefinitionException ex) {
logger.warn("未配置HttpServer,採用默認配置啓動");
context.getAutowireCapableBeanFactory().createBean(DefaultHttpServer.class);
}
} catch (BeansException e) {
e.printStackTrace();
}
}
}
複製代碼
public class DefaultHttpServer extends ApplicationObjectSupport {
private static final Logger logger = LoggerFactory.getLogger(DefaultHttpServer.class);
private static final String DEFAULT_HTTP_PORT = "8080";
private static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
private String port;
private HandlerMapping handlerMapping;
public void setPort(String port) {
this.port = port;
}
@Override
public void initApplicationContext(ApplicationContext applicationContext) {
beforeInit(applicationContext);
initHandlerMapping(applicationContext);
initServer();
}
void initHandlerMapping(ApplicationContext context) {
try {
this.handlerMapping = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
} catch (NoSuchBeanDefinitionException ex) {
this.handlerMapping = context.getAutowireCapableBeanFactory().createBean(DefaultHandlerMapping.class);
}
}
void initServer() {
logger.debug("初始化服務器");
if (!HttpUtils.isPort(port)) {
logger.warn("端口號不合法,使用默認端口{}", DEFAULT_HTTP_PORT);
port = DEFAULT_HTTP_PORT;
}
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(Integer.parseInt(port)))
.childHandler(new HttpPipelineInitializer(handlerMapping));
ChannelFuture f = b.bind().sync();
logger.info("服務啓動成功,監聽{}端口", port);
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
workerGroup.shutdownGracefully().sync();
bossGroup.shutdownGracefully().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
protected void beforeInit(ApplicationContext applicationContext) {
}
}
複製代碼
public class DefaultHandlerMapping extends ApplicationObjectSupport implements HandlerMapping {
Logger logger = LoggerFactory.getLogger(DefaultHandlerMapping.class);
private static Map<String, HttpHandler> httpHandlerMap = new HashMap<String, HttpHandler>();
@Override
public void initApplicationContext(ApplicationContext context) throws BeansException {
logger.debug("初始化處理匹配器");
Map<String, Object> handles = context.getBeansWithAnnotation(Controller.class);
try {
for (Map.Entry<String, Object> entry : handles.entrySet()) {
logger.debug("加載控制器{}", entry.getKey());
loadHttpHandler(entry.getValue());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
void loadHttpHandler(Object value) throws IllegalAccessException, InstantiationException {
Class clazz = value.getClass();
Object clazzFromInstance = clazz.newInstance();
Method[] method = clazz.getDeclaredMethods();
for (Method m : method) {
if (m.isAnnotationPresent(RequestMapping.class)) {
RequestMapping requestMapping = m.getAnnotation(RequestMapping.class);
for (String url : requestMapping.value()) {
HttpHandler httpHandler = httpHandlerMap.get(url);
if (httpHandler == null) {
logger.info("加載url爲{}的處理器{}", url, m.getName());
httpHandlerMap.put(url, new HttpHandler(clazzFromInstance, m));
} else {
logger.warn("url{}存在相同的處理器", url);
}
}
}
}
}
@Override
public HttpHandler getHadnler(FullHttpRequest request) {
return httpHandlerMap.get(request.uri());
}
}
複製代碼
public class AllocHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
private HandlerMapping handlerMapping;
public AllocHandler(HandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
/* 異常處理 */
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
super.exceptionCaught(ctx, cause);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
HttpHandler httpHandler = handlerMapping.getHadnler(fullHttpRequest);
if (httpHandler != null) {
Object obj = httpHandler.execute(fullHttpRequest);
if (obj instanceof String) {
sendMessage(ctx, obj.toString());
} else {
sendMessage(ctx, JSONObject.toJSONString(obj));
}
} else {
sendError(ctx, HttpResponseStatus.NOT_FOUND);
}
}
private void sendMessage(ChannelHandlerContext ctx, String msg) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
response.headers().set("Content-Type", "text/plain");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
private void sendError(ChannelHandlerContext ctx, HttpResponseStatus httpResponseStatus) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, httpResponseStatus, Unpooled.copiedBuffer(httpResponseStatus.toString(), CharsetUtil.UTF_8));
response.headers().set("Content-Type", "text/plain");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
複製代碼
@Controller
public class TestController {
@RequestMapping("/test")
public String testHandler(FullHttpRequest fullHttpRequest) {
return "1234";
}
@RequestMapping("/zx")
public String zx(FullHttpRequest fullHttpRequest) {
return "zhuxiong";
}
@RequestMapping("/obj")
public Object obj(FullHttpRequest fullHttpRequest) {
System.out.println("\n\n----------");
HttpHeaders httpHeaders = fullHttpRequest.headers();
Set<String> names = httpHeaders.names();
for (String name : names) {
System.out.println(name + " : " + httpHeaders.get(name));
}
System.out.println("");
ByteBuf byteBuf = fullHttpRequest.content();
byte[] byteArray = new byte[byteBuf.capacity()];
byteBuf.readBytes(byteArray);
System.out.println(new String(byteArray));
System.out.println("----------\n\n");
JSONObject json = new JSONObject();
json.put("errCode", "00");
json.put("errMsg", "0000000(成功)");
json.put("data", null);
return json;
}
}
複製代碼
public class HttpServerTest {
public static void main(String[] args) throws Exception {
CettyBootstrap.create();
// CettyBootstrap.create("classpath:applicationContext.xml");
}
}
複製代碼