Design and Implementation of a lightweight MVC Framework (1)

Source: Internet
Author: User

I was preparing to build a small website some time ago, but I didn't want to use a large header like Spring/Struts/WebWork. So I decided to write an MVC Framework myself. It took about three days to complete and is currently running well. The entire MVC framework is only 21KB. If you are interested, you can download the source code and jarpackage from http://code.google.com/p/lightweightmvc/downloads/list.

Design goals:

The simplest and most compact MVC Framework provides a fancy function. The simpler the better, the better. Instead of using an XML configuration file, it is completely configured with Java 5 annotations.

Function list:

Components must be configured with IoC;

Action for processing HTTP requests. For example, a new instance is generated for each WebWork request and attributes are automatically filled;

Similar to the Interceptor mechanism of Filter, but configured in the IoC container;

Unified exception handling;

Multi-view support.

Because components need to be configured with IoC containers, the first step is to find a small IoC container. Google Guice is a good choice and uses Java 5 annotations to configure components completely. The only dependency of this MVC Framework is the Guice and Commons Logging jar packages. If Velocity is used as the view, the Velocity jar package is also required.

Next, design the main functions:

The Action interface that must be implemented by the Action class that processes Http requests:

Package com. javaeedev. lightweight. mvc;

Public interface Action {

ModelAndView execute () throws Exception;

}

Copy From WebWork, but the returned value is changed from String to ModelAndView (copied from Spring). The advantage is that you do not have to search for the absolute path of the View Based on String again and include it directly in ModelAndView. Using Spring MVC, we can find that ModelAndView contains both a Model (essentially a Map) and a View path, which reduces the XML ing file required by Struts and WebWork, maintaining the XML configuration file is a very troublesome problem. It is often necessary to modify the configuration of the Code. Simply write it into the code, and the view path will not change frequently, there is no need to create a bunch of XML configuration files for extra flexibility.

ModelAndView returned by Action:

Package com. javaeedev. lightweight. mvc;

Public final class ModelAndView {

Private String view;
Private Map <String, Object> model;

/**
* Construct a View with empty model.
*
* @ Param view View's logic name.
*/
Public ModelAndView (String view ){
This. view = view;
This. model = Collections. emptyMap ();
}

/**
* Construct a View with model.
*
* @ Param view View's logic name.
* @ Param model Model as a Map.
*/
Public ModelAndView (String view, Map <String, Object> model ){
This. view = view;
This. model = model;
}

/**
* Return View.
*
* @ Return View's logic name.
*/
Public String getView (){
Return view;
}

/**
* Return model.
*
* @ Return Model as a Map.
*/
Public Map <String, Object> getModel (){
Return model;
}

}

This is completely copied from Spring MVC, and Map is changed to generic. The View path can start with "redirect:" to indicate redirection, which is consistent with Spring MVC. Although direct calls to HttpServletResponse can also be redirected, it may be difficult to handle the transaction, but it is better to let the MVC Framework handle it by itself.

The benefit of WebWork Action design is that it greatly simplifies parameter binding. However, in many cases, you also need to access objects such as HttpSession in Action. Therefore, you need to design an ActionContext class, threadLocal allows Action objects to easily access these objects:

Package com. javaeedev. Lightweight. MVC;

