日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

環(huán)境:Spring5.3.23


概述

通過(guò)Spring定義請(qǐng)求接口非常容器,通過(guò)幾個(gè)注解就可以完成,如下:

@RestController
@RequestMApping("/demos")
public class DemoController {
  @GetMapping("/index")
  public Object index() {
    return "index" ;
  }
}

通過(guò)上面的@RestController, @RequestMapping就完成了一個(gè)簡(jiǎn)單的接口定義。

實(shí)際Spring Web底層是做了很多的工作,其核心組件有HandlerMappingHandlerAdapterViewResolver等組件。

  1. HandlerMapping
    根據(jù)當(dāng)前請(qǐng)求的URI,查找對(duì)應(yīng)的Handler,如:HandlerExecutionChain,包裝的HandlerMethod
  2. HandlerAdapter
    根據(jù)上面的確定的HandlerMethod, 找到能夠處理該Handler的Adapter,進(jìn)行調(diào)用
  3. ViewResolver
    如果返回的ModelAndView對(duì)象那么會(huì)通過(guò)相應(yīng)的ViewResolver進(jìn)行渲染輸出

了解了上面的幾個(gè)核心組件之后,接下來(lái)就是自定義實(shí)現(xiàn)上面的核心類,來(lái)完成接口的請(qǐng)求處理。

自定義Endpoint

自定義注解,標(biāo)記Controller類及請(qǐng)求參數(shù)

 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface PackEndpoint {
 }

參數(shù)標(biāo)記,用來(lái)對(duì)接口參數(shù)進(jìn)行注解

 @Target(ElementType.PARAMETER)
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface PackParam {
 }

Endpoint接口參數(shù)封裝對(duì)象

該對(duì)象用來(lái)保存記錄,方法參數(shù)由@PackParam注解的參數(shù)

public class PackMethodParameter {

  // 用來(lái)解析接口參數(shù)的名稱
  private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer() ;
  private String name ;
  private Executable executable ;
  private int parameterIndex ;
  private Class<?> type ;
  
  public PackMethodParameter(String name, int parameterIndex, Executable executable) {
    this.name = name;
    this.parameterIndex = parameterIndex ;
    this.executable = executable ;
  }
  
  public PackMethodParameter(int parameterIndex, Executable executable, Class<?> type) {
    this.parameterIndex = parameterIndex ;
    this.executable = executable ;
    this.type = type ;
  }
  
  public boolean hasParameterAnnotation(Class<? extends Annotation> clazz) {
    Method method = (Method) this.executable ;
    Parameter[] parameters = method.getParameters() ;
    return parameters[this.parameterIndex].isAnnotationPresent(clazz) ;
  }
  
  public String getParameterName() {
    String[] parameterNames = parameterNameDiscoverer.getParameterNames((Method) this.executable) ;
    return parameterNames[this.parameterIndex] ;
  }
  
}

自定義HandlerMapping

自定義實(shí)現(xiàn)了SpringMVC標(biāo)準(zhǔn)的HandlerMapping,這樣在DispatcherServlet中才能夠識(shí)別。

public class PackHandlerMapping implements HandlerMapping, InitializingBean, ApplicationContextAware {

  private ApplicationContext context;
  private Map<String, PackMethodHandler> mapping = new HashMap<>();

