Java & Java EE 2o Μέρος: Διασφάλιση ευκολίας τροποποίησης με το πρότυπο MVC (Model View Controller) Κακαρόντζας Γεώργιος
Model-View-Controller (MVC) Όπως αναφέραμε ήδη σε εφαρμογές JEE οι JSPs χρησιμοποιούνται ως η όψη (View) σε μία αρχιτεκτονική Model-View-Controller όπου: Μοντέλο (Model) είναι μία κλάση της Java που ενσωματώνει τα δεδομένα και τις βασικές λειτουργίες σε σχέση με αυτά. Όψη (View) είναι μία JSP που εμφανίζει πληροφορίες στο χρήστη (π.χ. τα αποτελέσματα μιας επεξεργασίας) Ελεγκτής (Controller) είναι ένα Servlet το οποίο χειρίζεται την αλληλεπίδραση με το χρήστη (π.χ. δημιουργεί το μοντέλο κατά την πρώτη αλληλεπίδραση, ανακατευθύνει σε σελίδες λαθών αν τα δεδομένα εισόδου δεν είναι ορθά κλπ.) Το αρχιτεκτονικό πρότυπο MVC χρησιμοποιείται σήμερα ευρύτατα σε εφαρμογές ιστού και όχι μόνο στη JEE. Επινοήθηκε από το Νορβηγό Trygve Reenskaug ο οποίος δίνει κάποια Για περισσότερες πληροφορίες για το αρχιτεκτονικό ιστορικά στοιχεία του MVC σ' αυτή τη σελίδα: http://heim.ifi.uio.no/~trygver/themes/mvc/mvc-i πρότυπο Model-View-Controller (MVC) δείτε το: http://en.wikipedia.org/wiki/model-view-controller ndex.html
Ποιοτικές Ιδιότητες του MVC Ευκολία Τροποποίησης (Modifiability): είναι εύκολο να αλλάξουμε την όψη ή να προσθέσουμε νέες όψεις χωρίς να τροποποιήσουμε το μοντέλο. Ευχρηστία (Usability): είναι εύκολο να προσθέσουμε νέες όψεις για διαφορετικές συσκευές ή διαφορετικές ομάδες χρηστών βελτιώνοντας την ευχρηστία των εφαρμογών σε αυτές τις συσκευές και γι' αυτούς του χρήστες. Επαναχρησιμοποίηση (Reusability): Το μοντέλο είναι επαναχρησιμοποιήσιμο και σε άλλες εφαρμογές (π.χ. με άλλες όψεις).
Τροποποίηση του παραδείγματος Θα τροποποιήσουμε το παράδειγμα που κάναμε με την εγγραφή μουσικών ώστε: Να υπάρχει η κλάση Musician (Model) που έχει τα κατάλληλα πεδία για έναν μουσικό και (σε ένα πλήρες πρόγραμμα θα) ενσωματώνει τις λειτουργίες σχετικές με έναν μουσικό. Να υπάρχει ένα servlet (Controller) που ανταποκρίνεται στην αλληλεπίδραση του χρήστη δημιουργώντας ένα αντικείμενο Musician με τις τιμές που έδωσε ο χρήστης Η σελίδα εμφάνισης του αποτελέσματος της εγγραφής του μουσικού του προηγούμενου παραδείγματος (confirmation.jsp) θα αλλάξει και θα χρησιμοποιεί τα στοιχεία του μοντέλου, θα είναι δηλαδή η όψη (View).
Δημιουργία Μοντέλου: η κλάση Musician (Βήμα 1) Η κλάση Musician αποτελεί το μοντέλο του συγκεκριμένου παραδείγματος. Θα χρειαστεί να δημιουργήσουμε ένα αντικείμενο αυτής της κλάσης στο servlet αλλά πριν το κάνουμε θα πρέπει να δημιουργήσουμε την κλάση αυτή. Για να το κάνουμε αυτό κάνουμε αυτό επιλέγουμε από το μενού File --> New File και από την κατηγορία Java επιλέγουμε Java Class όπως δείχνει η Εικόνα.
Δημιουργία Μοντέλου: η κλάση Musician (Βήμα 2) Στο δεύτερο βήμα το οδηγού δίνουμε ως όνομα κλάσης το όνομα Musician και ως πακέτο το 'model'. Πατάμε το πλήκτρο 'Finish' για να ολοκληρώσουμε τη δημιουργία της κλάσης η οποία και ανοίγει για επεξεργασία στον editor.
Ο κώδικας της κλάσης Musician package model; public class Musician { private String fname; private String lname; private String nickname; private String[] instruments; Συμβουλή: Δηλώστε πρώτα τα πεδία της κλάσης και στη συνέχεια πατήστε δεξί κλικ και επιλέξτε Insert Code.... Από το αναδυόμενο μενού επιλέξτε 'Getter and Setter.... Θα εμφανισθεί πλαίσιο διαλόγου από το οποίο θα επιλέξετε όλα τα πεδία για να παράγετε αυτόματα τους getters και του setters. public String getfname() { return fname; } public void setfname(string fname) { this.fname = fname; } public String getlname() { return lname; } public void setlname(string lname) { this.lname = lname; } public String getnickname() { return nickname; } public void setnickname(string nickname) { this.nickname = nickname; } public String[] getinstruments() { return instruments; } public void setinstruments(string[] instruments) { this.instruments = instruments; } }
Δημιουργία Servlet (βήμα 1) Για την δημιουργία του controller servlet επιλέγετε από το μενού File --> New File... και από την κατηγορία Web επιλέγετε Servlet όπως φαίνεται στην Εικόνα. Πατήστε το πλήκτρο 'Next>' για το επόμενο βήμα.
Δημιουργία Servlet (βήμα 2) Στο δεύτερο βήμα του οδηγού δίνουμε όνομα και προσδιορίζουμε το πακέτο του servlet. Στο παράδειγμά μας θα χρησιμοποιήσουμε τις τιμές: MusicianRegCtrlServlet για το όνομα, και controllers για το πακέτο Πατήστε 'Next>' για το επόμενο βήμα.
Δημιουργία Servlet (βήμα 3) Στο τρίτο και τελευταίο βήμα του οδηγού έχουμε τη δυνατότητα να αλλάξουμε αν θέλουμε το URL του servlet. Εξ ορισμού το URL είναι το όνομα του servlet (μετά το όνομα της εφαρμογής και του server ως συνήθως). Στο παράδειγμά μας δεν θα το αλλάξουμε. Επίσης μας δίνεται η δυνατότητα να κάνουμε και κάποιες άλλες ρυθμίσεις όπως ο προσδιορισμός των παραμέτρων αρχικοποίησης του servlet κ.α. Στο παράδειγμά μας δεν θα αλλάξουμε κάτι από τις εξ ορισμού επιλογές. Πατήστε το 'Finish' για να δημιουργηθεί το servlet.
Κώδικας Servlet Με την ολοκλήρωση δημιουργίας του servlet ο κώδικας του servlet ανοίγει προς επεξεργασία στον Editor του NetBeans Οι βασικότερη μέθοδος εδώ είναι η processrequest η οποία θα κληθεί είτε έχουμε get είτε έχουμε post ως HTTP μέθοδο κλήσης του servlet. Αν επιθυμούμε την εκτέλεση μόνο της doget ή της dopost (για την μέθοδο GET ή POST αντίστοιχα) τότε σβήνουμε την processrequest και την μέθοδο που δεν θέλουμε να υποστηρίξουμε και βάζουμε τον κώδικα στην μέθοδο που θέλουμε να υποστηρίξουμε (π.χ. στην doget για την μέθοδο GET).
Η μέθοδος επεξεργασίας αιτήσεων: processrequest protected void processrequest(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { // Δημιουργία μουσικού και καταχώρηση πεδίων από τις παραμέτρους της ιστοσελίδας Musician m = new Musician(); m.setfname(request.getparameter("fname")); m.setlname(request.getparameter("lname")); m.setnickname(request.getparameter("nickname")); m.setinstruments(request.getparametervalues("instrument")); //Τοποθέτηση του αντικειμένου του μουσικού ως ιδιότητας του αντικειμένου //request έτσι ώστε να περαστεί στην confirmation.jsp request.setattribute("musician", m); //προώθηση της αίτησης στην confirmation.jsp request.getrequestdispatcher("confirmation.jsp").forward(request,response); }
Τροποποίηση της ιστοσελίδας index.html Τώρα η φόρμα της ιστοσελίδας θα πρέπει να στέλνει τα δεδομένα στο servlet και όχι απευθείας στην confirmation.jsp. Η αλλαγή είναι πολύ μικρή και αφορά την ετικέτα form: Πριν:<form action="confirmation.jsp" method="post"> Τώρα: <form action="musicianregctrlservlet" method="post"> Έτσι τώρα και πάλι ο χρήστης βλέπει την αρχική σελίδα αλλά ο χειρισμός των στοιχείων δεν γίνεται από την (όψη) confirmation.jsp αλλά από τον controller, δηλαδή από το servlet MusicianRegCtrlServlet. Το URL του servlet εξ ορισμού είναι ίδιο με το όνομα της κλάσης του αλλά μπορείτε να το δείτε και στον κώδικά του αφού έχει προστεθεί κατά την δημιουργία του σχετική επισήμανση (annotation) πριν την έναρξη της κλάσης: @WebServlet(name = "MusicianRegCtrlServlet", urlpatterns = {"/MusicianRegCtrlServlet"})
Εισαγωγή του Bean στην confirmation.jsp Ανοίγουμε τη confirmation.jsp και πηγαίνουμε τον δρομέα πριν την έναρξή της (πριν την ετικέτα <html>) - βλ. Εικόνα. Από την παλέτα επιλέγουμε το εργαλείο Use Bean για την εισαγωγή του bean στη σελίδα και το τραβάμε στη θέση του δρομέα. Στο πλαίσιο διαλόγου εισαγωγής του bean δίνουμε τις τιμές που φαίνονται στην εικόνα. Το όνομα του bean θα είναι musician Η κλάση του είναι η Musician στο πακέτο model Και η εμβέλεια στην οποία βρίσκεται το αντικείμενο είναι η αίτηση (request) μαι και εκεί τοποθετήθηκε από το servlet
Αποτέλεσμα της εισαγωγής Το αποτέλεσμα της εισαγωγής είναι πως θα παραχθεί η γραμμή που φαίνεται στην εικόνα (<jsp:useban>), την οποία βεβαίως θα μπορούσαμε να είχαμε γράψει αν δεν θέλαμε να χρησιμοποιήσουμε την παλέτα για την εισαγωγή. Το αντικείμενο musician θα πρέπει να είναι διαθέσιμο στην εμβέλεια του request για να ανακτηθεί με επιτυχία και αυτό διασφαλίζεται μια και για την άφιξη στην confirmation.jsp διερχόμαστε πρώτα από τον controller που είναι το servlet. Ο controller προωθεί την αίτηση του χρήστη εδώ αφού όμως προηγούμενα έχει δημιουργήσει το αντικείμενο musician και αφού το έχει τοποθετήσει στην εμβέλεια request.
Εισαγωγή των ιδιοτήτων του bean Για την εμφάνιση του ονόματος του μουσικού θα προσπελάσουμε στο κατάλληλο σημείο της σελίδας τις ιδιότητες της κλάσης-μοντέλου δηλαδή του bean. Ο τρόπος που γίνεται αυτό μέσω της παλέτας είναι με τη χρήση του εργαλείου Get Bean Property από το οποίο μπορούμε να επιλέξουμε το bean και την ιδιότητά του (βλ. Εικόνα). Μετά την επιλογή στο σημείο που τοποθετήσαμε τον δρομέα θα παραχθεί μία ετικέτα <jsp:getproperty> με τις επιλεχθείσες τιμές για το bean και την ιδιότητα. Η ιδιότητα θα εμφανισθεί σε εκείνο το σημείο.
Εισαγωγή των ιδιοτήτων του bean (συν.) Στην προηγούμενη έκδοση της confirmation.jsp για την εμφάνιση του ονόματος του μουσικού και του ψευδωνύμου είχαμε τον κώδικα που ακολουθεί: <li> Όνομα: <%=request.getparameter("fname")+" "+ request.getparameter("lname")%> </li> <li> Ψευδώνυμο: <%= request.getparameter("nickname") %> </li> Τώρα με τη χρήση της <jsp:getproperty> το ίδιο επιτυγχάνεται ως εξής: <li> Όνομα: <jsp:getproperty name="musician" property="fname" /> <jsp:getproperty name="musician" property="lname" /> </li> <li> Ψευδώνυμο: <jsp:getproperty name="musician" property="nickname" /> </li> Παρατηρείστε πως η νέα έκδοση δεν περιέχει κώδικα Java παρά μόνο ετικέτες.
Προσπέλαση συλλογών με Java Στην προηγούμενη έκδοση της confirmation.jsp η εμφάνιση της συλλογής των οργάνων που γνωρίζει ο μουσικός επιτυγχάνονταν ως εξής (ουσιαστικά με κώδικα Java και απευθείας ανάκτηση των παραμέτρων από την ιστοσελίδα): <% String[] instruments = request.getparametervalues("instrument"); if (instruments!= null) { for (String instrument:instruments) { %> <li>μουσικό όργανο: <%= instrument%></li> <% } } %>
Προσπέλαση συλλογών με την ετικέτα foreach Το ίδιο μπορεί να επιτευχθεί με τη χρήση της ετικέτας foreach η οποία ανήκει στην Java server pages Standard Tag Library (JSTL), ως εξής: <c:foreach var="instrument" items="${musician.instruments}"> <li> <c:out value="${instrument}"/> </li> </c:foreach> Η ετικέτα foreach (και η out) προϋποθέτει πως έχει εισαχθεί στην αρχή της σελίδας η βασική βιβλιοθήκη ετικετών της JSTL με την οδηγία: <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
Εισαγωγή της foreach μέσω της παλέτας Για να εισάγετε το foreach (και την οδηγία σελίδας <@taglib>) αυτόματα μπορείτε να επιλέξετε από την παλέτα το εργαλείο JSTL For Each. Αυτό θα εμφανίσει το πλαίσιο διαλόγου της εισαγωγής στο οποίο μπορείτε να δώσετε το όνομα της συλλογής που θέλετε να διασχίσετε καθώς και το όνομα της μεταβλητής στην οποία θα ανατίθεται η τρέχουσα τιμή της συλλογής σε κάθε επανάληψη. Στην εικόνα η συλλογή είναι η ${musician.instruments} που είναι τα περιεχόμενα της συλλογής instruments της κλάσης musician. Σε κάθε επανάληψη η τρέχουσα τιμή αυτής της συλλογής θα καταχωρείται στη μεταβλητή με το όνομα instrument. Ο κώδικας που θα παραχθεί είναι ο εξής: <c:foreach var="instrument" items="${musician.instruments}"> </c:foreach>
Εμφάνιση της μεταβλητής σε κάθε επανάληψη Για την εμφάνιση των οργάνων σε μορφή λίστας ανάμεσα από το άνοιγμα και το κλείσιμο της <foreach> εισάγουμε την ετικέτα <out> για την εμφάνιση των περιεχομένων της μεταβλητής instrument που περιέχει το όργανο της τρέχουσας επανάληψης. <c:foreach var="instrument" items="${musician.instruments}"> <li> <c:out value="${instrument}"/> </li> </c:foreach>
Η νέα σελίδα confirmation.jsp <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@page contenttype="text/html" pageencoding="utf-8"%> <!DOCTYPE html> <jsp:usebean id="musician" scope="request" class="model.musician" /> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>επιβεβαίωση Στοιχείων</title> </head> <body> <h1>επιβεβαίωση Στοιχείων</h1> Ευχαριστούμε για την εγγραφή σας. Δώσατε τα ακόλουθα στοιχεία: <ul> <li> Όνομα: <jsp:getproperty name="musician" property="fname" /> <jsp:getproperty name="musician" property="lname" /> </li> <li> Ψευδώνυμο: <jsp:getproperty name="musician" property="nickname" /> <c:foreach var="instrument" items="${musician.instruments}"> <li> <c:out value="${instrument}"/> </li> </c:foreach> </ul> </body> </html> </li>
Εκτέλεση της εφαρμογής Το αποτέλεσμα είναι το ίδιο με πριν με μία μόνο ορατή διαφορά. Η εμφάνιση των στοιχείων γίνεται με το URL του servlet και η διεύθυνση της confirmation.jsp δεν εμφανίζεται γιατί κάναμε forward το request μέσω του server (χωρίς επιστροφή στον browser). Το πραγματικό πλεονέκτημα είναι η ευκολία τροποποιήσεων τώρα που έχουμε το μοντέλο. Σενάριο τροποποίησης: Πως θα άλλαζε η εφαρμογή μας αν γίνονταν πραγματικά η εγγραφή του μουσικού στη ΒΔ; Πως θα υλοποιούσατε αυτή την αλλαγή; Επίσης πως θα χειριζόσασταν την πιθανότητα απόπειρας εγγραφής ήδη εγγεγραμμένου μουσικού;
Ερωτήσεις;