Public final class actioncontext {

Private Static threadlocal <actioncontext> contextthreadlocal = new threadlocal <actioncontext> ();

/**
* Get current actioncontext.
*
* @ Return actioncontext.
*/
Public static actioncontext getactioncontext (){
Return contextthreadlocal. Get ();
}

Private httpservletrequest request;
Private httpservletresponse response;
Private httpsession session;
Private servletcontext context;

/**
* Initiate all servlet objects as thread local.
*
* @ Param request HttpServletRequest object.
* @ Param response HttpServletResponse object.
* @ Param session HttpSession object.
* @ Param context ServletContext object.
*/
Static void setActionContext (HttpServletRequest request, HttpServletResponse response, HttpSession session, ServletContext context ){
ActionContext actionContext = new ActionContext ();
ActionContext. setRequest (request );
ActionContext. setResponse (response );
ActionContext. setSession (session );
ActionContext. setServletContext (context );
ContextThreadLocal. set (actionContext );
}

/**
* Remove all servlet objects from thread local.
*/
Static void remove (){
ContextThreadLocal. remove ();
}

/**
* Get HttpServletRequest object.
*
* @ Return HttpServletRequest object.
*/
Public HttpServletRequest getRequest (){
Return request;
}

/**
* Set HttpServletRequest object.
*
* @ Param request HttpServletRequest object.
*/
Void setRequest (HttpServletRequest request ){
This. request = request;
}

/**
* Get HttpServletResponse object.
*
* @ Return httpservletresponse object.
*/
Public httpservletresponse getresponse (){
Return response;
}

/**
* Set httpservletresponse object.
*
* @ Param response httpservletresponse object.
*/
Void setresponse (httpservletresponse response ){
This. Response = response;
}

/**
* Get httpsession object.
*
* @ Return HttpSession object.
*/
Public HttpSession getSession (){
Return session;
}

/**
* Set HttpSession object.
*
* @ Param session HttpSession object.
*/
Void setSession (HttpSession session ){
This. session = session;
}

/**
* Get ServletContext object.
*
* @ Return servletcontext object.
*/
Public servletcontext getservletcontext (){
Return context;
}

/**
* Set servletcontext object.
*
* @ Param context servletcontext object.
*/
Void setservletcontext (servletcontext context ){
This. Context = context;
}

}

Next, define an interceptor interface similar to the filter function:

Package com. javaeedev. Lightweight. MVC;

/**
* Intercept action's execution like servlet Filter, but interceptors are
* Configured and managed by IoC container. Another difference from Filter
* Is that Interceptor is executed around Action's execution, but before
* Rendering view.
*
* @ Author Xuefeng
*/
Public interface Interceptor {

/**
* Do intercept and invoke chain. doInterceptor () to process next interceptor.
* NOTE that process will not continue if chain. doInterceptor () method is not
* Invoked.
*
* @ Param action Action instance to handle http request.
* @ Param chain Interceptor chain.
* @ Throws Exception If any exception is thrown, process will not continued.
*/
Void intercept (Action action, InterceptorChain chain) throws Exception;

}

The InterceptorChain object is the same as the FilterChain object. It allows an interceptor to send the request to the next interceptor for processing or to interrupt the processing of the current request:

Package com. javaeedev. lightweight. mvc;

/**
* Holds all interceptors as a chain.
*
* @ Author Xuefeng
*/
Public interface InterceptorChain {

/**
* Apply next interceptor around the execution of Action.
*
* @ Param action Target Action to execute.
* @ Throws Exception Any exception if error occured.
*/
Void doInterceptor (Action action) throws Exception;

}

Finally, ViewResolver that supports multiple views is also copied from Spring MVC:

Package com. javaeedev. lightweight. mvc;

Import java. io. IOException;
Import java. util. Map;

Import javax. servlet. ServletContext;
Import javax. servlet. ServletException;
Import javax. servlet. http. HttpServletRequest;
Import javax. servlet. http. HttpServletResponse;

/**
* To resolve and render a view.
*
* @ Author Xuefeng
*/
Public interface ViewResolver {

/**
* Init this ViewResolver.
*
* @ Param context ServletContext object that holds information of current
* Web application.
* @ Throws ServletException If init failed.
*/
Void init (ServletContext context) throws ServletException;

/**
* To resolve view's name and render view if necessary.
*
* @ Param view View's logic name.
* @ Param model Model represent as a generic Map.
* @ Param request HttpServletRequest object.
* @ Param response HttpServletResponse object.
* @ Throws ServletException If any ServletException occur.
* @ Throws IOException If any IOException occur.
*/
Void resolveView (String view, Map <String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;

}

The first version supports two views: JSP and Velocity. In fact, supporting other views is completely scalable. You only need to refer to the two existing ViewResolver implementations and write another implementation, for example, ViewResolver that supports FreeMarker.

So far, the API provided to the client has been prepared. The next step is how to implement these Apis. Although both concepts and structures come from WebWork and Spring, their specific implementation does not refer to their source code, because it is very laborious to read the source code of a large block header, it is better to do it yourself. Writing code is usually faster than reading the code.

The following describes how to implement the MVC framework.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.