< 2021SC@SDUSC Blog software engineering application and practice of Shandong University jpress module product module code analysis

Summary of Model layer analysis

In the last two blogs, I mainly analyzed the code of the entity class Product and the parent class inherited by the Product class. To sum up, Jpress is mainly a framework established on jfinal and Jboot, so it is necessary to understand jfinal and Jboot

JAVA speed WEB+ORM framework JFinal_Demo

JFinal is a high-speed WEB + ORM framework based on Java language. Its core design goal is rapid development, less code, simple learning, powerful function, lightweight, easy to expand and Restful. While having all the advantages of Java language, it also has the development efficiency of dynamic languages such as ruby and python!

JFinal has the following main features

MVC Architecture, exquisite design and simple use
 follow COC Principle, support zero configuration, none XML
 original Db + Record Mode, flexible and convenient
ActiveRecord Support, making database development extremely fast
 Minimalist, powerful and high-performance template engine Enjoy,Master 90 in ten minutes% usage
 Automatically load modified Java File, and there is no need to restart the service during the development process
AOP Support, the interceptor configuration is flexible and powerful
Plugin Architecture, strong scalability
 Multi view support Enjoy,FreeMarker,JSP,Velocity
 Powerful Validator Back end verification function
 Fully functional and traditional SSH Most of the core functions of the framework
 Small size, only 777 KB,And there is no third-party dependence

The following is an example of JFinal implementing Blog management:

  1. Controller (supports Enjoy, JSP, Velocity, JSON, etc., and custom view rendering)
@Before(BlogInterceptor.class)
public class BlogController extends Controller {

    @Inject
    BlogService service;

    public void index() {
        set("blogPage", service.paginate(getParaToInt(0, 1), 10));
        render("blog.html");
    }

    public void add() {
    }

    @Before(BlogValidator.class)
    public void save() {
        getModel(Blog.class).save();
        redirect("/blog");
    }

    public void edit() {
        set("blog", service.findById(getParaToInt()));
    }

    @Before(BlogValidator.class)
    public void update() {
        getModel(Blog.class).update();
        redirect("/blog");
    }

    public void delete() {
        service.deleteById(getParaToInt());
        redirect("/blog");
    }
}

2. All services and sql are placed in the Service layer

public class BlogService {

    private Blog dao = new Blog().dao();
    
    public Page<Blog> paginate(int pageNumber, int pageSize) {
        return dao.paginate(pageNumber, pageSize, "select *", "from blog order by id asc");
    }
    
    public Blog findById(int id) {
        return dao.findById(id);
    }
    
    public void deleteById(int id) {
        dao.deleteById(id);
    }
}

3. Model (no xml, no annotation, no attribute)

public class Blog extends Model<Blog> {
    
}

4.Validator(API guided verification is N times more convenient than xml verification, and code checking is not easy to make mistakes)

public class BlogValidator extends Validator {
    protected void validate(Controller controller) {
        validateRequiredString("blog.title", "titleMsg", "Please enter Blog title!");
        validateRequiredString("blog.content", "contentMsg", "Please enter Blog content!");
    }

    protected void handleError(Controller controller) {
        controller.keepModel(Blog.class);
    }
}

5. Interceptor (this demo is only an example, and this demo does not need this interceptor)

public class BlogInterceptor implements Interceptor {
    public void intercept(Invocation inv) {
        System.out.println("Before invoking " + inv.getActionKey());
        inv.invoke();
        System.out.println("After invoking " + inv.getActionKey());
    }
}

Learning of JFinal official documents

JFinal simplified AOP: fast and convenient

Traditional AOP implementation requires the Introduction of a large number of complex and redundant concepts, such as Aspect, Advice, Joinpoint, Poincut, Introduction, Weaving, Around, etc., and the Introduction of IOC containers and a large number of XML or annotation for component assembly.
Traditional AOP not only has high learning cost, low development efficiency and poor development experience, but also affects the system performance, especially the slow start of the project in the development stage, which greatly affects the development efficiency.
JFinal adopts the extremely fast AOP design, focuses on the core goal of AOP, and reduces the concept to the extreme. There are only three concepts: Interceptor, Before and Clear, and there is no need to introduce IOC or use verbose XML.

Because JFinal does not use a lot of XML files, there will be no clue when analyzing Jpress at the beginning, because many functions and codes are encapsulated by JFinal and Jboot

Interceptor

Interceptor can intercept methods and provide an opportunity to add aspect code before and after methods to achieve the core goal of AOP. The interceptor interface only defines a method public void intercept(Invocation inv). The following is a simple example:

    public class DemoInterceptor implements Interceptor {
        public void intercept(Invocation inv) {
           System.out.println("Before method invoking");
           inv.invoke();
           System.out.println("After method invoking");
        }
    }

The DemoInterceptor in the above code will intercept the target method and output text to the console before and after the target method call. inv.invoke()
This line of code is a call to the target method. Inserting aspect code before and after this line of code can easily realize AOP.

As the only parameter in the intercept method of the Interceptor interface, Invocation provides many convenient methods for use in the Interceptor. The following are the methods in Invocation:

Interceptor It is globally shared, so if you want to use attributes in it, you need to ensure that their attributes are thread safe. The following code will be wrong:
    public class MyInterceptor implements Interceptor {
     
       private int value = 123;
       
       public void intercept(Invocation inv) {
           // Multithreading will access the value value concurrently, causing confusion
           value++;
           
           inv.invoke();
       }
    }

As shown in the above code, the value attribute will be accessed by multiple threads, causing thread safety problems.

Before

