这是一个JavaProject
首先是服务启动类MainApp.java
package com.jadyer.core; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.executor.ExecutorFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; /** * 服务启动类 * @see 服务启动后(即执行这里的main方法),可用浏览器访问下面两个地址 * @see http://127.0.0.1:8000/ (浏览器会显示这几个字:欢迎访问由Mina2.0.7编写的Web服务器) * @see http://127.0.0.1:8000/login(浏览器会显示这几个字:登录成功) * @see 另外这里并未配置backlog,那么它会采用操作系统默认的连接请求队列长度50 * @see 详见org.apache.mina.core.polling.AbstractPollingIoAcceptor类源码的96行 * @create Jul 7, 2013 1:28:04 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class MainApp { public static void main(String[] args) throws IOException { NioSocketAcceptor acceptor = new NioSocketAcceptor(); acceptor.setBacklog(0); acceptor.setReuseAddress(true); acceptor.getSessionConfig().setWriteTimeout(10000); acceptor.getSessionConfig().setBothIdleTime(90); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ServerProtocolCodecFactory())); acceptor.getFilterChain().addLast("executor", new ExecutorFilter()); acceptor.setHandler(new ServerHandler()); //服务端绑定两个端口,8000用于接收并处理HTTP请求,9901用于接收并处理TCP请求 List<SocketAddress> socketAddresses = new ArrayList<SocketAddress>(); socketAddresses.add(new InetSocketAddress(8000)); socketAddresses.add(new InetSocketAddress(9901)); acceptor.bind(socketAddresses); //判断服务端启动与否 if(acceptor.isActive()){ System.out.println("写 超 时: 10000ms"); System.out.println("发呆配置: Both Idle 90s"); System.out.println("端口重用: true"); System.out.println("服务端初始化完成......"); System.out.println("服务已启动....开始监听...." + acceptor.getLocalAddresses()); }else{ System.out.println("服务端初始化失败......"); } } }
package com.jadyer.core; import java.net.HttpURLConnection; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; import com.jadyer.util.JadyerUtil; /** * 业务分发类 * @see 本例中目前只接收两种请求 * @see TCP请求的固定业务编码为10005,HTTP请求的固定业务编码为/login(http://127.0.0.1:8000/login) * @see TCP报文格式为前6个字节表示报文整体长度(长度不足6位时左补零),第7位开始代表业务编码(固定长度为5),第12位开始是业务数据 * @create Jul 7, 2013 2:24:45 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class ServerHandler extends IoHandlerAdapter { @Override public void messageReceived(IoSession session, Object message) throws Exception { String respData = null; Token token = (Token)message; /* * 打印收到的原始报文 */ System.out.println("渠道:" + token.getBusiType() + " 交易码:" + token.getBusiCode() +" 完整报文(HEX):" + JadyerUtil.buildHexStringWithASCII(JadyerUtil.getBytes(token.getFullMessage(), "UTF-8"))); StringBuilder sb = new StringBuilder(); sb.append("\r\n------------------------------------------------------------------------------------------"); sb.append("\r\n【通信双方】").append(session); sb.append("\r\n【收发标识】Receive"); sb.append("\r\n【报文内容】").append(token.getFullMessage()); sb.append("\r\n------------------------------------------------------------------------------------------"); System.out.println(sb.toString()); /* * 根据请求的业务编码做不同的处理 */ if(token.getBusiCode().equals("/")){ respData = this.buildHTTPResponseMessage("<h2>欢迎访问由Mina2.0.7编写的Web服务器</h2>"); }else if(token.getBusiCode().equals("/favicon.ico")){ respData = this.buildHTTPResponseMessage("<link rel=\"icon\" href=\"https://epay.10010.com/per/favicon.ico\"" + "type=\"image/x-icon\"/>\n<link rel=\"shortcut icon\" href=\"http" + "s://epay.10010.com/per/favicon.ico\" type=\"image/x-icon\"/>"); }else if(token.getBusiCode().equals("/login")){ System.out.println("收到请求参数=[" + token.getBusiMessage() + "]"); respData = this.buildHTTPResponseMessage("登录成功"); }else if(token.getBusiCode().equals("10005")){ System.out.println("收到请求参数=[" + token.getBusiMessage() + "]"); respData = "00003099999999`20130707144028`"; }else{ if(token.getBusiType().equals(Token.BUSI_TYPE_TCP)){ respData = "ILLEGAL_REQUEST"; }else if(token.getBusiType().equals(Token.BUSI_TYPE_HTTP)){ respData = this.buildHTTPResponseMessage(501, null); } } /* * 打印应答报文 */ sb.setLength(0); sb.append("\r\n------------------------------------------------------------------------------------------"); sb.append("\r\n【通信双方】").append(session); sb.append("\r\n【收发标识】Response"); sb.append("\r\n【报文内容】").append(respData); sb.append("\r\n------------------------------------------------------------------------------------------"); System.out.println(sb.toString()); session.write(respData); } @Override public void messageSent(IoSession session, Object message) throws Exception { System.out.println("已回应给Client"); if(session != null){ session.close(true); } } @Override public void sessionIdle(IoSession session, IdleStatus status){ System.out.println("请求进入闲置状态....回路即将关闭...."); session.close(true); } @Override public void exceptionCaught(IoSession session, Throwable cause){ System.out.println("请求处理遇到异常....回路即将关闭...."); cause.printStackTrace(); session.close(true); } /** * 构建HTTP响应报文 * @see 该方法默认构建的是HTTP响应码为200的响应报文 * @param httpResponseMessageBody HTTP响应报文体 * @return 包含了HTTP响应报文头和报文体的完整报文 */ private String buildHTTPResponseMessage(String httpResponseMessageBody){ return buildHTTPResponseMessage(HttpURLConnection.HTTP_OK, httpResponseMessageBody); } /** * 构建HTTP响应报文 * @see 200--请求已成功,请求所希望的响应头或数据体将随此响应返回..即服务器已成功处理了请求 * @see 400--由于包含语法错误,当前请求无法被服务器理解..除非进行修改,否则客户端不应该重复提交这个请求..即错误请求 * @see 500--服务器遇到了一个未曾预料的状况,导致其无法完成对请求的处理..一般来说,该问题都会在服务器的程序码出错时出现..即服务器内部错误 * @see 501--服务器不支持当前请求所需要的某个功能..当服务器无法识别请求的方法,且无法支持其对任何资源的请求时,可能返回此代码..即尚未实施 * @param httpResponseCode HTTP响应码 * @param httpResponseMessageBody HTTP响应报文体 * @return 包含了HTTP响应报文头和报文体的完整报文 */ private String buildHTTPResponseMessage(int httpResponseCode, String httpResponseMessageBody){ if(httpResponseCode == HttpURLConnection.HTTP_OK){ StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: "); sb.append(JadyerUtil.getBytes(httpResponseMessageBody, "UTF-8").length); sb.append("\r\n\r\n"); sb.append(httpResponseMessageBody); return sb.toString(); } if(httpResponseCode == HttpURLConnection.HTTP_BAD_REQUEST){ return "HTTP/1.1 400 Bad Request"; } if(httpResponseCode == HttpURLConnection.HTTP_INTERNAL_ERROR){ return "HTTP/1.1 500 Internal Server Error"; } return "HTTP/1.1 501 Not Implemented"; } }
package com.jadyer.core; /** * 封装客户端请求报文 * @create Jul 7, 2013 1:42:57 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class Token { public static final String BUSI_TYPE_TCP = "TCP"; public static final String BUSI_TYPE_HTTP = "HTTP"; public String busiCode; //业务码 public String busiType; //业务类型:TCP or HTTP public String busiMessage; //业务报文:TCP请求时为TCP完整报文,HTTP_POST请求时为报文体部分,HTTP_GET时为报文头第一行参数部分 public String busiCharset; //报文字符集 public String fullMessage; //原始完整报文(用于在日志中打印最初接收到的原始完整报文) /*-- 五个属性的setter和getter略 --*/ }
package com.jadyer.core; import org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory; /** * 组装服务端的编解码器的工厂 * @see 暂不提供客户端编解码器(其实它与服务端的编解码器差不多差不多) * @see ==================================================================================== * @see 其内部维护了一个MessageDecoder数组,用于保存添加的所有解码器 * @see 每次decode()的时候就调用每个MessageDecoder的decodable()逐个检查 * @see 只要发现一个MessageDecoder不是对应的解码器,就从数组中移除,知道找到合适的MessageDecoder * @see 如果最后发现数组为空,就表示没有找到对应的MessageDecoder,最后抛出异常 * @see ==================================================================================== * @create Jul 7, 2013 1:41:10 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class ServerProtocolCodecFactory extends DemuxingProtocolCodecFactory { public ServerProtocolCodecFactory(){ super.addMessageEncoder(String.class, ServerProtocolEncoder.class); super.addMessageDecoder(ServerProtocolTCPDecoder.class); super.addMessageDecoder(ServerProtocolHTTPDecoder.class); } }
package com.jadyer.core; import java.nio.charset.Charset; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.filter.codec.demux.MessageEncoder; /** * Server端协议编码器 * @see 用于编码响应给Client的报文(报文编码一律采用UTF-8) * @create Jul 7, 2013 1:43:12 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class ServerProtocolEncoder implements MessageEncoder<String> { @Override public void encode(IoSession session, String message, ProtocolEncoderOutput out) throws Exception { IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true); buffer.putString(message, Charset.forName("UTF-8").newEncoder()); buffer.flip(); out.write(buffer); } }
package com.jadyer.core; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.apache.mina.filter.codec.demux.MessageDecoder; import org.apache.mina.filter.codec.demux.MessageDecoderResult; import com.jadyer.util.JadyerUtil; /** * Server端TCP协议解码器 * @see 用于解码接收到的TCP请求报文(报文编码一律采用UTF-8) * @see 当收到数据包时,程序首先会执行decodable()方法,通过读取数据判断当前数据包是否可进行decode * @see 当decodable()方法返回MessageDecoderResult.OK时,接着会调用decode()方法,正式decode数据包 * @see 在decode()方法进行读取操作会影响数据包的大小,decode需要判断协议中哪些已经decode完,哪些还没decode * @see decode完成后,通过ProtocolDecoderOutput.write()输出,并返回MessageDecoderResult.OK表示decode完毕 * @create Jul 7, 2013 1:44:53 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class ServerProtocolTCPDecoder implements MessageDecoder { /** * 该方法相当于预读取,用于判断是否是可用的解码器,这里对IoBuffer读取不会影响数据包的大小 * 该方法结束后IoBuffer会复原,所以不必担心调用该方法时,position已经不在缓冲区起始位置 */ @Override public MessageDecoderResult decodable(IoSession session, IoBuffer in) { //TCP报文格式约定为前6个字节表示报文整体长度,长度不足6位时左补零,第7位开始代表业务编码,业务编码固定长度为5,第12位开始是业务数据 if(in.remaining() < 6){ return MessageDecoderResult.NEED_DATA; } //服务端启动时已绑定9901端口,专门用来处理TCP请求的 if(session.getLocalAddress().toString().contains(":9901")){ byte[] messageLength = new byte[6]; in.get(messageLength); if(in.limit() >= Integer.parseInt(JadyerUtil.getString(messageLength, "UTF-8"))){ return MessageDecoderResult.OK; }else{ return MessageDecoderResult.NEED_DATA; } }else{ return MessageDecoderResult.NOT_OK; } } @Override public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { byte[] message = new byte[in.limit()]; in.get(message); String fullMessage = JadyerUtil.getString(message, "UTF-8"); Token token = new Token(); token.setBusiCharset("UTF-8"); token.setBusiType(Token.BUSI_TYPE_TCP); token.setBusiCode(fullMessage.substring(6, 11)); token.setBusiMessage(fullMessage); token.setFullMessage(fullMessage); out.write(token); return MessageDecoderResult.OK; } @Override public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { //暂时什么都不做 } }
package com.jadyer.core; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.apache.mina.filter.codec.demux.MessageDecoder; import org.apache.mina.filter.codec.demux.MessageDecoderResult; import com.jadyer.util.JadyerUtil; /** * Server端HTTP协议解码器 * @see 用于解码接收到的HTTP请求报文(报文编码一律采用UTF-8) * @create Jul 7, 2013 1:44:20 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class ServerProtocolHTTPDecoder implements MessageDecoder { @Override public MessageDecoderResult decodable(IoSession session, IoBuffer in) { if(in.remaining() < 5){ return MessageDecoderResult.NEED_DATA; } //服务端启动时已绑定8000端口,专门用来处理HTTP请求的 if(session.getLocalAddress().toString().contains(":8000")){ return this.isComplete(in) ? MessageDecoderResult.OK : MessageDecoderResult.NEED_DATA; }else{ return MessageDecoderResult.NOT_OK; } } @Override public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { byte[] message = new byte[in.limit()]; in.get(message); String fullMessage = JadyerUtil.getString(message, "UTF-8"); Token token = new Token(); token.setBusiCharset("UTF-8"); token.setBusiType(Token.BUSI_TYPE_HTTP); token.setFullMessage(fullMessage); if(fullMessage.startsWith("GET")){ if(fullMessage.startsWith("GET / HTTP/1.1")){ token.setBusiCode("/"); }else if(fullMessage.startsWith("GET /favicon.ico HTTP/1.1")){ token.setBusiCode("/favicon.ico"); }else{ //GET /login?aa=bb&cc=dd&ee=ff HTTP/1.1 if(fullMessage.substring(4, fullMessage.indexOf("\r\n")).contains("?")){ token.setBusiCode(fullMessage.substring(4, fullMessage.indexOf("?"))); token.setBusiMessage(fullMessage.substring(fullMessage.indexOf("?")+1, fullMessage.indexOf("HTTP/1.1")-1)); //GET /login HTTP/1.1 }else{ token.setBusiCode(fullMessage.substring(4, fullMessage.indexOf("HTTP")-1)); } } }else if(fullMessage.startsWith("POST")){ //先获取到请求报文头中的Content-Length int contentLength = 0; if(fullMessage.contains("Content-Length:")){ String msgLenFlag = fullMessage.substring(fullMessage.indexOf("Content-Length:") + 15); if(msgLenFlag.contains("\r\n")){ contentLength = Integer.parseInt(msgLenFlag.substring(0, msgLenFlag.indexOf("\r\n")).trim()); if(contentLength > 0){ token.setBusiMessage(fullMessage.split("\r\n\r\n")[1]); } } } //POST /login?aa=bb&cc=dd&ee=ff HTTP/1.1 //特别说明一下:此时报文体本应该是空的,即Content-Length=0,但不能排除对方偏偏在报文体中也传了参数 //特别说明一下:所以这里的处理手段是busiMessage=请求URL中的参数串 + "`" + 报文体中的参数串(如果存在报文体的话) if(fullMessage.substring(5, fullMessage.indexOf("\r\n")).contains("?")){ token.setBusiCode(fullMessage.substring(5, fullMessage.indexOf("?"))); String urlParam = fullMessage.substring(fullMessage.indexOf("?")+1, fullMessage.indexOf("HTTP/1.1")-1); if(contentLength > 0){ token.setBusiMessage(urlParam + "`" + fullMessage.split("\r\n\r\n")[1]); }else{ token.setBusiMessage(urlParam); } //POST /login HTTP/1.1 }else{ token.setBusiCode(fullMessage.substring(5, fullMessage.indexOf("HTTP/1.1")-1)); } } out.write(token); return MessageDecoderResult.OK; } @Override public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception { //暂时什么都不做 } /** * 校验HTTP请求报文是否已完整接收 * @see 目前仅授理GET和POST请求 * @see ==================================================================================== * @see GET /notify_yeepay?p1_MerId=11&r0_Cmd=Buy&r1_Code=1&r2_TrxId=22 HTTP/1.1^M * @see Content-Type: application/x-www-form-urlencoded; charset=GBK^M * @see Cache-Control: no-cache^M * @see Pragma: no-cache^M * @see User-Agent: Java/1.5.0_14^M * @see Host: 123.125.97.248^M * @see Accept: text/html, image/gif, image/jpeg, *; q=.2, 星号/*; q=.2^M * @see Connection: keep-alive^M * @see ^M * @see ==================================================================================== * @see POST /tra/trade/noCardNoPassword.htm HTTP/1.1^M * @see Content-Type: application/x-www-form-urlencoded;charset=GB18030^M * @see Cache-Control: no-cache^M * @see Pragma: no-cache^M * @see User-Agent: Java/1.6.0_24^M * @see Host: 192.168.20.1^M * @see Accept: text/html, image/gif, image/jpeg, *; q=.2, 星号/*; q=.2^M * @see Connection: keep-alive^M * @see Content-Length: 541^M * @see ^M * @see cooBankNo=CMBC_CREDIT&signType=MD5&amount=499900&orderValidityNum=15&CVVNo=255 * @see ==================================================================================== * @see 至于上面所列的GET和POST请求原始报文中为何会出现^M * @see 我的博客上有详细说明http://blog.csdn.net/jadyer/article/details/8212067 * @see ==================================================================================== * @param in 装载HTTP请求报文的IoBuffer */ private boolean isComplete(IoBuffer in){ /* * 先获取HTTP请求的原始报文 */ byte[] messages = new byte[in.limit()]; in.get(messages); String message = JadyerUtil.getString(messages, "UTF-8"); /* * 授理GET请求 */ if(message.startsWith("GET")){ return message.endsWith("\r\n\r\n"); } /* * 授理POST请求 */ if(message.startsWith("POST")){ if(message.contains("Content-Length:")){ //取Content-Length后的字符串 String msgLenFlag = message.substring(message.indexOf("Content-Length:") + 15); if(msgLenFlag.contains("\r\n")){ //取Content-Length值 int contentLength = Integer.parseInt(msgLenFlag.substring(0, msgLenFlag.indexOf("\r\n")).trim()); if(contentLength == 0){ return true; }else if(contentLength > 0){ //取HTTP_POST请求报文体 String messageBody = message.split("\r\n\r\n")[1]; if(contentLength == JadyerUtil.getBytes(messageBody, "UTF-8").length){ return true; } } } } } /* * 仅授理GET和POST请求 */ return false; } }
package com.jadyer.util; import java.io.UnsupportedEncodingException; public class JadyerUtil { private JadyerUtil(){} /** * 判断输入的字符串参数是否为空 * @return boolean 空则返回true,非空则flase */ public static boolean isEmpty(String input) { return null==input || 0==input.length() || 0==input.replaceAll("\\s", "").length(); } /** * 判断输入的字节数组是否为空 * @return boolean 空则返回true,非空则flase */ public static boolean isEmpty(byte[] bytes){ return null==bytes || 0==bytes.length; } /** * 字节数组转为字符串 * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 */ public static String getString(byte[] data, String charset){ if(isEmpty(data)){ return ""; } if(isEmpty(charset)){ return new String(data); } try { return new String(data, charset); } catch (UnsupportedEncodingException e) { System.out.println("将byte数组[" + data + "]转为String时发生异常:系统不支持该字符集[" + charset + "]"); return new String(data); } } /** * 字符串转为字节数组 * @see 如果系统不支持所传入的<code>charset</code>字符集,则按照系统默认字符集进行转换 */ public static byte[] getBytes(String data, String charset){ data = (data==null ? "" : data); if(isEmpty(charset)){ return data.getBytes(); } try { return data.getBytes(charset); } catch (UnsupportedEncodingException e) { System.out.println("将字符串[" + data + "]转为byte[]时发生异常:系统不支持该字符集[" + charset + "]"); return data.getBytes(); } } /** * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 * @see 该方法会将字节数组中的所有字节均格式化为字符串 * @see 使用说明详见<code>formatToHexStringWithASCII(byte[], int, int)</code>方法 */ public static String buildHexStringWithASCII(byte[] data){ return buildHexStringWithASCII(data, 0, data.length); } /** * 通过ASCII码将十进制的字节数组格式化为十六进制字符串 * @see 该方法常用于字符串的十六进制打印,打印时左侧为十六进制数值,右侧为对应的字符串原文 * @see 在构造右侧的字符串原文时,该方法内部使用的是平台的默认字符集,来解码byte[]数组 * @see 该方法在将字节转为十六进制时,默认使用的是<code>java.util.Locale.getDefault()</code> * @see 详见String.format(String, Object...)方法和new String(byte[], int, int)构造方法 * @param data 十进制的字节数组 * @param offset 数组下标,标记从数组的第几个字节开始格式化输出 * @param length 格式长度,其不得大于数组长度,否则抛出java.lang.ArrayIndexOutOfBoundsException * @return 格式化后的十六进制字符串 */ public static String buildHexStringWithASCII(byte[] data, int offset, int length){ int end = offset + length; StringBuilder sb = new StringBuilder(); StringBuilder sb2 = new StringBuilder(); sb.append("\r\n------------------------------------------------------------------------"); boolean chineseCutFlag = false; for(int i=offset; i<end; i+=16){ sb.append(String.format("\r\n%04X: ", i-offset)); //X或x表示将结果格式化为十六进制整数 sb2.setLength(0); for(int j=i; j<i+16; j++){ if(j < end){ byte b = data[j]; if(b >= 0){ //ENG ASCII sb.append(String.format("%02X ", b)); if(b<32 || b>126){ //不可见字符 sb2.append(" "); }else{ sb2.append((char)b); } }else{ //CHA ASCII if(j == i+15){ //汉字前半个字节 sb.append(String.format("%02X ", data[j])); chineseCutFlag = true; String s = new String(data, j, 2); sb2.append(s); }else if(j == i&&chineseCutFlag){ //后半个字节 sb.append(String.format("%02X ", data[j])); chineseCutFlag = false; String s = new String(data, j, 1); sb2.append(s); }else{ sb.append(String.format("%02X %02X ", data[j], data[j + 1])); String s = new String(data, j, 2); sb2.append(s); j++; } } }else{ sb.append(" "); } } sb.append("| "); sb.append(sb2.toString()); } sb.append("\r\n------------------------------------------------------------------------"); return sb.toString(); } }
package com.jadyer.test; import java.util.HashMap; import java.util.Map; import org.junit.Assert; import org.junit.Test; /** * 这里用到的MinaUtil和HttpClientUtil均取自我的博文,地址如下 * http://blog.csdn.net/jadyer/article/details/8088068 * http://blog.csdn.net/jadyer/article/details/8087960 * @create Jul 9, 2013 7:59:11 PM * @author 玄玉<http://blog.csdn.net/jadyer> */ public class TestServer { @Test public void testTcp(){ String message = "00004710005101101992012092222400000201307071605"; String respData = MinaUtil.sendTCPMessage(message, "127.0.0.1", 9901, "UTF-8"); Assert.assertEquals("00003099999999`20130707144028`", respData); } /** * 也可直接浏览器访问http://127.0.0.1:8000/login以及http://127.0.0.1:8000/login?a=b&c=d&e=f * 只要浏览器页面显示"登录成功",即表示HTTP_GET测试通过 */ @Test public void testHttpGet(){ //先测试带参数的GET请求 String respData11 = HttpClientUtil.sendGetRequest("http://127.0.0.1:8000/login?a=b&c=d&e=f"); Assert.assertEquals("登录成功", respData11); //再测试不带参数的GET请求 String respData22 = HttpClientUtil.sendGetRequest("http://127.0.0.1:8000/login"); Assert.assertEquals("登录成功", respData22); } @Test public void testHttpPost(){ //先测试带报文体的POST请求(即带参数,模拟表单提交) String reqURL = "http://127.0.0.1:8000/login"; Map<String, String> params = new HashMap<String, String>(); params.put("username", "Jadyer"); params.put("password", "hongyu"); String respData11 = HttpClientUtil.sendPostSSLRequest(reqURL, params, "UTF-8"); Assert.assertEquals("登录成功", respData11); //再测试不带报文体的POST请求(不带参数) String respData22 = HttpClientUtil.sendPostSSLRequest(reqURL, new HashMap<String, String>(), "UTF-8"); Assert.assertEquals("登录成功", respData22); //最后测试一下特殊情况,即不带报文体,但在请求地址上带有参数的POST请求(建行外联平台就这么干的) reqURL = "http://127.0.0.1:8000/login?username=Jadyer&password=hongyu&aa=bb&cc=dd"; String respData33 = HttpClientUtil.sendPostSSLRequest(reqURL, new HashMap<String, String>(), "UTF-8"); Assert.assertEquals("登录成功", respData33); } }