  @Override
  public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    String requestPath = request.getRequestURI();
    Optional<PackMethodHandler> opt = mapping.entrySet().stream().filter(entry -> entry.getKey().equals(requestPath)).findFirst()
        .map(Map.Entry::getValue);
    if (opt.isPresent()) {
      HandlerExecutionChain executionChain = new HandlerExecutionChain(opt.get()) ;
      return executionChain ;
    }
    return null;
  }

  // Bean初始化時(shí),從容器中查找所有符合條件的Bean對(duì)象,即Bean對(duì)象上有@PackEndpoint注解
  @Override
  public void afterPropertiesSet() throws Exception {
    String[] beanNames = context.getBeanNamesForType(Object.class) ;
    for (String beanName : beanNames) {
      Object bean = this.context.getBean(beanName) ;
      Class<?> clazz = bean.getClass() ;
      // 判斷當(dāng)前的Bean上是否有PackEndpoint注解,只對(duì)有該注解的類進(jìn)行處理
      if (clazz.getAnnotation(PackEndpoint.class) != null) {
        RequestMapping clazzMapping = clazz.getAnnotation(RequestMapping.class) ;
        String rootPath = clazzMapping.value()[0] ;
        if (clazzMapping != null) {
          ReflectionUtils.doWithMethods(clazz, method -> {
            RequestMapping nestMapping = AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class) ;
            if (nestMapping != null) {
              String nestPath = nestMapping.value()[0] ;
              String path = rootPath + nestPath ;
              PackMethodHandler handler = new PackMethodHandler(method, bean) ;
              mapping.put(path, handler) ;
            }
          }) ;
        }
      }
    }
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.context = applicationContext;
  }

  // 該類的作用:用來(lái)記錄接口對(duì)應(yīng)的信息,方法,對(duì)應(yīng)的實(shí)例,參數(shù)信息
  public static class PackMethodHandler {
    private Method method;
    private Object instance;
    private PackMethodParameter[] parameters ;
    public Method getMethod() {
      return method;
    }
    public void setMethod(Method method) {
      this.method = method;
    }
    public Object getInstance() {
      return instance;
    }
    public void setInstance(Object instance) {
      this.instance = instance;
    }
    public PackMethodHandler(Method method, Object instance) {
      super();
      this.method = method;
      this.instance = instance;
      Parameter[] params = method.getParameters() ;
      this.parameters = new PackMethodParameter[params.length] ;
      for (int i = 0; i < params.length; i++) {
        this.parameters[i] = new PackMethodParameter(i, method, params[i].getType()) ;
      }
    }
    public PackMethodParameter[] getParameter() {
      return this.parameters ;
    }
  }
}

自定義參數(shù)解析器

專門用來(lái)解析處理接口方法中的參數(shù)信息然后從請(qǐng)求中讀取。

public interface PackHandlerMethodArgumentResolver {

  boolean supportsParameter(PackMethodParameter methodParameter) ;
  
  Object resolveArgument(PackMethodParameter methodParameter, HttpServletRequest request);
  
}
public class PackParamHandlerMethodArgumentResolver implements PackHandlerMethodArgumentResolver {

  @Override
  public boolean supportsParameter(PackMethodParameter methodParameter) {
    return methodParameter.hasParameterAnnotation(PackParam.class) ;
  }

  @Override
  public Object resolveArgument(PackMethodParameter methodParameter, HttpServletRequest request) {
    String name = methodParameter.getParameterName() ;
    Object arg = null;
    String[] parameterValues = request.getParameterValues(name) ;
    if (parameterValues != null) {
      arg = parameterValues.length == 1 ? parameterValues[0] : parameterValues ;
    }
    return arg ;
  }

}

自定義HandlerAdapter

自定義實(shí)現(xiàn)了SpringMVC標(biāo)準(zhǔn)的HandlerAdatper,這樣在DispatcherServlet中才能夠識(shí)別。

public class PackHandlerAdapter implements HandlerAdapter{
  
  @Resource
  private ConversionService conversionService ;

  private PackParamHandlerMethodArgumentResolver argumentResolver = new PackParamHandlerMethodArgumentResolver() ;
  
  @Override
  public boolean supports(Object handler) {
    return handler instanceof PackMethodHandler;
  }

  @Override
  public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    PackMethodHandler methodHandler = (PackMethodHandler) handler ;
    
    PackMethodParameter[] parameters = methodHandler.getParameter() ;
    Object[] args = new Object[parameters.length] ;
    for (int i = 0; i < args.length; i++) {
      if (this.argumentResolver.supportsParameter(parameters[i])) {
        // 解析對(duì)應(yīng)的方法參數(shù)
        args[i] = this.argumentResolver.resolveArgument(parameters[i], request) ;
        // 類型轉(zhuǎn)換
        args[i] = this.conversionService.convert(args[i], parameters[i].getType()) ;
      }
    }
    // 調(diào)用目標(biāo)方法
    Object result = methodHandler.getMethod().invoke(methodHandler.getInstance(), args) ;
    // 設(shè)置響應(yīng)header,輸出內(nèi)容
    response.setHeader("Content-Type", "text/plain;charset=utf8") ;
    PrintWriter out = response.getWriter() ;
    out.write((String) result) ;
    out.flush() ;
    out.close() ; 
    return null ;
  }

  @Override
  public long getLastModified(HttpServletRequest request, Object handler) {
    return -1 ;
  }

}

通過(guò)以上的步驟就完成了一個(gè)完全自定義SpringMVC核心組件的實(shí)現(xiàn)。

在下一篇中我們將介紹如何將上面的代碼跑到一個(gè)嵌入式的Tomcat中,敬請(qǐng)期待。

分享到:
標(biāo)簽:SpringMVC
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定