เว็บแอปพลิเคชั่นที่เหมาะสมประกอบด้วยการผสมผสานรูปแบบการออกแบบ ฉันจะพูดถึงสิ่งที่สำคัญที่สุดเท่านั้น
แกน (สถาปัตยกรรม) รูปแบบการออกแบบที่คุณต้องการใช้เป็นรูปแบบ Model-View-Controller ควบคุมจะได้รับการแสดงโดย Servlet ซึ่ง (ใน) สร้างโดยตรง / ใช้เฉพาะรุ่นและดูอยู่บนพื้นฐานของการร้องขอ ตัวแบบจะถูกแสดงโดยคลาส Javabean ซึ่งมักจะสามารถแบ่งได้เพิ่มเติมในรูปแบบธุรกิจซึ่งมีการกระทำ (พฤติกรรม) และรูปแบบข้อมูลซึ่งมีข้อมูล (ข้อมูล) ดูคือการเป็นตัวแทนจากไฟล์ JSP ที่มีการเข้าถึงโดยตรงไป ( ข้อมูล ) รุ่นโดย EL (Expression Language)
จากนั้นจะมีการเปลี่ยนแปลงตามวิธีการจัดการการกระทำและกิจกรรม สิ่งที่ได้รับความนิยม ได้แก่ :
MVC ที่อิงตามคำขอ (การกระทำ) : นี่เป็นวิธีที่ง่ายที่สุดในการนำไปใช้ (การธุรกิจ ) รุ่นทำงานโดยตรงกับHttpServletRequest
และHttpServletResponse
วัตถุ คุณต้องรวบรวมแปลงและตรวจสอบพารามิเตอร์คำขอ (ส่วนใหญ่) ด้วยตัวคุณเอง ดูสามารถแสดงด้วยวานิลลาธรรมดา HTML / CSS / JS และไม่รักษาสถานะระหว่างการร้องขอ นี่คือวิธีที่หมู่คนอื่น ๆฤดูใบไม้ผลิ MVC , Strutsและลายเส้นแนวพระราชดำริ
MVC ที่อิงส่วนประกอบ : สิ่งนี้ยากที่จะนำไปใช้ แต่คุณท้ายด้วยรูปแบบที่เรียบง่ายกว่าเดิมและดูว่า Servlet API "ดิบ" ทั้งหมดถูกแยกออกไปอย่างสิ้นเชิง คุณไม่จำเป็นต้องรวบรวมแปลงและตรวจสอบพารามิเตอร์คำขอด้วยตัวเอง ควบคุมไม่งานนี้และชุดรวบรวมและตรวจสอบแปลงค่าคำขอในรุ่น สิ่งที่คุณต้องทำคือการกำหนดวิธีการกระทำที่ทำงานโดยตรงกับคุณสมบัติของรูปแบบ ดูเป็นตัวแทนจาก "ส่วนประกอบ" ในรสชาติของ taglibs JSP หรือองค์ประกอบ XML ซึ่งจะสร้าง HTML / CSS / JS สถานะของมุมมองสำหรับคำขอที่ตามมาจะได้รับการปรับปรุงในเซสชัน สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับเหตุการณ์การแปลงการตรวจสอบความถูกต้องและการเปลี่ยนแปลงค่า นี่คือวิธีอื่น ๆ ในกลุ่มJSF , Wicket and Play! โรงงาน
ในฐานะที่เป็นหมายเหตุด้านงานอดิเรกด้วยกรอบ MVC พื้นบ้านเป็นแบบฝึกหัดการเรียนรู้ที่ดีมากและฉันขอแนะนำตราบใดที่คุณเก็บไว้เพื่อวัตถุประสงค์ส่วนตัว / ส่วนตัว แต่เมื่อคุณเป็นมืออาชีพแล้วขอแนะนำอย่างยิ่งให้เลือกกรอบงานที่มีอยู่แทนที่จะสร้างใหม่ของคุณเอง การเรียนรู้กรอบงานที่มีอยู่และได้รับการพัฒนามาอย่างดีนั้นใช้เวลาน้อยกว่าในระยะยาวกว่าการพัฒนาและรักษากรอบงานที่แข็งแกร่งด้วยตัวคุณเอง
ในคำอธิบายโดยละเอียดด้านล่างฉันจะ จำกัด ตัวเองให้ขอ MVC ตามเนื่องจากง่ายต่อการใช้งาน
อันดับแรกส่วนคอนโทรลเลอร์ควรใช้รูปแบบ Front Controller (ซึ่งเป็นรูปแบบเฉพาะของMediator ) ควรประกอบด้วยเซิร์ฟเล็ตเพียงอันเดียวซึ่งมีจุดเข้าใช้งานส่วนกลางของการร้องขอทั้งหมด ควรสร้างแบบจำลองตามข้อมูลที่มีอยู่โดยการร้องขอเช่น pathinfo หรือ servletpath วิธีการและ / หรือพารามิเตอร์เฉพาะ รูปแบบธุรกิจที่เรียกว่าAction
ในด้านล่างHttpServlet
ตัวอย่างเช่น
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
}
else {
response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
}
}
catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
การดำเนินการแอ็คชันควรส่งคืนตัวบ่งชี้บางตัวเพื่อค้นหามุมมอง ที่ง่ายที่สุดคือใช้เป็นชื่อไฟล์ของ JSP แผนที่เซิร์ฟเล็ตนี้ในที่เฉพาะเจาะจงurl-pattern
ในweb.xml
เช่น/pages/*
, หรือแม้เพียงแค่*.do
*.html
ในกรณีที่คำนำหน้า - รูปแบบเป็นตัวอย่าง/pages/*
คุณสามารถเรียก URL เช่นนั้นได้ http://example.com/pages/register , http://example.com/pages/loginฯลฯ และให้/WEB-INF/register.jsp
, /WEB-INF/login.jsp
กับ GET ที่เหมาะสมและการกระทำ POST . ชิ้นส่วนregister
และlogin
อื่น ๆ จะมีให้ใช้งานตามrequest.getPathInfo()
ตัวอย่างด้านบน
เมื่อคุณใช้คำต่อท้ายรูปเหมือน*.do
, *.html
ฯลฯ แล้วคุณจะทำได้แล้ววิงวอน URL เช่น http://example.com/register.do , http://example.com/login.doฯลฯ และคุณควรจะเปลี่ยน ตัวอย่างรหัสในคำตอบนี้ (ยังActionFactory
) เพื่อแยกregister
และlogin
ชิ้นส่วนโดยrequest.getServletPath()
แทน
Action
ควรเป็นไปตามรูปแบบกลยุทธ์ จะต้องมีการกำหนดเป็นนามธรรม / ประเภทอินเตอร์เฟสซึ่งควรทำงานตามอาร์กิวเมนต์ที่ส่งผ่านของวิธีนามธรรม (นี่คือความแตกต่างกับรูปแบบคำสั่งซึ่งในนั้นประเภทนามธรรม / อินเตอร์เฟซควรทำงานตาม อาร์กิวเมนต์ที่ถูกส่งผ่านในระหว่างการสร้างการใช้งาน)
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
คุณอาจต้องการที่จะทำให้เฉพาะเจาะจงมากขึ้นด้วยข้อยกเว้นที่กำหนดเองเช่นException
ActionException
มันเป็นแค่ตัวอย่างกำหนดการพื้นฐานส่วนที่เหลือนั้นขึ้นอยู่กับคุณ
นี่คือตัวอย่างของการบันทึกLoginAction
(ในชื่อของมัน) ในผู้ใช้ User
ตัวเองอยู่ในการเปิดรูปแบบข้อมูล ดูUser
ตระหนักถึงการปรากฏตัวของ
public class LoginAction implements Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
return "home"; // Redirect to home page.
}
else {
request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
return "login"; // Go back to redisplay login form with error.
}
}
}
ActionFactory
ควรเป็นไปตามรูปแบบวิธีการโรงงาน โดยพื้นฐานแล้วมันควรจะมีวิธีการสร้างที่ส่งกลับการดำเนินการที่เป็นรูปธรรมของประเภทนามธรรม / อินเตอร์เฟซ ในกรณีนี้ควรส่งคืนการดำเนินการAction
ตามอินเตอร์เฟสตามข้อมูลที่ได้รับจากคำขอ ตัวอย่างเช่นวิธีการและpathinfo (pathinfo เป็นส่วนหนึ่งหลังจากบริบทและเส้นทาง servlet ใน URL คำขอไม่รวมสตริงแบบสอบถาม)
public static Action getAction(HttpServletRequest request) {
return actions.get(request.getMethod() + request.getPathInfo());
}
actions
ในทางกลับกันควรจะมีบางคงที่ / applicationwide Map<String, Action>
ซึ่งถือการกระทำที่รู้จักกันทั้งหมด มันขึ้นอยู่กับคุณว่าจะเติมแผนที่นี้อย่างไร hardcoding:
actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
หรือกำหนดค่าได้ตามไฟล์คุณสมบัติ / XML ใน classpath: (หลอก)
for (Entry entry : configuration) {
actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}
หรือแบบไดนามิกโดยอาศัยการสแกนใน classpath สำหรับคลาสที่ใช้อินเทอร์เฟซและ / หรือหมายเหตุประกอบที่แน่นอน: (หลอก)
for (ClassFile classFile : classpath) {
if (classFile.isInstanceOf(Action.class)) {
actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
}
}
อย่าลืมสร้าง "ไม่ทำอะไรเลย" Action
สำหรับกรณีที่ไม่มีการแมป ปล่อยให้มันกลับตัวอย่างโดยตรงrequest.getPathInfo().substring(1)
แล้ว
รูปแบบอื่น ๆ
นั่นเป็นรูปแบบที่สำคัญจนถึงตอนนี้
ในการก้าวไปอีกขั้นคุณสามารถใช้รูปแบบ Facadeเพื่อสร้างContext
คลาสซึ่งจะล้อมวัตถุคำขอและตอบสนองและเสนอวิธีการที่สะดวกหลายอย่างที่มอบหมายให้กับวัตถุคำขอและตอบสนองและส่งผ่านเป็นอาร์กิวเมนต์ไปยังAction#execute()
เมธอดแทน สิ่งนี้จะเพิ่มเลเยอร์นามธรรมพิเศษเพื่อซ่อน raw servlet API ออกไป จากนั้นคุณควรจะจบลงด้วยการประกาศเป็นศูนย์ import javax.servlet.*
ในAction
การใช้งานทุกครั้ง ในแง่ JSF นี่คือสิ่งที่FacesContext
และExternalContext
ชั้นเรียนกำลังทำ คุณสามารถหาตัวอย่างที่เป็นรูปธรรมได้ในคำตอบนี้
จากนั้นมีรูปแบบสถานะสำหรับกรณีที่คุณต้องการเพิ่มเลเยอร์นามธรรมพิเศษเพื่อแบ่งงานของการรวบรวมพารามิเตอร์คำขอแปลงพวกเขาตรวจสอบพวกเขาปรับปรุงค่ารุ่นและดำเนินการการกระทำ ในแง่ของ JSF นี่คือสิ่งที่LifeCycle
กำลังทำอยู่
จากนั้นจะมีรูปแบบคอมโพสิตสำหรับกรณีที่คุณต้องการสร้างมุมมองตามองค์ประกอบซึ่งสามารถแนบกับโมเดลและพฤติกรรมที่ขึ้นอยู่กับสถานะของวงจรชีวิตการร้องขอตาม ในแง่ JSF นี่คือสิ่งที่UIComponent
เป็นตัวแทน
วิธีนี้คุณสามารถวิวัฒนาการทีละนิดไปสู่เฟรมเวิร์กที่ใช้องค์ประกอบ
ดูสิ่งนี้ด้วย: