dongxian7194
2011-01-06 18:06 阅读 67
已采纳

JSF - 一些初学者问题(来自PHP开发人员)[关闭]

I am looking into Java Server Faces for a school project and because I am a developer in PHP, I am not able to grasp the overall concept of JSF.

In usual PHP MVC framework, the requested URL is bound via routing system with an invoked class methods (controller life cycle) and rendered template, so I can trigger some logic before any output is sent to a browser, e. g. perform a redirect.

Correct me if I am wrong - I was not able to recognize this pattern in JSF. URL is bound to the rendered template (faces/index.xhtml -> index.xhtml in my source code) and if I want to call some method in backing bean (JSF equivalent to controller), I can call any getter in a template (#{bean.property}), but for example I don't know how to perform a redirect when a URL is requested. I was able to perform some custom method in my backing bean after clicking on <h:commandLink> or <h:commandButton>, but after looking to the generated HTML (which always looked like a submitting form), I don't think it's the only way to do this.

I also looked into faces-config.xml which looks like a nice way to configure multistep form wizards, but I don't know how to use this mechanism to define structure of the whole web. Which is it primarily used for? Defining URLs?

Also, I would like to know something about the dependency injection system. I don't know what injects my facades into the backed bean class attributes when I annotate them with @EJB. I don't know what mechanism injects EntityManager into my facades if I annotate the "em" attribute with PersistenceContext. And how I can alter these mechanisms in unit tests that run without this DI container (Glassfish?).

Please, can anybody clarify for me how does these things work in some friendly-PHP way? Thank you! :)

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

