api接口签名加密请求,从springmvc4项目搭建开始
本文一步一步教你如何实现简单API接口请求。
很多业务需要用到简单的api接口请求。通俗的说,例如客户端,客户端不做逻辑处理,只是简单的发起业务请求完成操作。复杂的说,由于互联网发展迅速,大到各种语言php、java、.net之间通讯,各种移动设备层出不穷,分布式架构不断应用,各种客户端Client到处都是;小到内部通讯接口业务、提供合作方某业务接口等等;为了不重复开发,统一管理,这时候需要一个统一的机制,所以api诞生了,更有标准架构设计风格RESTful。
那么如何设计一个简单api请求签名接口呢?
这里不谈WebService,不谈OAuth2.0,只谈简单的api签名接口。
下面来跟我一步一步实现,真正的从无到有介绍。
本请求接口的实现,是模拟支付宝支付接口签名方案,支付宝支付接口签名方式大家也比较熟悉,对简单接口请求来说已经太够用了。
api接口设计方式和思路
1、公开性
接口是公网可访问的,不希望被随便请求,需要token签名认证才能调用,接口提供方提供接口密钥。
2、安全性
模拟支付宝接口签名方式签名,请求参数按照key=value&key=value方式拼接的未签名原始字符串(含时间戳),再对原始字符串进行签名(加密钥)。如:md5(id=1×tamp=1514020967 + 密钥)
3、模式性
请求
请求参数 + 时间戳 + 签名(请求参数+时间戳+密钥)
接收
md5(接收参数(去除签名) + 密钥) == 接收参数(签名)
后再比较 接收参数(时间戳) 跟 当前系统时间戳 的时效性
准备工作
本项目采用maven搭建,框架采用springmvc4.3。
我的JDK版本:jdk 1.7
我的开发工具:Intellij IDEA 6.1
我的测试工具:Postman
搭建简单springmvc项目
如果你已有项目,请跳过该步骤。
1、打开IDEA新建项目,选择maven -> 勾选Create from archetype -> 选择maven-archetype->webapp
2、输入递属项目命名空间 和 项目名称
3、选择maven版本
4、输入项目名称 和 项目目录位置
5、配置项目,打开Project Structure,配置api模块,在main下添加java目录,标记为Sources
6、配置tomcat,按+号选择Tomcat Server -> Local。输入名称,选择Deployment再点击右侧+号选择api:war exploded
7、简单配置springmvc
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.weizhixi</groupId> <artifactId>api</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>api Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- SpringMVC 相关依赖 --> <spring.version>4.3.1.RELEASE</spring.version> <jackson.version>2.5.0</jackson.version> <!-- JSP 相关依赖 --> <jsp.version>2.1</jsp.version> <jstl.version>1.2</jstl.version> <servlet.version>3.0.1</servlet.version> <!-- 其他 相关依赖 --> <slf4j.version>1.7.5</slf4j.version> <commons-codec.version>1.9</commons-codec.version> <commons-lang3.version>3.2.1</commons-lang3.version> <junit.version>3.8.1</junit.version> </properties> <dependencies> <!-- SpringMVC 相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <!-- JSP 相关依赖 --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>${jsp.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <!-- 其他 相关依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>${commons-codec.version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>api</finalName> </build> </project>
log4j.properties
### FATAL, ERROR, WARN, INFO, DEBUG log4j.rootLogger=INFO,stdout,D ### stdout ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.COnversionPattern= %d{ABSOLUTE} %5p %c{1}:%L - %m%n ### logFile ### ### save error to another file ### log4j.appender.D=org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File=logs/log.log log4j.appender.D.Append=true log4j.appender.D.Threshold=INFO log4j.appender.D.layout=org.apache.log4j.PatternLayout log4j.appender.D.layout.COnversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%t\:%r] - [%p] %m%n log4j.logger.com.weizhixi=DEBU
spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:cOntext="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd"> <!--扫描包--> <context:component-scan base-package="com.weizhixi.*" /> <!--依赖注入--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <!--防止请求和响应乱码 默认--> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="defaultCharset" value="UTF-8" /> <property name="writeAcceptCharset" value="false" /> </bean> <!--防止请求和响应乱码 JSON--> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="defaultCharset" value="UTF-8" /> </bean> </mvc:message-converters> </mvc:annotation-driven> <!--静态资源访问--> <mvc:default-servlet-handler/> <!--视图解释类--> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑--> <property name="suffix" value=".jsp"></property> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> </bean> </beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!--设置字符编码 --> <filter> <filter-name>encodingFilter</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>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置SpringMVC --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
简单项目springmvc4建立完成,这时候可以点击右侧栏MavenProjects->Lifecycle->clean/compile/package打包,和右上角tomcat运行了,接下来进入开发工作。
API接口实现
1、自定义业务异常类(BussException) - 用于抛出业务类异常
package com.weizhixi.util; /** * 自定义业务异常 * Created by cxq on 2017-12-23. */ public class BussException extends Exception { private static final long serialVersionUID = 7125646661082731971L; private String errorMessage; private String errorCode; public BussException() { super(); } public BussException(String message) { super(message); this.errorMessage = message; } public BussException(String code, String message) { super(message); this.errorCode = code; this.errorMessage = message; } public BussException(Throwable cause) { super(cause); } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } public String getErrorCode(){ return this.errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } }
2、JSON结构集(JsonResult) - 用于接口返回JSON数据给客户端
package com.weizhixi.vo; import java.io.Serializable; /** * JSON结果集 * Created by cxq on 2017-12-23. */ public class JsonResult<T> implements Serializable { private static final long serialVersionUID = -1382917362444380590L; /**成功标识*/ private Boolean success; /**错误代号*/ private String errorCode; /**错误信息*/ private String errorMsg; /**错误信息追踪*/ private String errorTrace; /**结果*/ private T data; public JsonResult(String errorCode, String errorMsg, String errorTrace){ this.success = false; this.errorCode = errorCode; this.errorMsg = errorMsg; this.errorTrace = errorTrace; this.data = null; } public JsonResult(String errorCode, String errorMsg){ this.success = false; this.errorCode = errorCode; this.errorMsg = errorMsg; this.data = null; } public JsonResult(T data) { this.success = true; this.data = data; } public JsonResult(){ this.success = true; this.data = null; } public Boolean getSuccess() { return success; } public void setSuccess(Boolean success) { this.success = success; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getErrorTrace() { return errorTrace; } public void setErrorTrace(String errorTrace) { this.errorTrace = errorTrace; } }
3、用户值对象(UserVo) - 用于测试
package com.weizhixi.vo; import java.io.Serializable; /** * 用户Vo * Created by cxq on 2017-12-23. */ public class UserVo implements Serializable{ private static final long serialVersionUID = -3184783144438300884L; /** id */ private Integer id; /** 姓名 */ private String name; /** 标签 */ private Integer[] tags; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer[] getTags() { return tags; } public void setTags(Integer[] tags) { this.tags = tags; } }
4、简单HTTP请求(HttpRequest) - 用于测试
package com.weizhixi.util; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; /** * 测试请求,只是简单的模拟GET/POST请求.你也可以用HttpClient或已有的请求方式 * Created by cxq on 2017-12-24. */ public class HttpRequest { /** * 为了测试,只是简单的模拟GET请求,按你实际的来 * @param reqUrl * @return String 响应结果 */ public static String get(String reqUrl){ try { URL url = new URL(reqUrl); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setDoOutput(false); urlConnection.setDoInput(true); urlConnection.setRequestMethod("GET"); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Connection", "Keep-Alive"); urlConnection.setRequestProperty("Charset", "UTF-8"); urlConnection.setConnectTimeout(10000); urlConnection.setReadTimeout(10000); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); StringBuffer sb = new StringBuffer(); String line = in.readLine(); while(line != null){ sb.append(line); line = in.readLine(); } in.close(); urlConnection.disconnect(); return sb.toString(); }catch(Exception e){ e.printStackTrace(); return e.getMessage(); } } /** * 为了测试,只是简单的模拟POST请求,按你实际的来 * @param reqUrl * @param reqParams * @return String 响应结果 */ public static String post(String reqUrl, String reqParams){ try { URL url = new URL(reqUrl); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setDoOutput(true); urlConnection.setDoInput(true); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); urlConnection.setRequestProperty("Connection", "Keep-Alive"); urlConnection.setRequestProperty("Charset", "UTF-8"); urlConnection.setConnectTimeout(10000); urlConnection.setReadTimeout(10000); DataOutputStream dos = new DataOutputStream(urlConnection.getOutputStream()); dos.writeBytes(reqParams); dos.flush(); dos.close(); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8")); StringBuffer sb = new StringBuffer(); String line = in.readLine(); while(line != null){ sb.append(line); line = in.readLine(); } in.close(); urlConnection.disconnect(); return sb.toString(); }catch (Exception e){ e.printStackTrace(); return e.getMessage(); } } }
5、自定义签名类(Sign)- 用户请求签名及认证,是签名核心类
package com.weizhixi.util; import org.apache.commons.codec.digest.DigestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.*; /** * 签名类,模拟支付宝接口签名机制,部分摘录于支付宝Demo * Created by cxq on 2017-12-23. */ public class Sign { private static Logger logger = LoggerFactory.getLogger(Sign.class); /** 加密密钥 */ private final static String SECRET_KEY = "weizhixi"; /** 字符编码 */ private final static String INPUT_CHARSET = "UTF-8"; /** 超时时间 */ private final static int TIME_OUT = 15; //TODO 公用 /** * 请求参数Map转换验证Map * @param requestParams 请求参数Map * @param charset 是否要转utf8编码 * @return * @throws UnsupportedEncodingException */ public static Map<String,String> toVerifyMap(Map<String, String[]> requestParams, boolean charset) { Map<String,String> params = new HashMap<String,String>(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化 if(charset) valueStr = getContentString(valueStr, INPUT_CHARSET); params.put(name, valueStr); } return params; } /** * 除去数组中的空值和签名参数 * @param sArray 签名参数组 * @return 去掉空值与签名参数后的新签名参数组 */ public static Map<String, String> paraFilter(Map<String, String> sArray) { Map<String, String> result = new HashMap<String, String>(); if (sArray == null || sArray.size() <= 0) { return result; } for (String key : sArray.keySet()) { String value = sArray.get(key); if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) { continue; } result.put(key, value); } return result; } /** * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 * @param params 需要排序并参与字符拼接的参数组 * @return 拼接后字符串 */ public static String createLinkString(Map<String, String> params) { return createLinkString(params, false); } /** * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 * @param params 需要排序并参与字符拼接的参数组 * @param encode 是否需要UrlEncode * @return 拼接后字符串 */ public static String createLinkString(Map<String, String> params, boolean encode) { List<String> keys = new ArrayList<String>(params.keySet()); Collections.sort(keys); String prestr = ""; for (int i = 0; i < keys.size(); i++) { String key = keys.get(i); String value = params.get(key); if (encode) value = urlEncode(value, INPUT_CHARSET); if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符 prestr = prestr + key + "=" + value; } else { prestr = prestr + key + "=" + value + "&"; } } return prestr; } /** * 编码转换 * @param content * @param charset * @return * @throws UnsupportedEncodingException */ private static byte[] getContentBytes(String content, String charset) { if (charset == null || "".equals(charset)) { return content.getBytes(); } try { return content.getBytes(charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset); } } /** * 编码转换 * @param content * @param charset * @return */ private static String getContentString(String content, String charset) { if (charset == null || "".equals(charset)) { return new String(content.getBytes()); } try { return new String(content.getBytes("ISO-8859-1"), charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset); } } /** * URL转码 * @param content * @param charset * @return */ private static String urlEncode(String content, String charset) { try { return URLEncoder.encode(content, charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset); } } //TODO 签名 /** * 生成要请求的签名参数数组 * @param sParaTemp 需要签名的参数Map * @return 要请求的签名参数数组 */ public static Map<String, String> signMap(Map<String, String[]> sParaTemp) { //请求参数Map转换验证Map,并生成要请求的签名参数数组 return sign(toVerifyMap(sParaTemp, false)); } /** * 生成要请求的签名参数数组 * @param sParaTemp 需要签名的参数 * @return 要请求的签名参数数组 */ public static Map<String, String> sign(Map<String, String> sParaTemp) { //时间戳加入签名参数组中 sParaTemp.put("timestamp", String.valueOf(System.currentTimeMillis()/1000)); //除去数组中的空值和签名参数 Map<String, String> sPara = paraFilter(sParaTemp); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 String prestr = createLinkString(sPara); //生成签名结果 String mysign = DigestUtils.md5Hex(getContentBytes(prestr + SECRET_KEY, INPUT_CHARSET)); //签名结果加入请求提交参数组中 sPara.put("sign", mysign); return sPara; } /** * 生成要请求的签名参数字符串“参数=参数值”&链接 * @param sParaTemp 需要签名的参数Map * @return 请求的签名参数字符串 */ public static String signStringMap(Map<String, String[]> sParaTemp) { //生成要请求的签名参数数组 Map<String, String> sign = signMap(sParaTemp); //生成要请求的签名参数字符串“参数=参数值”&链接 return createLinkString(sign, true); } /** * 生成要请求的签名参数字符串“参数=参数值”&链接 * @param sParaTemp 需要签名的参数 * @return */ public static String signString(Map<String, String> sParaTemp) { //生成要请求的签名参数数组 Map<String, String> sign = sign(sParaTemp); //生成要请求的签名参数字符串“参数=参数值”&链接 return createLinkString(sign, true); } //TODO 验证签名 /** * 根据反馈回来的信息,生成签名结果 * @param paramsMap 通知返回来的请求参数Map * @return 验证结果 */ public static boolean verifyMap(Map<String, String[]> paramsMap) { //请求参数Map转换验证Map,并根据反馈回来的信息,生成签名结果 return verify(toVerifyMap(paramsMap, false)); } /** * 根据反馈回来的信息,生成签名结果 * @param params 通知返回来的参数数组 * @return 验证结果 */ public static boolean verify(Map<String, String> params) { String sign = ""; if(params.get("sign") != null) {sign = params.get("sign");} String timestamp = ""; if(params.get("timestamp") != null) {timestamp = params.get("timestamp");} //过滤空值、sign Map<String, String> sParaNew = paraFilter(params); //获取待签名字符串 String preSignStr = createLinkString(sParaNew); //获得签名验证结果 String mysign = DigestUtils.md5Hex(getContentBytes(preSignStr + SECRET_KEY, INPUT_CHARSET)); logger.debug("mysign:"+mysign+" sign:"+sign+" timestamp:"+(System.currentTimeMillis()/1000)); if(mysign.equals(sign)) { //时间不能为空 if((timestamp.trim()).equals("")) return false; //是否超时 if(((System.currentTimeMillis()/1000) - Long.valueOf(timestamp)) > TIME_OUT) return false; return true; } else { return false; } } }
6、新建控制器(IndexController)- 用于演示及用法
package com.weizhixi.controller; import com.weizhixi.util.BussException; import com.weizhixi.util.HttpRequest; import com.weizhixi.util.Sign; import com.weizhixi.vo.JsonResult; import com.weizhixi.vo.UserVo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; /** * 控制器 * Created by cxq on 2017-12-23. */ @Controller @RequestMapping(value = "/api/v1/index") public class IndexController { protected Logger logger = LoggerFactory.getLogger(this.getClass()); //模拟接收签名请求GET //传入参数 id timestamp sign @RequestMapping(value = "/find", method = RequestMethod.GET) @ResponseBody public JsonResult<Object> find(HttpServletRequest request, @RequestParam Integer id) { logger.debug("访问了控制器IndexController.find"); JsonResult<Object> result = new JsonResult<Object>(); try { //认证签名 if(!Sign.verifyMap(request.getParameterMap())) throw new BussException("签名错误"); logger.debug("正确签名 - 正常访问"); //这里是业务 - 模拟findById(id) UserVo vo = new UserVo(); vo.setId(id); vo.setName("微知兮"); result.setData(vo); }catch(BussException be){ logger.debug(be.getMessage()); result.setSuccess(false); result.setErrorMsg(be.getMessage()); }catch(Exception e){ logger.error("ERROR:", e); result.setSuccess(false); result.setErrorMsg(e.getMessage()); } return result; } //模拟接收签名请求POST //传入参数 UserVo:id name tags timestamp sign @RequestMapping(value = "/save", method = RequestMethod.POST) @ResponseBody public JsonResult<Object> save(HttpServletRequest request, UserVo vo) { logger.debug("访问了控制器IndexController.save"); JsonResult<Object> result = new JsonResult<Object>(); try { //认证签名 if(!Sign.verifyMap(request.getParameterMap())) throw new BussException("签名错误"); logger.debug("正确签名 - 正常访问"); //这里是业务 - 模拟 save(vo) result.setData(vo); }catch(BussException be){ logger.debug(be.getMessage()); result.setSuccess(false); result.setErrorMsg(be.getMessage()); }catch(Exception e){ logger.error("ERROR:", e); result.setSuccess(false); result.setErrorMsg(e.getMessage()); } return result; } }
注释的很多了,就不再啰嗦了。
使用演示
下面运行项目,测试下请求这2个接口。
打开:Postman 模拟GET、POST请求。
请求:
http://localhost:8080/api/v1/index/find?id=1×tamp=1514020967&sign=012a62ef8f26fce6cddf4c3691656a89
响应:
{ "success": true, "errorCode": null, "errorMsg": null, "errorTrace": null, "data": { "id": 1, "name": "微知兮" } }
请求:
http://localhost:8080/api/v1/index/save
参数:
field = value
id = 1
name = 微知兮
tags = 1
tags = 2
timestamp = 1514027981
sign = 776880607e2a8161499ba67da8fb505e
响应:
{ "success": true, "errorCode": null, "errorMsg": null, "errorTrace": null, "data": { "id": 1, "name": "微知兮", "tags": [ 1, 2 ] } }
再模拟下程序请求:
以下代码加入控制器就可以了
//模拟调用接口API获取参数 - GET @RequestMapping(value = "/get", method = RequestMethod.GET) @ResponseBody public String get(HttpServletRequest request){ Map<String,String> map = new HashMap<String, String>(); map.put("id","1"); //生成签名Get请求参数 String params = Sign.signString(map); //这里只是个参考和测试,只是简单的模拟GET请求 你也可以用HttpClient String inputLine = HttpRequest.get("http://localhost:8080/api/v1/index/find?"+params); logger.info(inputLine); return inputLine; } //模拟调用接口API获取参数 - POST @RequestMapping(value = "/post", method = RequestMethod.GET) @ResponseBody public String post(HttpServletRequest request){ Map<String,String> map = new HashMap<String, String>(); map.put("id","1"); map.put("name","微知兮"); map.put("tags","1,2,3"); //生成签名Post请求参数 String params = Sign.signString(map); //这里只是个参考和测试,只是简单的模拟POST请求 你也可以用HttpClient String inputLine = HttpRequest.post("http://localhost:8080/api/v1/index/save", params); logger.info(inputLine); return inputLine; }
再地址栏敲入:
http://localhost:8080/api/v1/index/get
http://localhost:8080/api/v1/index/post
发现一切happy
至此,全部已经介绍完毕,已附上完整例子,如需要请自行下载,附上php版本例子。
php例子请查看:http://www.weizhixi.com/user/index/article/id/58.html
本例子仅供学习研究,由于写的比较仓促,如有不妥当的地方欢迎指出。
已下载:526 次
已下载:840 次
原创文章,转载请注明出处:https://www.weizhixi.com/article/40.html