首页 limemvc

limemvc

举报
开通vip

limemvc IntroductionIntroductionIntroductionIntroduction As you know, the MVC in Spring is composed from the dispatcher servlet, which turns the HTTP requests into the method’s calls, and from various annotations, which help to bind the parameters. I kept this idea i...

limemvc
IntroductionIntroductionIntroductionIntroduction As you know, the MVC in Spring is composed from the dispatcher servlet, which turns the HTTP requests into the method’s calls, and from various annotations, which help to bind the parameters. I kept this idea in Lime MVC. The whole concept of Lime MVC describes image below: Let’s assume a book store web application. In the application, we’ve got BookStore controller class and we want to execute the controller’s getBooks method by the following request: http://server.com/bookstoreapp/bookstorecontroller/getbooks?author=Gosling public class BookStoreController { private BookStoreDao dao; BookStoreController(BookStoreDao dao) { this.dao = dao; } public List getBooks(String author) { //code do some processing and fill a list of books ... return booksList; } public Book getBook(String bookId) { //code do some processing and get a concrete book return book; } } How can we turn this class into a web controller for the HTTP request? There are two steps required to do so – to annotate the controller class and map the controller class to some URI and view. It’s good to be familliar with the Google Guice Servlet, because Lime configuration is built upon it. Let’s do the first step. We need to annotate the controller class, because we need to somehow tell Lime how the parameters are bound and what’s the name of the model. As you can see, we need to inject a DAO implementation as well. @Controller @Session public class BookStoreController { private BookStoreDao dao; @Inject BookStoreController(BookStoreDao dao) { this.dao = dao; } @Path("/books") @Model("books") @View("view.jsp") public List getBooks(@RequestParameter("author") String author){ //code do some processing and fill a list of books ... return booksList; } } All controller classes must be annotated with @Controller. It’s a mark which tells Lime that the class is a controller. @Session annotation is Guice’s annotation. This annotation specifies the controller’s scope. All the controllers exist in Guice. It means that all controller’s objects are constructed via Guice. So the controller can be injected, and we can use injection in the controller as well. As you can see, we’ve used this technique for Dao. Controller class is some kind of container for the actions which we can perform and which produce the model’s data. So the most important annotations are used around methods. The @Path specifies for what URL is the action executed and under which name is the method’s result stored. @RequestParameter binds the value from the POST parameter to the method’s parameter. It means that ?author=Gosling will be forwarded to the method’s ‘author’ parameter. As I mentioned above, the second step is to put the controller into the configuration and link it to the view. If you’re familiar with the Guice Servlet, you know that we need to extend GuiceServletContextListener, and to implement the createInjector() method. I recommend to read the Guice Servlet documentation if you’re not familiar with this. Lime’s core is represented by the MvcModule class which is constructed when we create the Guice Injector. The MvcModule has abstract method configureControllers(), and we put all configuration around controllers here. It’s the same principle like in the Guice’s ServletModule. public class BookStoreConfiguration extends GuiceServletContextListener { @Override protected Injector getInjector() { Injector injector = Guice.createInjector( new MvcModule() { @Override protected void configureControllers() { control("/bookstorecontroller/*") .withController(BookStoreController.class); } } }); return injector; } } This configuration tells Lime that all URLs for /bookstorecontroller are processed by the BookStoreController class and that the model is shown in view.jsp. • Controllers o Controllers as interfaces o Parameters in controller’s methods � POST/GET � Parse values from URI � Values from session � Request scoped attributes � Special types ControllersControllersControllersControllers The controller class may be any class or interface annotated by @Controller annotation. Basically all your logic is placed into the controller class. Controller classes produce data model and selects the view, which renders the data. Controller classes composes from various methods. You will annotate these methods and tell to the Lime MVC for what request the method will be invoked and how will be parameter's values picked up from request/sessione etc. Each controller must be binded to some path in MvcModule. ControllersControllersControllersControllers asasasas interfacesinterfacesinterfacesinterfaces In Introduction you saw a simple example of the controller. The controller has been directly binded to some URL in MvcModule. There is also another usage of controller. You may split up controller's implementation and definition. You may have definition described as interface and implementation in separated class which implements the interface. Example: @Controller public interface IBookstoreController { @Path("/allbooks") @View("allbooks.jsp") public Model allBooksInStore(); @Path("/bookinfo/(.*)") @View("bookinfo.jsp") public Model bookInfo(@UriParameter(1) String bookId); @Path("/reserver/(.*)") @View("bookreservation.jsp") public String reserveBook(@UriParameter(1) String bookId); } public class BookstoreControllerImpl implements IBookstoreController{ public ModelMap allBooksInStore() { ModelMap m = new ModelMap(); ... return m; } public ModelMap bookInfo(String bookId) { ModelMap m = new ModelMap(); ... return m; } public String reserveBook(String bookId) { String result = ...; return result; } } We've got the fully annotated IBookstoreController and BookstoreControllerImpl which implements this interface. Next step is tell to Lime MVC how to use the controller. You will put the configuration code into your WebAppModule. public class WebAppModule extends MvcModule { protected void configureControllers() { ... bind(IBookstoreController.class).to(BookstoreControllerImpl.clas s); control("/bookstore/*") .withController(IBookstoreController.class); } } ParametersParametersParametersParameters inininin controllercontrollercontrollercontroller’’’’ssss methodsmethodsmethodsmethods Only in a few cases we’ve got the controller’s methods without parameters. The main goal of this section is to describe and show how the data are bound and forwarded from the HTTP Requests to the method’s parameters. POST/GETPOST/GETPOST/GETPOST/GET Since long ago, Web developers are using these two methods for posting data to server. Also it was the first implemtented binding in Lime. For that purpose serves the @RequestParameter annotation. In our BookStore example, we used it in a simple form. Let’s see it on advanced examples like conversions and arrays. Method expects integer parameter: public void someMethod( @RequestParameter(“somenumber”) int somenumber) Method expects date parameter, if the parameter is missing, then it is set to default value: public void someMethod( @RequestParameter(“somedate”) @DateConv(value="yyyyMMdd", defaultValue="20010101") Date somedate) { } Method expects boolean parameter where in HTTP request ‘N’ means false and ‘Y’ means true: public void someMethod( @RequestParameter(“somebool”) @BooleanConv(trueVal=”Y”, falseVal=”N”) boolean somebool) { } Method expects array of integers (note: in HTTP request all values must be named like somearray0, somearray1 … somearrayn): public void someMethod( @RequestParameter(“somearray”) int[] numbers) { } Actually only conversions to boolean, date, long, float, double and String values and arrays are supported. ParseParseParseParse valuesvaluesvaluesvalues fromfromfromfrom URIURIURIURI This is a nice technique adapted especially in the REST APIs. Let’s imagine following request: ‘http://www.someserver.com/app/article/group/123/id/45’. As you can see, the last number means the ID of the article and the previous means the group. In Lime, we can parse these IDs from URI and forward them to the method’s parameters. Let’s consider the fact that we can use regular expressions in path mapping and the existence of @UriParameter annotation. For our illustration case we can use the method below: @Path("/article/group/(\\d+)/id/(\\d+)") public Article getArticle(@UriParameter(1) int articleGroup, @UriParameter(2) int articleId) { ... } Note: the same conversion like in POST/GET method is used here. ValuesValuesValuesValues fromfromfromfrom sessionsessionsessionsession Sometimes we want to forward a value from the session into the method’s parameter. For that purpose there is @SessionParameter annotation and its usage is simple: @Path("/userprofile") public User showUserProfile( @SessionParameter("loggeduser") User loggedUser) { ... } The logged user’s object is stored in the session under the name ‘loggeduser’. @SessionParameter picks up this object from the session and forwards it to the method’s parameter loggedUser. RequestRequestRequestRequest scopedscopedscopedscoped attributesattributesattributesattributes This term means request's attributes data. If you want extract data from request attributes and fill up into method's parameter, just use the annotation @RequestScopedAttribute with attribute's name. This is useful when you have some special interceptor which fill in something into attribute and you want use this value in you method. Let's assume we've got security interceptor which prepare the 'USER' request attribute. class SecutiryInterceptor implements InterceptorHandler { ... public void preHandle(HttpRequest request, ...) { User actualUser = ...; request.setAttribute("USER", actualUser); } } In your controller then you could access to this attribute: @Controller class MyController { ... @Path("/somepath"); public voidhandleRequest( @RequestScopedAttribute("USER") User actualUser ) { ... } } The parameter actualUser will be filled in with value from our security interceptor. SpecialSpecialSpecialSpecial typestypestypestypes There is a set of special parameter types in the methods. These special types are automatically filled by Lime. It’s Model, HttpServletRequest, HttpServletResponse. Following method automatically obtains the request from the servlet and actual model object: @Path("/books") public List getBooks( HttpServletRequest request, ModelMap m) { ... } Maybe you’re asking yourself: why Model? The main idea was to create some kind of chain. Let’s imagine the following situation: In the books page, we want to show all the books and also the user’s information. In the User view, we want to show only the user’s information: @Controller @Session public class BookStoreController { private Dao someDao = ...; @Path("/books") public ModelMap showBooks(@SessionParameter("loggeduser") String userId) { ModelMap m = new ModelMap(); ... m.put("books", books); User user = getUserProfile(userId); m.put("userprofile", user); return m; } private User getUserProfile(String userId) { return someDao.getUser(userId); } @Path("/user") public ModelMap showUserProfile(@SessionParameter("loggeduser") String userId) { ModelMap m = new ModelMap(); User user = getUserProfile(userId); m.put("userprofile", user); return m; } } Because there’s the possibility to forward the model object into the method, we can remove one method and reduce the code to: @Controller @Session public class BookStoreController { private Dao someDao = ...; @Path("/books") public ModelMap showBooks(@SessionParameter("loggeduser") String userId) { ModelMap m = new ModelMap(); ... m.put("books", books); ... return getUserProfile(userId, m); } @Path("/user") private ModelMap getUserProfile(@SessionParameter("loggeduser") String userId, ModelMap m) { User user = someDao.getUserProfile(userId); m.put("userprofile", user); return m; } } ModelModelModelModel The model represents all the data produced in the controller, which are forwarded to the view. The BookStore example shows us how we can forward a list of books to the view. What if we need to forward more data from the method? For that purpose we can return the ModelMap object as a result of the method. Let’s assume that we want to return various data (author’s books and also the user’s information). The controller’s method will then be: @Controller @Session public class BookStoreController { @Path("/books") public ModelMap getBooks(@RequestParameter("author") String author) { ModelMap m = new ModelMap(); … m.put("books", books); … m.put("loggedUser", loggedUser); … return m; } } By default, all the model’s data are stored like the request’s attributes. In JSP we can access the data: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

