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

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. - Vorteil: Nutzung der HTTP Semantik (z.B. Verben) möglich -

    Implementierungen müssen Adapter für JSP und JSF bereitstellen − −
  2. 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' //… }
  3. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello World</title> </head>

    <body> <h1>Hello World!</h1> </body> </html> 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"; } }
  4. @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"; } // ...
  5. @Path("/bookings") @Controller public class BookingController { // ... @Inject private

    Models models; @GET public String showIndex() { // ... models.put("bookings", bookings); return "index.jsp"; } // ... } <c:forEach var="booking" items="${bookings}"> <tr> <td>${booking.bookingNumber}</td> <td>${booking.name}</td> … </c:forEach>
  6. @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"; } // ... }
  7. @Inject private Models models; <c:forEach var="booking" items="${bookings}"> <tr> <td>${booking.bookingNumber}</td> <td>${booking.name}</td>

    … </c:forEach> @Path("/bookings") @Controller public class BookingController { // ... @Inject private Models models; @GET public String showIndex() { // ... return "index.jsp"; } // ... }
  8. @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(); } } // ...
  9. @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 { // ... } }
  10. @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(); } }
  11. <a class="btn btn-link" href="${mvc.uriBuilder('BookingController#showDetailsOfBooking').build(booking.bookingNumber)}"> Details </a> @Path("/bookings") @Controller public class

    BookingController { // ... @GET @Path("/{bookingNumber}") public String showDetailsOfBooking(@PathParam("bookingNumber") final UUID bookingNumber) { // ... } // ...
  12. <a class="btn btn-link" href="${mvc.uriBuilder('showBookingDetails').build(booking.bookingNumber)}">Details </a> @Path("/bookings") @Controller public class BookingController

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

    public String showNewBookingForm() { return "form.jsp"; } // ... }
  14. <form method="post" action="${mvc.uri('BookingController#createNewBooking')}"> <div class="form-row"> <div class="col-md-6"> <label for="name">Name</label> <input

    id="name" name="name" class="form-control" placeholder="Name of booking" required> </div> </div> <div class="form-row mt-2"> <div class="col-md-3"> <button type="submit" class="btn btn-primary">Save</button> </div> </div> </form>
  15. // ... @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(); } // ... <input id="name" name="name" class="form-control" placeholder="Name of booking" required>
  16. <form method="post" action="${mvc.uri('BookingController#createNewBooking')}" accept-charset="UTF-8"> <div class="form-row"> <div class="col-md-6"> <label for="name">${msg.get("form.label.name")}</label>

    <input id="name" name="name" class="form-control" placeholder="${msg.get("form.label.name.placeholder")}" required> </div> </div> <c:choose> <c:when test="${not errors.isEmpty()}"> <div class="row mt-2"> <c:forEach var="error" items="${errors}"> <div class="col-md-12"> <div class="alert alert-danger">${error.getParamName()}: ${error.getMessage()}</div> </div> </c:forEach> </div> </c:when> </c:choose> <div class="form-row mt-2"> <div class="col-md-3"> <button type="submit" class="btn btn-primary">${msg.get("form.btn.save")}</button> </div> </div> </form>
  17. <form method="post" action="${mvc.uri('BookingController#createNewBooking')}"> <div class="form-row"> <div class="col-md-6"> <label for="name">Name</label> <input

    id="name" name="name" class="form-control" placeholder="Name of booking" required> </div> </div> <div class="form-row mt-2"> <div class="col-md-3"> <button type="submit" class="btn btn-primary">Save</button> </div> </div> </form>
  18. <form method="post" action="${mvc.uri('BookingController#createNewBooking')}"> <div class="form-row"> <div class="col-md-6"> <label for="name">Name</label> <input

    id="name" name="name" class="form-control" placeholder="Name of booking" required> </div> </div> <div class="form-row mt-2"> <input type="hidden" name="${mvc.csrf.name}" value="${mvc.csrf.token}"/> <div class="col-md-3"> <button type="submit" class="btn btn-primary">Save</button> </div> </div> </form>
  19. // ... @DELETE @Path("/{bookingNumber}") public String cancelBooking(@PathParam("bookingNumber") final UUID bookingNumber)

    { final var isCancelled = bookingService.cancelBooking(bookingNumber); return isCancelled ? "redirect:/bookings" : "404.jsp"; } // ...
  20. <form class="d-inline" method="post" action="${mvc.uriBuilder('BookingController#cancelBooking').build(booking.bookingNumber)}" onsubmit="return confirm('Do you really want to

    cancel the booking?');"> <input type="hidden" name="_method" value="DELETE"> <button type="submit" class="btn btn-link">Cancel</button> </form>
  21. /** * <p>Locale resolvers are used to determine the locale

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

    of the current request and are * discovered using CDI. *</p> * * … */ public interface LocaleResolver { /** * <p>Resolve the locale of the current request given a {@linkLocaleResolverContext}.</p> * * … * * @param context the context needed for processing. * @return The resolved locale or <code>null</code>. */ Locale resolveLocale(LocaleResolverContext context); } org.eclipse.krazo.locale.LocaleResolverChain MvcContext
  23. 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!
  24. @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); } }
  25. <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html lang="en"> <head> <meta charset="UTF-8">

    <title>${msg.get("page.title")}</title> </head> <body> <h1>${msg.get("hello.world")}</h1> </body> </html>
  26. //messages.properties <html lang="en"> <head> <meta charset="UTF-8"> <title> My awesome application

    </title> </head> <body> <h1> Hello World! </h1> </body> </html> //messages_fr.properties <html lang="en"> <head> <meta charset="UTF-8"> <title> My awesome application </title> </head> <body> <h1> Bonjour le monde! </h1> </body> </html> //messages_de.properties <html lang="en"> <head> <meta charset="UTF-8"> <title> My awesome application </title> </head> <body> <h1> Hallo Welt! </h1> </body> </html>