3条回答 默认 最新

  • 已采纳
    doz15449 doz15449 2011-01-07 14:26

    Since two years I have been planning to write a blog post on the subject of "JSF for PHP programmers" and never got around to do it... but some thoughts collected over the time: (I understand you know most of this):

    1. Switching between PHP and JSF is painful - both ways. Prepare for bitterness and frustration - I am serious. The problem is you do not need to ask "how to do X using JSF" but "does it make sense to do X in JSF or should I be doing Y".

    2. The pattern used in most PHP frameworks (Cake, CI, ZF) is not plain MVC - it is Front Controller (and friends): you work with requests, you route them, you dispatch them to actions, actions read request parameters, talk to model, pass data to the view, view gets rendered to response and uses some kind of helpers to render fragments that get reused, response gets serialized, finished. A form in a typical MVC PHP app might lead to a different action than the one that rendered it. Controller calls view and has a chance to act before the view is rendered. Routing is important, because actions are tied to urls.

      In JSF there is no such thing. Routing and redirecting (at least the one that happens before processing the view) are not part of JSF, they are one level of abstraction below JSF. You can add routing and redirects using some other libraries or custom code, it's rather easy. The mechanism in faces-config.xml is not really routing and yes, you are right, it is particall only with wizard-like scenarius. You do not use it to structure your web application (if only because it only applies to POST requests).

      Actions in JSF are not chosen by a centralized router/dispatcher but by components. In most cases you do not even need an action, because view and model suffice. You might imagine that JSF treats each component of a page as a little MVC stack of its own. The component itself (eg. a text input, a dropdown) is responsible for retreiving data from request, converting and validating the data, rendering HTML, and passing the data to controllers (and other components) by putting them in the right place in the model.

      Thanks to this, things that require an action controller in, say, Zend Framework, like paginating data, searching, editing multipage forms with custom view logic etc. usually do not require more than view and model in JSF (possibly validators or converters). Components invoke actions only when persisting data to database or when data processing becomes more complex. Even then the actions get triggered after the view has read all the data from request, so dispatching an action is not in any way connected with routing. Each commandlink or commandbutton must come back to the precise page that rendered the original form, because only the components on this page are able to understand the request and update the model. Because routing has nothing to do with firing actions, it is left out of the framework (you can do pretty urls and nice routing using libraries like PrettyFaces, but it's not part of JSF).

      JSF redirects are executed as results of actions (based on a string returned by actions), so while it is possible to execute a redirect and some logic before it, the template must be processed before the redirect.

      In PHP it is common to think of reading data from database as "an action to do before I display the view". In JSF it is not an action, but a part of initializing your model; as such it belongs in a method inside your model managed bean - such method should be annotated with @PostConstruct and it will be executed by the JSF DI container before you get the reference to the bean and after all the dependencies had been injected.

      If you really think you need to fire some action before page displays, use event listeners - but be warned: probably you are doing something wrong.

      The hidden assumption behind Cake/Zend framework is "there is one main thing to do on each HTML page and the display concerns mainly this one thing". The hidden assumption behind JSF is "as far as we can tell, the whole application is just this one page full of stateful controls"

    3. By definition, injecting is done by a container -- since your managed beans are not produced by you, but given to JSF components by some EL resolver. JSF contains a simple standalone container and in Java EE 5 you also get an EJB container. Java EE 6 begins unification of DI by introducing CDI (Contexts and Dependency Injection, JSR 299) and redefining EJB as a special kind of CDI bean. Also in Java EE 6 you have an option to skip the JSF DI container and use CDI beans. The CDI implementation used in Glassfish is Weld.

      While it is possible to use embedded Glassfish to run your test, the whole idea of Dependency Injection being unit test friendly comes from ability of testing classes outside the container (that's why they are UNIT tests, not INTEGRATION tests). The dependencies should be mocked and inserted manually.

    4. If you did not invest too much time in JSF already, you may first try to switch to JSR-311. It is a new alternative presentation layer for Java EE, that is focused on restful approach: restful urls, routing, resources etc. It has pluggable templating and its RI has a beautiful MVC layer. If you like Zend Framework, you will love it. You can use JSR-311 to practice EJBs, JPA and other Java EE stuff, and then come back to JSF when you are already experienced with Dependency Injection, transaction management and so on, and can focus on stateful web presentation. An example code in Jersey (a jsr-311 RI, you have it bundled with your glassfish/netbeans) might look like this:

      
      @EJB
      UsersDao usersDao;
      
      @Path("/users/detail/{userId}")
      public void userDetail(@PathParam("userId") int userId){
         return new Viewable("users/template.jsp", usersDao.getById(userId));
      }
      

      Warning: jsr-311 is service-centric (json, xml) not web-application-centric, and the templating engine is pluggable, so there are no jsr-311 view helpers (when reconstructing urls you are pretty much on your own).

    点赞 评论 复制链接分享
  • dsgnze6572 dsgnze6572 2011-01-06 18:21

    First of all, Here is a nice introduction to JSF.

    Second, the way your jsf pages go from page to page is through its navigation mechanism, something you configure in your faces-config.xml file, like:

    <faces-config>
      <navigation-rule>
       <from-view-id>/pages/inputname.jsp</from-view-id>
        <navigation-case>
         <from-outcome>greeting</from-outcome>
         <to-view-id>/pages/greeting.jsp</to-view-id>
       </navigation-case>
      </navigation-rule>
    </faces-config>
    

    As for DI, the JSF specification defines a very basic, not to say primitive, DI mechanism, you can also define that in your faces-config.xml file, like:

     <managed-bean>
      <managed-bean-name>iteration</managed-bean-name>
      <managed-bean-class>net.dbyrne.agile.Iteration</managed-bean-class>
      <managed-bean-scope>request</managed-bean-scope>
     <managed-property> <!-- setStart called first -->
      <property-name>start</property-name>
      <value>#{projectBean.currentStart}</value>
      </managed-property>
      <managed-property>
      <property-name>end</property-name>
      <value>#{projectBean.currentEnd}</value>
      </managed-property>
      <managed-property><!-- setLast called last -->
      <property-name>last</property-name>
      <value>hack</value>
    </managed-property>
    </managed-bean>
    

    Regards,

    点赞 评论 复制链接分享
  • douxueke5653 douxueke5653 2011-01-06 22:40

    If you want some friendly behavior, I'd suggest you to start with PrettyFaces.

    It's built on top of JSF 2, allows URL actions, friendly URLs and saves a lot of time. Just include jar in your web-app and you're done.

    Great extension, it's not a replacement for JSF, it just simplifies a lot JSF internals and adds humanity to your JSF projects.

    点赞 评论 复制链接分享

相关推荐