Implementing a Web framework based on a servlet

Source: Internet
Author: User

The servlet, as a web specification, is itself a web development framework, but its implementation of Web action (in response to a URI implementation) is class-based, not very convenient, and the previous version of 3.0 must also add a new action through the Web. XML configuration. There is a filter function in the servlet, and the ability to configure all URIs is filtered. We can implement a simple web framework based on the function of filter. In this framework, the mapping of the URI action is primarily improved, as is the configuration of the route in the play framework:

GET     /hello      com.codemacro.webdemo.test.TestController.helloGET     /route      Com.codemacro.webdemo.test.TestController.routePOST    /hello      Com.codemacro.webdemo.test.TestController.sayHello

A URI is mapped to the class interface level. The benefits of implementing a Web framework based on a servlet are simple and can be run on all Web servers that support the servlet container specification, such as Tomcat, Jetty.

The web framework demo mentioned in this article can be obtained from my GitHub: Servlet-web-framework-demo

Function

This web framework URI action part (or URI routing) is described earlier, and the action is written like this:

public class TestController extends Basecontroller {  //return string public  Result index () {    return ok ("Hello World" );  }  HTTP 404 Public  Result code404 () {    return status (404, ' not Found ');  }  Render public  Result template using a JSP template () {    string[] langs = new string[] {"C + +", "Java", "Python"};    Return OK (JSP ("index.jsp")        . Put ("name", "Kevin")        . Put ("Langs",  langs)        );}  }

Once you have the action, the profile route mapping URI is available:

Get/index  com.codemacro.webdemo.test.testcontroller.indexget/404    com.codemacro.webdemo.test.testcontroller.code404get/index.jsp Com.codemacro.webdemo.test.TestController.template

Then configure web.xml , add a filter:

<filter>  <filter-name>MyWebFilter</filter-name>  <filter-class> Com.codemacro.webdemo.myservletfilter</filter-class></filter><filter-mapping>  < Filter-name>mywebfilter</filter-name>  <url-pattern>/*</url-pattern></ Filter-mapping>

Finally, the war is deployed in the form of jetty to webapps run. Think about what to look for next time Lightweight Java web framework, directly with this demo is enough. Next, let's talk about the implementation of some key parts.

Servlet Basic

In the case of servlet-based development, the introduction of the Servlet API is necessary:

<dependency>    <groupId>javax.servlet</groupId>    <artifactid>servlet-api</ artifactid>    <version>2.5</version>    <type>jar</type>    <scope> Compile</scope></dependency>

The interface of the servlet filter contains:

public class Myservletfilter implements Filter {  //web app is invoked once when it is started and can be used for web framework initialization of public  void Init (filterconfig conf) throws Servletexception {}  //satisfies the filter url-pattern, and req/res corresponds to HTTP request and response public  void DoFilter ( ServletRequest req, servletresponse Res,    Filterchain chain) throws IOException, servletexception {} public  void Destroy () {}}

initThe interface can be used to load routes a configuration file at startup and to establish a URI-to-action mapping.

Action Manager

ActionManagerResponsible for loading the configuration at startup routes and establishing a URI-to-action mapping. A URI contains the HTTP method and Uri String, for example GET /index . Now that the action is mapped to a class interface, the corresponding class and interface can be found at startup with the same Java reflection. For simplicity, each time a request for a URI is received, the object corresponding to that class is created and the mapped interface is called.

//for example: registerAction ("Com.codemacro.webdemo.test.TestController", "Index", "/index", "GET");p ublic void Registeraction (String clazname,    String methodName, String uri, string method) {try {uri = "/" + AppName + uri; Load the corresponding Class class<?    Extends basecontroller> clazz = (class<? extends basecontroller>) loadclass (clazname);    Get the corresponding interface Method m = Clazz.getmethod (MethodName, (class<?>[]) null); The interface requirement must return Result if (M.getreturntype ()! = Result.class) {throw new RuntimeException ("action method return type M    IsMatch: "+ uri");    } actionkey k = new Actionkey (URI, GetMethod (method));    Actionvalue v = new Actionvalue (Clazz, M);    Logger.debug ("register action {} {} {} {}", Clazname, MethodName, Uri, method);  Establish mapping Actions.put (k, v);  } catch (Exception e) {throw new RuntimeException ("Registeraction failed:" + URI, E); }}

Controllers are required to derive BaseController , so that they can take advantage of BaseController more convenient access to request data, such as query String/cookie, and so on.

When a request is received, it is necessary to obtain the previously established mapping based on the requested HTTP method and URI string, and call it:

Public boolean Invoke (HttpServletRequest req, HttpServletResponse resp) throws IOException {  String uri = req.getrequ Esturi ();  String method = Req.getmethod (). toUpperCase ();  try {    //Get the previously established mapping, map lookup    Actionvalue v = getaction (Uri, method);    Create a new controller object    Basecontroller ctl = (basecontroller) v.clazz.newinstance ();    Ctl.init (req, resp, this);    Logger.debug ("Invoke Action {}", URI);    The interface on which the binding was invoked    result result = (result) V.method.invoke (CTL, (object[]) null);    Render result    Result.render ();  } catch (Exception e) {    ...  }}
Result rendering

The result rendering is simply rendering the result returned by the framework user as a string, written in HttpServletResponse . This rendering process can be straightforward Object.toString , either through the template engine rendering, or formatted as JSON.

By implementing a specific Result class, you can extend different rendering methods, for example, the most basic Result is to invoke the returned object toString :

public class Result {public  void render () throws IOException, servletexception {    printwriter writer = response.ge Twriter ();    Result is the    writer.append (result.tostring ()) returned in the controller action;    Writer.close ();  }}

To be simple, do not introduce a third-party library, you can directly through the JSP to complete. The JSP itself is compiled into a Servlet object in the Servlet container.

public class Jspresult extends Result {  ...  @Override public  Void Render () throws IOException, servletexception {    //pass in some objects into the template for    (map.entry< String, object> Entry:content.entrySet ()) {      Request.setattribute (Entry.getkey (), Entry.getvalue ());    }    Delegate to the JSP to complete rendering    request.getrequestdispatcher (file). Forward (request, response);}  }

You can use a traditional scriptlets expression in a JSP, or you can use a new El method, such as:

<%@ taglib prefix= "C" uri= "Http://java.sun.com/jsp/jstl/core"%>

If you use EL, you need to introduce<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

Basecontroller

BaseControlleris a template pattern implementation that wraps a number of convenient interfaces for use by specific controllers, such as:

public class Basecontroller {  //Gets the name parameter value in/index?name=kevin  protected string getquerystring (string key) {    return Request.getparameter (key);  }  protected Result Status (int code, String text) {    response.setstatus (code);    return new Result (response, text);  }  The default is HTTP  protected result ok (Object obj) {    return new result (response, obj);  }  Protected result OK (Result result) {    return result;  }  Protected Jspresult jsp (String file) {    return new Jspresult (request, response, file, actionmgr);}  }
Reverse Routing

Reverse routing refers to the development of the web process, in order to introduce a URL, we do not directly write the URL string, but rather write its mapped interface to make the code easier to maintain (because the URL may change as the project progresses). Also, after the Servlet app is deployed, the URL takes the name prefix of the app, for example, /web-demo/index in /web-demo . In a template file, for example to link to another URI, the better way is to write directly /index .

The implementation here is ugly, or string-based, for example:

<a href= ' <route:reverse action= "Com.codemacro.webdemo.test.TestController.hello" name= "Kevin"/> ' > Index</a>

Implemented by customizing an El function reverse . Here you need to introduce a library of JSPs:

<dependency>    <groupId>javax.servlet</groupId>    <artifactid>jsp-api</ artifactid>    <version>2.0</version>    <optional>true</optional></dependency >

First, to SimpleTagSupport support ?name=kevin This dynamic parameter, you also need to implements DynamicAttributes :

public class Jsproutetag extends Simpletagsupport implements Dynamicattributes {  @Override  //output final URL  public void Dotag () throws IOException {    Jspcontext context = Getjspcontext ();    ActionManager actionmgr = (actionmanager) context.findattribute (action_mgr);    JspWriter out = Context.getout ();    String URI = actionmgr.getreverseaction (action, attrmap);    Out.println (URI);  }  @Override  //name= "Kevin" when calling public  void Setdynamicattribute (string uri, string name, Object value) throws Jsp Exception {    attrmap.put (name, value);  }  ' action= ' xxx ' will call ' setaction ' public  void Setaction (String action) {    this.action = action;  }}

In order to access ActionManager , here is achieved by writing to Request context , rather hack.

Public Jspresult (HttpServletRequest req, HttpServletResponse resp, String file,     ActionManager actionmgr) {  Super (RESP, null);.  Put (Jsproutetag.action_mgr, actionmgr);}

The second step is to add a file that describes the new tag WEB-INF/route_tag.tld :

<taglib>    <tlibversion>1.0</tlibversion>    <jspversion>1.1</jspversion>    <shortname>URLRouteTags</shortname>    <uri>/myweb-router</uri>    <info> </info>    <tag>        <name>reverse</name>        <tagclass> com.codemacro.webdemo.result.jsproutetag</tagclass>        <bodycontent></bodycontent>        < info></info>        <attribute>            <name>action</name>            <required>true </required>        </attribute>        <dynamic-attributes>true</dynamic-attributes>    </tag></taglib>

Finally, this custom tag is introduced in the JSP that needs to be used:

<%@ taglib prefix= "route" uri= "/myweb-router"%>
Resources
    • Servlet life cycle and how it works
    • Jsp/servlet Working principle
    • El expression
    • Developing web programs using Servlets and JSPs
    • Introduction to the filter filter in Java Web note –servlet and the use of write filters
    • Implement a simple servlet container

Original address: http://codemacro.com/2015/06/07/servlet-web-framework/
Written by Kevin Lynx posted athttp://codemacro.com

Implementing a Web framework based on a servlet

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.