MVC mapping function of 30 classes handwritten Spring core principles

This article is excerpted from Spring 5 core principles

Next, let's complete the functions of the MVC module. There should be no need to explain. The entry of Spring MVC starts with the dispatcher servlet, and the web has been completed in the previous chapter Basic configuration of XML. Let's start with the dispatcher servlet.

1 MVC top level design

1.1 GPDispatcherServlet

We have learned that the life cycle of a Servlet consists of init() to service() and then to destruction (). We do not implement the destruction () method. As we mentioned earlier, this is a typical application of template pattern in J2EE. Let's define the global variables first:

package com.tom.spring.formework.webmvc.servlet;

import com.tom.spring.formework.annotation.GPController;
import com.tom.spring.formework.annotation.GPRequestMapping;
import com.tom.spring.formework.context.GPApplicationContext;
import com.tom.spring.formework.webmvc.*;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//Servlet is only used as a startup entry for MVC
@Slf4j
public class GPDispatcherServlet extends HttpServlet {

    private  final String LOCATION = "contextConfigLocation";

    //Readers can think about the classics of this design
    //GPHandlerMapping is the core design and the most classic
    //It directly kills MVC frameworks such as Struts and Webwork
    private List<GPHandlerMapping> handlerMappings = new ArrayList<GPHandlerMapping>();

    private Map<GPHandlerMapping,GPHandlerAdapter> handlerAdapters = new HashMap<GPHandlerMapping, GPHandlerAdapter>();

    private List<GPViewResolver> viewResolvers = new ArrayList<GPViewResolver>();

    private GPApplicationContext context;

}