Before annotation is used to configure interceptors. This annotation can configure interceptors at Class and Method levels. The following is a code example:

    // Configure a Class level interceptor, which will intercept all methods in this Class
    @Before(AaaInter.class)
    public class BlogController extends Controller {
     
      // Configure multiple Method level interceptors to intercept only this Method
      @Before({BbbInter.class, CccInter.class})
      public void index() {
      }
     
      // The Method level interceptor is not configured, but will be intercepted by the Class level interceptor aainter
      public void show() {
      }
    }

As shown in the above code, Before can configure interceptors at Class level and Method level. The former will intercept all methods in this Class, and the latter only intercepts this Method. In addition, Before can configure multiple interceptors at the same time, just separate multiple interceptors with commas in braces.

In addition to Class and Method level interceptors, JFinal also supports global interceptors and Routes interceptors. Global interceptors are divided into control layer global interceptors and business layer global interceptors. The former intercepts all Action methods of the control layer and the latter intercepts all methods of the business layer.

The global interceptor needs to be configured in YourJFinalConfig. The following is a configuration example:

    public class YourJFinalConfig extends JFinalConfig {
       public void configInterceptor(Interceptors me) {
          // Add control layer global interceptor
          me.addGlobalActionInterceptor(new GlobalActionInterceptor());
      
          // Add business layer global interceptor
          me.addGlobalServiceInterceptor(new GlobalServiceInterceptor());
      
          // The method reserved for compatibility with the old version has exactly the same function as addGlobalActionInterceptor
          me.add(new GlobalActionInterceptor());
       }
    }

When a Method is intercepted by multiple levels of interceptors, the execution order of each level of interceptors is: Global, Routes, Class and Method. If there are multiple interceptors in the same level, the execution order in the same level is: the one configured in front is executed first.

Clear

Interceptors are divided into four levels from top to bottom: Global, Routes, Class and Method. Clear is used to clear interceptors above their own level.

Clear declares that Global, Routes and Class will be cleared in the Method layer. Clear declares that Global and Routes will be cleared in the Class layer. When the clear annotation carries parameters, the interceptors specified in the target layer will be cleared.

In some application scenarios, Global or Class interceptors need to be removed. For example, a background management system is configured with a Global permission interceptor, but its login action must be cleared, otherwise the login operation cannot be completed. The following is a code example:

    // The login method needs to remove the permission interceptor to log in normally
    @Before(AuthInterceptor.class)
    public class UserController extends Controller {
        // AuthInterceptor has been cleared by Clear and will not be blocked
        @Clear
        public void login() {
        }
        
        // This method will be intercepted by AuthInterceptor
        public void show() {
        }
    }

When the Clear annotation has parameters, the specified interceptor can be cleared. The following is a more comprehensive example:

    @Before(AAA.class)
    public class UserController extends Controller {
      @Clear
      @Before(BBB.class)
      public void login() {
         // Global and Class level interceptors will be cleared, but the BBB declared on this method will not be affected
      }
     
      @Clear({AAA.class, CCC.class})// Clear the specified interceptor AAA and CCC
      @Before(CCC.class)
      public void show() {
         // Although the Clear annotation specifies to Clear CCC, it cannot be cleared because the Clear operation is only for layers above this layer
      }
    }

The above clearing is used for method and can also be used for class, for example:

    @Clear(AAA.class)
    public class UserController {
       public void index() {
          ...
       }
    }

As shown above, @ Clear(AAA.class) will clear the AAA.java interceptor configured in the upper layer, that is, the Global and Route layers.

Inject dependency injection
@Bean
public class ProductServiceProvider extends JbootServiceBase<Product> implements ProductService {

    private static final String DEFAULT_ORDER_BY = "order_number desc,id desc";

    @Inject
    private UserService userService;

    @Inject
    private ProductCommentService commentService;

    @Inject
    private ProductCategoryService categoryService;
    }

The @ Inject annotation can be used to Inject dependent objects into the Controller and Interceptor. The injection function requires the following configuration:

    public void configConstant(Constants me) {
        // Enable the injection of jfinal web project components Controller, Interceptor and Validator
        me.setInjectDependency(true);
        
        // Enable injection of superclasses. When it is not enabled, it can be injected through Aop.get(...) in the superclass
        me.setInjectSuperClass(true);
    }

The above me.setInjectDependency(true) is only a configuration for jfinal web components. Aop.get(...) and Aop.inject(...) can support injection without configuration.
After configuration, it can be used in the controller, for example:

    public class AccountController {
       
       @Inject
       AccountService service;    // Dependent objects will be injected here
       
       public void index() {
           service.justDoIt();    // Call the method of the injected object
       }
    }

@Inject can also be used for attribute injection of interceptors, for example:

    public class MyInterceptor implements Interceptor {
        
        @Inject
        Service service;    // Dependent objects will be injected here
        
        public void intercept(Invocation inv) {
            service.justDoIt();    // Call the method of the injected object
            inv.invoke();
        }
    }

The premise of Inject injection is that the creation of objects of classes annotated with @ Inject is taken over by jfinal, so jfinal
To have the opportunity to Inject it. For example, jfinal takes over the creation of Controller, Interceptor and Validator, so @ Inject can be used in these three components.
If the object to be created is not taken over by jfinal, you can use the Aop.get(...) method to create and inject dependent objects, for example:

    public class MyKit {
       
       static Service service = Aop.get(Service.class);
       
       public void doIt() {
          service.justDoIt();
       }
    }

Since the creation of MyKit is not taken over by jfinal, @ Inject cannot be used for dependency injection. The creation and assembly of Controller and Interceptor are taken over by jfinal, so @ Inject can be used to Inject dependencies.

With Aop.get(...), you can create objects anywhere and inject the created objects. In addition, you can use Aop.inject(...) to only inject dependencies into objects without creating objects.

Tags: Java

Posted on Sat, 23 Oct 2021 21:56:40 -0400 by jumpfroggy