Slide 1

Slide 1 text

THE STATE OF SERVER-SIDE JAVA WEBAPPS #serverside #java #web Maarten Mulders (@mthmulders)

Slide 2

Slide 2 text

Quick poll #serverside #java #web Maarten Mulders (@mthmulders)

Slide 3

Slide 3 text

$ whoami @mthmulders $ groups @Java_Champions @OracleACE @InfoSupportBV @ASFMavenProject #serverside #java #web Maarten Mulders (@mthmulders)

Slide 4

Slide 4 text

TODAY'S AGENDA 1. What's Wrong With Single-Page Apps? 2. Server-Side Rendering 101 3. Architectures 4. Implementations 5. But... #serverside #java #web Maarten Mulders (@mthmulders)

Slide 5

Slide 5 text

WHAT'S WRONG WITH SINGLE-PAGE APPS? #serverside #java #web Maarten Mulders (@mthmulders)

Slide 6

Slide 6 text

Picture: , used with permission Tom Cools #serverside #java #web Maarten Mulders (@mthmulders)

Slide 7

Slide 7 text

User Browser Single-page app (REST) API Navigate to app Request index page Return almost empty HTML Render HTML Show almost empty page Return JavaScript bundle(s) Execute JavaScript Render user interface Interact with page Execute JavaScript Fetch data Return data Execute JavaScript Render updated user interface #serverside #java #web Maarten Mulders (@mthmulders)

Slide 8

Slide 8 text

1. INITIAL LOADING TIME Stack Over ow: 556.37 kB of initial HTML document 2.2 MB of JavaScript GitHub: 238.45 kB of initial HTML document another 821.25 kB of HTML documents 2.7 MB of JavaScript #serverside #java #web Maarten Mulders (@mthmulders)

Slide 9

Slide 9 text

KEY METRICS FROM Stack Over ow GitHub First Contentful Paint sec 2.8 2.6 Total Blocking Time ms 340 3,150 Speed Index s 6.5 5.5 Largest Contentful Paint s 10.8 9.5 Cumulative Layout Shift 0.075 0 LIGHTHOUSE #serverside #java #web Maarten Mulders (@mthmulders)

Slide 10

Slide 10 text

⚠ INITIAL LOADING TIME CAN SEVERELY IMPACT THE USER EXPERIENCE #serverside #java #web Maarten Mulders (@mthmulders)

Slide 11

Slide 11 text

2. BAD FOR SEARCH ENGINES 2. BAD FOR SEARCH ENGINES 2. BAD FOR SEARCH ENGINES 2. BAD FOR SEARCH ENGINES 2. BAD FOR SEARCH ENGINES Crawlers index the information they nd on the internet: 1. Navigate to a page 2. Attempt to extract structure and text ⚠ 3. Follow reference(s) to new page(s) 4. Repeat until eternity Picture: own work #serverside #java #web Maarten Mulders (@mthmulders)

Slide 12

Slide 12 text

⚠ HERE BE DRAGONS! 1. Initially, the spider receives an almost empty page 2. The spider must process (execute!) all the JavaScript 3. Finally, the spider can extract page structure and content Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 13

Slide 13 text

3. HARD ACCESSIBILITY 3. HARD ACCESSIBILITY 3. HARD ACCESSIBILITY 3. HARD ACCESSIBILITY 3. HARD ACCESSIBILITY Visual impaired people can use braille displays and screen readers. Both rely heavily on structure and metadata of a page. Picture by - Sebastien Delorme CC BY-SA 3.0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 14

Slide 14 text

⚠ HERE BE DRAGONS! 1. Initially, the spider receives an almost empty page 2. The spider must process (execute!) all the JavaScript 3. Finally, the spider can extract page structure and content Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 15

Slide 15 text

