陆陆续续用闲暇时间写的自用 MVC 框架,本来想利用十一期间整理整理代码放出来,结果一直拖延症终于缓慢地完工了(然后这帖又写了两天……)
先放地址: https://github.com/cloudeecn/mocha-mvc 求 Star 和 Fork , orz
README 和 Wiki 还不全,大家先凑合一下看看这里和 example 工程
运行环境要求:
- Java7
- Servlet3.0 容器
运行 Example
clone 工程,用 eclipse/IDEA/whatever 你喜欢的 IDE 导入 maven 工程,用支持 Servlet3.0 的容器启动里面的 example 子工程就 OK 啦
在 web.xml 中有使用Spring和Guice作为 DI 的两套配置,默认打开的是用Guice作 DI 的,也可以打开Spring来试一下。
Spring的配置在 example 工程中src/main/resources/works/cirno/mocha/example/spring/applicationContext.xml
Guice的配置在
works.cirno.mocha.example.guice
包下
快速上手
用过Guice的同学应该对这种方式很熟悉,创建一个works.cirno.mocha.MVCConfigurator的子类,并在public void configure()方法中进行配置。配置好后配置到 DispatcherFilter / DispatcherServlet 的 init-param["configurator"]中
配置路由项
serve({路径}[, "GET/POST/PUT..."]) 会产生一个路由项,利用方法链的方式可以进一步对匹配这个路径的访问进行配置
配置响应
serve({路径}[, "GET/POST/PUT..."]).with({controller}, {method}); 中的 with 方法给路由项配置响应的Controller和其中的方法method
Controller 返回
Controller 方法可以支持返回一下几个类型
Integer :直接用 response.sendError 返回返回码
String :作为 view 的名字寻找对应的 jsp 进行渲染
View 对象:根据 view 的名字寻找对应的 jsp 进行渲染, view 对象中有 attribute(key, value)方法可以给 request 的 attribute 提供值
null 或者方法返回类型为 void :不做后续处理
配置 view 返回
可以通过 forward 方法执行响应 view 名对应的 jsp 文件( forward 方法返回一个支持 to 方法的接口,其中的 to 方法执行 JSP 的位置)
可以配置多个
serve({路径}[, "GET/POST/PUT..."]).with({controller}, {method}) .forward("view 名").to("JSP 位置") .forward("view 名").to("JSP 位置") ... ; 支持 Restful 风格的 api
serve("/parameter/\\+${userId}").with(ParameterController.class, "user").forward("success").to("/WEB-INF/jsp/parameter-rest.jsp"); serve("/parameter/\\+${userId}", "POST").with(ParameterController.class, "userPost"); serve("/parameter/\\+${userId}.json").with(ParameterController.class, "userJson"); 会匹配 /parameter/+后面的任何内容,并作为 userId 参数和候选
目前有两种写法:
JDK7 终于支持了的 namedGroup :写法如下:(?<name>pattern),会匹配 pattern 正则并且作为 name 参数的候选
另外支持一种比较基本的${name}写法,会被翻译成(?<name>.*?),最小匹配接下来的内容作为 name 参数的候选
参数获取
Controller 方法中的参数目前会根据以下的规则获取:
按类型匹配
- 类型为 HttpServletRequest 的参数会给予 request 对象
- 类型为 HttpServletResponse 的参数会给予 response 对象
- 类型为 ServletOutputStream 或 OutputStream 的参数会给予 response.getOutputStream()的结果
- 类型为 PrintWriter 或 Writer 的参数会给予 response.getWriter()的结果
如果是 multipart 请求,如果参数类型是 InputStream 或者 Reader ,根据参数名匹配上传文件的内容
根据参数的名称,按照
url 中的变量 - multipart 中解析到的表单域 - request.getParameter的顺序获取字符串,并尝试通过系统中的 PropertyEditor 进行类型转换,如果转换成功将转换结果给予参数将这个类型用无参构造函数实例化,如果成功作为 JavaBean 遍历其中的属性,根据规则 1-4 获取
参数名.属性名的参数值进行填充,如果能获取到至少一个,将这个实例给予参数以上都不匹配返回参数的默认值(基本类型给 false/0 ,对象类型给 null )
TODO
- 写文档( README.md 居然有只写了一半的句子!)
- 写文档(注释简直是没有)
- 写文档( Wiki 也没有!)
- 修改路径匹配的规则,现在是用正则匹配的,对带正则元字符的的路径不友好
- 优化获取参数的性能……从 request 中填充一个 5 个属性的 Bean 居然要 16 毫秒简直不能忍
- 重构一下 View 的结构,现在的 View 机制是在 Renderer 之下的,结构很诡异
- 用一个比较优雅的方式封装参数获取和转换的配置(目前是写死的规则……)
随后我会慢慢在 GitHub 的 README.md 和 Wiki 中补充上各种文档,请大家期待;)
