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=DEBUspring-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
本例子仅供学习研究,由于写的比较仓促,如有不妥当的地方欢迎指出。
已下载:580 次
已下载:930 次
原创文章,转载请注明出处:https://www.weizhixi.com/article/40.html