4. COMPLEX SECURITY 4. COMPLEX SECURITY 4. COMPLEX SECURITY 4. COMPLEX SECURITY 4. COMPLEX SECURITY Separating user interface (UI) and the data means Properly securing the data (d'oh!) ... and the UI Validating user input in the UI ... and once again in the API Not leaking API credentials in the JavaScript bundles Session management on client and server ... Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 16

Slide 16 text

5. NEEDS FALLBACK 5. NEEDS FALLBACK 5. NEEDS FALLBACK 5. NEEDS FALLBACK 5. NEEDS FALLBACK But what... if the user doesn't allow JavaScript to run? Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 17

Slide 17 text

THE ANSWER Server-Side Rendering But this time with a fancier names, such as "pre-rendering" or "server hydration". #serverside #java #web Maarten Mulders (@mthmulders)

Slide 18

Slide 18 text

SERVER-SIDE RENDERING 101 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 19

Slide 19 text

User Browser Web app Navigate to app Request index page Return completely populated HTML Render HTML Show completely populated page Interact with page Request different page Return completely populated HTML Show completely populated page #serverside #java #web Maarten Mulders (@mthmulders)

Slide 20

Slide 20 text

WHEN TO APPLY? #serverside #java #web Maarten Mulders (@mthmulders)

Slide 21

Slide 21 text

1. SEARCH ENGINE OPTIMISATION 1. SEARCH ENGINE OPTIMISATION 1. SEARCH ENGINE OPTIMISATION 1. SEARCH ENGINE OPTIMISATION 1. SEARCH ENGINE OPTIMISATION Picture: own work #serverside #java #web Maarten Mulders (@mthmulders)

Slide 22

Slide 22 text

2. SIMPLE USER EXPERIENCE 2. SIMPLE USER EXPERIENCE 2. SIMPLE USER EXPERIENCE 2. SIMPLE USER EXPERIENCE 2. SIMPLE USER EXPERIENCE Because not every web application needs to be a Hollywood star Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 23

Slide 23 text

3. TIME AND/OR BUDGET 3. TIME AND/OR BUDGET 3. TIME AND/OR BUDGET 3. TIME AND/OR BUDGET 3. TIME AND/OR BUDGET CONSTRAINTS CONSTRAINTS CONSTRAINTS CONSTRAINTS CONSTRAINTS ̎ PROOF-OF-CONCEPTS Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 24

Slide 24 text

4. CONSTRAINED CONNECTIVITY 4. CONSTRAINED CONNECTIVITY 4. CONSTRAINED CONNECTIVITY 4. CONSTRAINED CONNECTIVITY 4. CONSTRAINED CONNECTIVITY AND/OR CLIENTS AND/OR CLIENTS AND/OR CLIENTS AND/OR CLIENTS AND/OR CLIENTS Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 25

Slide 25 text

USE CASES #serverside #java #web Maarten Mulders (@mthmulders)

Slide 26

Slide 26 text

VOTING APPLICATION FOR CONFERENCE TALKS #serverside #java #web Maarten Mulders (@mthmulders)

Slide 27

Slide 27 text

DASHBOARD FOR CHECKING DMARC REPORTS #serverside #java #web Maarten Mulders (@mthmulders)

Slide 28

Slide 28 text

ADMINISTERING CAR TRIP RECORDS #serverside #java #web Maarten Mulders (@mthmulders)

Slide 29

Slide 29 text

ARCHITECTURES #serverside #java #web Maarten Mulders (@mthmulders)

Slide 30

Slide 30 text

ACTION-BASED (PUSH) ACTION-BASED (PUSH) ACTION-BASED (PUSH) ACTION-BASED (PUSH) ACTION-BASED (PUSH) Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 31

Slide 31 text

User/Browser Controller Model Request page Implemented by you! Retrieve opt Operate Select / Construct View Render Often delegated to a View Engine Read Rendered page #serverside #java #web Maarten Mulders (@mthmulders)

Slide 32

Slide 32 text

POPULAR EXAMPLES Jakarta MVC Jakarta Server Pages, Jakarta Faces Spring MVC Jakarta Server Pages, Jakarta Faces, Thymeleaf Quarkus Qute Struts Freemarker, Velocity, Jakarta Server Pages #serverside #java #web Maarten Mulders (@mthmulders)

Slide 33

Slide 33 text

COMPONENT-BASED (PULL) COMPONENT-BASED (PULL) COMPONENT-BASED (PULL) COMPONENT-BASED (PULL) COMPONENT-BASED (PULL) Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)

Slide 34

Slide 34 text

User/Browser Controller Model Request view Provided by framework Select / Construct Component (View) Render Often delegated to a View Engine loop [Components in view] Render component Access opt Operate Rendered page #serverside #java #web Maarten Mulders (@mthmulders)

Slide 35

Slide 35 text

POPULAR EXAMPLES Jakarta Faces Apache Wicket Vaadin #serverside #java #web Maarten Mulders (@mthmulders)

Slide 36

Slide 36 text

IMPLEMENTATIONS 1. Jakarta MVC 2. Jakarta Faces #serverside #java #web Maarten Mulders (@mthmulders)

Slide 37

Slide 37 text

ACTION BASED: JAKARTA MVC #serverside #java #web Maarten Mulders (@mthmulders)

Slide 38

Slide 38 text

CONTROLLER FOR SHOWING DATA @Path("/show") @Controller @RequestScoped public class ShowPollController { @Inject private Models models; @Inject private PollRepository pollRepository; @Inject private VoteSummaryService voteSummaryService; } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 39

Slide 39 text

CONTROLLER FOR SHOWING DATA (CTD) @GET @Path("/{slug}") @Produces("text/html; charset=UTF-8") public Response show(@PathParam("slug") String slug) { return pollRepository.f ndBySlug(slug) .map(this populateModelAndPrepareResponse) .orElse(Response.status(Response.Status.NOT_FOUND).build()); } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 40

Slide 40 text

