在Spring Cloud项目开发中,一般的目录结构
各个模块是做什么的就不用多说了,主要是web模块,比如我们实现一个登陆功能,首先要在Web模块下面新建一个LoginController,然后再后写接口层和实现层,然后我们需要查询用户又要新建一个UserController,新增加一个功能就要新建一个Controller,那么我不想建这么多的Controller,我想用一个Controller来统一调用接口可不可以,答案是可以。这就是我们接下来要讲的ApiController
ApiController
作用,不用每个功能都写一个Controller,只要写在一个公共的模块里面,其他模块引入就可以了
优点:因为是统一的Controller入口,所以可以做一些拦截,鉴权操作
下面只提供一些核心代码和思路供大家参考
@RestController
@RequestMapping({"/api"})
public class ApiController implements ApplicationContextAware {
private static final Logger log = LoggerFactory.getLogger(ApiController.class);
private ApplicationContext applicationContext;
private static Map serviceCache = new HashMap();
public ApiController() {
}
@CrossOrigin
@RequestMapping(
value = {"/{serviceName}/{method}"},
method = {RequestMethod.POST}
)
/**
* Api入口
*/
public Object post(@PathVariable("serviceName") String serviceName, @PathVariable("method") String method, @RequestBody String params, HttpServletRequest request, HttpServletResponse response) {
long startTime = System.currentTimeMillis();
ServletThreadLocal.put(request, response);
Object object = this.doService(serviceName, method, params);
long executeTime = System.currentTimeMillis() - startTime;
log.info("调用服务[{}.{}]执行时间:{}ms", new Object[]{serviceName, method, executeTime});
return object;
}
/**
* doService
*
* @param serviceName
* @param method
* @param params
* @return
*/
private Object doService(String serviceName, String method, String params) {
Object serviceBean = this.getServiceBean(serviceName);
Result commonResult = null;
if (serviceBean == null) {
commonResult = Result.fail(ResultCodeEnum.SERVICE_NOT_FOUND.getDesc());
log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult.toString())});
return commonResult;
} else {
Method currentMethod = this.getInvokeMethod(serviceBean, method);
//方法不存在
if (currentMethod == null) {
commonResult = Result.fail(ResultCodeEnum.METHOD_NOT_FOUND.getDesc());
log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult.toString())});
return commonResult;
} else {
Type[] paramTypes = currentMethod.getGenericParameterTypes();
if (paramTypes.length != 0 && paramTypes.length <= 1) {
CallTypeEnum callType = CallTypeEnum.REAL;
BaseParam baseParam = null;
try {
//获取入参
Object inputParam = JSONObject.parseObject(params, paramTypes[0]);
baseParam = (BaseParam) inputParam;
log.info("调用服务[{}.{}]请求参数:{}", new Object[]{serviceName, method, JSONObject.toJSONString(inputParam)});
callType = baseParam.getCallType();
//判断是真实调用还是mock调用,mock调用自己实现
if (callType == CallTypeEnum.REAL) {
//获取返回结果
Object callResult = currentMethod.invoke(serviceBean, inputParam);
//判断返回结果类型
if (!(callResult instanceof Result)) {
throw new RuntimeException("接口返回类型必须为[com.xxx.base.bean.Result]类型");
}
commonResult = (Result) callResult;
log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, JSONObject.toJSONString(commonResult)});
return commonResult;
}
} catch (Exception var17) {
commonResult = Result.buildFail(ResultCodeEnum.FAIL.getDesc());
log.error("服务[{}.{}]处理失败", new Object[]{serviceName, method, var17});
}
} else {
log.info("调用服务[{}.{}]响应结果:{}", new Object[]{serviceName, method, "服务定义形参个数只能为一个"});
return Result.buildFail("服务定义形参个数只能为一个");
}
}
}
return commonResult;
}
/**
* 获取ServiceBean
*
* @param serviceName
* @return
*/
private Object getServiceBean(String serviceName) {
Object serviceBean = serviceCache.get(serviceName);
try {
if (serviceBean == null) {
if (serviceName.contains(".")) {
Class apiClass = null;
try {
apiClass = Class.forName(serviceName);
serviceBean = this.applicationContext.getBean(apiClass);
} catch (ClassNotFoundException var5) {
log.error("获取服务[" + serviceName + "]出错", var5);
} catch (Exception var6) {
log.error("获取服务[" + serviceName + "]出错", var6);
}
} else {
serviceBean = this.applicationContext.getBean(serviceName);
}
}
} catch (Exception var7) {
log.error("获取服务[" + serviceName + "]出错", var7);
}
if (serviceBean != null) {
serviceCache.put(serviceName, serviceBean);
}
return serviceBean;
}
/**
* 获取方法
*
* @param serviceBean
* @param method
* @return
*/
private Method getInvokeMethod(Object serviceBean, String method) {
Method currentMethod = null;
Method[] methods = serviceBean.getClass().getDeclaredMethods();
Method[] var5 = methods;
int var6 = methods.length;
for (int var7 = 0; var7 < var6; ++var7) {
Method method1 = var5[var7];
if (method1.getName().equals(method)) {
currentMethod = method1;
}
}
return currentMethod;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
public class ServletThreadLocal {
private static ThreadLocal requestThreadLocal = new ThreadLocal();
private static ThreadLocal responseThreadLocal = new ThreadLocal();
public ServletThreadLocal() {
}
public static HttpServletRequest getRequest() {
return (HttpServletRequest)requestThreadLocal.get();
}
public static HttpServletResponse getResponse() {
return (HttpServletResponse)responseThreadLocal.get();
}
public static void putRequest(HttpServletRequest request) {
requestThreadLocal.set(request);
}
public static void putResponse(HttpServletResponse response) {
responseThreadLocal.set(response);
}
public static void put(HttpServletRequest request, HttpServletResponse response) {
putRequest(request);
putResponse(response);
}
}
Api模块
public interface OrderServiceFacade {
Result getOrderById(OrderParam param);
}
Service模块
@Service("orderServiceFacade")
public class OrderServiceFacadeImpl implements OrderServiceFacade {
@Resource
OrderMainMapper orderMainMapper;
@Override
public Result getOrderById(OrderParam param){
}
这样就不需要我们在写Controller了
接口调用
http://localhost:9091/api/orderServiceFacade/getOrderById