Jo, ni är inne på rätt spår. Servlet/JSP-tekniken bygger på det designmönster som kallas för Model-View-Controller eller MVC. I den modellen är Model era olika "komponenter" eller operationer som jag skulle föredra att kalla det. Det är alltså de som innehåller själva logiken.
View representeras av JSP-sidorna och skall visa upp resultatet. Försök att se till att de innehåller så lite logik som möjligt. Den logik som skall finnas i jsp-sidorna skall BARA vara sådan som behövs för att få rätt utseende baserat på vad som kommit som resultat.
Controller i det här fallet är en, eller flera, servlets som kopplar jsp-sidor med en viss operation.
När vi bygger den här typen av system så använder vi oss ofta av ett servlet som vi kallar för dispatcher. Denna får ett anrop från någon och baserat på frågesträngen (query string) så väljer den att skicka vidare frågan till en operation.
En typisk sida är en sida med ett formulär där formuläret postas till dispatchern. I formuläret finns ett gömt fält med namnet "operation" och sedan "koden" för operationen.
Antag att vi har en sida där jag frågar efter kunduppgifter baserat på ett kundnummer. Sidan ser då ut såhär:
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<title>Get Customer Information</title>
</head>
<body bgcolor="#FFFFFF">
<h1>Get Customer Information</h1>
<form name='getCustomerForm' action='/dispatcher'>
<input type='hidden' name='operation' value='getCustomer'/>
Customer number: <input name='customerNumber' size='10' /><br>
<input type='submit'>Fetch</input>
</form>
</body>
</html>
Dispatcher-servleten ser ut något såhär:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
* Created on Nov 21, 2005
* (c) Lime on educational purposes.
*/
/**
* @author lime
*
* Servlet that dispatch calls to the right operation.
*/
public class Dispatcher extends HttpServlet
{
private static Map controllerMap = new HashMap();
static
{
// Lägg till alla era operationer här.
addOperation(new GetCustomerInfoOperation());
}
public static void addOperation(Operation operation)
{
controllerMap.put(operation.getName(),operation);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException
{
String operationKey = request.getParameter("operation");
Operation operation = (Operation) controllerMap.get(operationKey);
if(operation != null)
{
operation.loadProperties(request);
if(operation.execute())
{
Result result = operation.getResult();
request.getSession().setAttribute("result", result);
// OBS!!! Efter denna får man inte göra NÅGOT ALLS!!!
response.sendRedirect(operation.getViewUrl());
return;
}
else
{
response.sendRedirect(operation.getErrorUrl());
return;
}
}
}
}
Dispatchern använder sig av Operation som är en abstrakt klass som används som basklass för alla operationer. Den ser ut såhär:
import java.util.HashMap;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
/**
* @author lime
*
* Base class for all operations in our system.
*/
public abstract class Operation
{
public static String name = "";
HashMap properties = new HashMap();
public Operation()
{
init();
if(name.trim().length() == 0)
System.out.println("Operation name not set");
}
// Loads the properties into the properties
public void loadProperties(HttpServletRequest request)
{
Iterator keyIterator = properties.keySet().iterator();
String value;
while (keyIterator.hasNext())
{
String key = (String) keyIterator.next();
value = request.getParameter(key);
properties.put(key, value);
}
}
protected abstract void init();
public abstract boolean execute();
public abstract Result getResult();
public abstract String getViewUrl();
public abstract String getErrorUrl();
public abstract String getName();
}
Min implementation av operationen GetCustomerInfo ser ut såhär:
public class GetCustomerInfoOperation extends Operation
{
// Keys
public static String CUSTOMER_NUMBER ="customerNumber";
// Result
private Result result;
protected void init()
{
// lägg till alla Keys i HashMap:en
properties.put(CUSTOMER_NUMBER, "");
// Sätt namnet på operationen
name = "getCustomer";
}
public boolean execute()
{
boolean result = false;
// TODO: Slå upp kunden i databasen och skapa Result-objektet.
// Hur ni gör det får ni fundera på själva.
// Returnera true om det finns ett result-object och false om det inte gör det...
return result;
}
public Result getResult()
{
return result;
}
public String getViewUrl()
{
return "/customer/showCustomerInfo.jsp";
}
public String getErrorUrl()
{
return "/customer/customerNotFound.jsp";
}
public String getName()
{
return name;
}
}
Om jag får ett resultat så skickar jag allt till showCustomerInfo.jsp som ser ut såhär:
<%@ page language="java" pageEncoding="UTF-8" %>
<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<title>Lomboz JSP</title>
</head>
<body bgcolor="#FFFFFF">
<jsp:useBean id="result" scope="page" class="GetCustomerInfoResult" />
Name: <%=result.getValue(GetCustomerInfoResult.NAME) %></br>
Address: <%=result.getValue(GetCustomerInfoResult.ADDRESS) %></br>
Email: <%=result.getValue(GetCustomerInfoResult.EMAIL) %></br>
</body>
</html>
Hur jag specificerat och implementerat Result och GetCustomerInfoResult får ni fundera ut själva... ;-)