CONTROLLER FOR SHOWING DATA (CTD) private Response populateModelAndPrepareResponse(f nal Poll poll) { models.put("poll", poll); models.put("votePercentages", voteSummaryService.calculateVotePercentages(poll)); models.put("voteCount", voteSummaryService.calculateVoteCount(poll)); return Response.ok("polls/show.jsp").build(); } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 41

Slide 41 text

VIEW FOR SHOWING DATA

${poll.question} h2> <% QR code omitted %> div>
<% more details omitted %> div> div> layout:main> #serverside #java #web Maarten Mulders (@mthmulders)

Slide 42

Slide 42 text

VIEW FOR PERFORMING AN ACTION
form> #serverside #java #web Maarten Mulders (@mthmulders)

Slide 43

Slide 43 text

CONTROLLER FOR AN ACTION @Path("/vote") @Controller @RequestScoped public class VoteController { @Inject private Models models; @Inject private PollRepository pollRepository; @Inject private VotingService votingService; } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 44

Slide 44 text

CONTROLLER FOR AN ACTION (CTD) @CsrfProtected @POST @Path("/{slug}") @Produces("text/html; charset=UTF-8") @Transactional public Response processVote( @PathParam("slug") String slug, @FormParam("vote.selectedOption") Integer selectedOption) { return pollRepository.f ndBySlug(slug) .map(poll votingService .castVote(poll, ticketId, selectedOption) .map(vote prepareResponseAfterVote(poll, vote)) .orElse(Response.status(Response.Status.NOT_FOUND).build()); } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 45

Slide 45 text

CONTROLLER FOR AN ACTION (CTD) private Response prepareResponseAfterSuccessfulVote( f nal Poll poll, f nal Vote vote) { models.put("poll", poll); models.put("vote", vote); return Response.ok("polls/thanks.jsp").build(); } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 46

Slide 46 text

ACTION BASED: JAKARTA FACES With PrimeFaces (optional) as UI toolkit. #serverside #java #web Maarten Mulders (@mthmulders)

Slide 47

Slide 47 text

COMPONENT FOR SHOWING DATA continued p:datatable> ui:composition> #serverside #java #web Maarten Mulders (@mthmulders)

Slide 48

Slide 48 text

MODEL FOR SHOWING DATA @Named("vehicleListView") @ViewScoped public class VehicleListView { private Collection vehicles; @Inject public VehicleListView(f nal VehicleRepository vehicleRepository) { this.vehicles = vehicleRepository.f ndAll() } public Collection getVehicles() { return vehicles; } } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 49

Slide 49 text

OPERATING ON THE MODEL

Slide 50

Slide 50 text

OPERATING ON THE MODEL public void deleteVehicle() { this.vehicleRepository.removeVehicle(selectedVehicle); var msg = new FacesMessage( "Vehicle %s removed".formatted(selectedVehicle.getCode())); FacesContext.getCurrentInstance().addMessage(null, msg); PrimeFaces.current().ajax().update("form:messages", "form:vehicles"); } #serverside #java #web Maarten Mulders (@mthmulders)

Slide 51

Slide 51 text

BUT... #serverside #java #web Maarten Mulders (@mthmulders)

Slide 52

Slide 52 text

I NEED A DYNAMIC UI/UX! I NEED A DYNAMIC UI/UX! I NEED A DYNAMIC UI/UX! I NEED A DYNAMIC UI/UX! I NEED A DYNAMIC UI/UX! Picture: - Action-based: look at , Component-based: look at the component framework, optionally add extra component libraries PxHere CC0 htmx alpine.js #serverside #java #web Maarten Mulders (@mthmulders)

Slide 53

Slide 53 text

YOU USED TO ADVOCATE REACT?! YOU USED TO ADVOCATE REACT?! YOU USED TO ADVOCATE REACT?! YOU USED TO ADVOCATE REACT?! YOU USED TO ADVOCATE REACT?! Picture: screenshot from . Both SPA and SSR have their use cases, make a conscious choice! JFokus' YouTube channel #serverside #java #web Maarten Mulders (@mthmulders)

Slide 54

Slide 54 text

WRAP UP WRAP UP WRAP UP WRAP UP WRAP UP #serverside #java #web Maarten Mulders (@mthmulders)

Slide 55

Slide 55 text

Quick poll #serverside #java #web Maarten Mulders (@mthmulders)

Slide 56

Slide 56 text

WRAP UP WRAP UP WRAP UP WRAP UP WRAP UP 1. X Challenge "we need a single-page app for this" 2. Architectures: push (action) vs. pull (component) 3. Implementations: Jakarta MVC, Jakarta Faces, Spring MVC, Quarkus 4. " Experiment with hybrid approaches: htmx, alpine.js ⭐ RATE THIS TALK IN THE NLJUG APP! Picture: - PxHere CC0 #serverside #java #web Maarten Mulders (@mthmulders)