UI modernisieren
Später kann React/Angular denselben Use Case nutzen.
Eine Action-Klasse enthält Session-State, Validierung, Berechtigungen, EJB-Aufruf und JSP-Modellaufbereitung. Das Refactoring trennt Controller, Form Validator, Presenter und Use Case.
| Aspekt | Beschreibung |
|---|---|
| Symptom | UI-Klasse entscheidet fachlich, ruft EJB direkt und füllt Request-Attribute mit Datenbank-/Legacy-Begriffen. |
| Risiko | Neue UI oder REST API kann nicht wiederverwenden, weil Fachlogik im Web-Layer klebt. |
| Refactoring-Ziel | UI sammelt nur Eingabe, Presenter baut Anzeige, Use Case entscheidet fachlich. |
public class LegacyOrderAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession(false);
User user = (User) session.getAttribute("USER");
LegacyOrderForm orderForm = (LegacyOrderForm) form;
if (user == null || !user.hasRole("ORDER_WRITE")) {
request.setAttribute("error", "Keine Berechtigung");
return mapping.findForward("forbidden");
}
if (orderForm.getCustomerNo() == null || orderForm.getCustomerNo().trim().equals("")) {
request.setAttribute("error", "Kunde fehlt");
return mapping.findForward("input");
}
if (orderForm.getAmount() == null || new BigDecimal(orderForm.getAmount()).signum() <= 0) {
request.setAttribute("error", "Betrag ungueltig");
return mapping.findForward("input");
}
InitialContext ctx = new InitialContext();
LegacyOrderBeanRemote bean = (LegacyOrderBeanRemote) ctx.lookup("ejb/LegacyOrderBean");
LegacyOrderRequest legacy = new LegacyOrderRequest();
legacy.setCustomerNo(orderForm.getCustomerNo());
legacy.setAmount(new BigDecimal(orderForm.getAmount()));
legacy.setPriority("on".equals(orderForm.getPriority()) ? "H" : "N");
legacy.setUser(user.getLogin());
LegacyOrderResponse legacyResponse = bean.createOrder(legacy);
if (!"00".equals(legacyResponse.getReturnCode())) {
request.setAttribute("error", legacyResponse.getReturnText());
request.setAttribute("legacyCode", legacyResponse.getReturnCode());
return mapping.findForward("input");
}
request.setAttribute("orderNo", legacyResponse.getOrderNo());
request.setAttribute("successText", "Auftrag " + legacyResponse.getOrderNo() + " wurde angelegt");
request.setAttribute("showPrintButton", user.hasRole("ORDER_PRINT"));
return mapping.findForward("success");
}
}
class OrderFormValidatorTest {
@Test
void rejectsMissingCustomerBeforeCallingLegacySystem() {
OrderFormInput input = new OrderFormInput("", "25.00", false);
UserSession user = UserSession.withRoles("ORDER_WRITE");
ValidationResult result = new OrderFormValidator().validate(input, user);
assertThat(result.errorCodes()).contains("CUSTOMER_REQUIRED");
}
}
public class OrderAction extends Action {
private final OrderFormValidator validator = new OrderFormValidator();
private final OrderPresenter presenter = new OrderPresenter();
private final OrderApplicationFacade facade = ServiceLocator.orderFacade(); // Pattern: Facade Adapter
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
UserSession user = UserSession.from(request);
OrderFormInput input = OrderFormInput.from((LegacyOrderForm) form);
ValidationResult validation = validator.validate(input, user); // Pattern: Form Object
if (validation.hasErrors()) {
presenter.presentInput(request, input, validation);
return mapping.findForward("input");
}
CreateOrderResult result = facade.createOrder(input.toCommand(user.login()));
OrderViewModel viewModel = presenter.toViewModel(result, user); // Pattern: Presenter
presenter.write(request, viewModel);
return mapping.findForward(viewModel.forwardName());
}
}
public final class OrderPresenter {
public OrderViewModel toViewModel(CreateOrderResult result, UserSession user) {
if (result.rejected()) {
return OrderViewModel.inputWithError(result.message(), result.legacyCode());
}
return OrderViewModel.success(
"Auftrag " + result.orderNo() + " wurde angelegt",
result.orderNo(),
user.hasRole("ORDER_PRINT")
);
}
}
Später kann React/Angular denselben Use Case nutzen.
Validierung und Presenter ohne Application Server testbar.
Berechtigungsentscheidung wird explizit.
JSP bekommt ein ViewModel statt Legacy-Rohdaten.