Skip to main content

Design Patterns

Exception Handling Methods

Global Exception Handling Class ExceptionHandlingController
package com.whalefall.learncases.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;

/**
* @author WhaleFall
* @create 2022-05-28 10:41
* codes copy from => https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
*/
@Slf4j
@ControllerAdvice// Specify as global exception handling
public class ExceptionHandlingController {

// Specify name of a specific view that will be used to display the error:
@ExceptionHandler(SQLException.class)
public String databaseError() {
// Nothing to do. Returns the logical view name of an error page, passed
// to the view-resolver(s) in usual way.
// Note that the exception is NOT available to this view (it is not added
// to the model) but see "Extending ExceptionHandlerExceptionResolver"
// below.
return "databaseError";
}

// Total control - setup a model and return the view name yourself. Or
// consider subclassing ExceptionHandlerExceptionResolver (see below).
@ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception ex) {
log.error("Request: " + req.getRequestURL() + " raised " + ex);

ModelAndView mav = new ModelAndView();
mav.addObject("exception", ex);
mav.addObject("url", req.getRequestURL());
mav.setViewName("error");
return mav;
}

}

Interface-Based Design

Interface Class
package com.whalefall.learncases.design;

/**
* @author WhaleFall
* @create 2022-07-25 19:21
*/
public interface IService {
boolean doService();

boolean doServiceBefore();

boolean doServiceAfter();

void doLog();
}

Interface Implementation Class
package com.whalefall.learncases.design;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
* @author WhaleFall
* @create 2022-07-24 6:34
*/
@Slf4j
@Component
public class AService implements IService {
@Override
public boolean doService() {
log.info("do A service");
if (true)
throw new RuntimeException("Exception msg1");
return true;
}

@Override
public boolean doServiceBefore() {
return false;
}

@Override
public boolean doServiceAfter() {
return false;
}

@Override
public void doLog() {
if (true)
throw new RuntimeException("Exception msg2");
log.error("A1 do log");
}
}

Core Process Encapsulation

  1. Singleton Template Design Pattern
Singleton Template Design Pattern
package com.whalefall.learncases.design;

import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.NotNull;
import java.util.function.Consumer;

/**
* @author WhaleFall
* @create 2022-07-24 6:26
*/
@Slf4j
public class SProcessService {
private SProcessService() {

}

private static class SProcessServiceHolder {
private static final SProcessService INSTANCE = new SProcessService();
}

public static SProcessService getInstance() {
return SProcessServiceHolder.INSTANCE;
}

public boolean handle(IService service, Consumer<Exception> exceptionConsumer) {
serviceBefore(service);
service(service, exceptionConsumer);
serviceAfter(service);
log(service, exceptionConsumer);
return true;
}

private void serviceAfter(@NotNull IService service) {
service.doServiceAfter();
}

private void serviceBefore(@NotNull IService service) {
service.doServiceBefore();
}

private void service(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doService();
} catch (Exception e1) {
exceptionConsumer.accept(e1);
throw e1;
}
}

private void log(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doLog();
} catch (Exception e2) {
log.error("failed do log");
exceptionConsumer.accept(e2);
}
}
}

  1. Inject into Container
Inject into Container
package com.whalefall.learncases.design;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.function.Consumer;

/**
* @author WhaleFall
* @create 2022-07-24 6:26
*/
@Component
@Slf4j
public class ProcessService {

public boolean handle(IService service, Consumer<Exception> exceptionConsumer) {
serviceBefore(service);
service(service, exceptionConsumer);
serviceAfter(service);
log(service, exceptionConsumer);
return true;
}

private void serviceAfter(@NotNull IService service) {
service.doServiceAfter();
}

private void serviceBefore(@NotNull IService service) {
service.doServiceBefore();
}

private void service(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doService();
} catch (Exception e1) {
exceptionConsumer.accept(e1);
throw e1;
}
}

private void log(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doLog();
} catch (Exception e2) {
log.error("failed do log");
exceptionConsumer.accept(e2);
}
}
}

Calling Class

package com.whalefall.learncases.design;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* @author WhaleFall
* @create 2022-07-24 6:37
*/
@RestController
@Slf4j
public class ControllerA {

private IService service;

private ProcessService processService;

public ControllerA(IService service, ProcessService processService) {
this.service = service;
this.processService = processService;
}

@GetMapping("/testA")
public boolean getA(){
return processService.handle(service, e -> log.error(e.getMessage(), e));
}
}

Complete Code

DDD

Entity objects cannot be assigned directly, domain objects cannot be newed directly, factory methods and builder patterns should be used to implement.

Application Layer Responsibilities:

  • Basic data validation
  • Data conversion
  • Security authentication
  • Permission check
  • Transaction control
  • Message sending

Principles:

  1. If it is difficult to split, you can write the code to application service first.
  2. If you cannot confirm whether it is an entity or a value object, you can treat it as an entity first.
  3. Entity (has unique identifier, mutable state, has life cycle).
  4. Value Object (Address, Amount, Measurement, Date, Time, Color, Transaction Snapshot).
  5. Entities should not depend on Spring container.

Domain Object Relationship Handling

  1. Composition, Aggregation Relationships: One contains another; each object is a whole.
  2. Association Relationships: Non-composition, aggregation association relationships.
  3. Generalization Relationships: Inheritance.

Only business exceptions can be reported in SupportImpl.

Jar file FunctionalInterface can be extended by user implement class

FunctionalInterface.java
    @Resource
private Custom customImpl;

/**
* Define {@link FunctionalInterface} in Jar package<br/>
* Of course, the usage class in Jar implements ApplicationContextAware, then gets the injected object of the application, and then writes where the function is triggered<br/>
* User defines implementation class and injects it into container.<br/>
* @param str function input parameter
*/
public void custom(String str) {
Consumer<Custom> consumer = custom -> custom.custom(str);
consumer.accept(customImpl);
}

Jar file FunctionalInterface can be extended by user implement class

Agreement
The code part of this work is licensed under Apache License 2.0 . You may freely modify and redistribute the code, and use it for commercial purposes, provided that you comply with the license. However, you are required to:
  • Attribution: Retain the original author's signature and code source information in the original and derivative code.
  • Preserve License: Retain the Apache 2.0 license file in the original and derivative code.
The documentation part of this work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . You may freely share, including copying and distributing this work in any medium or format, and freely adapt, remix, transform, and build upon the material. However, you are required to:
  • Attribution: Give appropriate credit, provide a link to the license, and indicate if changes were made.
  • NonCommercial: You may not use the material for commercial purposes. For commercial use, please contact the author.
  • ShareAlike: If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.