java调用第三方api实践记录
准备工作
0. 前导图
项目文件结构
1. idea创建项目(不采用maven)
1)new > project > java > 项目名称
2)右键项目,添加框架支持,选择JAVAEE
3)配置idea的tomcat服务器,设置URL以及发布的上下文路径
4)在项目下新建lib文件夹,用于存放所需要的jar包
(注) 试图直接导入本地的jar包到项目时,不成功,没找到资源,所以采用项目下复制所需的jar包导入
2. 导spring以及springmvc必要jar包
commons-logging-1.2.jar
spring-aop-5.3.8.jar
spring-beans-5.3.8.jar
spring-context-5.3.8.jar
spring-core-5.3.8.jar
spring-expression-5.3.8.jar
spring-web-5.3.8.jar
spring-webmvc-5.3.8.jar
加到模块中
注:idea貌似不会自动调用tomcat的servlet-api.jar包,必须手动导入!
3. springmvc创建Hello World
采用分容器管理方式管理spring以及springmvc,配置文件放于src下
spring-service.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="top.dreamcenter.epoch" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <context:property-placeholder location="classpath:ThirdPartyService.properties"/> <bean id="apikey" class="java.lang.String"> <constructor-arg name="original" value="${APIKEY}"/> </bean> <bean id="chinaZKey" class="java.lang.String"> <constructor-arg name="original" value="${CHINAZ.KEY}"></constructor-arg> </bean> <bean id="qWeatherKey" class="java.lang.String"> <constructor-arg name="original" value="${QWEATHER.KEY}"></constructor-arg> </bean> </beans>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="top.dreamcenter.epoch" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> </context:component-scan> <mvc:default-servlet-handler/> <mvc:annotation-driven/> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- method 1 <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-service.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> --> <servlet> <servlet-name>thirdParty</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>thirdParty</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
编写代码
1. 创建工具类
ThirdPartyRequest [ 调用第三方api工具类]
package top.dreamcenter.epoch.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; public class ThirdPartyRequest { private static String doRequest(String urlPath,String data,String method) throws IOException { if (method.equalsIgnoreCase("GET") && data != null) urlPath = urlPath + "?" + data; // System.out.println(urlPath); URL url = new URL(urlPath); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod(method); OutputStreamWriter osw = null; if (data != null && method.equalsIgnoreCase("POST")) { connection.setDoOutput(true); osw = new OutputStreamWriter(connection.getOutputStream(),"utf-8"); osw.write(data); osw.flush(); } connection.setDoInput(true); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8")); String result = br.readLine(); if (osw != null) osw.close(); br.close(); return result; } /** * GET request * @param urlPath * @param data * @return * @throws IOException */ public static String getGETRequest(String urlPath,String data) throws IOException { return doRequest(urlPath,data,"GET"); } /** * POST request * @param urlPath * @param data * @return * @throws IOException */ public static String getPOSTRequest(String urlPath,String data) throws IOException { return doRequest(urlPath,data,"POST"); } }
JsonDataRegex [粗糙的json字符串类型结果取值]
package top.dreamcenter.epoch.util; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JsonDataRegex { /** * basic way to get Json Data by regex, not useful when too many cycle * @param jsonData * @param target * @return */ public static String getResult(String jsonData,String target){ Pattern pattern1 = Pattern.compile(target + "\":\"(.*?)\""); Pattern pattern2 = Pattern.compile(target + "\":\\{(.*?)\\}"); Pattern pattern3 = Pattern.compile(target + "\":\\[(.*?)\\]"); Matcher matcher = pattern1.matcher(jsonData); if (matcher.find()) return matcher.group(1); matcher = pattern2.matcher(jsonData); if (matcher.find()) return "{" + matcher.group(1) + "}"; matcher = pattern3.matcher(jsonData); if (matcher.find()) return "[" + matcher.group(1) + "]"; return ""; } }
2. 创建controller和service
ThirdPartyController
package top.dreamcenter.epoch.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import top.dreamcenter.epoch.service.ThirdPartyService; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Controller @RequestMapping("/api/third") public class ThirdPartyController { @Autowired private ThirdPartyService tps; @RequestMapping("/date") public void getDateDetail(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getDateDetail()); } @RequestMapping("/flatterer") public void getFlattererSentence(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getFlattererSentence()); } @RequestMapping("/rainbow") public void getRainbowPiSentence(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getRainbowPiSentence()); } @RequestMapping("/gold") public void getGoldSentence(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getGoldSentence()); } @RequestMapping("/ip/number") public void getIP(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getIP()); } @RequestMapping("/ip/detail") public void getIPDetail(HttpServletResponse response) throws IOException { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getIPDetail()); } }
ThirdPartyService
package top.dreamcenter.epoch.service; import org.springframework.stereotype.Service; import top.dreamcenter.epoch.util.JsonDataRegex; import top.dreamcenter.epoch.util.ThirdPartyRequest; import javax.annotation.Resource; import java.io.IOException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Calendar; @Service public class ThirdPartyService { @Resource(name = "apikey") private String apikey; @Resource(name = "chinaZKey") private String chinaZKey; @Resource(name = "qWeatherKey") private String qWeatherKey; public String getDateDetail() throws IOException { return ThirdPartyRequest.getGETRequest( "http://api.tianapi.com/txapi/lunar/index", "key=" + apikey); } public String getFlattererSentence() throws IOException { return ThirdPartyRequest.getGETRequest( "http://api.tianapi.com/txapi/tiangou/index", "key=" + apikey); } public String getRainbowPiSentence() throws IOException { return ThirdPartyRequest.getGETRequest( "http://api.tianapi.com/txapi/caihongpi/index", "key=" + apikey); } public String getGoldSentence() throws IOException { return ThirdPartyRequest.getGETRequest( "http://api.tianapi.com/txapi/one/index", "key=" + apikey); } public String getIP() throws IOException { return ThirdPartyRequest.getGETRequest( "http://api.ipify.org/",null); } public String getIPDetail() throws IOException { return ThirdPartyRequest.getGETRequest( "https://apidatav2.chinaz.com/single/ip", "key=" + chinaZKey + "&ip=" + getIP()); } }
开始测试与运行
1. 启动tomcat服务
第一次启动失败了,原因:端口被占用了。😓
改了端口后成功了,并且正常的访问到了各个api的数据
2. 添加新的api调用需求
@RequestMapping("/weather") public void getWeather(HttpServletResponse response) throws Exception { response.setContentType("application/json;charset=utf-8"); response.getWriter().write(tps.getWeather()); }
此时,如果仍然用我之前的调用api工具类的方法,出现500错误,
考虑到可能是url中的中文可能无法识别的原因,进行了UrlEncoding,结果确实不报错了,
只是返回的结果出现乱码,更改了各种可能的编码格式,都不能成功。
无论怎样修改都没有效果。
无奈之下百度,结果大多数都用的httpcomponent这个apache旗下的jar包
3. 导入httpcomponent
经过不断的测试,发现这些包是必须的:
slf4j-api-1.7.25.jar
httpcore5-5.1.1.jar
httpclient5-5.1.jar
并且,貌似发布到tomcat时,这些资源没有发布过去,
所以,配置发布的时候,把这几项加到WEB-INF/lib下
4. 添加httpcomponent方式的get请求
public static String doGetApache(String url){ //创建HttpClient对象 CloseableHttpClient httpClient = HttpClientBuilder.create().build(); HttpGet get = new HttpGet(url); try { get.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36"); HttpResponse response = httpClient.execute(get); if (response.getCode() == HttpStatus.SC_OK){ //返回json格式 String res = EntityUtils.toString(((CloseableHttpResponse) response).getEntity()); return res; } } catch (Exception e) { e.printStackTrace(); } return null; }
编写新api的请求服务
private String getDistrictInf(String district) throws IOException { return ThirdPartyRequest.doGetApache( "https://geoapi.qweather.com/v2/city/lookup" + "?" + "key=" + qWeatherKey + "&location=" + URLEncoder.encode(district,"utf-8")); } public String getWeather() throws Exception { String districtInf = getDistrictInf( JsonDataRegex.getResult(getIPDetail(), "District")); String districtCode = JsonDataRegex.getResult(districtInf, "id"); Calendar calendar = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String dateFormatted = sdf.format(calendar.getTime()); System.out.println(districtCode); return ThirdPartyRequest.doGetApache( "https://devapi.qweather.com/v7/weather/3d" + "?" + "key=" + qWeatherKey + "&location=" + districtCode +"&date=" + dateFormatted); }
一些总结
- 手动导jar包的话,jar包需要复制到项目下,并且servlet-api需要手动导入
- tomcat的url后面项目名字和发布的项目上下文一样才能访问的到
- ssm的整合有两中国方式,一种是DispatcherServlet配置时上下文值设置成通配,或者设置context-param/listener
- 配置文件放在src目录下
- maven真的香,虽然会对jar包不熟悉,但是,相比之下,太香了