前面与大家分享了几篇在 Smart 中有关数据持久层的重构解决方案,今天我们把目光集中到 MVC 框架上来吧。众所周知,Smart 是一款看起来还不错的轻量级 Java Web 框架,如果连 MVC 框架都不好用或者不容易扩展,那岂不是自己给自己找麻烦吗?
当我刚说完上面这句话时,我们团队中的一名帅哥 快枪手 同学,他指出了我在 Smart MVC 上的严重问题,请允许我再次感谢我的小伙伴快枪手,感谢他深厚的功力与犀利的言语!解救我于水火之中,让我学到了很多,受益匪浅。
重构前的 DispatcherServlet
我们先来看看 Smart MVC 中一个非常重要的类 —— 前端控制器,它就是 DispatcherServlet
,重构前是这样的:
<!-- lang: java -->
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
@Override
public void init(ServletConfig config) throws ServletException {
// 初始化相关配置
ServletContext servletContext = config.getServletContext();
UploadHelper.init(servletContext);
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求编码方式
request.setCharacterEncoding(FrameworkConstant.UTF_8);
// 获取当前请求相关数据
String currentRequestMethod = request.getMethod();
String currentRequestPath = WebUtil.getRequestPath(request);
logger.debug("[Smart] {}:{}", currentRequestMethod, currentRequestPath);
// 将“/”请求重定向到首页
if (currentRequestPath.equals("/")) {
WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
return;
}
// 去掉当前请求路径末尾的“/”
if (currentRequestPath.endsWith("/")) {
currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1);
}
// 定义几个变量(在下面的循环中使用)
ActionBean actionBean = null;
Matcher requestPathMatcher = null;
// 获取并遍历 Action 映射
Map<RequestBean, ActionBean> actionMap = ActionHelper.getActionMap();
for (Map.Entry<RequestBean, ActionBean> actionEntry : actionMap.entrySet()) {
// 从 RequestBean 中获取 Request 相关属性
RequestBean requestBean = actionEntry.getKey();
String requestMethod = requestBean.getRequestMethod();
String requestPath = requestBean.getRequestPath(); // 正则表达式
// 获取请求路径匹配器(使用正则表达式匹配请求路径并从中获取相应的请求参数)
requestPathMatcher = Pattern.compile(requestPath).matcher(currentRequestPath);
// 判断请求方法与请求路径是否同时匹配
if (requestMethod.equalsIgnoreCase(currentRequestMethod) && requestPathMatcher.matches()) {
// 获取 ActionBean 及其相关属性
actionBean = actionEntry.getValue();
// 若成功匹配,则终止循环
break;
}
}
// 若未找到 Action,则跳转到 404 页面
if (actionBean == null) {
WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response);
return;
}
// 初始化 DataContext
DataContext.init(request, response);
try {
// 调用 Action 方法
invokeActionMethod(request, response, actionBean, requestPathMatcher);
} catch (Exception e) {
// 处理 Action 异常
handleActionException(request, response, e);
} finally {
// 销毁 DataContext
DataContext.destroy();
}
}
private void invokeActionMethod(HttpServletRequest request, HttpServletResponse response, ActionBean actionBean, Matcher requestPathMatcher) throws Exception {
// 获取 Action 相关信息
Class<?> actionClass = actionBean.getActionClass();
Method actionMethod = actionBean.getActionMethod();
// 从 BeanHelper 中创建 Action 实例
Object actionInstance = BeanHelper.getBean(actionClass);
// 获取 Action 方法参数
List<Object> paramList = createParamList(request, actionBean, requestPathMatcher);
Class<?>[] paramTypes = actionMethod.getParameterTypes();
if (paramTypes.length != paramList.size()) {
throw new RuntimeException("由于参数不匹配,无法调用 Action 方法!");
}
// 调用 Action 方法
actionMethod.setAccessible(true); // 取消类型安全检测(可提高反射性能)
Object actionMethodResult = actionMethod.invoke(actionInstance, paramList.toArray());
// 处理 Action 方法返回值
handleActionMethodReturn(request, response, actionMethodResult);
}
private List<Object> createParamList(HttpServletRequest request, ActionBean actionBean, Matcher requestPathMatcher) throws Exception {
// 定义参数列表
List<Object> paramList = new ArrayList<Object>();
// 获取 Action 方法参数类型
Class<?>[] actionParamTypes = actionBean.getActionMethod().getParameterTypes();
// 添加路径参数列表(请求路径中的带占位符参数)
paramList.addAll(createPathParamList(requestPathMatcher, actionParamTypes));
// 分两种情况进行处理
if (UploadHelper.isMultipart(request)) {
// 添加 Multipart 请求参数列表
paramList.addAll(UploadHelper.createMultipartParamList(request));
} else {
// 添加普通请求参数列表(包括 Query String 与 Form Data)
Map<String, Object> requestParamMap = WebUtil.getRequestParamMap(request);
if (MapUtil.isNotEmpty(requestParamMap)) {
paramList.add(new Params(requestParamMap));
}
}
// 返回参数列表
return paramList;
}
private List<Object> createPathParamList(Matcher requestPathMatcher, Class<?>[] actionParamTypes) {
// 定义参数列表
List<Object> paramList = new ArrayList<Object>();
// 遍历正则表达式中所匹配的组
for (int i = 1; i <= requestPathMatcher.groupCount(); i++) {
// 获取请求参数
String param = requestPathMatcher.group(i);
// 获取参数类型(支持四种类型:int/Integer、long/Long、double/Double、String)
Class<?> paramType = actionParamTypes[i - 1];
if (paramType.equals(int.class) || paramType.equals(Integer.class)) {
paramList.add(CastUtil.castInt(param));
} else if (paramType.equals(long.class) || paramType.equals(Long.class)) {
paramList.add(CastUtil.castLong(param));
} else if (paramType.equals(double.class) || paramType.equals(Double.class)) {
paramList.add(CastUtil.castDouble(param));
} else if (paramType.equals(String.class)) {
paramList.add(param);
}
}
// 返回参数列表
return paramList;
}
private void handleActionMethodReturn(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) {
// 判断返回值类型
if (actionMethodResult != null) {
if (actionMethodResult instanceof Result) {
// 分两种情况进行处理
Result result = (Result) actionMethodResult;
if (UploadHelper.isMultipart(request)) {
// 对于 multipart 类型,说明是文件上传,需要转换为 HTML 格式并写入响应中
WebUtil.writeHTML(response, result);
} else {
// 对于其它类型,统一转换为 JSON 格式并写入响应中
WebUtil.writeJSON(response, result);
}
} else if (actionMethodResult instanceof View) {
// 转发 或 重定向 到相应的页面中
View view = (View) actionMethodResult;
if (view.isRedirect()) {
// 获取路径
String path = view.getPath();
// 重定向请求
WebUtil.redirectRequest(path, request, response);
} else {
// 获取路径
String path = FrameworkConstant.JSP_PATH + view.getPath();
// 初始化请求属性
Map<String, Object> data = view.getData();
if (MapUtil.isNotEmpty(data)) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
request.setAttribute(entry.getKey(), entry.getValue());
}
}
// 转发请求
WebUtil.forwardRequest(path, request, response);
}
}
}
}
private void handleActionException(HttpServletRequest request, HttpServletResponse response, Exception e) {
// 判断异常原因
Throwable cause = e.getCause();
if (cause instanceof AccessException) {
// 分两种情况进行处理
if (WebUtil.isAJAX(request)) {
// 跳转到 403 页面
WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
} else {
// 重定向到首页
WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
}
} else if (cause instanceof PermissionException) {
// 跳转到 403 页面
WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
} else {
// 跳转到 500 页面
logger.error("执行 Action 出错!", e);
WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response);
}
}
}
代码量虽然不算太多,但是大家可以发现,这个类犯了一个严重的错误,或许应该说是编程中的一个大忌! —— 严重违反了“单一职责原则”。
当快枪手指出这个问题时,我仿佛被一根针狠狠扎了一下,瞬间就清醒过来了,自己果然是犯了错误。
定义 MVC 接口
正所谓“知错能改,善莫大焉”,所以我虚心地向快枪手请教,于是他开始舞弄笔墨,只需一分钟就帮我画了一张草图:
这貌似哪里见过呀,没错,Spring MVC 就长这样子!
可见结构非常清晰:
- 请求首先进入
DispatcherServlet
(前端控制器) - 由
DispatcherServlet
调用HandlerMapping
接口,获取Handler
对象(该对象是对 Action 方法的抽象) - 由
DispatcherServlet
调用HandlerInvoker
接口,调用具体的 Action 方法(同时需要获取 Action 参数) - 由
HandlerInvoker
调用ViewResolver
接口,进行视图解析(视图可以是 JSP、HTML 或 Velocity 模板等) - 由
DispatcherServlet
调用HandlerExceptionResolver
接口,进行相关的异常处理(可能会跳转到相应的错误页面)
大家可能会问:为什么要使用如此之多的接口呢?
因为在每个成功接口的背后,总会有一个默默支持它的实现,而这些实现都是 Smart 框架内部提供的默认实现,开发人员可以根据实际需要进行定制,此时就需要与 InstanceFactory
打交道了。
<!-- lang: java -->
/**
* 实例工厂
*
* @author huangyong
* @since 2.3
*/
public class InstanceFactory {
/**
* 用于缓存对应的实例
*/
private static final Map<String, Object> cache = new ConcurrentHashMap<String, Object>();
...
/**
* HandlerMapping
*/
private static final String HANDLER_MAPPING = "smart.framework.custom.handler_mapping";
/**
* HandlerInvoker
*/
private static final String HANDLER_INVOKER = "smart.framework.custom.handler_invoker";
/**
* HandlerExceptionResolver
*/
private static final String HANDLER_EXCEPTION_RESOLVER = "smart.framework.custom.handler_exception_resolver";
/**
* ViewResolver
*/
private static final String VIEW_RESOLVER = "smart.framework.custom.view_resolver";
...
/**
* 获取 HandlerMapping
*/
public static HandlerMapping getHandlerMapping() {
return getInstance(HANDLER_MAPPING, DefaultHandlerMapping.class);
}
/**
* 获取 HandlerInvoker
*/
public static HandlerInvoker getHandlerInvoker() {
return getInstance(HANDLER_INVOKER, DefaultHandlerInvoker.class);
}
/**
* 获取 HandlerExceptionResolver
*/
public static HandlerExceptionResolver getHandlerExceptionResolver() {
return getInstance(HANDLER_EXCEPTION_RESOLVER, DefaultHandlerExceptionResolver.class);
}
/**
* 获取 ViewResolver
*/
public static ViewResolver getViewResolver() {
return getInstance(VIEW_RESOLVER, DefaultViewResolver.class);
}
@SuppressWarnings("unchecked")
public static <T> T getInstance(String cacheKey, Class<T> defaultImplClass) {
// 若缓存中存在对应的实例,则返回该实例
if (cache.containsKey(cacheKey)) {
return (T) cache.get(cacheKey);
}
// 从配置文件中获取相应的接口实现类配置
String implClassName = ConfigHelper.getString(cacheKey);
// 若实现类配置不存在,则使用默认实现类
if (StringUtil.isEmpty(implClassName)) {
implClassName = defaultImplClass.getName();
}
// 通过反射创建该实现类对应的实例
T instance = ObjectUtil.newInstance(implClassName);
// 若该实例不为空,则将其放入缓存
if (instance != null) {
cache.put(cacheKey, instance);
}
// 返回该实例
return instance;
}
}
比如说,当开发者想提供自己的 HandlerInvoker 实现,怎么做到呢?
他只需要在 smart.properties
配置文件中,添加如下配置项:
<!-- lang: java -->
smart.framework.custom.handler_invoker=自己的 HandlerInvoker 实现类
abel533 同学就实现了一个更强大的 HandlerInvoker,他的代码地址如下:
http://git.oschina.net/free/Args/tree/smart_plugin_args/
非常感谢他的贡献!
说到这里,大家应该迫不及待想看看,快枪手这位大神究竟是如何定义这些接口的。别急,下面的才是精华!
这是 HandlerMapping
接口:
<!-- lang: java -->
/**
* 处理器映射
*
* @author huangyong
* @since 2.3
*/
public interface HandlerMapping {
/**
* 获取 Handler
*
* @param currentRequestMethod 当前请求方法
* @param currentRequestPath 当前请求路径
* @return Handler
*/
Handler getHandler(String currentRequestMethod, String currentRequestPath);
}
这是 HandlerInvoker
接口:
<!-- lang: java -->
/**
* Handler 调用器
*
* @author huangyong
* @since 2.3
*/
public interface HandlerInvoker {
/**
* 调用 Handler
*
* @param request 请求对象
* @param response 响应对象
* @param handler Handler
* @throws Exception 异常
*/
void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception;
}
这是 ViewResolver
接口:
<!-- lang: java -->
/**
* 视图解析器
*
* @author huangyong
* @since 2.3
*/
public interface ViewResolver {
/**
* 解析视图
*
* @param request 请求对象
* @param response 响应对象
* @param actionMethodResult Action 方法返回值
*/
void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult);
}
这是 HandlerExceptionResolver
接口:
<!-- lang: java -->
/**
* Handler 异常解析器
*
* @author huangyong
* @since 2.3
*/
public interface HandlerExceptionResolver {
/**
* 解析 Handler 异常
*
* @param request 请求对象
* @param response 响应对象
* @param e 异常
*/
void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e);
}
可见,每个接口中只包含一个方法,充分做到了“单一职责”,而且接口方法的参数非常简单。
其中有一个 Handler
类需要说明一下,它就是曾经的 ActionBean
,这里只是把它改了一个名字,让它看起来更加的专业,说白了,Handler
就是 Action 方法,没什么神奇的。
此外,快枪手建议将以前的 RequestBean
重命名为 Requestor
,用于封装请求对象的相关信息。
有必要再对 Handler
的代码说明一下:
<!-- lang: java -->
/**
* 封装 Action 方法相关信息
*
* @author huangyong
* @since 1.0
*/
public class Handler {
private Class<?> actionClass;
private Method actionMethod;
private Matcher requestPathMatcher;
public Handler(Class<?> actionClass, Method actionMethod) {
this.actionClass = actionClass;
this.actionMethod = actionMethod;
}
public Class<?> getActionClass() {
return actionClass;
}
public Method getActionMethod() {
return actionMethod;
}
public Matcher getRequestPathMatcher() {
return requestPathMatcher;
}
public void setRequestPathMatcher(Matcher requestPathMatcher) {
this.requestPathMatcher = requestPathMatcher;
}
}
该类中包括三个成员变量:
Class<?> actionClass
:表示该 Handler 所在的 Action 类Method actionMethod
:表示当前的 Action 方法Matcher requestPathMatcher
:表示请求路径的正则表达式匹配器(用于根据请求 URL 匹配 Action 方法)
准备工作现已就绪,下面就来看看这些接口的默认实现吧。
提供接口的默认实现
接口定义清楚了,重构犹如复制粘贴,下面根据以上 MVC 相关接口的出现顺序,分别展示具体的实现代码。
这是 HandlerMapping
接口的默认实现:
<!-- lang: java -->
/**
* 默认处理器映射
*
* @author huangyong
* @since 2.3
*/
public class DefaultHandlerMapping implements HandlerMapping {
/**
* 用于缓存 Handler 实例
*/
private static final Map<String, Handler> cache = new ConcurrentHashMap<String, Handler>();
@Override
public Handler getHandler(String currentRequestMethod, String currentRequestPath) {
// 若缓存中存在对应的实例,则返回该实例
String cacheKey = currentRequestMethod + ":" + currentRequestPath;
if (cache.containsKey(cacheKey)) {
return cache.get(cacheKey);
}
// 定义一个 Handler
Handler handler = null;
// 获取并遍历 Action 映射
Map<Requestor, Handler> actionMap = ActionHelper.getActionMap();
for (Map.Entry<Requestor, Handler> actionEntry : actionMap.entrySet()) {
// 从 Requestor 中获取 Request 相关属性
Requestor requestor = actionEntry.getKey();
String requestMethod = requestor.getRequestMethod();
String requestPath = requestor.getRequestPath(); // 正则表达式
// 获取请求路径匹配器(使用正则表达式匹配请求路径并从中获取相应的请求参数)
Matcher requestPathMatcher = Pattern.compile(requestPath).matcher(currentRequestPath);
// 判断请求方法与请求路径是否同时匹配
if (requestMethod.equalsIgnoreCase(currentRequestMethod) && requestPathMatcher.matches()) {
// 获取 Handler 及其相关属性
handler = actionEntry.getValue();
// 设置请求路径匹配器
if (handler != null) {
handler.setRequestPathMatcher(requestPathMatcher);
}
// 若成功匹配,则终止循环
break;
}
}
// 若该实例不为空,则将其放入缓存
if (handler != null) {
cache.put(cacheKey, handler);
}
// 返回该 Handler
return handler;
}
}
这是 HandlerInvoker
接口的默认实现:
<!-- lang: java -->
/**
* 默认 Handler 调用器
*
* @author huangyong
* @since 2.3
*/
public class DefaultHandlerInvoker implements HandlerInvoker {
private ViewResolver viewResolver = InstanceFactory.getViewResolver();
@Override
public void invokeHandler(HttpServletRequest request, HttpServletResponse response, Handler handler) throws Exception {
// 获取 Action 相关信息
Class<?> actionClass = handler.getActionClass();
Method actionMethod = handler.getActionMethod();
// 从 BeanHelper 中创建 Action 实例
Object actionInstance = BeanHelper.getBean(actionClass);
// 创建 Action 方法的参数列表
List<Object> actionMethodParamList = createActionMethodParamList(request, handler);
// 检查参数列表是否合法
checkParamList(actionMethod, actionMethodParamList);
// 调用 Action 方法
Object actionMethodResult = invokeActionMethod(actionMethod, actionInstance, actionMethodParamList);
// 解析视图
viewResolver.resolveView(request, response, actionMethodResult);
}
public List<Object> createActionMethodParamList(HttpServletRequest request, Handler handler) throws Exception {
// 定义参数列表
List<Object> paramList = new ArrayList<Object>();
// 获取 Action 方法参数类型
Class<?>[] actionParamTypes = handler.getActionMethod().getParameterTypes();
// 添加路径参数列表(请求路径中的带占位符参数)
paramList.addAll(createPathParamList(handler.getRequestPathMatcher(), actionParamTypes));
// 分两种情况进行处理
if (UploadHelper.isMultipart(request)) {
// 添加 Multipart 请求参数列表
paramList.addAll(UploadHelper.createMultipartParamList(request));
} else {
// 添加普通请求参数列表(包括 Query String 与 Form Data)
Map<String, Object> requestParamMap = WebUtil.getRequestParamMap(request);
if (MapUtil.isNotEmpty(requestParamMap)) {
paramList.add(new Params(requestParamMap));
}
}
// 返回参数列表
return paramList;
}
private List<Object> createPathParamList(Matcher requestPathMatcher, Class<?>[] actionParamTypes) {
// 定义参数列表
List<Object> paramList = new ArrayList<Object>();
// 遍历正则表达式中所匹配的组
for (int i = 1; i <= requestPathMatcher.groupCount(); i++) {
// 获取请求参数
String param = requestPathMatcher.group(i);
// 获取参数类型(支持四种类型:int/Integer、long/Long、double/Double、String)
Class<?> paramType = actionParamTypes[i - 1];
if (ClassUtil.isInt(paramType)) {
paramList.add(CastUtil.castInt(param));
} else if (ClassUtil.isLong(paramType)) {
paramList.add(CastUtil.castLong(param));
} else if (ClassUtil.isDouble(paramType)) {
paramList.add(CastUtil.castDouble(param));
} else if (ClassUtil.isString(paramType)) {
paramList.add(param);
}
}
// 返回参数列表
return paramList;
}
private Object invokeActionMethod(Method actionMethod, Object actionInstance, List<Object> actionMethodParamList) throws IllegalAccessException, InvocationTargetException {
// 通过反射调用 Action 方法
actionMethod.setAccessible(true); // 取消类型安全检测(可提高反射性能)
return actionMethod.invoke(actionInstance, actionMethodParamList.toArray());
}
private void checkParamList(Method actionMethod, List<Object> actionMethodResult) {
// 判断 Action 方法参数的个数是否匹配
Class<?>[] actionMethodParameterTypes = actionMethod.getParameterTypes();
if (actionMethodParameterTypes.length != actionMethodResult.size()) {
throw new RuntimeException("由于参数不匹配,无法调用 Action 方法!");
}
}
}
这是 ViewResolver
接口的默认实现:
<!-- lang: java -->
/**
* 默认视图解析器
*
* @author huangyong
* @since 2.3
*/
public class DefaultViewResolver implements ViewResolver {
@Override
public void resolveView(HttpServletRequest request, HttpServletResponse response, Object actionMethodResult) {
if (actionMethodResult != null) {
// Action 返回值可为 View 或 Result
if (actionMethodResult instanceof View) {
// 若为 View,则需考虑两种视图类型(重定向 或 转发)
View view = (View) actionMethodResult;
if (view.isRedirect()) {
// 获取路径
String path = view.getPath();
// 重定向请求
WebUtil.redirectRequest(path, request, response);
} else {
// 获取路径
String path = FrameworkConstant.JSP_PATH + view.getPath();
// 初始化请求属性
Map<String, Object> data = view.getData();
if (MapUtil.isNotEmpty(data)) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
request.setAttribute(entry.getKey(), entry.getValue());
}
}
// 转发请求
WebUtil.forwardRequest(path, request, response);
}
} else {
// 若为 Result,则需考虑两种请求类型(文件上传 或 普通请求)
Result result = (Result) actionMethodResult;
if (UploadHelper.isMultipart(request)) {
// 对于 multipart 类型,说明是文件上传,需要转换为 HTML 格式并写入响应中
WebUtil.writeHTML(response, result);
} else {
// 对于其它类型,统一转换为 JSON 格式并写入响应中
WebUtil.writeJSON(response, result);
}
}
}
}
}
这是 HandlerExceptionResolver
接口的默认实现:
<!-- lang: java -->
/**
* 默认 Handler 异常解析器
*
* @author huangyong
* @since 2.3
*/
public class DefaultHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public void resolveHandlerException(HttpServletRequest request, HttpServletResponse response, Exception e) {
// 判断异常原因
Throwable cause = e.getCause();
if (cause instanceof AccessException) {
// 分两种情况进行处理
if (WebUtil.isAJAX(request)) {
// 跳转到 403 页面
WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
} else {
// 重定向到首页
WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
}
} else if (cause instanceof PermissionException) {
// 跳转到 403 页面
WebUtil.sendError(HttpServletResponse.SC_FORBIDDEN, "", response);
} else {
// 跳转到 500 页面
WebUtil.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, cause.getMessage(), response);
}
}
}
代码量虽然有增无减,但这样的结构更加清晰了,职责更加分明,便于日后的扩展与维护。看来快枪手真不是一般的神人啊!
这些实现类的代码都来自于重构前的 DispatcherServlet
,这里只是根据职责进行了分类,那么现在的 DispatcherServlet
又是啥样子呢?
重构后的 DispatcherServlet
最后给大家奉上重构后的 DispatcherServlet
:
<!-- lang: java -->
/**
* 前端控制器
*
* @author huangyong
* @since 1.0
*/
@WebServlet(urlPatterns = "/*", loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
private HandlerMapping handlerMapping = InstanceFactory.getHandlerMapping();
private HandlerInvoker handlerInvoker = InstanceFactory.getHandlerInvoker();
private HandlerExceptionResolver handlerExceptionResolver = InstanceFactory.getHandlerExceptionResolver();
@Override
public void init(ServletConfig config) throws ServletException {
// 初始化相关配置
ServletContext servletContext = config.getServletContext();
UploadHelper.init(servletContext);
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求编码方式
request.setCharacterEncoding(FrameworkConstant.UTF_8);
// 获取当前请求相关数据
String currentRequestMethod = request.getMethod();
String currentRequestPath = WebUtil.getRequestPath(request);
logger.debug("[Smart] {}:{}", currentRequestMethod, currentRequestPath);
// 将“/”请求重定向到首页
if (currentRequestPath.equals("/")) {
WebUtil.redirectRequest(FrameworkConstant.HOME_PAGE, request, response);
return;
}
// 去掉当前请求路径末尾的“/”
if (currentRequestPath.endsWith("/")) {
currentRequestPath = currentRequestPath.substring(0, currentRequestPath.length() - 1);
}
// 获取 Handler
Handler handler = handlerMapping.getHandler(currentRequestMethod, currentRequestPath);
// 若未找到 Action,则跳转到 404 页面
if (handler == null) {
WebUtil.sendError(HttpServletResponse.SC_NOT_FOUND, "", response);
return;
}
// 初始化 DataContext
DataContext.init(request, response);
try {
// 调用 Handler
handlerInvoker.invokeHandler(request, response, handler);
} catch (Exception e) {
// 处理 Action 异常
handlerExceptionResolver.resolveHandlerException(request, response, e);
} finally {
// 销毁 DataContext
DataContext.destroy();
}
}
}
此时,只需在 DispatcherServlet
中调用 InstanceFactory
的相关方法,便可获取相应的接口,代码看起来也轻松了许多。
重构是一个永恒的话题,也是一件永无休止的事情,好代码绝不是一开始就写得出来的,一定是经过了反复的重构,将不合理的地方变成更合理,以后有机会再与大家分享重构的心得与体会。
欢迎下载 Smart 源码:
http://git.oschina.net/huangyong/smart
欢迎阅读 Smart 博文:
http://my.oschina.net/huangyong/blog/158380