简介:轻量封装Spring MVC
因为本人在国内最大的电子商务公司工作期间,深感一个好的Web框架可以大大提高工作效率,而一个不好的Web框架,又可以大大的降低开发效率。所以,在根据笔者在从事电子商务开发的这几年中,对各个应用场景而开发的一个轻量封装Spring MVC的一个Web框架。
笔者工作的这几年之中,总结并开发了如下几个框架: summercool-web(Web框架,已经应用于某国内大型网络公司的等重要应用)、summercool-hsf(基于Netty实现的RPC框架,已经应用国内某移动互联网公司)、summercool-ddl(基于Mybaits的分表分库框架,已经应用国内某移动互联网公司);相继缓存方案、和消息系统解决方案也会慢慢开源。Summercool框架做为笔者的第一个开源框架
框架地址:http://summercool.googlecode.com/svn/trunk/summercool-web
应用地址:http://summercool.googlecode.com/svn/trunk/summercool-petstore
工具地址:http://summercool.googlecode.com/svn/trunk/summercool-tools
说明:此框架要用到spring-tools文件夹中的security文件夹中的文件,使用此框架的人员请将security文件夹的内容替换到JDK中的security文件夹中
一、先让我们看一下Spring MVC的AbstractController和SimpleFormController的处理流程图
为什么作者在这里要先查介绍这两个处理器呢?是因为笔者认为注解形势的Controller会让代码的可读性变理很差,并且因为配置在代码里,会发生很多映射关系不容易找到等问题。当然,SimpleFormController的生命周期也是非常强大,而且了注解之后,笔者认为表面上的灵活更容易让程序员犯错误。(当然为什么Spring在3.0之后不推荐使用,笔者也感觉很困惑)
1. AbstractController和SimpleFormController的处理流程
2. Summercool请求处理流程图
说明:
1. 了解Spring MVC底层代码或是了解Spring MVC处理流程的人可能知道,AroundPipeline、PreProcessPipeline、PostpRrocessPipeline和ExceptionPipeline是笔者加进去的元素
2. 处理流程的一个细节也调整了一下,具体如下:
1) request --> /index.htm --> /IndexController.java --> /index.ftl
如果Spring MVC在没有/IndexController.java这个处理类的话,会自动返回NotFound;不会渲染/index.ftl
2) Summercool框架改造成: request --> /index.htm --> [/indexController.java] --> [/index.ftl]
如果没有/IndexController.java这个处理类,那么Summercool会自动查找/index.ftl页面
3) 上面的这个特性非常有用,因为有些动态页面(如帮助页面)是不需要Controller处理的,但是却包括一些动态信息(据说Spring MVC 3.1已经支持了)
3. summercool框架的相关说明
1) AroundPipeline接口说明
A. 因为Summercool框架是基于Filter实现的,所以AroundPipeline会过滤所有的请求,因为AroundPipeline笔者也是跟据Filter的模式进行调用的
B. PriorityOrdered接口是一个顺序接口,这样可以指定一个AroundPipeline的执行顺序
C. 这个类的主要应用场景是,可以对监控所有请求的执行时间,日志打点和定制相关图片压缩功能
D. 该类的相关功能演示,笔者会在后续编章中给出演示
package org.summercool.web.servlet.pipeline;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.PriorityOrdered;
import org.summercool.web.servlet.AroundPipelineChain;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
*
*/
public interface AroundPipeline extends PriorityOrdered {
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
* @param request
* @param response
* @param aroundPipelineChain
* @throws Exception
*/
public void handleAroundInternal(HttpServletRequest request, HttpServletResponse response, AroundPipelineChain aroundPipelineChain) throws Exception;
}
2) PreProcessPipeline接口说明
A. PreProcessPipeline接口会在允许处理的请求范围内继续向下执行(这句话的意思会在实践篇讲解)
B. PriorityOrdered接口是一个顺序接口,这样可以指定一个AroundPipeline的执行顺序
C. 这个类的主要应用场景是权限检查,如某个请求在处理过权限检查之后,则继续执行;反之,则跳转到另一个指定页面或资源
D. 如果isPermitted()函数返回为true,则不会执行handleProcessInternal()函数,请求会继续向下执行,最终执行Controller或是渲染页面
E. 如果isPermitted()函数返回为false,则会执行handleProcessInternal()函数,请求就不会继续向下执行,而是直接处理handleProcessInternal()函数返回的ModelAndView接口,然后终于此次请求
package org.summercool.web.servlet.pipeline;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.PriorityOrdered;
import org.springframework.web.servlet.ModelAndView;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
*
*/
public interface PreProcessPipeline extends PriorityOrdered {
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
* @param request
* @param response
* @return
* @throws Exception
*/
public boolean isPermitted(HttpServletRequest request, HttpServletResponse response) throws Exception;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
* @param request
* @param response
* @return
* @throws Exception
*/
public ModelAndView handleProcessInternal(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
3) PostProcessPipeline接口说明
A. PostProcessPipeline接口,是在Controller或是页面渲染之前的一个处理类,可以拦截请求马上要处理的相关资源
B. 此处的应用场景是,如果一个人想到重定向到另一个页面,那么我们可以查看一下是否在重定向的白名单地址列表里面而防止被“钓鱼”
C. 如果isPermitted()函数返回为true,则不会执行handleProcessInternal()函数,请求会继续向下执行,最终执行Controller或是渲染页面
D. 如果isPermitted()函数返回为false,则会执行handleProcessInternal()函数,请求就不会继续向下执行,而是直接处理handleProcessInternal()函数返回的ModelAndView接口,然后终于此次请求
E. isPermitted()函数中的ModelAndView里面包含要跳转或是要处理的资源,所以可以进行白名单等功能的检验
package org.summercool.web.servlet.pipeline;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.PriorityOrdered;
import org.springframework.web.servlet.ModelAndView;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
*
*/
public interface PostProcessPipeline extends PriorityOrdered {
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
* @param request
* @param response
* @param modelAndView
* @return
* @throws Exception
*/
public boolean isPermitted(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) throws Exception;
public ModelAndView handleProcessInternal(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
3) ExceptionPipeline接口说明
A. 当Controller或是渲染页面的时候发生异常,会调用ExceptionPipeline
B. 为什么Spring MVC有Exception处理类,笔者还要再扩展一下呢?
因为Spring MVC只能处理:Exception --> /error.ftl 这样的,异常类型对应相关渲染页面处理
有时候我们需要这样处理: Exception (errorcode = 1) --> /error_1.ftl
Exception (errorcode = 2) --> /error_2.ftl
像这样的情况,是我们可以通过一种异常类型,不同的errorcode可以自定义不同的显示页面
当然,笔者也考虑到了原有的Spring MVC处理异常的方式;所以原始的Spring MVC的处理方式也是支持的
C. 在发生异常的时候,就可以通过此接口的ModelAndView接口来定制渲染页面
package org.summercool.web.servlet.pipeline;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.PriorityOrdered;
import org.springframework.web.servlet.ModelAndView;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
*
*/
public interface ExceptionPipeline extends PriorityOrdered {
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-10
* @param request
* @param response
* @param modelAndView
* @param throwable
* @throws Exception
*/
public void handleExceptionInternal(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView, Throwable throwable) throws Exception;
}
4) FreeMarkerWidget接口说明
A. 在我们渲染一个页面的时候,我们可以使用${widget("/header")}
B. 渲染时候的顺序是:${widget("/header")} --> "/HeaderWidget.java" --> "/header.ftl"
C. 如果在渲染的时候,没有"/HeaderWdiget.java"处理类,则直接渲染"/header.ftl"页面
D. 这个函数的好处是,可以为每个页面的嵌套子页面提供独立的业务处理类Widget,使子页面的逻辑独立
package org.summercool.web.servlet.view.freemarker;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-18
*
*/
public interface FreeMarkerWidget {
/**
*
* @author:shaochuan.wangsc
* @date:2010-3-18
* @param request
* @param model
*/
public void referenceData(HttpServletRequest request, Map<String, Object> model);
}
最后说明:
1. 此框架目的不是在于想打造一个全新的框架
2. 一个框架的学习成本还是有些高的,要是全新打造一个框架也势必会让新的开发人员重新学习,所以会严重影响一个框架的学习
3. 一个框架的考虑周全性也是比较困难的,当时笔者想自己独立开发一个框架的时候也是有此担心,所以想从Struts2和Spring MVC为基础的原型上面进行二次开发
4. 笔者最后选中了Spring MVC,主要还是因为它的设计非常优雅并且容易扩展
5. Summercool只是在Spring MVC的基础上封装的一个框架,也就是说严格上来说它是一个依拖于别人的框架,严格上来说不算是一个框架;只是二次开发之后的一个Spring MVC框架