文档章节

APP后端架构之Bean后端接口

Coody
 Coody
发布于 2017/02/17 13:57
字数 773
阅读 50
收藏 5
点赞 0
评论 0

 

 

PS:一个成熟的架构师必须懂得的技术:反射技术。

 

PS:一个优秀的架构师必须懂得的艺术:偷懒的艺术。

 

本文整套项目源码打包:链接: http://pan.baidu.com/s/1geGliKV 密码: 3hwc

上文中我们讲过JAVA的APP架构。那么在APP开发中。有一个东西一直让我们反复搬砖。

那是什么呢,没错,参数验证。很快就七夕了,看到这篇文章的友友们,有没有妹子愿意给个机会我送送玫瑰练胆子呢。

所谓参数验证,无非是一个接口需要哪些参数,然而当这些参数是否存在或者存在不满足格式的情况下。要响应一个参数有误的标志。

笔者怀着对妹子守株待兔的心情,写下这篇文章。如何用注解来规避那些各种验证而引发的一大堆if判断。

 图片

首先我们建立一个简单的注解。里面包含空验证以及格式的正则。

@Retention(RetentionPolicy.RUNTIME)   在这个注解标记下。当前注解将可以被反射读取到。

 

@Target(ElementType.FIELD)  代表当前注解用于字段。

 

如果是spring项目或者web项目,可以用AOP来实现自动验参。笔者近日为了方便,直接在上次的那个APP架构上来进行处理。

 

那么验证将放在API接口的入口。

 

 图片

 

 

调整之后

 

图片

 

 

图片

 

然后我们来看下效果

图片

 

如下是当前过滤器的全部代码。

package com.app.server.filter;



import java.io.IOException;

import java.io.PrintWriter;

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

import java.util.List;



import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;



import com.app.server.annotation.ParamCheck;

import com.app.server.annotation.ReqType;

import com.app.server.api.base.TurboApi;

import com.app.server.enm.APIRespEnum;

import com.app.server.entity.BeanFieldEntity;

import com.app.server.util.GsonUtil;

import com.app.server.util.PropertUtil;

import com.app.server.util.SpringContextHelper;

import com.app.server.util.StringUtils;

import com.app.server.vo.base.BaseReqVO;



public class APIFilter implements Filter {

private static final String apiFunctionName="execute";

@Override

public void doFilter(ServletRequest servReq, ServletResponse servResp,

FilterChain chain) throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servReq;

HttpServletResponse response = (HttpServletResponse) servResp;

response.setCharacterEncoding("utf-8");

String apiName = request.getHeader("APIName");

System.out.println("请求接口名:" + apiName);

TurboApi api = (TurboApi) SpringContextHelper.getBean(apiName);

if (api == null) {

writeEnum(response,APIRespEnum.API_NOT_FOUND);

return;

}

try {

//获得接口方法所需ReqVO类型

Class<?> reqVoCla=getAPIParaType(api);

//接受客户端json参数

String json=GsonUtil.getJsonContent(request);

System.out.println("请求参数:"+json);

//获得请求对象

BaseReqVO reqVO=(BaseReqVO) GsonUtil.jsonToObject(json, reqVoCla);

//进行参数验证

APIRespEnum errEnum=checkPara(reqVO);

if(!StringUtils.isNullOrEmpty(errEnum)){

writeEnum(response,errEnum);

return;

}

//执行api方法

Object obj=api.execute(request, reqVO);

//响应json结果

String context=GsonUtil.objectToJson(obj);

writeMsg(response,context);

return;

} catch (Exception e) {

// TODO: handle exception

}

return;

}

private Class<?> getAPIParaType(TurboApi api){

Method method=PropertUtil.getMethod(api.getClass(), apiFunctionName, HttpServletRequest.class,BaseReqVO.class);

Annotation[][] annoss=method.getParameterAnnotations();

for (Annotation[] annos:annoss) {

for (Annotation anno:annos) {

if(anno instanceof ReqType){

return ((ReqType) anno).value();

}

}

}

return null;

}

