因为需要实现java下的基于http的服务,因此开始了相应的扫盲旅程,因为之前是个完全的小白,为了帮助测试,客户端和服务端都实现了一下,写的比较简单,仅提供思路。
客户端:上网搜了一下,客户端的实现主要有两种方式:(1)基于第三方插件实现,例如用的比较多的HTTPClient;(2)基于java的标准类HTTPURLConnection实现;两种方法都试了一下,具体原理没有深究,最后还是选用的第二种方法。感觉操作较少,功能上差别不大。
服务端:服务端的实现走了不少弯路,起初以为建个普通的java工程就ok了,结果,发现网上的实例都没有main函数,顿时蒙了,这是个什么机制,后来才发现需要构建web工程,汗!构建了web工程又发现怎么没有web.xml文件,发现还需要一个服务运行的web容器,就下了tomcat,按照网上教程自己配置tomcat失败了,在eclipse中怎么都发现不了tomcat,后来还是通过eclipse中的help-install new software才配置成功,参考文章:https://blog.csdn.net/mmayanshuo/article/details/79461384,然后再建web工程就有了web.xml文件了,该文件是web工程的入口配置文件。
下面是我在实验过程中遇到的一些问题和心得:
1、tomcat能够帮助服务起一个线程,让服务一直处于运行态;
2、服务在tomcat中运行起来后,如果修改程序,tomcat会自动识别到程序发生了修改,自动将修改程序运行到其中,这就方便了实现测试,不需要每次都重新运行程序启动tomcat;
3、若是web.xml文件中的内容发生变化,tomcat是识别不到的,这种情况需要重新运行程序,重启tomcat;
4、在web.xml文件中需要定义服务相关信息:
<servlet>
<servlet-name>HTTPServer</servlet-name>
<servlet-class>com.server.HTTPServer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HTTPServer</servlet-name>
<url-pattern>/HTTPServer</url-pattern>
其中servlet描述了服务信息,servlet-name是服务类名,servlet-class是包名+类名,servlet-mapping描述了URL相关信息,url-pattern表示服务所在路径;
5、在客户端定义URL:
String url = "http://localhost:8080/mytest/HTTPServer,其中mytest是构建工程名,HTTPServer是要调用的服务所在的类名;
6、实现过程中还碰到了一个坑,就是jar包的添加,构建web工程后,我按照普通java工程添加jar包的方式新建了个文件夹放jar包,再添加到路径,结果总是提示出错,后来参考了这篇文章,才成功https://blog.csdn.net/tylor_ljh/article/details/72628844
上代码:
客户端:
package com.client;
import java.awt.List;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
/********通过java内置类URLConnection实现http的客户端请求**************/
public class HTTPClient {
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url) {
String result = "";
BufferedReader in = null;
try {
//String urlNameString = url + "?" + param;
String urlNameString = url + "?";
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, java.util.List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
//POST方式发送HTTP请求
public static void main(String[] args) {
//String json = "key=123&v=456";
String url = "http://localhost:8080/mytest/HTTPServer";
String outPackage = null;
outPackage = sendGet(url);
//System.out.println("客户端日志----POST方式调用HTTP,请求报文为:" + json);
System.out
.println("\nauthor<pantp>===========客户端日志----POST方式调用HTTP服务,HTTP服务端响应报文如下:=============\n");
System.out.println(outPackage);
System.out
.println("\nauthor<pantp>================================================================\n");
}
}
服务端:创建工程名为mytest,添加的库见下图
package com.server;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.io.FileUtils;
import net.sf.json.JSONObject;
import net.sf.json.JSONArray;
//import net.sf.json.JSONException;
import java.io.File;
/**
* ********************************************************
* 模拟的一个Http服务,处理客户端的post请求
***********************************************************/
public class HTTPServer extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String inJson = null;// 保存HTTP客户端请求报文
String outJson = null;// 保存HTTP服务端输出报文
String outJson1 = null;// 保存HTTP服务端输出报文
System.out.println("come to doPost method");
// 获得输人报文然后打印出来
inJson = getInJson(request);
System.out
.println("\nauthor<pantp>===========服务端日志----POST方式接收HTTP请求,HTTP服务端收到的请求报文如下:==========\n");
System.out.println(inJson);
System.out
.println("\nauthor<pantp>=================================================================\n");
// 以下代码部分获得请求报文,然后去做校验,转换以及其他的调用其他的业务逻辑等,这里就不管它
// ........................................................................
// 下面部分是输出部分的处理
JSONArray jsonArray = null;
String dir = request.getSession().getServletContext().getRealPath("/resource/data.json");
try {
System.out.println("come to doPost method outjson1");
outJson1 = FileUtils.readFileToString(new File("D:/eclipseworkspace/webServer/resource/data.json"), "UTF-8");
JSONObject jsonObject = JSONObject.fromObject(outJson1);
if (jsonObject != null) {
jsonArray = jsonObject.getJSONArray("serviceList");
}
System.out.println("文件内容:"+jsonObject.getJSONArray("serviceList"));
System.out.println("serviceName:"+jsonArray.getJSONObject(0).get("serviceName"));
System.out.println("文件内容strings####:"+outJson1);
} catch (Exception e) {
e.printStackTrace();
jsonArray = null;
}
response.setContentType("application/json; charset=UTF-8");
response.getWriter().print(outJson1);
}
// 获得请求的报文,并作简单的校验
public String getInJson(HttpServletRequest request) throws IOException {
byte buffer[] = new byte[64 * 1024];
InputStream in = request.getInputStream();// 获取输入流对象
int len = in.read(buffer);
// 必须对数组长度进行判断,否则在new byte[len]会报NegativeArraySizeException异常
if (len < 0) {
throw new IOException("请求报文为空");
}
String encode = request.getCharacterEncoding();// 获取请求头编码
// 必须对编码进行校验,否则在new String(data, encode);会报空指针异常
if (null == encode || encode.trim().length() < 0) {
throw new IOException("请求报文未指明请求编码");
}
byte data[] = new byte[len];
// 把buffer数组的值复制到data数组
System.arraycopy(buffer, 0, data, 0, len);
// 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
String inJson = new String(data, encode);
return inJson;
}
// get的处理方式
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String inJson = null;// 保存HTTP客户端请求报文
String outJson = null;// 保存HTTP服务端输出报文
String outJson1 = null;// 保存HTTP服务端输出报文
System.out.println("come to doGet method So return");
// 获得输人报文然后打印出来
//inJson = getInJson(request);
System.out
.println("\nauthor<pantp>===========服务端日志----POST方式接收HTTP请求,HTTP服务端收到的请求报文如下:==========\n");
//System.out.println(inJson);
System.out
.println("\nauthor<pantp>=================================================================\n");
// 以下代码部分获得请求报文,然后去做校验,转换以及其他的调用其他的业务逻辑等,这里就不管它
// ........................................................................
// 下面部分是输出部分的处理
JSONArray jsonArray = null;
String dir = request.getSession().getServletContext().getRealPath("/resource/data.json");
try {
System.out.println("come to doPost method outjson1");
outJson1 = FileUtils.readFileToString(new File("D:/mysoftware/eclipseworkspace/webServer/resource/data.json"), "UTF-8");
JSONObject jsonObject = JSONObject.fromObject(outJson1);
if (jsonObject != null) {
jsonArray = jsonObject.getJSONArray("serviceList");
}
System.out.println("文件内容:"+jsonObject.getJSONArray("serviceList"));
System.out.println("文件内容:"+jsonArray.getJSONObject(0).get("serviceName"));
System.out.println("文件内容strings####:"+outJson1);
} catch (Exception e) {
e.printStackTrace();
jsonArray = null;
}
response.setContentType("application/json; charset=UTF-8");
response.getWriter().print(outJson1);
}
}