本系列博文,将会一步一步介绍如何构建一个轻量级的web框架jbeer git地址:http://git.oschina.net/bieber/jbeer前端
本文主要分享一下在JBeer中MVC模块的Controller解析,主要分享JBeer如何解析一个Controller,映射到各个action处理的路径以及Request参数注入。 ###1、Controller解析### 下面列举出简单的Action实例<br/>java
<!-- lang: java --> @Controller(urlPattern="/first") public class FirstController extends BaseController{ @Action(urlPatterns="invoke_${id}_${name}.htm") public String pathParam(@PathParam("id")Integer id,@PathParam("name")String name){ return "view"; } }
下面对框架解析一个Controller以及分析Action进行分享:<br/> 一) 应用启动,触发JBeerWeb
的init()方法<br/> 二) 经过ClassUtils
的scanClassesByAnnotation方法获取全部注解了@Controller
的类,并解析类中方法,并判断是否被@Action
注解过。<br/> 三) 对每一个注解了@Action
的方法,生成一个ActionEntity
,该类中描述了一个Action接受的处理路径,须要调用哪一个方法以及是哪一个controller类。下面粘贴处ActionEntity
的类定义:<br/>git
<!-- lang:java --> /** * action须要调用的方法对象 */ private Method actionInvokeMethod; /** * action须要调用的className */ private String controllerClassName; /** * 存储当前Action的方法参数信息 */ private Collection<ActionMethodParam> methodParams; /** * 当前Action处理的请求方式 */ private RequestType requestType; /** * 当前Action能够匹配的请求路径集合 */ private Collection<PatternableUrl> patternedUrls;
其中定义了该Action方法触发的上下文。上面对一些属性进行了封装,好比方法入参和匹配的路径。web
一、ActionMethodParam
封装了Action的各个入参信息,若是Action没有入参,则methodParams
为空,下面看看ActionMethodParam
中定义了什么<br/>正则表达式
<!-- lang:java --> /** * 方法参数名 */ private String paramName; /** * 方法参数位置 */ private int paramIndex; private Class<?> parameterType; /** * 关联的ID,能够是bean的ID,也能够是引用Properties或者IN18消息信息 */ private String refId; private String[] in18Args;
paramName
表示匹配url上面占位符的内容,paramIndex
表示该参数是Action的第几个位置的入参,parameterType
是参数的类型,用于进行类型转换,上面三个属性就能够完成在路径上进行占位符配置的参数注入。而refId
则是经过配置@RefBean
,@Properties
或者@Message
注解来关联框架内的资源,好比依赖一个bean,配置信息等。而in18Args
是当引用的是IN18的message配置信息时候,须要传递的参数。经过上面几个参数,就能够实现Action的入参的实际来源。数组
二、PatternableUrl
定义了匹配路径的信息,具体定义以下:框架
<!-- lang:java --> /** * 匹配路径的正则表达式 */ private String urlMatcher; /** * 配置的url路径占位符相关信息 */ private Collection<URLParam> urlParams;
其中urlMatcher
是待匹配的路径正则表达式,而urlParams
则是路径上面的参数信息。关于URLParam
定义信息以下:工具
<!-- lang:java --> /** * 占位符参数名 */ private String paramName; /** * 占位符参数所在的位置是第几个,方面在请求时,肯定第几个占位符的值是当前参数的值 */ private int urlParamIndex;
上面经过解析配置的url,获取占位符中的内容赋值到paramName
中,以及记录当前占位符的位置(urlParamIndex
)。这里的paramName
是和ActionMethodParam
中的paramName
保持一直的,否则没法匹配对应的路径参数值。url
到此,当一个请求路径,经过匹配ActionEntity.patternedUrls
集合中的某一个来肯定当前的ActionEntity
是否可以处理当前一个请求,若是匹配经过,那么在解析请求的路径,从而实例化须要传入Action方法的入参。<br/> 四)当解析完毕Controller中的Action后,那么将会把Contrller放入到IOC容器中,后面须要引用Controller类的实体,将会从IOC中获取。 ###2、Request参数注入### Jbeer框架的参数注入提供了两种方式,一种是经过配置Controller非单例模式,框架自动注入到Controller类的属性,这点相似struts2的风格。第二种是Controller单例模式,开发人员经过框架提供的工具类来获取Request请求的参数。下面对这两种原理进行介绍。 首先来看看JBeer是如何处理用户一个请求的吧。 .net
上图阐述了框架在接收到一个请求,通过哪些过程来进行处理。那么ControllerInitialization
负责对Controller的实例化,包括对Controller对象的实例化(从IOC容器中获取)和Action方法参数的实例化。而Request参数注入发生在generateController
方法中,而initActionMethodParams
方法则是初始化Action方法的参数。下面将主要分享这两个方法。 ####一)、generateController####
Map<String,Object>
(其中文件上传的文件也在其中)。<br/>Map<String,Object>
对象,咱们知道前端传递过来的参数是键值对的,好比name="bieber",user.name="bieber",names[0]="bieber0"或者users[0].name="bieber0"这种形式,这三种分别表示普通的键值对,对象的属性键值对,数组形式键值对,对象数组键值对。上面这种层级关系,能够经过对象引用树来进行分析,那么能够假设这些对象属性的公共父节点是Controller实体,那么name则是这个Controller的字符串属性,user则是Controller的对象属性,一次类推names,users则是对象的数组属性或者是集合。下面则给出下面树形结构图。 Map<String,Object>
的目的,就是把无结构Map
解析成树形结构。经过“.”来对Map的key进行分析,以及经过正则表达式来匹配key是否存在\[[0-9]{1,}\]
结构,能够分析每一个.
则是一个树的分层,.
以前的是父节点,以后的是子节点。经过该步骤对Map<String,Object>
分析,会获得树的第一层子节点。Map<String,Object>
若是其中key对不包含.
,其value则是一个Object[]
数组,若是包含.
,则value则是一个Map<String,Object>[]
数组。这两经过树的深度优先遍历,可完成整个Request参数注入。固然,这一步先只分析一个深度,并把获得的Map<String,Object>
放到JBeerWebContext
中。<br/>Map<String,Object>
自动注入到Controller的对应属性中。若是是单例,则完成自动注入。RequestParameterUtil
来手动获取请求参数。下图展现了提供的接口。 @PathParam
来指定参数名),以及系统层面的参数(好比:HttpServletRequest
,HttpServletResponse
等等)。分析规则,则是按照解析Action方法时生成的对应信息。具体可见上面内容。<br/>关于具体实现,还但愿经过项目源码进行分析,此处只是进行简单的分享。若是有什么意见还但愿你们可以提点意见。