HTTP简单介绍:http是属于应用层的面向对象传输协议,适用于分布式超媒体信息系统。
HTTP的特点:
(1)支持client/server模式
(2)简单
(3)灵活
(4)无状态
HTTP请求消息:
(1)请求行
(2)请求头
(3)请求体
HTTP响应消息:
(1)状态行
(2)消息报头
(3)响应正文
Netty+HTTP+XML实战:
1.对象和工具类准备
package com.netty.wcy20210713.netty02;
import com.netty.wcy20210713.netty02.util.XMLUtil;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* @PackageName:com.netty.wcy20210713.netty02 Description
* @author:
* @date:2021/7/14
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"id","name","age","sex"})
@XmlRootElement(name="xml")
@Data
public class Person {
/**
* id
*/
private int id;
/**
* 姓名
*/
private String name;
/**
* 性别
*/
private String sex;
/**
* 年龄
*/
private int age;
public static void main(String[] args){
Person p = new Person();
p.setAge(20);
p.setId(1);
p.setName("ahh");
p.setSex("国家规定带 xiao jj de shi nan");
String xml = XMLUtil.objectToXmlStr(p,Person.class);
System.out.println(xml);
}
}
package com.netty.wcy20210713.netty02;
/**
* @PackageName:com.netty.wcy20210713.netty02 Description
* @author:
* @date:2021/7/14
*/
public class PayFactory {
public static Person create(long orderID) {
Person p = new Person();
p.setAge(20);
p.setId(1);
p.setName("ahh");
p.setSex("国家规定带 xiao jj de shi nan");
return p;
}
}
package com.netty.wcy20210713.netty02.util;
/**
* @PackageName:com.zh.zhservice.util Description
* @author:
* @date:2020/12/25
*/
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
/**
* 将对象直接转换成String类型的 XML输出
*
* @param
* @return
*/
public class XMLUtil {
/**
* xml字符串转对象
* @param clazz
* @param xmlStr
* @return
*/
public static Object xmlStrToObject(Class clazz, String xmlStr) {
Object xmlObject = null;
StringReader sr = null;
try {
JAXBContext context = JAXBContext.newInstance(clazz);
// 进行将Xml转成对象的核心接口
Unmarshaller unmarshaller = context.createUnmarshaller();
sr = new StringReader(xmlStr);
xmlObject = unmarshaller.unmarshal(sr);
} catch (JAXBException e) {
e.printStackTrace();
}finally {
if (sr != null){
sr.close();
}
}
return xmlObject;
}
/**
* 对象转xml字符串
* @param obj
* @param load
* @return
* @throws JAXBException
*/
public static String objectToXmlStr(Object obj,Class<?> load){
String result = "";
StringWriter writer = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(obj.getClass());
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
writer = new StringWriter();
writer.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
jaxbMarshaller.marshal(obj, writer);
result = writer.toString();
} catch (JAXBException e) {
e.printStackTrace();
}finally {
try {
if (writer != null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
2.HttpXmlClient客户端
package com.netty.wcy20210713.netty02.client;
import com.netty.wcy20210713.netty02.Person;
import com.netty.wcy20210713.netty02.clienthandle.HttpXmlClientHandle;
import com.netty.wcy20210713.netty02.decode.HttpXmlResponseDecoder;
import com.netty.wcy20210713.netty02.encode.HttpXmlRequestEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import java.net.InetSocketAddress;
/**
* @PackageName:com.netty.wcy20210713.netty02.client Description
* @author:
* @date:2021/7/14
*
* 步骤1 :启动客户端
* ChannelPipeLine中添加了xml解码器,xml编码器与用户自定义的HttpXmlClientHandle
*/
public class HttpXmlClient {
public void connect(int port) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
// xml解码器
ch.pipeline().addLast("http-decoder", new HttpResponseDecoder());
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
//ChannelPipeLine中添加了xml解码器
ch.pipeline().addLast("xml-decoder", new HttpXmlResponseDecoder(Person.class, true));
ch.pipeline().addLast("http-encoder", new HttpRequestEncoder());
// xml编码器,先编码,在发送服务端
ch.pipeline().addLast("xml-encoder", new HttpXmlRequestEncoder());
//客户端与服务端连接成功后发送请求消息:
ch.pipeline().addLast("xmlClientHandler", new HttpXmlClientHandle());
}
});
ChannelFuture f = b.connect(new InetSocketAddress(port)).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8087;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
new HttpXmlClient().connect(port);
}
}
3.HttpXmlClientHandle业务处理
package com.netty.wcy20210713.netty02.clienthandle;
import com.netty.wcy20210713.netty02.PayFactory;
import com.netty.wcy20210713.netty02.common.HttpXmlRequest;
import com.netty.wcy20210713.netty02.common.HttpXmlResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @PackageName:com.netty.wcy20210713.netty02.clienthandle Description
* @author:
* @date:2021/7/14
*步骤2:客户端与服务端连接成功后发送请求消息:
* 客户端成功联接服务器之后,激活HttpXmlClientHandle中的channelActive方法,客户端构造HttpXmlRequest对象并写入到ChannelPipeLine中,
* 其中HttpXmlRequest包括FullHttpRequest对象与Object对象。
*
* HttpXmlClientHandle中使用了OrderFactory来获得一个Order对象,OrderFactory的代码如下:
*/
public class HttpXmlClientHandle extends SimpleChannelInboundHandler<HttpXmlResponse> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
// 给客户端发送请求消息,HttpXmlRequest包含FullHttpRequest和Order这个了类
HttpXmlRequest request = new HttpXmlRequest(null, PayFactory.create(123));
ctx.writeAndFlush(request);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpXmlResponse httpXmlResponse) throws Exception {
System.out
.println("The client receive response of http header is : " + httpXmlResponse.getHttpResponse().headers().names());
System.out.println("The client receive response of http body is : " + httpXmlResponse.getResult());
}
}
4.HttpXmlRequest通用请求报文对象
package com.netty.wcy20210713.netty02.common;
import io.netty.handler.codec.http.FullHttpRequest;
/**
* @PackageName:com.netty.wcy20210713.netty02.common Description
* @author:
* @date:2021/7/14
*/
public class HttpXmlRequest {
private FullHttpRequest request;
private Object body;
public HttpXmlRequest(FullHttpRequest request, Object body) {
this.request = request;
this.body = body;
}
public final FullHttpRequest getRequest() {
return request;
}
public final void setRequest(FullHttpRequest request) {
this.request = request;
}
public final Object getBody() {
return body;
}
public final void setBody(Object body) {
this.body = body;
}
@Override
public String toString() {
return "HttpXmlRequest [request=" + request + ", body =" + body + "]";
}
}
5.通用响应报文对象
package com.netty.wcy20210713.netty02.common;
/**
* @PackageName:com.shineyue.cn.bean Description
* @author:
* @date:2021/7/12
* 它包含两个成员变量:FullHttpResponse和Object,Object就是业务需要发送的应答POJO对象。
*/
import io.netty.handler.codec.http.FullHttpResponse;
public class HttpXmlResponse {
private FullHttpResponse httpResponse;
private Object result;
public HttpXmlResponse(FullHttpResponse httpResponse, Object result) {
this.httpResponse = httpResponse;
this.result = result;
}
public final FullHttpResponse getHttpResponse() {
return httpResponse;
}
public final void setHttpResponse(FullHttpResponse httpResponse) {
this.httpResponse = httpResponse;
}
public final Object getResult() {
return result;
}
public final void setResult(Object result) {
this.result = result;
}
}
6.HttpXmlRequestDecoder请求编码
package com.netty.wcy20210713.netty02.decode;
import com.netty.wcy20210713.netty02.common.HttpXmlRequest;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.util.List;
/**
* @PackageName:com.netty.wcy20210713.netty02.decode Description
* @author:
* @date:2021/7/14
*
* 步骤6:
* 服务端的HttpRequestDecoder接收到来自客户端的消息,再交由HttpObjectAggregator处理
*
* 步骤7:
* 第六步处理完之后获得一个FullHttpRequest对象,并传递到HttpXmlRequestDecoder解码器中
*
*
* HttpXmlRequestDecoder继承了AbstractHttpXmlDecoder,decode方法中调用服父类的decode0方法将xml字符串转换成Object对象。
* 然后构造了一个HttpXmlRequest对象。
*/
public class HttpXmlRequestDecoder extends AbstractHttpXmlDecoder<FullHttpRequest> {
public HttpXmlRequestDecoder(Class<?> clazz) {
this(clazz, false);
}
public HttpXmlRequestDecoder(Class<?> clazz, boolean isPrint) {
super(clazz, isPrint);
}
@Override
protected void decode(ChannelHandlerContext arg0, FullHttpRequest arg1, List<Object> arg2) throws Exception {
// 返回客户端错误信息
if (!arg1.decoderResult().isSuccess()) {
sendError(arg0, HttpResponseStatus.BAD_GATEWAY);
return;
}
HttpXmlRequest request = new HttpXmlRequest(arg1, decode0(arg0, arg1.content()));
// 将请求交给下一个解码器处理
arg2.add(request);
}
private static void sendError(ChannelHandlerContext ctx, 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");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
7.HttpXmlResponseDecoder请求解码器
package com.netty.wcy20210713.netty02.decode;
import com.netty.wcy20210713.netty02.common.HttpXmlResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import java.util.List;
/**
* @PackageName:com.shineyue.cn.decode Description
* @author:
* @date:2021/7/13
*/
public class HttpXmlResponseDecoder extends AbstractHttpXmlDecoder {
public HttpXmlResponseDecoder(Class clazz) {
this(clazz, false);
}
public HttpXmlResponseDecoder(Class clazz, boolean isPrintlog) {
super(clazz, isPrintlog);
}
@Override
protected void decode(ChannelHandlerContext ctx, Object o, List out) throws Exception {
DefaultFullHttpResponse msg = (DefaultFullHttpResponse)o;
HttpXmlResponse resHttpXmlResponse = new HttpXmlResponse(msg, decode0(
ctx, msg.content()));
out.add(resHttpXmlResponse);
}
}
8.AbstractHttpXmlDecoder公共请求编解码器
package com.netty.wcy20210713.netty02.decode;
import com.netty.wcy20210713.netty02.Person;
import com.netty.wcy20210713.netty02.util.XMLUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.nio.charset.Charset;
/**
* @PackageName:com.netty.wcy20210713.netty02.decode Description
* @author:
* @date:2021/7/14
*/
public abstract class AbstractHttpXmlDecoder<T> extends MessageToMessageDecoder<T> {
private Class<?> clazz;
// 是否输出码流的标志,默认为false
private boolean isPrint;
private final static String CHARSET_NAME = "UTF-8";
private final static Charset UTF_8 = Charset.forName(CHARSET_NAME);
// 当调用这个构造方法是,默认设置isPrint为false
protected AbstractHttpXmlDecoder(Class<?> clazz) {
this(clazz, false);
}
protected AbstractHttpXmlDecoder(Class<?> clazz, boolean isPrint) {
this.clazz = clazz;
this.isPrint = isPrint;
}
protected Object decode0(ChannelHandlerContext arg0, ByteBuf body) throws Exception {
String content = body.toString(UTF_8);
if (isPrint)
System.out.println("The body is : " + content);
Object result = XMLUtil.xmlStrToObject(Person.class,content);
return result;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
}
}
9.HttpXmlRequestEncoder响应编码器
package com.netty.wcy20210713.netty02.encode;
import com.netty.wcy20210713.netty02.common.HttpXmlRequest;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import java.net.InetAddress;
import java.util.List;
/**
* @PackageName:com.netty.wcy20210713.netty02.encode Description
* @author:
* @date:2021/7/14
*
* 步骤3:消息传到HttpXmlRequestEncoder,并进行编码
*
* encode方法中接收到的的msg就是之前HttpXmlClientHandle中我们写入ChannelPipeLine中的对象。
* HttpXmlRequestEncoder获得的msg中的Object对象,通过父类的encode0方法将其转换为Bytebuf对象。
* 因为这个例子中上述request必定为null,所以会构造新的FullHttpRequest对象。
* 在构造方法中将数据body传入FullHttpRequest对象中。最后要记得设置CONTENT_LENGTH请求头,并将request对象添加到out对象中。
*
*
* HttpXmlRequestEncoder继承了AbstractHttpXmlEncoder,AbstractHttpXmlEncoder中定义了encode0方法,
* 将Object对象转化为对应的xml字符串,然后将返回xml字符串的ByteBuf对象
*
* 步骤4 :
* 四、在HttpXmlRequestEncoder中写入的FullHttpRequest对象经由客户端的HttpRequestEncoder编码器处理,发送至服务端
*/
public class HttpXmlRequestEncoder extends AbstractHttpXmlEncoder<HttpXmlRequest> {
@Override
protected void encode(ChannelHandlerContext ctx, HttpXmlRequest msg, List<Object> out) throws Exception {
// 调用父类的encode0方法将Person对象转换为xml字符串,并将其封装为ByteBuf
ByteBuf body = encode0(ctx, msg.getBody());
FullHttpRequest request = msg.getRequest();
// 如request为空,则新建一个FullHttpRequest对象,并将设置消息头
if (request == null) {
// 在构造方法中,将body设置为请求消息体
request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/do", body);
HttpHeaders headers = request.headers();
// 表示请求的服务器网址
headers.set(HttpHeaderNames.HOST, InetAddress.getLocalHost().getHostAddress());
// Connection表示客户端与服务连接类型;Keep-Alive表示长连接;CLOSE表示短连接
// header中包含了值为close的connection,都表明当前正在使用的tcp链接在请求处理完毕后会被断掉。
// 以后client再进行新的请求时就必须创建新的tcp链接了。
headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
// 浏览器支持的压缩编码是 gzip 和 deflate
headers.set(HttpHeaderNames.ACCEPT_ENCODING,
HttpHeaderValues.GZIP.toString() + ',' + HttpHeaderValues.DEFLATE.toString());
// 浏览器支持的解码集
headers.set(HttpHeaderNames.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
// 浏览器支持的语言
headers.set(HttpHeaderNames.ACCEPT_LANGUAGE, "zh");
// 使用的用户代理是 Netty xml Http Client side
headers.set(HttpHeaderNames.USER_AGENT, "Netty xml Http Client side");
// 浏览器支持的 MIME类型,优先顺序为从左到右
headers.set(HttpHeaderNames.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
}
// 由于此处没有使用chunk方式,所以要设置消息头中设置消息体的CONTENT_LENGTH
request.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, body.readableBytes());
// 将请求消息添加进out中,待后面的编码器对消息进行编码
out.add(request);
}
}
10.HttpXmlResponseEncoder响应解码器
package com.netty.wcy20210713.netty02.encode;
import com.netty.wcy20210713.netty02.common.HttpXmlResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import java.util.List;
/**
* @PackageName:com.netty.wcy20210713.netty02.encode Description
* @author:
* @date:2021/7/14
*
* 步骤 9: javabean传入到HttpXmlResponseEncoder中,进行应答解码
*
* 步骤 10、HttpXmlResponseEncoder处理完之后获得一个FullHttpResponse对象,该对象传入到HttpXmlResponseEncoder中进行编码
*
* 步骤 11、服务器的应答消息发至客户端的HttpResponseDecoder处理后
*
*
* 步骤 12、HttpXmlResponseEncoder处理FullHttpResponse对象
*/
public class HttpXmlResponseEncoder extends AbstractHttpXmlEncoder<HttpXmlResponse> {
@Override
protected void encode(ChannelHandlerContext ctx, HttpXmlResponse msg, List<Object> out) throws Exception {
ByteBuf body = encode0(ctx, msg.getResult());
FullHttpResponse response = msg.getHttpResponse();
if (response == null) {
response = new DefaultFullHttpResponse(HTTP_1_1, OK, body);
} else {
response = new DefaultFullHttpResponse(msg.getHttpResponse().protocolVersion(),
msg.getHttpResponse().status(), body);
}
response.headers().set(CONTENT_TYPE, "text/xml");
response.headers().setInt(CONTENT_LENGTH, body.readableBytes());
out.add(response);
}
}
11.AbstractHttpXmlEncoder公共响应解码器
package com.netty.wcy20210713.netty02.encode;
import com.netty.wcy20210713.netty02.util.XMLUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.nio.charset.Charset;
/**
* @PackageName:com.netty.wcy20210713.netty02.encode Description
* @author:
* @date:2021/7/14
*/
public abstract class AbstractHttpXmlEncoder<T> extends MessageToMessageEncoder<T> {
final static String CHARSET_NAME = "UTF-8";
final static Charset UTF_8 = Charset.forName(CHARSET_NAME);
protected ByteBuf encode0(ChannelHandlerContext ctx, Object body) throws Exception {
// 将Person类转换为xml流
String xml = XMLUtil.objectToXmlStr(body,Object.class);
System.out.println(xml);
ByteBuf encodeBuf = Unpooled.copiedBuffer(xml, UTF_8);
return encodeBuf;
}
//@Skip
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("fail to encode");
}
}
12.HttpXmlServerHandler服务端业务处理器
package com.netty.wcy20210713.netty02.serverhandle;
import com.netty.wcy20210713.netty02.Person;
import com.netty.wcy20210713.netty02.common.HttpXmlRequest;
import com.netty.wcy20210713.netty02.common.HttpXmlResponse;
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.FullHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.util.ArrayList;
import java.util.List;
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
/**
* @PackageName:com.netty.wcy20210713.netty02.serverhandle Description
* @author:
* @date:2021/7/14
* 步骤8:
* 服务器的HttpXmlServerHandler接收到HttpXmlRequestDecoder传来的HttpXmlRequest对象:
* <p>
* HttpXmlServerHandler代码如下
*
* dobusiness(order)方法获得应答的javabean,然后写入到ChannelPipeLine
*/
public class HttpXmlServerHandler extends SimpleChannelInboundHandler {
private Person dobusiness(Person dog) {
dog.setId(2);
dog.setName("汪汪");
dog.setAge(5);
dog.setSex("公");
return dog;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {
cause.printStackTrace();
if (ctx.channel().isActive()) {
sendError(ctx, INTERNAL_SERVER_ERROR);
}
}
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
status, Unpooled.copiedBuffer("失败: " + status.toString()
+ "\r\n", CharsetUtil.UTF_8));
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
@Override
protected void channelRead0(final ChannelHandlerContext ctx,Object o) throws Exception {
HttpXmlRequest xmlRequest = (HttpXmlRequest)o;
HttpRequest request = xmlRequest.getRequest();
Person dog = (Person) xmlRequest.getBody();
System.out.println("Http server receive request : " + dog);
dobusiness(dog);
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, OK);
ChannelFuture future = ctx.writeAndFlush(new HttpXmlResponse(httpResponse, dobusiness(dog)));
if (!isKeepAlive(request)) {
future.addListener(new GenericFutureListener() {
@Override
public void operationComplete (Future future)throws Exception {
ctx.close();
}
});
}
}
}
13.服务端
package com.netty.wcy20210713.netty02.server;
import com.netty.wcy20210713.netty02.Person;
import com.netty.wcy20210713.netty02.decode.HttpXmlRequestDecoder;
import com.netty.wcy20210713.netty02.encode.HttpXmlResponseEncoder;
import com.netty.wcy20210713.netty02.serverhandle.HttpXmlServerHandler;
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 java.net.InetSocketAddress;
/**
* @PackageName:com.netty.wcy20210713.netty02.server Description
* @author:
* @date:2021/7/14
*
* 步骤5、服务端代码:
*
* 服务端同样有xml编码器和xml解码器,还有HttpXmlServerHandler。
*/
public class HttpXmlServer {
public void run(final int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("xml-decoder", new HttpXmlRequestDecoder(Person.class, true));
ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
ch.pipeline().addLast("xml-encoder", new HttpXmlResponseEncoder());
ch.pipeline().addLast("xmlServerHandler", new HttpXmlServerHandler());
}
});
ChannelFuture future = b.bind(new InetSocketAddress(port)).sync();
System.out.println("HTTP服务器启动,网址是 : " + "http://localhost:" + port);
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8087;
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
new HttpXmlServer().run(port);
}
}
14.启动服务端
15.启动客户端
总结:程序存在缺陷,参考《Neyy权威指南第二版》开发