Implementation below init()Method, we mainly complete IoC Container initialization and Spring MVC Initialization of nine components.
    @Override
    public void init(ServletConfig config) throws ServletException {
        //This is equivalent to initializing the IoC container
        context = new GPApplicationContext(config.getInitParameter(LOCATION));
        initStrategies(context);
    }

    protected void initStrategies(GPApplicationContext context) {

        //There are nine strategies
        //For each user request, it will be processed by some processing strategies before the result can be output
        //Each strategy can customize the intervention, but the final results are consistent

        // =============Here is the legendary nine components================
        initMultipartResolver(context);//File upload parsing. If the request type is multipart, file upload parsing will be performed through MultipartResolver
        initLocaleResolver(context);//Localization resolution
        initThemeResolver(context);//Topic resolution

        /** We will achieve it ourselves */
        //GPHandlerMapping is used to save the correspondence between RequestMapping and Method configured in the Controller
        initHandlerMappings(context);//Mapping requests to processors through HandlerMapping
        /** We will achieve it ourselves */
        //HandlerAdapters are used to dynamically match Method parameters, including class conversion and dynamic assignment
        initHandlerAdapters(context);//Multi type parameter dynamic matching through HandlerAdapter

        initHandlerExceptionResolvers(context);//If an exception is encountered during execution, it will be handed over to the HandlerExceptionResolver for resolution
        initRequestToViewNameTranslator(context);//Resolve the request directly to the view name

        /** We will achieve it ourselves */
        //Dynamic template parsing through ViewResolvers
        //Analyze a set of template language by yourself
        initViewResolvers(context);//The logical view is parsed to the concrete view implementation through viewResolver

        initFlashMapManager(context);//Flash mapping manager
    }

    private void initFlashMapManager(GPApplicationContext context) {}
    private void initRequestToViewNameTranslator(GPApplicationContext context) {}
    private void initHandlerExceptionResolvers(GPApplicationContext context) {}
    private void initThemeResolver(GPApplicationContext context) {}
    private void initLocaleResolver(GPApplicationContext context) {}
    private void initMultipartResolver(GPApplicationContext context) {}

    //Make one-to-one correspondence between RequestMapping and Method configured in the Controller
    private void initHandlerMappings(GPApplicationContext context) {
        //According to our common understanding, it should be a Map
        //Map<String,Method> map;
        //map.put(url,Method)

        //First, get all the instances from the container
        String [] beanNames = context.getBeanDefinitionNames();
        try {
            for (String beanName : beanNames) {
                //In the MVC layer, there is only one getBean() method provided externally
                //What if the returned object is not a BeanWrapper?
                Object controller = context.getBean(beanName);
                //Object controller = GPAopUtils.getTargetObject(proxy);
                Class<?> clazz = controller.getClass();

                if (!clazz.isAnnotationPresent(GPController.class)) {
                    continue;
                }

                String baseUrl = "";

                if (clazz.isAnnotationPresent(GPRequestMapping.class)) {
                    GPRequestMapping requestMapping = clazz.getAnnotation(GPRequestMapping.class);
                    baseUrl = requestMapping.value();
                }

                //Scan all public type methods
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (!method.isAnnotationPresent(GPRequestMapping.class)) {
                        continue;
                    }

                    GPRequestMapping requestMapping = method.getAnnotation(GPRequestMapping.class);
                    String regex = ("/" + baseUrl + requestMapping.value().replaceAll("\\*", ".*")).replaceAll("/+", "/");
                    Pattern pattern = Pattern.compile(regex);
                    this.handlerMappings.add(new GPHandlerMapping(pattern, controller, method));
                    log.info("Mapping: " + regex + " , " + method);

                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void initHandlerAdapters(GPApplicationContext context) {
        //In the initialization phase, all we can do is save the names or types of these parameters in a certain order
        //Because when you call with reflection later, the formal parameter passed is an array
        //You can take values from the array one by one by recording the position index of these parameters, which is independent of the order of the parameters
        for (GPHandlerMapping handlerMapping : this.handlerMappings){
            //Each method has a parameter list. Here is the formal parameter list
            this.handlerAdapters.put(handlerMapping,new GPHandlerAdapter());
        }

    }

    private void initViewResolvers(GPApplicationContext context) {
        //Enter in the page http://localhost/first.html
        //Solve the problem of associating the page name with the template file
        String templateRoot = context.getConfig().getProperty("templateRoot");
        String templateRootPath = this.getClass().getClassLoader().getResource (templateRoot).getFile();

        File templateRootDir = new File(templateRootPath);

        for (File template : templateRootDir.listFiles()) {
            this.viewResolvers.add(new GPViewResolver(templateRoot));
        }

    }

In the above code, we only realize the basic functions of three core components among the nine components, namely HandlerMapping, HandlerAdapter and ViewResolver, to complete the most core scheduling function of MVC. HandlerMapping is the application of policy mode, which indirectly calls different methods with input URL to obtain results. As the name suggests, HandlerAdapter applies the adapter mode, which automatically adapts the character parameters of Request to the Java arguments of Method, and mainly realizes the functions of automatic adaptation of parameter list and type conversion. ViewResolver is also a strategy to select different template engines for page rendering according to different requests. Next, look at the service() Method, which is mainly responsible for receiving requests and obtaining Request and Response objects. In the Servlet subclass, the service() Method is split into doGet() Method and doPost() Method. We call the doPost() Method directly in the doGet() Method and invoke the doDispatch() Method in the doPost() Method, and the real calling logic is executed by doDispatch().

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            doDispatch(req, resp);
        }catch (Exception e){
            resp.getWriter().write("<font size='25' color='blue'>500 Exception</font><br/>Details: <br/>" + Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\]","")
                    .replaceAll("\\s","\r\n") +  "<font color='green'><i>Copyright@GupaoEDU </i></font>");
            e.printStackTrace();
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception{

        //Get a Handler based on the URL requested by the user
        GPHandlerMapping handler = getHandler(req);
        if(handler == null){
            processDispatchResult(req,resp,new GPModelAndView("404"));
            return;
        }

        GPHandlerAdapter ha = getHandlerAdapter(handler);

        //This step just calls the method to get the return value
        GPModelAndView mv = ha.handle(req, resp, handler);

        //This step is the real output
        processDispatchResult(req,resp, mv);

    }

    private void processDispatchResult(HttpServletRequest request,HttpServletResponse response, GPModelAndView mv) throws Exception {
        //Call the resolveViewName() method of viewResolver
        if(null == mv){ return;}

        if(this.viewResolvers.isEmpty()){ return;}

        if (this.viewResolvers != null) {
            for (GPViewResolver viewResolver : this.viewResolvers) {
                GPView view = viewResolver.resolveViewName(mv.getViewName(), null);
                if (view != null) {
                    view.render(mv.getModel(),request,response);
                    return;
                }
            }
        }

    }

    private GPHandlerAdapter getHandlerAdapter(GPHandlerMapping handler) {
        if(this.handlerAdapters.isEmpty()){return  null;}
        GPHandlerAdapter ha = this.handlerAdapters.get(handler);
        if (ha.supports(handler)) {
            return ha;
        }
        return null;
    }

    private GPHandlerMapping getHandler(HttpServletRequest req) {

        if(this.handlerMappings.isEmpty()){ return  null;}

        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replace(contextPath,"").replaceAll("/+","/");

        for (GPHandlerMapping handler : this.handlerMappings) {
            Matcher matcher = handler.getPattern().matcher(url);
            if(!matcher.matches()){ continue;}
            return handler;
        }

        return null;
}

GPDisptcherServlet's complete code, please pay attention to WeChat official account reply to "Spring". The following supplements the implementation of the missing dependency classes in the above code.

1.2 GPHandlerMapping

We already know that HandlerMapping is mainly used to save the correspondence between URL and Method. In fact, the policy mode is used here.

package com.tom.spring.formework.webmvc;

import java.lang.reflect.Method;
import java.util.regex.Pattern;

public class GPHandlerMapping {
    private Object controller; //The contraller object where the target method is located
    private Method method; //Target method corresponding to URL
    private Pattern pattern;  //Encapsulation of URL

    public GPHandlerMapping(Pattern pattern,Object controller, Method method) {
        this.controller = controller;
        this.method = method;
        this.pattern = pattern;
    }

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Pattern getPattern() {
        return pattern;
    }

    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }
}

1.3 GPHandlerAdapter

The HandlerAdapter of native Spring mainly completes the correspondence between the parameter list and the Method argument list passed from the request to the server, and completes the type conversion of parameter values. The core Method is handle(). In the handle() Method, reflection is used to call the adapted target Method, and the transformation wrapped parameter list is passed in the past.

package com.tom.spring.formework.webmvc;

import com.tom.spring.formework.annotation.GPRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

//Specially assigned person
public class GPHandlerAdapter {

    public boolean supports(Object handler){
        return (handler instanceof GPHandlerMapping);
    }

    public GPModelAndView handle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception{
        GPHandlerMapping handlerMapping = (GPHandlerMapping)handler;

        //Each method has a parameter list. Here is the formal parameter list
        Map<String,Integer> paramMapping = new HashMap<String, Integer>();

        //Here are only named parameters
        Annotation[][] pa = handlerMapping.getMethod().getParameterAnnotations();
        for (int i = 0; i < pa.length ; i ++) {
            for (Annotation a : pa[i]) {
                if(a instanceof GPRequestParam){
                    String paramName = ((GPRequestParam) a).value();
                    if(!"".equals(paramName.trim())){
                        paramMapping.put(paramName,i);
                    }
                }
            }
        }

        //Dynamically match the parameter information in the Method according to the parameter information requested by the user
        //resp is passed in for only one purpose: assign it to a method parameter, that's all

        //A default ModelAndView will be created only when the ModelAndView passed by the user is empty

        //1. Prepare the formal parameter list of this method
        //The determinants of formal parameters during method overloading: the number of parameters, the type of parameters, the order of parameters, and the name of the method
        //Only Request and Response are processed
        Class<?>[] paramTypes = handlerMapping.getMethod().getParameterTypes();
        for (int i = 0;i < paramTypes.length; i ++) {
            Class<?> type = paramTypes[i];
            if(type == HttpServletRequest.class ||
                    type == HttpServletResponse.class){
                paramMapping.put(type.getName(),i);
            }
        }



        //2. Get the location of the user-defined named parameter
        //Parameter list passed by user through URL
        Map<String,String[]> reqParameterMap = req.getParameterMap();

        //3. Construct argument list
        Object [] paramValues = new Object[paramTypes.length];

        for (Map.Entry<String,String[]> param : reqParameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]",""). replaceAll("\\s","");

            if(!paramMapping.containsKey(param.getKey())){continue;}

            int index = paramMapping.get(param.getKey());

            //Because the values passed from the page are of String type, and the types defined in the method are ever-changing
            //Therefore, we need to carry out type conversion for the parameters we pass
            paramValues[index] = caseStringValue(value,paramTypes[index]);
        }

        if(paramMapping.containsKey(HttpServletRequest.class.getName())) {
            int reqIndex = paramMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex] = req;
        }

        if(paramMapping.containsKey(HttpServletResponse.class.getName())) {
            int respIndex = paramMapping.get(HttpServletResponse.class.getName());
            paramValues[respIndex] = resp;
        }

        //4. Take out the Controller and Method from the handler, and then use the reflection mechanism to call

        Object result = handlerMapping.getMethod().invoke(handlerMapping.getController(), paramValues);

        if(result == null){ return  null; }

        boolean isModelAndView = handlerMapping.getMethod().getReturnType() == GPModelAndView.class;
        if(isModelAndView){
            return (GPModelAndView)result;
        }else{
            return null;
        }
    }

    private Object caseStringValue(String value,Class<?> clazz){
        if(clazz == String.class){
            return value;
        }else if(clazz == Integer.class){
            return  Integer.valueOf(value);
        }else if(clazz == int.class){
            return Integer.valueOf(value).intValue();
        }else {
            return null;
        }
    }

}