${loggedUser.userName}

${book.title} - ${book.author}
The data’s scope is limited to one request. Fortunately, we can implicitly set the attribute to be stored into the session. Let’s assume that we want to store loggedUser into the session: @Controller(sessionAttributes={"loggedUser"}) @Singleton public class BookStoreController { @Path(path = "/login") public ModelMap login(@RequestParameter("user") String user, @RequestParameter("password") String password) { ModelMap m = new ModelMap(); … m.put("loggedUser", user); … return m; } @Path(path = "/login") public ModelMap logout() { ModelMap m = new ModelMap(); … m.put("loggedUser", null); … return m; } } • View o In annotation o Method returns View o Redirecting view • View Resolver ViewViewViewView In Lime, the view is a object, which takes care how the data are shown. All views in Lime are implementing a View interface. Probably one of the most used representations of data is the JSP. In Lime, there exists JspView, which forwards model data to this view and the view is shown like a result of the request. There are several ways how we can specify the view for the controller. InInInIn annotationannotationannotationannotation Lime automatically creates NamedView for each method which annotated by @View. Example below shown how to use this parameter. @Controller public class BookStoreController { ... @Path("/logout") @View("logout.jsp") public void logout() { ... } } You might define a named view for whole Controller class: @Controller @View("main.jsp") public class BookStoreController { ... @Path("/action1") public void action1(...) { ... } ... @Path("/action2") public void action1(...) { ... } } MethodMethodMethodMethod returnsreturnsreturnsreturns ViewViewViewView In many cases we want to specify different views for each method in controller. You will eturn the view object as a result. @Controller public class BookStoreController { @Path("/logout") public View logout() { return new JspView("logout.jsp"); } @Path("/basket") public ModelAndView showBasket() { ModelMap ml = new ModelMap(); ... return ModelAndView(m, new JspView("basket.jsp")); } } RedirectingRedirectingRedirectingRedirecting viewviewviewview You could annotate your method with @RedirectView. This annotation etermines that the view should redirect to some URL. The annotation's value can be absolute URL in form 'http://someserver:port/path' or also can be relative path in form '/somepath'. Relative path can be relative onto controller context when contextRelative is set to true or onto server when contextRelative is set to false. Model data are transformed as URL parameters. Let's assume controller's method: ... @Path("/somepath") @Model("param") @RedirectView("http://server/path") public String redirectToSomewhere() { return "value"; } ... The redirection URL will looks like 'http://server/path?param=value'. You could also returns the redirect view directly from method: ... @Path("/logout") public ViewPoint logout() { return new RedirectViewPoint("/somepath"); } ... ViewViewViewView ResolverResolverResolverResolver Concept of the View Resolver is very simple and is used only for NamedViews. NamedView is special view, which purpose is only for identify. Views are identified by name. View resolver then resolves the names to a cocrete views. Let's assume situation. The controller produce data model and select some NamedView 'main.jsp'. The NamedView is translated by View Resolver to the JspView. You can defined different JSP for this view, and you don't need change every occurence of the 'main.jsp' in code. You will bind in your WebAppModule for name 'main.jsp' a different JSP or even different View implementation. Example: @Controller class BookstoreController { @Path("/login") @View("main.jsp"); public void login(String user, String pass) { ... } } ... public class WebAppModule extends MvcModule { protected void configureControllers() { ... bindViewName("main.jsp").toJsp("/path/to/jsps/main.jsp"); control("/bookstore").withController(BookStoreController.class); } } • View Extensions (JSilver, Velocity, Freemarker) o JSilver o Velocity o Freemarker ViewViewViewView ExtensionsExtensionsExtensionsExtensions (JSilver,(JSilver,(JSilver,(JSilver, Velocity,Velocity,Velocity,Velocity, Freemarker)Freemarker)Freemarker)Freemarker) The JSPs are basically fine, but they have one disadvantage. You might put into the JSP a Java code. This ability is completely out of the MVC. Ok, let's cancel the JSPs. But how we will generate dynamic content? My personal opinion is that a template engine is right answer. I've created 3 extensions which are implementing 3 different template engines. They are similar to each other. JSilverJSilverJSilverJSilver JSilver is lightweight, pure java implementation of ClearSilver which is suitable for HTML very well. JSilver is used in the Doclava as well. If you want to use JSilver as the template engine, you will download the JSilver extension, install the JSilverModule and you will annotate your methods with @JSilverView annotation. Module: public class SomeModule extends MvcModule { protected void configureControllers() { ... install(new JSilverModule(getServletContext())); //example of how to bind JSilver view bindViewName("someview").toViewInstance( new JSilverViewPoint("page1.jsilver")); } } Controller: public class SomeController{ @Inject private JSilver jsilver; @Path("/path") @Model("data") @JSilverView("page2.jsilver") public void Data doAction() { Data data = jsilver.createData(); ... return data; } } VelocityVelocityVelocityVelocity If you prefer the Velocity template engine, you will download the Velocity extension for the Lime MVC. Again, you will install the VelocityModule in your MvcModule and after that you can use the @VelocityView and VelocityView in you web app. Module: public class SomeModule extends MvcModule { protected void configureControllers() { ... install(new FreemarkerModule(getServletContext())); bindViewName("someview").toViewInstance(new VelocityViewPoint("page1.velocity")); } } Controller: public class SomeController{ @Path("/path") @Model("data") @VelocityView("test.velocity") public void HashMap doAction() { HashMap data = new HashMap(); data.put("param", "Lime MVC"); return data; } } Velocity template (test.velocity): Hello $data FreemarkerFreemarkerFreemarkerFreemarker The last extensions is implementing the Freemarker template engine. You will do same steps as in JSilver and Velocity case.Download the Freemarker and install the FreemarkerModule. After that you can use the @FreemarkerView. Module: public class SomeModule extends MvcModule { protected void configureControllers() { ... install(new FreemarkerModule(getServletContext())); //example of how to bind JSilver view
本文档为【limemvc】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_185431
暂无简介~
格式:pdf
大小:292KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2013-03-31
浏览量:8