private APIRespEnum checkPara(BaseReqVO reqVO){

List<BeanFieldEntity>  entitys=PropertUtil.getBeanFields(reqVO);

for (BeanFieldEntity entity:entitys) {

ParamCheck check= entity.getSourceField().getAnnotation(ParamCheck.class);

if(!check.allowNull()){

Object obj=PropertUtil.getFieldValue(reqVO, entity.getFieldName());

String msg=check.errorMsg();

if(StringUtils.isNullOrEmpty(obj)){

return getParaErrEnum(APIRespEnum.PARA_IS_NULL,entity.getFieldName(),msg);

}

if(!StringUtils.isNullOrEmpty(check.format())){

if(!StringUtils.isMatcher(obj.toString(), check.format())){

return getParaErrEnum(APIRespEnum.PARA_ERROR,entity.getFieldName(),msg);

}

}

if(!StringUtils.isNullOrEmpty(check.orNulls())){

List<Object> values=PropertUtil.getFieldValues(reqVO, check.orNulls());

if(!StringUtils.isAllNull(values)){

return getParaErrEnum(APIRespEnum.PARAS_IS_NULL,entity.getFieldName()+":"+check.orNulls().toString(),msg);

}

}

}

}

return null;

}

private APIRespEnum getParaErrEnum(APIRespEnum enm,String fieldName,String msg){

APIRespEnum currNum=enm;

if(!StringUtils.isNullOrEmpty(msg)){

currNum.setMsg(msg);

}

currNum.setMsg(currNum.getMsg()+":"+fieldName);

return currNum;

}

private void writeEnum(HttpServletResponse response,APIRespEnum msgEnum) {

String context = msgEnum.toJson();

writeMsg(response,context);

}

private void writeMsg(HttpServletResponse response,String context) {

try {

PrintWriter out = response.getWriter();

out.print(context);

out.flush();

out.close();



} catch (IOException e) {

e.printStackTrace();

}

}

@Override

public void init(FilterConfig arg0) throws ServletException {

}

@Override

public void destroy() {

}

}

 

 

JAVA技术交流群:218481849

© 著作权归作者所有

共有 人打赏支持
Coody
粉丝 19
博文 14
码字总数 13868
作品 5
广州
架构师
一个O2O后端架构问题咨询

一个后端架构问题咨询 业务: O2O,采购方通过App向供应商申请供货,供应商审核通过后 , 采购方可在App上进入该供货商的店铺中进行下单。 后端 仅负责提供Rest Api,前端调用后端提供的接口来...

zgw06629 ⋅ 2015/11/01 ⋅ 1

app后端设计--总目录

做了3年app相关的系统架构,api设计,先后在3个创业公司中工作,经历过手机网页端,android客户端,iphone客户端,现就职于app云后端平台bmob(想了解bmob点击这里)。其中的乐与苦,得与失,...

云栖希望。 ⋅ 2017/12/04 ⋅ 0

互联网架构,为啥要前后端分离?

通用业务服务化之后,系统的典型后端结构如上: web-server通过RPC接口,从通用业务服务获取数据 biz-service通过RPC接口,从多个基础数据service获取数据 基础数据service通过DAO,从独立d...

xqtesting ⋅ 2017/12/15 ⋅ 0

互联网分层架构,为啥要前后端分离?

作者:58沈剑,来源:架构师之路 一,典型后端架构 通用业务服务化之后,系统的典型后端结构如上: web-server通过RPC接口,从通用业务服务获取数据 biz-service通过RPC接口,从多个基础数据...

bjweimengshu ⋅ 2017/12/07 ⋅ 0

互联网分层架构系列之四:前后端为什么要分离

通用业务服务化之后,系统的典型后端结构如上: web-server通过RPC接口,从通用业务服务获取数据 biz-service通过RPC接口,从多个基础数据service获取数据 基础数据service通过DAO,从独立d...

wqhlmark64 ⋅ 04/12 ⋅ 0

APP后端服务架构,接口安全

关于APP的后端服务器,接口安全应该具有哪些方面的考虑。 架构需要有哪些方面的考量 创业项目预备20人开发团队。JAVA后端。电商项目。 其实已有一些参考。但纯属我个人想知道大家是怎么做的...

码农的道途 ⋅ 2016/06/13 ⋅ 9

Pomelo架构浅析

Pomelo架构浅析 1. pomelo简介: 网易在2012年11月开源的一个网游服务器框架,使用javascript作为开发语言,运行在node.js环境下。具体说明请查阅:https://github.com/NetEase/pomelo pomel...

