$30 off During Our Annual Pro Sale. View Details »

Webanwendungen mit der MVC API und Eclipse Krazo

Webanwendungen mit der MVC API und Eclipse Krazo

Tobias Erdle

January 23, 2020
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. - Vorteil: Nutzung der HTTP Semantik (z.B. Verben) möglich
    - Implementierungen müssen Adapter für JSP und JSF bereitstellen


    View Slide

  8. View Slide

  9. plugins {
    id 'java'
    id 'war'
    }
    repositories {
    jcenter()
    mavenCentral()
    }
    dependencies {
    //…
    implementation 'javax.mvc:javax.mvc-api:1.0.0‘
    implementation 'org.eclipse.krazo:krazo-resteasy:1.0.0‘
    // implementation 'org.eclipse.krazo.ext:krazo-thymeleaf:1.0.0'
    providedCompile 'jakarta.platform:jakarta.jakartaee-web-api:8.0.0'
    //…
    }

    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. View Slide




  39. Name





    Save



    View Slide

  40. View Slide

  41. View Slide

  42. View Slide




  43. Name






    Save



    View Slide

  44. @POST
    @CsrfProtected
    public String createNewBooking(@MvcBinding @FormParam("name")
    @NotBlank @Size(min = 5, max = 255) final String name) {
    // ...
    }

    View Slide

  45. View Slide

  46. // ...
    @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

  47. View Slide

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

    Cancel

    View Slide

  49. View Slide

  50. /**
    * 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

  51. /**
    * 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

  52. 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

  53. @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

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



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


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


    View Slide

  55. //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

  56. View Slide

  57. View Slide