1.4 GPModelAndView

The ModelAndView class in the native Spring is mainly used to encapsulate the correspondence between the page template and the parameters to be transferred to the page.

package com.tom.spring.formework.webmvc;

import java.util.Map;

public class GPModelAndView {

    private String viewName; //The name of the page template
    private Map<String,?> model; //Parameters transferred to the page

    public GPModelAndView(String viewName) {
        this(viewName,null);
    }
    public GPModelAndView(String viewName, Map<String, ?> model) {
        this.viewName = viewName;
        this.model = model;
    }

    public String getViewName() {
        return viewName;
    }

    public void setViewName(String viewName) {
        this.viewName = viewName;
    }

    public Map<String, ?> getModel() {
        return model;
    }

    public void setModel(Map<String, ?> model) {
        this.model = model;
    }
}

1.5 GPViewResolver

ViewResolver in native Spring mainly completes the matching between template name and template resolution engine. The resolveViewName() method is invoked in Serlvet to get the View corresponding to the template. In this Mini version, the implementation is simplified, only a set of default template engine is implemented, and the syntax is completely customized.

package com.tom.spring.formework.webmvc;

import java.io.File;
import java.util.Locale;

//The main purpose of designing this class is:
//1. Change a static file into a dynamic file
//2. Different results will be generated according to different parameters transmitted by the user
//The final output string is given to the Response for output
public class GPViewResolver {
    private final String DEFAULT_TEMPLATE_SUFFIX = ".html";