霹靂小金剛 ⋅ 2013/03/01 ⋅ 1

通过Express4构建Restful API服务器 - 结合AngularJS前后端分离开发

初衷 很久没有写Nodejs了,记得去年还很兴致勃勃的打算搞一搞,结果工作一变动大半年都扑在了项目上,玩起了AngularJS. 最近打算做项目的架构转型,也是受了"前后端二次分离"的大浪潮的影响,看了...

顽Shi ⋅ 2014/11/26 ⋅ 4

Docker registryV2源码解读【一】整体架构与启动过程

Docker registry概述 用一句话解释Docker registry就是:存放docker image的远程仓库。在使用docker的过程中,我们一定会用到docker Registry,当我们使用docker的pull命令(下载镜像),或者...

有容云 ⋅ 2016/11/24 ⋅ 0

基于NodeJS的全栈式开发

随着不同终端(Pad/Mobile/PC)的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,我们往往需要针对不同的终端开发定制的版本。为了提升开发效率,前后端分...

唐僧他大叔 ⋅ 2015/02/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

前台对中文编码,后台解码

前台:encodeURI(sbzt) 后台:String param = URLDecoder.decode(sbzt,"UTF-8");

west_coast ⋅ 昨天 ⋅ 0

VS2015配置并运行汇编(一步一步照图做)【vs2017的链接在最后】

前言 我是上学期学的汇编,因为有vs又不想用课上教的麻烦的dosbox以及masm32,但是一直没找到高亮插件和能调试的(难在运行不了而找不到答案上,出现的错误在最后放出,还请先达们不吝指点)...

simpower ⋅ 昨天 ⋅ 0

一起读书《深入浅出nodejs》-node模块机制

node 模块机制 前言 说到node,就不免得提到JavaScript。JavaScript自诞生以来,经历了工具类库、组件库、前端框架、前端应用的变迁。通过无数开发人员的努力,JavaScript不断被类聚和抽象,...

小草先森 ⋅ 昨天 ⋅ 0

Java桌球小游戏

其实算不上一个游戏,就是两张图片,不停的重画,改变ball图片的位置。一个左右直线碰撞的,一个有角度碰撞的。 左右直线碰撞 package com.bjsxt.test;import javax.swing.*;import j...

森林之下 ⋅ 昨天 ⋅ 0

你真的明白RPC 吗?一起来探究 RPC 的实质

你真的明白RPC 吗?一起来探究 RPC 的实质 不论你是科班出身还是半路转行,这么优秀的你一定上过小学语文,那么对扩句和缩句你一定不陌生。缩句就是去除各种修饰提炼出一句话的核心,而不失基...

AI9o後 ⋅ 昨天 ⋅ 0

z-index设置失效?

今天碰到了一个问题,就是在给li设置提示框的时候,有用到遮罩效果,本来想把对应的出现在最顶层,可是不管将li设置的z-index值设为多大,li都没有出现在遮罩层之上。 我在网上查了z-index设...

IrisHunag ⋅ 昨天 ⋅ 0

CyclicBarrier、CountDownLatch以及Semaphore使用及其原理分析

CyclicBarrier、CountDownLatch以及Semaphore是Java并发包中几个常用的并发组件,这几个组件特点是功能相识很容易混淆。首先我们分别介绍这几个组件的功能然后再通过实例分析和源码分析其中设...

申文波 ⋅ 昨天 ⋅ 0

Java对象的序列化与反序列化

Java对象的序列化与反序列化

Cobbage ⋅ 昨天 ⋅ 0

Sqoop

1.Sqoop: 《=》 SQL to Hadoop 背景 1)场景:数据在RDBMS中,我们如何使用Hive或者Hadoop来进行数据分析呢? 1) RDBMS ==> Hadoop(广义) 2) Hadoop ==> RDBMS 2)原来可以通过MapReduce I...

GordonNemo ⋅ 昨天 ⋅ 0

全量构建和增量构建的区别

1.全量构建每次更新时都需要更新整个数据集,增量构建只对需要更新的时间范围进行更新,所以计算量会较小。 2.全量构建查询时不需要合并不同Segment,增量构建查询时需要合并不同Segment的结...

无精疯 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部