在发送HTTP请求的时候会使用到POST和GET两种方式,如果是传送普通的表单数据,我们直接将参数到一个Key-value形式的Map中即可,随着JSON的应用越来越广,我们在很多场合需要传送JSON格式的参数。
下面我使用HttpClient类库提供的功能来实现这个,以便以后参考。
一.完善SpringMVC工程
完善SpringMVC工程(修改之前的Spring工程地址:http://bijian1013.iteye.com/blog/2307353),使其不仅支持GET、POST两种方式的请求,且支持普通表单数据请求和JSON格式的两种请求数据,完整工程代码见附件《SpringMVC.zip》,日志相关的依赖jar包可直接从HttpClient.zip中获取到。
@Controller
public class HelloController {
private static Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
private HelloService helloService;
@RequestMapping("/greeting")
public ModelAndView greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
Map map = new HashMap();
try {
//由于浏览器会把中文直接换成ISO-8859-1编码格式,如果用户在地址打入中文,需要进行如下转换处理
String tempName = new String(name.getBytes("ISO-8859-1"), "utf-8");
logger.trace("tempName:" + tempName);
logger.info(tempName);
String userName = helloService.processService(tempName);
map.put("userName", userName);
logger.trace("运行结果:" + map);
} catch (UnsupportedEncodingException e) {
logger.error("HelloController greeting方法发生UnsupportedEncodingException异常:" + e);
} catch (Exception e) {
logger.error("HelloController greeting方法发生Exception异常:" + e);
}
return new ModelAndView("/hello", map);
}
@RequestMapping(value="/processing", method = RequestMethod.POST)
public ModelAndView processing(HttpServletRequest request, HttpServletResponse response) {
Enumeration en = request.getParameterNames();
while (en.hasMoreElements()) {
String paramName = (String) en.nextElement();
String paramValue = request.getParameter(paramName);
}
String name = request.getParameter("name");
String age = request.getParameter("age");
UserDTO userDTO = new UserDTO();
userDTO.setName(name);
userDTO.setAge(Integer.valueOf(age));
logger.info("process param is :{}" + userDTO);
Map map = new HashMap();
try {
userDTO = helloService.processService(userDTO);
//返回请求结果
map.put("name", userDTO.getName());
map.put("age", userDTO.getAge());
} catch (Exception e) {
logger.info("请求处理异常:" + e);
}
return new ModelAndView("/user", map);
}
/**
* @responseBody表示该方法的返回结果直接写入HTTP response body中
* 一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径
* 加上@responseBody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。
* 比如异步获取json数据,加上@responsebody后,会直接返回json数据。
*/
@ResponseBody
@RequestMapping(value="/greet",method = RequestMethod.GET)
public Map greet(HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "name", defaultValue = "World") String name) {
Map map = null;
try {
//由于浏览器会把中文直接换成ISO-8859-1编码格式,如果用户在地址打入中文,需要进行如下转换处理
String tempName = new String(name.getBytes("ISO-8859-1"), "utf-8");
logger.trace("tempName:" + tempName);
logger.info(tempName);
String userName = helloService.processService(tempName);
map = new HashMap();
map.put("userName", userName);
logger.trace("运行结果:" + map);
} catch (UnsupportedEncodingException e) {
logger.error("HelloController greet方法发生UnsupportedEncodingException异常:" + e);
} catch (Exception e) {
logger.error("HelloController greet方法发生Exception异常:" + e);
}
return map;
}
@ResponseBody
@RequestMapping(value="/process",method = RequestMethod.POST)
public String process(HttpServletRequest request, @RequestBody String requestBody) {
logger.info("process param is :{}" + requestBody);
JSONObject result = new JSONObject();
try {
JSONObject jsonObject = JSONObject.fromObject(requestBody);
UserDTO userDTO = (UserDTO) JSONObject.toBean(jsonObject, UserDTO.class);
userDTO = helloService.processService(userDTO);
//返回请求结果
result.put("status", "SUCCESS");
result.put("userDTO", userDTO);
} catch (Exception e) {
logger.info("请求处理异常! params is:{}", requestBody);
result.put("status", "FAIL");
}
return result.toString();
}
}
二.HttpClient请求普通的表单数据,返回HTML页面
package com.bijian.study;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.http.client.methods.HttpPost;
/**
* Http请求工具类
* 请求的是普通的表单数据,返回HTML页面
*
* 需要导入commons-codec-1.3.jar
*/
public class HttpClientUtil {
/**
* httpClient的get请求方式
*
* @param url
* @param charset
* @return
* @throws Exception
*/
public static String doGet(String url, String charset) throws Exception {
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(url);
if (null == url || !url.startsWith("http")) {
throw new Exception("请求地址格式不对");
}
// 设置请求的编码方式
if (null != charset) {
method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=" + charset);
} else {
method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=" + "utf-8");
}
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {// 打印服务器返回的状态
System.out.println("Method failed: " + method.getStatusLine());
}
// 返回响应消息
byte[] responseBody = method.getResponseBodyAsString().getBytes(method.getResponseCharSet());
// 在返回响应消息使用编码(utf-8或gb2312)
String response = new String(responseBody, "utf-8");
System.out.println("------------------response:" + response);
// 释放连接
method.releaseConnection();
return response;
}
/**
* httpClient的get请求方式2
*
* @param url
* @param charset
* @return
* @throws Exception
*/
public static String doGet2(String url, String charset) throws Exception {
/*
* 使用 GetMethod 来访问一个 URL 对应的网页,实现步骤: 1:生成一个 HttpClinet 对象并设置相应的参数。
* 2:生成一个 GetMethod 对象并设置响应的参数。 3:用 HttpClinet 生成的对象来执行 GetMethod 生成的Get
* 方法。 4:处理响应状态码。 5:若响应正常,处理 HTTP 响应内容。 6:释放连接。
*/
/* 1 生成 HttpClinet 对象并设置参数 */
HttpClient httpClient = new HttpClient();
// 设置 Http 连接超时为5秒
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
/* 2 生成 GetMethod 对象并设置参数 */
GetMethod getMethod = new GetMethod(url);
// 设置 get 请求超时为 5 秒
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
// 设置请求重试处理,用的是默认的重试处理:请求三次
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
String response = "";
/* 3 执行 HTTP GET 请求 */
try {
int statusCode = httpClient.executeMethod(getMethod);
/* 4 判断访问的状态码 */
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + getMethod.getStatusLine());
}
/* 5 处理 HTTP 响应内容 */
// HTTP响应头部信息,这里简单打印
Header[] headers = getMethod.getResponseHeaders();
for (Header h : headers)
System.out.println(h.getName() + "------------ " + h.getValue());
// 读取 HTTP 响应内容,这里简单打印网页内容
byte[] responseBody = getMethod.getResponseBody();// 读取为字节数组
response = new String(responseBody, charset);
System.out.println("----------response:" + response);
// 读取为 InputStream,在网页内容数据量大时候推荐使用
// InputStream response = getMethod.getResponseBodyAsStream();
} catch (HttpException e) {
// 发生致命的异常,可能是协议不对或者返回的内容有问题
System.out.println("Please check your provided http address!");
e.printStackTrace();
} catch (IOException e) {
// 发生网络异常
e.printStackTrace();
} finally {
/* 6 .释放连接 */
getMethod.releaseConnection();
}
return response;
}
/**
* 执行一个HTTP POST请求,返回请求响应的HTML
*
* @param url 请求的URL地址
* @param params 请求的查询参数,可以为null
* @param charset 字符集
* @param pretty 是否美化
* @return 返回请求响应的HTML
*/
public static String doPost(String url, Map _params, String charset, boolean pretty) {
StringBuffer response = new StringBuffer();
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
// 设置Http Post数据
if (_params != null) {
for (Map.Entry entry : _params.entrySet()) {
method.setParameter(entry.getKey(), String.valueOf(entry.getValue()));
}
}
// 设置Http Post数据 方法二
// if(_params != null) {
// NameValuePair[] pairs = new NameValuePair[_params.size()];//纯参数了,键值对
// int i = 0;
// for (Map.Entry entry : _params.entrySet()) {
// pairs[i] = new NameValuePair(entry.getKey(), String.valueOf(entry.getValue()));
// i++;
// }
// method.addParameters(pairs);
// }
try {
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
// 读取为 InputStream,在网页内容数据量大时候推荐使用
BufferedReader reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(),
charset));
String line;
while ((line = reader.readLine()) != null) {
if (pretty)
response.append(line).append(System.getProperty("line.separator"));
else
response.append(line);
}
reader.close();
}
} catch (IOException e) {
System.out.println("执行HTTP Post请求" + url + "时,发生异常!");
e.printStackTrace();
} finally {
method.releaseConnection();
}
System.out.println("--------------------" + response.toString());
return response.toString();
}
}
测试类HttpClientTest.java
package com.bijian.study;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpClientTest {
private static Logger logger = LoggerFactory.getLogger(HttpRequestTest.class);
public static void main(String[] args) {
getRequestTest();
getRequestTest2();
postRequestTest();
}
private static void getRequestTest() {
String url = "http://localhost:8080/SpringMVC/greeting?name=lisi";
try {
String str = HttpClientUtil.doGet(url, "UTF-8");
if (str != null) {
logger.info("http Get request result:" + str);
} else {
logger.info("http Get request process fail");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void getRequestTest2() {
String url = "http://localhost:8080/SpringMVC/greeting?name=lisi";
try {
String str = HttpClientUtil.doGet2(url, "UTF-8");
if (str != null) {
logger.info("http Get request result:" + str);
} else {
logger.info("http Get request process fail");
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static void postRequestTest() {
String url = "http://localhost:8080/SpringMVC/processing";
Map _params = new HashMap();
_params.put("name", "zhangshang");
_params.put("age", 25);
String str = HttpClientUtil.doPost(url, _params, "UTF-8", true);
if (str != null) {
logger.info("http Post request result:" + str);
} else {
logger.info("http Post request process fail");
}
}
}
三.HttpClient请求json数据返回json数据
package com.bijian.study;
import java.io.IOException;
import java.net.URLDecoder;
import net.sf.json.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Http请求工具类,发送json返回json
*
* 除了要导入json-lib-2.1.jar之外,还必须有其它几个依赖包:
* commons-beanutils.jar
* commons-httpclient.jar
* commons-lang.jar
* ezmorph.jar
* morph-1.0.1.jar
* 另外,commons-collections.jar也需要导入
*/
public class HttpRequestUtil {
private static Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class);
/**
* 发送get请求
* @param url 路径
* @return
*/
public static JSONObject httpGet(String url){
//get请求返回结果
JSONObject jsonResult = null;
try {
DefaultHttpClient client = new DefaultHttpClient();
//发送get请求
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
/**请求发送成功,并得到响应**/
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
/**读取服务器返回过来的json字符串数据**/
String strResult = EntityUtils.toString(response.getEntity());
/**把json字符串转换成json对象**/
jsonResult = JSONObject.fromObject(strResult);
url = URLDecoder.decode(url, "UTF-8");
} else {
logger.error("get请求提交失败:" + url);
}
} catch (IOException e) {
logger.error("get请求提交失败:" + url, e);
}
return jsonResult;
}
/**
* httpPost
* @param url 路径
* @param jsonParam 参数
* @return
*/
public static JSONObject httpPost(String url,JSONObject jsonParam){
return httpPost(url, jsonParam, false);
}
/**
* post请求
* @param url url地址
* @param jsonParam 参数
* @param noNeedResponse 不需要返回结果
* @return
*/
public static JSONObject httpPost(String url,JSONObject jsonParam, boolean noNeedResponse){
//post请求返回结果
DefaultHttpClient httpClient = new DefaultHttpClient();
JSONObject jsonResult = null;
HttpPost method = new HttpPost(url);
try {
if (null != jsonParam) {
//解决中文乱码问题
StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
method.setEntity(entity);
}
HttpResponse result = httpClient.execute(method);
url = URLDecoder.decode(url, "UTF-8");
/**请求发送成功,并得到响应**/
if (result.getStatusLine().getStatusCode() == 200) {
String str = "";
try {
/**读取服务器返回过来的json字符串数据**/
str = EntityUtils.toString(result.getEntity());
if (noNeedResponse) {
return null;
}
/**把json字符串转换成json对象**/
jsonResult = JSONObject.fromObject(str);
} catch (Exception e) {
logger.error("post请求提交失败:" + url, e);
}
}
} catch (IOException e) {
logger.error("post请求提交失败:" + url, e);
}
return jsonResult;
}
}
测试类HttpRequestTest.java
package com.bijian.study;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.json.JSONObject;
import com.bijian.study.dto.UserDTO;
/**
* Http请求测试类
*/
public class HttpRequestTest {
private static Logger logger = LoggerFactory.getLogger(HttpRequestTest.class);
public static void main(String[] args) {
getRequestTest();
postRequestTest();
}
private static void getRequestTest() {
String url = "http://localhost:8080/SpringMVC/greet?name=lisi";
JSONObject jsonObject = HttpRequestUtil.httpGet(url);
if(jsonObject != null) {
String userName = (String) jsonObject.get("userName");
logger.info("http Get request process sucess");
logger.info("userName:" + userName);
}else {
logger.info("http Get request process fail");
}
}
private static void postRequestTest() {
String url = "http://localhost:8080/SpringMVC/process";
UserDTO userDTO = new UserDTO();
userDTO.setName("zhangshang");
userDTO.setAge(25);
JSONObject jsonParam = JSONObject.fromObject(userDTO);
JSONObject responseJSONObject = HttpRequestUtil.httpPost(url, jsonParam);
if(responseJSONObject != null && "SUCCESS".equals(responseJSONObject.get("status"))) {
JSONObject userStr = (JSONObject) responseJSONObject.get("userDTO");
userDTO = (UserDTO) JSONObject.toBean(userStr, UserDTO.class);
logger.info("http Post request process sucess");
logger.info("userDTO:" + userDTO);
}else {
logger.info("http Post request process fail");
}
}
}
完整的工程代码请下载附件《HttpClient.zip》。
四.补充说明
1.如果会出现异常:java.lang.NoClassDefFoundError: net/sf/ezmorph/Morpher,原因是少了JAR包,造成类找不到,除了要导入JSON网站上面下载的json-lib-2.1.jar包之外,还必须有其它几个依赖包:
commons-beanutils.jar commons-httpclient.jar commons-lang.jar ezmorph.jar morph-1.0.1.jar
2.@responseBody表示该方法的返回结果直接写入HTTP response body中。一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@responseBody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。比如异步获取json数据,加上@responsebody后,会直接返回json数据。
3.关于HttpClient的其它方面的学习使用,可以参考:http://www.iteblog.com/archives/1379。附件《httpclientutil.zip》就是从这里下载的。
4.在实际使用当中,我们可能需要随机变换请求数据,甚至随机请求不同的服务器,可以参考如下方式。
public static void main(String arg[]) throws Exception {
while (true) {
String[] urlArray = {Constant.URL_1, Constant.URL_2};
int index = new Random().nextInt(2);
String requestUrl = urlArray[index];
System.out.println(requestUrl);
...
JSONObject jsonMsg = JSONObject.fromObject(obj);
String ret = HttpRequestUtil.doPost(requestUrl, jsonMsg);
System.out.println(ret);
Thread.sleep(50);
}
}
Constant.java
public class Constant {
public static final String URL_1 = PropertiesFileUtil.getPropValue("url1", "config");
public static final String URL_2 = PropertiesFileUtil.getPropValue("url2", "config");
}
import java.util.ResourceBundle;
import org.apache.commons.lang.StringUtils;
public final class PropertiesFileUtil {
public static String getPropValue(String keyName, String propsName) {
ResourceBundle resource = ResourceBundle.getBundle(propsName);
String value = resource.getString(keyName);
return value;
}
/**
* 获取配置文件中keyName对应的value
*/
public static String getPropValue(String keyName, String propsName, String defaultValue) {
ResourceBundle resource = ResourceBundle.getBundle(propsName);
String value = resource.getString(keyName);
if (StringUtils.isEmpty(value)) {
value = defaultValue;
}
return value;
}
}
url1=http://localhost:8080/SpringMVC/greet?name=lisi
url2=http://127.0.0.1:8080/SpringMVC/greet?name=zhangshan