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

Vorschau auf Webanwendungen mit MVC 1.0 und Eclipse Krazo

Tobias Erdle
September 10, 2019

Vorschau auf Webanwendungen mit MVC 1.0 und Eclipse Krazo

Seit Jahren wird die Java Enterprise Welt von zwei Frontends beherrscht: Java Server Pages (JSP) und Java Server Faces (JSF). Beide Technologien sind mittlerweile sehr alt und können die Anforderungen an moderne und verteilte Systeme kaum erfüllen. Mit der MVC API 1.0 soll dieses Problem gelöst werden.

Der Vortrag geht zuerst auf die Grundlagen der API und ihren Platz in der Java Enterprise Welt ein. Danach wird anhand eines durchgängigen Beispiels gezeigt, wie MVC Ressourcen angelegt und verschiedene Use-Cases damit implementiert werden.

Tobias Erdle

September 10, 2019
Tweet

More Decks by Tobias Erdle

Other Decks in Programming

Transcript

  1. View Slide

  2. View Slide

  3. FacesServlet

    View Slide

  4. View Slide

  5. View Slide





  6. View Slide



  7. • JSP und Facelets müssen
    grundsätzlich unterstützt werden
    • diverse Krazo-Extensions existieren
    schon (eingeschränkte Features)



    View Slide

  8. View Slide

  9. plugins {
    id 'java'
    id 'war'
    }
    repositories {
    jcenter()
    mavenCentral()
    maven {
    url "https://oss.sonatype.org/content/repositories/snapshots"
    }
    }
    dependencies {
    //…
    implementation 'javax.mvc:javax.mvc-api:1.0-pfd‘
    implementation 'org.eclipse.krazo:krazo-resteasy:1.0.0-SNAPSHOT‘
    // implementation 'org.eclipse.krazo.ext:krazo-thymeleaf:1.0.0-SNAPSHOT'
    providedCompile 'javax:javaee-api:8.0.1‘
    //…
    }

    View Slide

  10. View Slide

  11. import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    @ApplicationPath("/mvc")
    public class App extends Application {
    }

    View Slide





  12. Hello World


    Hello World!


    import javax.mvc.Controller;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    @Path("hello")
    @Controller
    public class
    HelloWorldController {
    @GET
    public String sayHello() {
    return "hello.jsp";
    }
    }

    View Slide

  13. View Slide

  14. View Slide

  15. @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @Inject
    private Models models;
    @GET
    public String index() {
    final var bookings = bookingService.getAllBookings();
    models.put("bookings", bookings);
    return "index.jsp";
    }
    // ...

    View Slide

  16. @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @Inject
    private Models models;
    @GET
    public String showIndex() {
    // ...
    models.put("bookings", bookings);
    return "index.jsp";
    }
    // ...
    }


    ${booking.bookingNumber}
    ${booking.name}


    View Slide

  17. @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @Inject
    private Models models;
    @GET
    public String showIndex() {
    final var bookings =
    bookingService.getAllBookings();
    models.put("bookings", bookings);
    return "index.jsp";
    }
    // ...
    }

    View Slide

  18. @Inject
    private Models models;


    ${booking.bookingNumber}
    ${booking.name}


    @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @Inject
    private Models models;
    @GET
    public String showIndex() {
    // ...
    return "index.jsp";
    }
    // ...
    }

    View Slide

  19. View Slide

  20. @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @GET
    @Path("/{bookingNumber}")
    public Response showDetailsOfBooking(@PathParam("bookingNumber") final UUID bookingNumber) {
    final var booking = bookingService.findBookingForBookingNumber(bookingNumber);
    if (booking.isPresent()) {
    models.put("booking", booking.get());
    return Response.ok("details.jsp").build();
    } else {
    models.put("bookingNumber", bookingNumber);
    return Response.status(Response.Status.NOT_FOUND).entity("404.jsp").build();
    }
    }
    // ...

    View Slide

  21. @GET
    @Path("/{bookingNumber}")
    public Response showDetailsOfBooking(
    @PathParam("bookingNumber") final UUID bookingNumber) {
    // ...
    if (booking.isPresent()) {
    models.put("booking", booking.get());
    return Response.ok("details.jsp").build();
    } else {
    // ...
    }
    }

    View Slide

  22. @GET
    @Path("/{bookingNumber}")
    public Response showDetailsOfBooking(
    @PathParam("bookingNumber") final UUID bookingNumber) {
    // ...
    if (booking.isPresent()) {
    // ...
    } else {
    models.put("bookingNumber", bookingNumber);
    return Response
    .status(Response.Status.NOT_FOUND)
    .entity("404.jsp")
    .build();
    }
    }

    View Slide

  23. View Slide

  24. href="/bookings/${booking.bookingNumber}">
    Details

    View Slide

  25. href="/bookings/${booking.bookingNumber}">
    Details

    View Slide

  26. href="/bookings/${booking.bookingNumber}">
    Details

    View Slide

  27. href="${mvc.uriBuilder('BookingController#showDetailsOfBooking').build(booking.bookingNumber)}">
    Details

    View Slide

  28. href="${mvc.uriBuilder('BookingController#showDetailsOfBooking').build(booking.bookingNumber)}">
    Details

    @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @GET
    @Path("/{bookingNumber}")
    public String showDetailsOfBooking(@PathParam("bookingNumber") final UUID bookingNumber) {
    // ...
    }
    // ...

    View Slide



  29. Details

    View Slide

  30. href="${mvc.uriBuilder('showBookingDetails').build(booking.bookingNumber)}">Details

    @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @GET
    @Path("/{bookingNumber}")
    @UriRef("showBookingDetails")
    public String showDetailsOfBooking(@PathParam("bookingNumber") final UUID bookingNumber) {
    // ...
    }
    // ...

    View Slide



  31. Details

    View Slide

  32. View Slide

  33. @Path("/bookings")
    @Controller
    public class BookingController {
    // ...
    @GET
    @Path("/new")
    public String showNewBookingForm() {
    return "form.jsp";
    }
    // ...
    }

    View Slide




  34. Name





    Save



    View Slide

  35. // ...
    @Inject private BindingResult bindingResult;
    @POST
    public String createNewBooking(@MvcBinding @FormParam("name")
    @NotBlank @Size(min = 5, max = 255) final String name) {
    if (bindingResult.isFailed()) {
    models.put("errors", new ArrayList<>(bindingResult.getAllErrors()));
    return "form.jsp";
    }
    final var booking = bookingService.createNewBooking(name);
    return "redirect:/bookings/" + booking.getBookingNumber();
    }
    // ...
    placeholder="Name of booking" required>

    View Slide




  36. ${msg.get("form.label.name")}








    ${error.getParamName()}: ${error.getMessage()}







    ${msg.get("form.btn.save")}



    View Slide

  37. View Slide

  38. // ...
    @DELETE
    @Path("/{bookingNumber}")
    public String cancelBooking(@PathParam("bookingNumber") final UUID bookingNumber) {
    final var isCancelled = bookingService.cancelBooking(bookingNumber);
    return isCancelled ? "redirect:/bookings" : "404.jsp";
    }
    // ...

    View Slide

  39. View Slide

  40. action="${mvc.uriBuilder('BookingController#cancelBooking').build(booking.bookingNumber)}"
    onsubmit="return confirm('Do you really want to cancel the booking?');">

    Cancel

    View Slide

  41. View Slide

  42. /**
    * Locale resolvers are used to determine the locale of the current request and are
    * discovered using CDI.
    *
    *
    * …
    */
    public interface LocaleResolver {
    /**
    * Resolve the locale of the current request given a {@linkLocaleResolverContext}.
    *
    * …
    *
    * @param context the context needed for processing.
    * @return The resolved locale or null.
    */
    Locale resolveLocale(LocaleResolverContext context);
    }

    View Slide

  43. /**
    * Locale resolvers are used to determine the locale of the current request and are
    * discovered using CDI.
    *
    *
    * …
    */
    public interface LocaleResolver {
    /**
    * Resolve the locale of the current request given a {@linkLocaleResolverContext}.
    *
    * …
    *
    * @param context the context needed for processing.
    * @return The resolved locale or null.
    */
    Locale resolveLocale(LocaleResolverContext context);
    }
    org.eclipse.krazo.locale.LocaleResolverChain
    MvcContext

    View Slide

  44. messages
    //messages.properties

    #Index Page
    page.title=My awesome application
    #Hello World
    hello.world=Hello World!
    //messages_fr.properties
    #Hello World
    hello.world=Bonjour le monde!
    //messages_de.properties
    #Hello World
    hello.world=Hallo Welt!

    View Slide

  45. @RequestScoped
    @Named("msg")
    public class Messages {
    @Inject
    private MvcContext mvcContext;
    public final String get(final String key) {
    LOGGER.info(String.format("Getting message '%s' for locale '%s'", key,
    mvcContext.getLocale()));
    final var bundle = ResourceBundle.getBundle("messages", mvcContext.getLocale());
    return bundle.containsKey(key) ? bundle.getString(key) : formatUnknownKey(key);
    }
    private static String formatUnknownKey(final String key) {
    return String.format("???%s???", key);
    }
    }

    View Slide

  46. <%@ page contentType="text/html;charset=UTF-8" language="java" %>



    ${msg.get("page.title")}


    ${msg.get("hello.world")}


    View Slide

  47. //messages.properties




    My awesome application




    Hello World!



    //messages_fr.properties




    My awesome application




    Bonjour le monde!



    //messages_de.properties




    My awesome application




    Hallo Welt!



    View Slide


  48. - Dokumentation für TCK erstellen
    - Lizenzrechtliche Prüfungen durch Oracle bei Krazo

    View Slide

  49. View Slide

  50. - Cookbook: https://www.mvc-spec.org/learn/cookbook/

    View Slide