阅读本文大概需要 10 分钟。
做接口需要考虑的问题
什么是接口
接口怎么开发
Result
package com.caiex.vb.model;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Result", propOrder = { "resultCode", "resultMsg" })
public class Result implements Serializable {
private static final long serialVersionUID = 10L;
protected int resultCode;
protected String resultMsg;
public int getResultCode() {
return this.resultCode;
}
public void setResultCode(int value) {
this.resultCode = value;
}
public String getResultMsg() {
return this.resultMsg;
}
public void setResultMsg(String value) {
this.resultMsg = value;
}
}
Response
package com.caiex.vb.model;
import java.io.Serializable;
public class Response implements Serializable {
private static final long serialVersionUID = 2360867989280235575L;
private Result result;
private Object data;
public Result getResult() {
if (this.result == null) {
this.result = new Result();
}
return result;
}
public void setResult(Result result) {
this.result = result;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
reponse code
public static int NO_AGENT_RATE = 1119; //未找到兑换率
public static int SCHEME_COMMIT_FAIL = 4000; //方案提交失败
public static int SCHEME_CONFIRMATION = 4001; //方案确认中
public static int SCHEME_NOT_EXIST = 4002; //方案不存在
public static int SCHEME_CANCEL= 4005; //方案不存在
//。。。。
package com.caiex.vb.interceptor;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.caiex.vb.model.Response;
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 所有异常报错
* @param request
* @param exception
* @return
* @throws Exception
*/
@ExceptionHandler(value=Exception.class)
public Response allExceptionHandler(HttpServletRequest request,
Exception exception) throws Exception
{
logger.error("拦截到异常:", exception);
Response response = new Response();
response.setData(null);
response.getResult().setResultCode(9999);
response.getResult().setResultMsg("系统繁忙");
return response;
}
}
WebMvcConfigurerAdapter
实现springboot
的拦截器链。实现HandlerInterceptor
方法编写业务拦截器。SignInterceptor
package com.caiex.vb.interceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import com.caiex.redis.service.api.RedisApi;
import com.caiex.vb.model.Response;
import com.caiex.vb.utils.CaiexCheckUtils;
@Component
public class SignInterceptor extends BaseValidator implements HandlerInterceptor{
private Logger logger = LogManager.getLogger(this.getClass());
@Resource
private RedisApi redisApi;
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
// TODO Auto-generated method stub
}
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
if(isTestIpAddr(arg0)){
return true;
}
String securityKey = redisApi.hGet("securityKey", arg0.getParameter("agentid"));
if(StringUtils.isEmpty(securityKey)){
Response response = new Response();
response.setData(null);
response.getResult().setResultCode(8001);
response.getResult().setResultMsg("缺少私钥, 渠道号:" + arg0.getParameter("agentid"));
logger.error("缺少私钥, 渠道号:" + arg0.getParameter("agentid"));
InterceptorResp.printJson(arg1, response);
return false;
}
if(StringUtils.isEmpty(arg0.getParameter("sign")) || !arg0.getParameter("sign").equals(CaiexCheckUtils.getSign(arg0.getParameterMap(), securityKey))){
Response response = new Response();
response.setData(null);
response.getResult().setResultCode(3203);
response.getResult().setResultMsg("参数签名认证失败");
logger.error("参数签名认证失败:" + JSON.toJSONString(arg0.getParameterMap()) + " securityKey = " + securityKey);
InterceptorResp.printJson(arg1, response);
return false;
}else{
return true;
}
}
}
WebAppConfigurer
package com.caiex.oltp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.caiex.oltp.interceptor.APILimitRateValidator;
import com.caiex.oltp.interceptor.CommonValidator;
import com.caiex.oltp.interceptor.DDSAuthValidator;
import com.caiex.oltp.interceptor.QueryPriceParamsValidator;
import com.caiex.oltp.interceptor.TradeParamsValidator;
@EnableWebMvc
@Configuration
@ComponentScan
public class WebAppConfigurer extends WebMvcConfigurerAdapter {
@Bean
CommonValidator commonInterceptor() {
return new CommonValidator();
}
@Bean
DDSAuthValidator ddsAuthInterceptor() {
return new DDSAuthValidator();
}
@Bean
QueryPriceParamsValidator queryPriceParamsInterceptor() {
return new QueryPriceParamsValidator();
}
@Bean
TradeParamsValidator tradeParamsInterceptor() {
return new TradeParamsValidator();
}
@Bean
APILimitRateValidator aPILimitRateInterceptor() {
return new APILimitRateValidator();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//访问速率限制
registry.addInterceptor(aPILimitRateInterceptor())
.addPathPatterns("/*/*");
//.addPathPatterns("/price/getPriceParam");
//参数签名认证
registry.addInterceptor(ddsAuthInterceptor())
.addPathPatterns("/tradeState/*")
.addPathPatterns("/recycle/*")
.addPathPatterns("/matchInfo/*")
.addPathPatterns("/price/tradeTicketParam");
//公共参数检查
registry.addInterceptor(commonInterceptor())
.addPathPatterns("/price/tradeTicketParam")
.addPathPatterns("/tradeState/*")
.addPathPatterns("/recycle/*");
//询价参数校验
registry.addInterceptor(queryPriceParamsInterceptor())
.addPathPatterns("/price/getPriceParam");
//交易参数检查
registry.addInterceptor(tradeParamsInterceptor())
.addPathPatterns("/price/tradeTicketParam");
super.addInterceptors(registry);
}
}
创建令牌(Token)
获取私钥
private String createToken(){
String utk = "Msk!D*"+System.currentTimeMillis()+"UBR&FLP";
logger.info("create token --- "+Md5Util.md5(utk));
return Md5Util.md5(utk);
}
如何提高接口的高并发和高可用
接口的高并发解决方案(其实没有唯一答案,业界针对不同业务也有很多不同的方法)
负载均衡
,缓存
和集群
。负载均衡
阿里云的nginx负载均衡,我们使用的是加权轮询策略,其实轮询是最低效的方式;
集群
缓存
用ConcurrentHashMap缓存对象,并设置过期时间 redis缓存数据,结合spring定时任务定时获取不会经常改动的key 提高使用redis的效率:比如使用mGet一次获取多个key ....等
接口高可用问题
redis主从分布式(redis的单点故障和访问速度的提高和主从备份) 分布式dubbo服务的zookeeper主从集群 strom的主从集群 ...等
总结
1.是拉还是推:
2.多台分布式服务器上,怎么保证交易的幂等和订单的唯一性
3.处理时间超过10s,自动返回该订单交易失败
推荐阅读:
最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
朕已阅