    private File templateRootDir;
    private String viewName;

    public GPViewResolver(String templateRoot){
        String templateRootPath = this.getClass().getClassLoader().getResource(templateRoot). getFile();
        this.templateRootDir = new File(templateRootPath);
    }

    public GPView resolveViewName(String viewName, Locale locale) throws Exception {
        this.viewName = viewName;
        if(null == viewName || "".equals(viewName.trim())){ return null;}
        viewName = viewName.endsWith(DEFAULT_TEMPLATE_SUFFIX) ? viewName : (viewName + DEFAULT_TEMPLATE_SUFFIX);
        File templateFile = new File((templateRootDir.getPath() + "/" + viewName).replaceAll ("/+", "/"));
        return new GPView(templateFile);
    }

    public String getViewName() {
        return viewName;
    }
}

1.6 GPView

GPView here is the aforementioned custom template parsing engine, and its core method is render(). Complete the rendering of the template in the render() method, and finally return the string recognized by the browser and output it through the Response.

package com.tom.spring.formework.webmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.RandomAccessFile;
import java.util.Map;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GPView {

    public static final String DEFAULT_CONTENT_TYPE = "text/html;charset=utf-8";

    private File viewFile;

    public GPView(File viewFile){
        this.viewFile = viewFile;
    }

    public String getContentType(){
        return DEFAULT_CONTENT_TYPE;
    }

    public void render(Map<String, ?> model,HttpServletRequest request, HttpServletResponse response) throws Exception{
        StringBuffer sb = new StringBuffer();
        RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");


        try {
            String line = null;
            while (null != (line = ra.readLine())) {
                line = new String(line.getBytes("ISO-8859-1"),"utf-8");
                Pattern pattern = Pattern.compile("¥\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
                Matcher matcher = pattern.matcher(line);

                while (matcher.find()) {

                    String paramName = matcher.group();
                    paramName = paramName.replaceAll("¥\\{|\\}","");
                    Object paramValue = model.get(paramName);
                    if (null == paramValue) { continue; }
                    //Take out the string in the middle of ¥ {}
                    line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
                    matcher = pattern.matcher(line);

                }

                sb.append(line);
            }
        }finally {
            ra.close();
        }
        response.setCharacterEncoding("utf-8");
        //response.setContentType(DEFAULT_CONTENT_TYPE);
        response.getWriter().write(sb.toString());
    }

    //Handling special characters
    public static String makeStringForRegExp(String str) {
         return str.replace("\\", "\\\\").replace("*", "\\*")
        .replace("+", "\\+").replace("|", "\\|")
        .replace("{", "\\{").replace("}", "\\}")
        .replace("(", "\\(").replace(")", "\\)")
        .replace("^", "\\^").replace("$", "\\$")
        .replace("[", "\\[").replace("]", "\\]")
        .replace("?", "\\?").replace(",", "\\,")
        .replace(".", "\\.").replace("&", "\\&");
    }

}

As can be seen from the above code, GPView renders pages based on HTML files. However, some custom syntax is added. For example, if an expression such as ¥ {name} is scanned in the template page, the value corresponding to name will be found in the Model of ModelAndView and replaced with a regular expression (foreigners like to use the dollar symbol $, our template engine uses the RMB symbol ¥).

2. Business code implementation

2.1 IQueryService

Define a top-level interface IQueryService responsible for query business, and provide a query() method:

package com.tom.spring.demo.service;

/**
 * Query service
 *
 */
public interface IQueryService  {

   /**
    * query
    */
   public String query(String name);
	 
}

2.2 QueryService

The implementation of QueryService is also very simple, that is, print the call time and the passed in parameters, encapsulate them and return them in JSON format:

package com.tom.spring.demo.service.impl;

import java.text.SimpleDateFormat;
import java.util.Date;

import com.tom.spring.demo.service.IQueryService;
import com.tom.spring.formework.annotation.GPService;
import lombok.extern.slf4j.Slf4j;

/**
 * Query service
 *
 */
@GPService
@Slf4j
public class QueryService implements IQueryService {

   /**
    * query
    */
   public String query(String name) {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      String time = sdf.format(new Date());
      String json = "{name:\"" + name + "\",time:\"" + time + "\"}";
      log.info("This is printed in the business method:" + json);
      return json;
   }

}

2.3 IModifyService

Define a top-level interface IModifyService for adding, deleting and modifying businesses:


package com.tom.spring.demo.service;
/**
 * Add, delete and modify business
 */
public interface IModifyService {
   /**
    * increase
    */
   public String add(String name, String addr) ;
   /**
    * modify
    */
   public String edit(Integer id, String name);
   /**
    * delete
    */
   public String remove(Integer id);
	 
}

2.4 ModifyService

The implementation of ModifyService for adding, deleting and modifying businesses is also very simple. It mainly prints the parameters transmitted:

package com.tom.spring.demo.service.impl;
import com.tom.spring.demo.service.IModifyService;
import com.tom.spring.formework.annotation.GPService;

/**
 * Add, delete and modify business
 */
@GPService
public class ModifyService implements IModifyService {
   /**
    * increase
    */
   public String add(String name,String addr) {
      return "modifyService add,name=" + name + ",addr=" + addr;
   }
   /**
    * modify
    */
   public String edit(Integer id,String name) {
      return "modifyService edit,id=" + id + ",name=" + name;
   }
   /**
    * delete
    */
   public String remove(Integer id) {
      return "modifyService id=" + id;
   }
}

2.5 MyAction

The main function of the Controller is to be responsible for scheduling without business implementation. The business implementation methods are all in the Service layer. Generally, we will inject the Service instance into the Controller. MyAction mainly implements the scheduling of IQueryService and IModifyService, and uniformly returns the results:


package com.tom.spring.demo.action;

import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tom.spring.demo.service.IModifyService;
import com.tom.spring.demo.service.IQueryService;
import com.tom.spring.formework.annotation.GPAutowired;
import com.tom.spring.formework.annotation.GPController;
import com.tom.spring.formework.annotation.GPRequestMapping;
import com.tom.spring.formework.annotation.GPRequestParam;
import com.tom.spring.formework.webmvc.GPModelAndView;

/**
 * Publish interface URL
 */
@GPController
@GPRequestMapping("/web")
public class MyAction {

   @GPAutowired IQueryService queryService;
   @GPAutowired IModifyService modifyService;

   @GPRequestMapping("/query.json")
   public GPModelAndView query(HttpServletRequest request, HttpServletResponse response,
                        @GPRequestParam("name") String name){
      String result = queryService.query(name);
      return out(response,result);
   }
   @GPRequestMapping("/add*.json")
   public GPModelAndView add(HttpServletRequest request,HttpServletResponse response,
            @GPRequestParam("name") String name,@GPRequestParam("addr") String addr){
      String result = modifyService.add(name,addr);
      return out(response,result);
   }
   @GPRequestMapping("/remove.json")
   public GPModelAndView remove(HttpServletRequest request,HttpServletResponse response,
         @GPRequestParam("id") Integer id){
      String result = modifyService.remove(id);
      return out(response,result);
   }
   @GPRequestMapping("/edit.json")
   public GPModelAndView edit(HttpServletRequest request,HttpServletResponse response,
         @GPRequestParam("id") Integer id,
         @GPRequestParam("name") String name){
      String result = modifyService.edit(id,name);
      return out(response,result);
   }
   
   private GPModelAndView out(HttpServletResponse resp,String str){
      try {
         resp.getWriter().write(str);
      } catch (IOException e) {
         e.printStackTrace();
      }
      return null;
   }
}

2.6 PageAction

PageAction is specially designed to demonstrate the Mini version of Spring's support for the template engine, transfer parameters from the Controller layer to the View layer, and finally output the rendering of the template:

package com.tom.spring.demo.action;

import java.util.HashMap;
import java.util.Map;
import com.tom.spring.demo.service.IQueryService;
import com.tom.spring.formework.annotation.GPAutowired;
import com.tom.spring.formework.annotation.GPController;
import com.tom.spring.formework.annotation.GPRequestMapping;
import com.tom.spring.formework.annotation.GPRequestParam;
import com.tom.spring.formework.webmvc.GPModelAndView;

/**
 * Publish interface URL
 */
@GPController
@GPRequestMapping("/")
public class PageAction {

   @GPAutowired IQueryService queryService;

   @GPRequestMapping("/first.html")
   public GPModelAndView query(@GPRequestParam("teacher") String teacher){
      String result = queryService.query(teacher);
      Map<String,Object> model = new HashMap<String,Object>();
      model.put("teacher", teacher);
      model.put("data", result);
      model.put("token", "123456");
      return new GPModelAndView("first.html",model);
   }

}

3 customized template page

In order to more fully demonstrate the page rendering effect, first. 0 is defined respectively HTML corresponds to first in PageAction HTML request, 404 HTML default page and 500 HTML exception default page.

3.1 first.html

first.html is defined as follows:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
   <meta charset="utf-8">
   <title>SpringMVC Template engine demo</title>
</head>
<center>
   <h1>Hello, I'm¥{teacher}teacher<br/>Welcome to explore together Spring The world of</h1>
   <h3>Hello,My name is ¥{teacher}</h3>
   <div>¥{data}</div>
   Token Value:¥{token}
</center>
</html>

3.2 404.html

404.html is defined as follows:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>I went to Mars</title>
</head>
<body>
    <font size='25' color='red'>404 Not Found</font><br/><font color='green'><i>Copyright @GupaoEDU</i></font>
</body>
</html>

3.3 500.html

500.html is defined as follows:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <title>The server seems tired</title>
</head>
<body>
    <font size='25' color='blue'>500 The server seems a little tired and needs a rest</font><br/>
    <b>Message:¥{detail}</b><br/>
    <b>StackTrace:¥{stackTrace}</b><br/>
    <font color='green'><i>Copyright@GupaoEDU</i></font>
</body>
</html>

4. Operation effect demonstration

Enter in the browser http://localhost/web/query.json?name=Tom , it will be mapped to the query() method corresponding to @ GPRequestMapping("query.json") in MyAction, and the results are as shown in the following figure.

Enter in the browser http://localhost/web/addTom.json?name=tom&addr=HunanChangsha , it will be mapped to the add() method corresponding to @ GPRequestMapping("add*.json") in MyAction, and the results are as shown in the following figure.

Enter in the browser http://localhost/web/remove.json?id=66 , it will be mapped to the remove() method corresponding to @ GPRequestMapping("remove.json") in MyAction, and the id will be automatically converted to int type to get the result as shown in the following figure.

Enter in the browser http://localhost/web/edit.json?id=666&name=Tom , it will be mapped to the edit() method corresponding to @ GPRequestMapping("edit.json") in MyAction, and the id will be automatically converted to int type to get the result as shown in the following figure.

Enter in the browser http://localhost/first.html?teacher=Tom , it will be mapped to the query() method corresponding to @ GPRequestMapping("first.html") in PageAction, and the results are as shown in the following figure.

So far, the complete functions of spring from IoC, ID to MVC have been realized. Although some details have been ignored, we have learned that the core design idea of spring is not as mysterious as we thought. We have skillfully used factory mode, static agent mode, adapter mode, template mode, policy mode, delegation mode and so on, making the code very elegant. Pay attention to WeChat official account Tom bomb structure and reply to "Spring" to get the complete source code.

This article is the original of "Tom bomb architecture". Please indicate the source for reprint. Technology lies in sharing, I share my happiness!
If this article is helpful to you, you are welcome to pay attention and praise; If you have any suggestions, you can also leave comments or private letters. Your support is the driving force for me to adhere to my creation. Focus on WeChat official account Tom structure, get more dry cargo!

It's not easy to be original. It's cool to insist. I've seen it here. Little partners remember to like, collect and watch it. Pay attention to it three times a button! If you think the content is too dry, you can share and forward it to your friends!

Added by Drezek on Mon, 13 Dec 2021 13:03:04 +0200