Upgrade to Pro — share decks privately, control downloads, hide ads and more …

FenixEdu Training: Part three - Struts, Renders...

FenixEdu Training: Part three - Struts, Renders, Faces & Spring

Avatar for Artur Ventura

Artur Ventura

May 15, 2014

More Decks by Artur Ventura

Other Decks in Technology

Transcript

  1. Schedule 12 15 Introduction Concepts Architecture Bennu Fenix Framework Struts

    & Renderers JSP & Renderers Faces & Spring New technologies Git & Maven Collaboration Coffee Break Coffee Break You are here Oracle: Java 8 & MySQL 18:30
  2. Fenix Framework Bennu Framework Bennu Core Bennu IO Bennu Scheduler

    Bennu Portal Bennu Renderers Bennu Spring Bankai Angular Persistence Web Infrastructure Presentation Application Modules FenixEdu (IST) FenixEdu Id Cards FenixEdu Core Second Session Today
  3. UI

  4. How do we make these work together? While keeping a

    consistent design across the application?
  5. Struts • Struts was already in place since the very

    beginning • Using Tiles (which is now Apache Tiles) to organize the application’s design • Struts entry point with custom controller
  6. Bennu Portal • UI Integration Framework • Uniform styling across

    the entire application • Dynamically change the theme of your application • Dynamic menu construction and rendering • Out of the box scaffolding for web applications
  7. Bennu Portal • Code declares what functionalities it exposes •

    Dynamic model built from declared functionalities • This allows for full customisation of the menu • Semantic URLs from the path in the tree • Catch: The same functionality can only be installed in a single place
  8. Custom Portal Backends • Integrating your favourite presentation technology is

    quite simple • Contributions welcome! • Functionality discovery • Mapping custom URLs to functionalities • Currently supported: Struts, Spring, JSF 1.x, Redirect, Forward
  9. Apache Struts 1.2 • Open-source web-application framework • EOL’ed in

    April 2013 • Model-View-Controller architecture • https://struts.apache.org/development/1.x/ • Grab it while you can, parts of the site are offline
  10. Apache Struts 1.2 • Based on the concept of Actions

    (Controller) • Actions are responsible for handling the request, and forwarding to the response • Typically another action or a JSP • Originally configured using XML • Extended for annotation-based configuration
  11. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { ! @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { ! Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); ! return mapping.findForward("showEvents"); } }
  12. Actions • Module-aware • DispatchActions run the method provided in

    the parameters • FenixAction / FenixDispatchAction • getFromRequest, redirect, getDomainObject, addActionMessage, writeFile • Don’t put @Atomic annotations in handler methods!!
  13. Actions • Once you’re done with the request, how to

    show the correct page? • @Forward + mapping.findForward • new ActionForward(“/xpto.jsp”) • Handle the response manually • File download, custom redirects, complex forwards
  14. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { ! @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { ! Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); ! return mapping.findForward("showEvents"); } }
  15. @StrutsFunctionality(app = StudentViewApp.class, path = "residence-payments", titleKey = "link.title.residencePayments") @Mapping(path

    = "/viewResidencePayments", module = "student") @Forwards(@Forward(name = "showEvents", path = "/student/residenceServices/showResidenceEvents.jsp")) public class ViewResidencePayments extends FenixDispatchAction { ! @EntryPoint public ActionForward listEvents(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { ! Person person = getLoggedPerson(request); request.setAttribute("person", person); request.setAttribute("payedEntries", person.getPayments(ResidenceEvent.class)); ! return mapping.findForward("showEvents"); } }
  16. Action Form • Devilish way to handle user-input • Per-module,

    declared in the module’s XML file • In the @Mapping, you can choose the form for your action • Forms are populated from request parameters, and validated according to specific rules • Parameters are accessible in a map-like interface DON’T USE!
  17. Bennu Renderers • Our attempt at making Struts suck less

    • Two major components: • Struts modernisation / Portal Integration • Renderers Framework • No matter how hard we try, it’s still struts…
  18. Struts Integration • Modular, annotation-based struts configuration • @StrutsApplication /

    @StrutsFunctionality • “Security” features - A checksum is injected into every link in the response, and checked when the functionality is accessed • Parsers for multipart requests • Synchronisation between Struts and application locales
  19. Renderers • Taglib for automatic object visualisation/edition • Generates HTML

    code from Java objects • Able to render/edit both Domain Objects and POJOs
  20. Renderers • Two main parts: • Renderers know how to

    render an object of a given type. Can be both for input and output • Schemas define how an object is presented by defining the slots and their layouts
  21. JSP • Is the HTML Template normally for java web

    applications • We use tag libs from struts to add more behaviour to JSP.
  22. JSP @StrutsFunctionality(app = ExternalSupervisionConsultApp.class, path = "year", titleKey = "label.selectDegree.executionYear")

    @Mapping(path = "/viewYear", module = "externalSupervision") @Forwards({ @Forward(name = "selectYear", path = "/externalSupervision/consult/selectYear.jsp") }) public class ExternalSupervisorViewYearDA extends FenixDispatchAction { ! @EntryPoint public ActionForward beginTaskFlow(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { ExternalSupervisorViewsBean bean = new ExternalSupervisorViewsBean(); request.setAttribute("sessionBean", bean); return mapping.findForward("selectYear"); }
  23. JSP <fr:view name="sessionBean" property="students"> <fr:layout name="tabular-sortable"> <fr:property name="order(view-details)" value="1" />

    <fr:property name="key(view-details)" value="link.selectYear.viewStudentDetails" /> <fr:property name="bundle(view-details)" value="EXTERNAL_SUPERVISION_RESOURCES" /> <fr:property name="sortParameter" value="sortBy"/> <fr:property name="sortableSlots" value="istUsername,name, student.number"/> <fr:property name="classes" value="tstyle1 thleft" /> <fr:property name="headerClasses" value="acenter,acenter,,," /> <fr:property name="columnClasses" value="acenter,acenter,,,,," /> </fr:layout> <fr:schema type="net.sourceforge.fenixedu.domain.Person" bundle="EXTERNAL_SUPERVISION_RESOURCES"> <fr:slot name="student.number" key="label.selectYear.studentNumber" /> <fr:slot name="istUsername" key="label.selectYear.istUsername" /> <fr:slot name="name" key="label.selectYear.name" /> <fr:slot name="student.activeRegistrations" key="label.selectYear.degreeSigla"> <fr:property name="eachSchema" value="registration.view-degree-sigla"/> <fr:property name="eachLayout" value="values-comma"/> <fr:property name="classes" value="nobullet ulindent0 mvert0"/> </fr:slot> </fr:schema> </fr:view>
  24. Resource Bundles • For each module there is a resource

    bundle for each locale. Each file contains a list of strings internationalised for that locale. • Don’t write text directly in the JSPs. • Use the Resource Bundle Editor
  25. Renderers • Renderers also work the other way around. You

    can create forms for some type, and then, on the request get the object back.
  26. Renderers <fr:edit id="addAttendsBean" name="addAttendsBean" schema="AddAttendsBean" action="<%="/registration.do? method=addAttends&registrationId=" + registrationId %>">

    <fr:layout name="tabular"> <fr:property name="classes" value="tstyle4 thright thlight mtop05"/> <fr:destination name="showForm" path="<%="/registration.do? method=prepareAddAttends&amp;registrationId=" + registrationId %>"/> </fr:layout> </fr:edit> /fenix/src/main/webapp/academicAdminOffice/student/registration/addAttends.jsp
  27. Renderers <schema name="AddAttendsBean" type="n.s.f.dataTransferObject.AddAttendsBean" bundle="APPLICATION_RESOURCES"> <slot name="executionDegree" layout=“menu-select-postback" validator="p.i.f.renderers.validators.RequiredValidator"> <property

    name="providerClass" value="n.s.f.p.renderers.providers.ExecutionDegreeForExecutionPeriodProvider" /> <property name="format" value="${presentationName}" /> <property name="destination" value="showForm"/> </slot> </schema> /fenix/src/main/webapp/WEB-INF/fenix/schemas/academicAdminOffice-schemas.xml
  28. Renderers @Mapping(path = "/registration", module = "academicAdministration", functionality = SearchForStudentsDA.class)

    @Forwards({@Forward(name = "addAttends", path = "/academicAdminOffice/student/registration/addAttends.jsp"),}) public class RegistrationDA extends StudentRegistrationDA { public ActionForward addAttends(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception { final Registration registration = getAndSetRegistration(request); request.setAttribute("registration", registration); ! final AddAttendsBean addAttendsBean = (AddAttendsBean) getObjectFromViewState("addAttendsBean"); final ExecutionCourse executionCourse = addAttendsBean.getExecutionCourse(); ! WriteStudentAttendingCourse.runWriteStudentAttendingCourse(registration, executionCourse.getExternalId()); ! return viewAttends(mapping, actionForm, request, response); } }
  29. Faces • It doesn’t have that much presence in FenixEdu.

    • We don’t do anything in faces, we are trying to remove it from FenixEdu.
  30. Servlet 2.3 <logic:present name="LOGGED_USER_ATTRIBUTE" property="person.homepage"> <logic:present name="LOGGED_USER_ATTRIBUTE" property="person.homepage.activated"> <logic:equal name="LOGGED_USER_ATTRIBUTE"

    property="person.homepage.activated" value="true"> <p> <bean:write name="LOGGED_USER_ATTRIBUTE" property=“person.homepage.fullPath"/>. </p> </logic:equal> </logic:present> </logic:present>
  31. Bennu Spring • If you are writing something from scratch,

    you should use Bennu Spring • Is fully compatible with Spring, meaning that you can use the same knowledge in here.
  32. Bennu Spring @BennuSpringController(AdminPortal.class) @RequestMapping("/cms/manage") public class AdminMenu { @RequestMapping(value="{slug}/menus", method

    = RequestMethod.GET) public String posts(Model model, @PathVariable(value="slug") String slug){ Site site = Site.fromSlug(slug); model.addAttribute("site", site); model.addAttribute("menus", site.getMenusSet()); return "menus"; } @SpringApplication(group = "anyone", path = "cms", title = "cms-manage") @SpringFunctionality(app = AdminPortal.class, title = "cms-manage") @RequestMapping("/cms/manage") public class AdminPortal { ! @RequestMapping(value = "{slug}/edit", method = RequestMethod.POST) public RedirectView edit(Model model, @PathVariable(value = "slug") String slug, @RequestParam String name, @RequestParam String description, @RequestParam String theme) { ! Site s = Site.fromSlug(slug); editSite(name, description, theme, s); return new RedirectView("/cms/manage", true); }