亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

寫(xiě)簡(jiǎn)單的mvc框架實(shí)例講解

 更新時(shí)間:2019年02月13日 16:27:23   投稿:laozhang  
在本篇內(nèi)容中教給大家寫(xiě)一個(gè)簡(jiǎn)單的mvc框架步驟以及相關(guān)知識(shí)點(diǎn),有需要的朋友們學(xué)習(xí)下。

這一章先把支持注解的功能加上,這樣就不需要經(jīng)常地修改配置文件了。

至于視圖處理的地方,就還是先用json吧,找時(shí)間再寫(xiě)。

項(xiàng)目地址在:https://github.com/hjx601496320/aMvc 。

測(cè)試代碼在:https://github.com/hjx601496320/amvc-test 。

怎么寫(xiě)呢?

因?yàn)樵谥皩?xiě)代碼的時(shí)候,我把每個(gè)類(lèi)要做的事情分的比較清楚,所以在添加這個(gè)功能的時(shí)候?qū)懫饋?lái)還是比較簡(jiǎn)單的,需要修改的地方也比較小。

這一章里我們需要干的事情有:

  • 定義一個(gè)注解,標(biāo)識(shí)某一個(gè)class中的被添加注解的方法是一個(gè)UrlMethodMapping。
  • 修改配置文件,添加需要掃描的package。
  • 寫(xiě)一個(gè)方法,根據(jù)package中值找到其中所有的class。
  • 在UrlMethodMapping的工廠類(lèi)UrlMethodMappingFactory中新加一個(gè)根據(jù)注解創(chuàng)建UrlMethodMapping的方法。
  • 在Application中的init()方法中,根據(jù)是否開(kāi)啟注解支持,執(zhí)行新的工廠類(lèi)方法。
  • 完了。

多么簡(jiǎn)單呀~~~

現(xiàn)在開(kāi)始寫(xiě)

定義一個(gè)注解Request

關(guān)于怎樣自定義注這件事,大家可以上網(wǎng)搜一下,比較簡(jiǎn)單。我這里只是簡(jiǎn)單的說(shuō)一下。我先把代碼貼出來(lái):

import com.hebaibai.amvc.RequestType;
import java.lang.annotation.*;

/**
 * 表示這個(gè)類(lèi)中的,添加了@Request注解的method被映射為一個(gè)http地址。
 *
 * @author hjx
 */
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Request {

  /**
   * 請(qǐng)求類(lèi)型
   * 支持GET,POST,DELETE,PUT
   *
   * @return
   */
  RequestType[] type() default {RequestType.GET, RequestType.POST, RequestType.DELETE, RequestType.PUT};

  /**
   * 請(qǐng)求地址
   * 添加在class上時(shí),會(huì)將value中的值添加在其他方法上的@Request.value()的值前,作為基礎(chǔ)地址。
   *
   * @return
   */
  String value() default "/";
}

定義一個(gè)注解,需要用到一下幾個(gè)東西:

1:@interface:說(shuō)明這個(gè)類(lèi)是一個(gè)注解。

2:@Retention:注解的保留策略,有這么幾個(gè)取值范圍:

代碼 說(shuō)明
@Retention(RetentionPolicy.SOURCE) 注解僅存在于源碼中
@Retention(RetentionPolicy.CLASS) 注解會(huì)在class字節(jié)碼文件中存在
@Retention(RetentionPolicy.RUNTIME) 注解會(huì)在class字節(jié)碼文件中存在,運(yùn)行時(shí)可以通過(guò)反射獲取到

因?yàn)槲覀冊(cè)诔绦蛑行枰〉阶远x的注解,所以使用:RetentionPolicy.RUNTIME。

3:@Target:作用目標(biāo),表示注解可以添加在什么地方,取值范圍有:

代碼 說(shuō)明
@Target(ElementType.TYPE) 接口、類(lèi)、枚舉、注解
@Target(ElementType.FIELD) 字段、枚舉的常量
@Target(ElementType.METHOD) 方法
@Target(ElementType.PARAMETER) 方法參數(shù)
@Target(ElementType.CONSTRUCTOR) 構(gòu)造函數(shù)
@Target(ElementType.LOCAL_VARIABLE) 局部變量
@Target(ElementType.ANNOTATION_TYPE) 注解
@Target(ElementType.PACKAGE)

3:@Documented:這個(gè)主要是讓自定義注解保留在文檔中,沒(méi)啥實(shí)際意義,一般都給加上。

4:default:是給注解中的屬性(看起來(lái)像是一個(gè)方法,也可能就是一個(gè)方法,但是我就是叫屬性,略略略~~~)一個(gè)默認(rèn)值。

上面大致上講了一下怎么定義一個(gè)注解,現(xiàn)在注解寫(xiě)完了,講一下這個(gè)注解的用處吧。

首先這個(gè)注解可以加在class和method上。加在class上的時(shí)候表示這個(gè)類(lèi)中會(huì)有method將要被處理成為一個(gè)UrlMethodMapping,然后其中的value屬性將作為這個(gè)class中所有UrlMethodMapping的基礎(chǔ)地址,type屬性不起作用。加在method上的時(shí)候,就是說(shuō)明這個(gè)method將被處理成一個(gè)UrlMethodMapping,注解的兩個(gè)屬性發(fā)揮其正常的作用。

注解寫(xiě)完了,下面把配置文件改一改吧。

修改框架的配置文件

只需要添加一個(gè)屬性就好了,修改完的配置文件這個(gè)樣子:

{
 "annotationSupport": true,
 "annotationPackage": "com.hebaibai.demo.web",
// "mapping": [
//  {
//   "url": "/index",
//   "requestType": [
//    "get"
//   ],
//   "method": "index",
//   "objectClass": "com.hebaibai.demo.web.IndexController",
//   "paramTypes": [
//    "java.lang.String",
//    "int"
//   ]
//  }
// ]
}

1:annotationSupport 值是true的時(shí)候表示開(kāi)啟注解。

2:annotationPackage 表示需要掃描的包的路徑。

3:因?yàn)殚_(kāi)了注解支持,為了防止重復(fù)注冊(cè) UrlMethodMapping,所以我把下面的配置注釋掉了。

寫(xiě)一個(gè)包掃描的方法

這個(gè)方法需要將項(xiàng)目中jar文件和文件夾下所有符合條件的class找到,會(huì)用到遞歸,代碼在ClassUtils.java中,由三個(gè)方法構(gòu)成,分別是:

1:void getClassByPackage(String packageName, Set

這個(gè)方法接收兩個(gè)參數(shù),一個(gè)是包名packageName,一個(gè)是一個(gè)空的Set(不是null),在方法執(zhí)行完畢會(huì)將包下的所有class填充進(jìn)Set中。這里主要是判斷了一下這個(gè)包中有那些類(lèi)型的文件,并根據(jù)文件類(lèi)型分別處理。

注意:如果是jar文件的類(lèi)型,獲取到的filePath是這樣的:

file:/home/hjx/idea-IU/lib/idea_rt.jar!/com

需要去掉頭和尾,然后就可以吃了,雞肉味!嘎嘣脆~~ 處理之后的是這個(gè)樣子:

/home/hjx/idea-IU/lib/idea_rt.jar

下面是方法代碼:

/**
 * 從給定的報(bào)名中找出所有的class
 *
 * @param packageName
 * @param classes
 */
@SneakyThrows({IOException.class})
public static void getClassByPackage(String packageName, Set<Class> classes) {
  Assert.notNull(classes);
  String packagePath = packageName.replace(DOT, SLASH);
  Enumeration<URL> resources = ClassUtils.getClassLoader().getResources(packagePath);
  while (resources.hasMoreElements()) {
    URL url = resources.nextElement();
    //文件類(lèi)型
    String protocol = url.getProtocol();
    String filePath = URLDecoder.decode(url.getFile(), CHARSET_UTF_8);
    if (TYPE_FILE.equals(protocol)) {
      getClassByFilePath(packageName, filePath, classes);
    }
    if (TYPE_JAR.equals(protocol)) {
      //截取文件的路徑
      filePath = filePath.substring(filePath.indexOf(":") + 1, filePath.indexOf("!"));
      getClassByJarPath(packageName, filePath, classes);
    }
  }
}

2:void getClassByFilePath(String packageName, String filePath, Set

將文件夾中的全部符合條件的class找到,用到遞歸。需要將class文件的絕對(duì)路徑截取成class的全限定名,代碼這個(gè)樣子:

/**
 * 在文件夾中遞歸找出該文件夾中在package中的class
 *
 * @param packageName
 * @param filePath
 * @param classes
 */
static void getClassByFilePath(
  String packageName,
  String filePath,
  Set<Class> classes
) {
  File targetFile = new File(filePath);
  if (!targetFile.exists()) {
    return;
  }
  if (targetFile.isDirectory()) {
    File[] files = targetFile.listFiles();
    for (File file : files) {
      String path = file.getPath();
      getClassByFilePath(packageName, path, classes);
    }
  } else {
    //如果是一個(gè)class文件
    boolean trueClass = filePath.endsWith(CLASS_MARK);
    if (trueClass) {
      //提取完整的類(lèi)名
      filePath = filePath.replace(SLASH, DOT);
      int i = filePath.indexOf(packageName);
      String className = filePath.substring(i, filePath.length() - 6);
      //不是一個(gè)內(nèi)部類(lèi)
      boolean notInnerClass = className.indexOf("$") == -1;
      if (notInnerClass) {
        //根據(jù)類(lèi)名加載class對(duì)象
        Class aClass = ClassUtils.forName(className);
        if (aClass != null) {
          classes.add(aClass);
        }
      }
    }
  }
}

3:void getClassByJarPath(String packageName, String filePath, Set

將jar文件中的全部符合條件的class找到。沒(méi)啥說(shuō)的,下面是代碼:

/**
 * 在jar文件中找出該文件夾中在package中的class
 *
 * @param packageName
 * @param filePath
 * @param classes
 */
@SneakyThrows({IOException.class})
static void getClassByJarPath(
  String packageName,
  String filePath,
  Set<Class> classes
) {
  JarFile jarFile = new URLJarFile(new File(filePath));
  Enumeration<JarEntry> entries = jarFile.entries();
  while (entries.hasMoreElements()) {
    JarEntry jarEntry = entries.nextElement();
    String jarEntryName = jarEntry.getName().replace(SLASH, DOT);
    //在package下的class
    boolean trueClass = jarEntryName.endsWith(CLASS_MARK) && jarEntryName.startsWith(packageName);
    //不是一個(gè)內(nèi)部類(lèi)
    boolean notInnerClass = jarEntryName.indexOf("$") == -1;
    if (trueClass && notInnerClass) {
      String className = jarEntryName.substring(0, jarEntryName.length() - 6);
      System.out.println(className);
      //根據(jù)類(lèi)名加載class對(duì)象
      Class aClass = ClassUtils.forName(className);
      if (aClass != null) {
        classes.add(aClass);
      }
    }
  }
}

這樣,獲取包名下的class就寫(xiě)完了~

修改UrlMethodMappingFactory

這里新添加一個(gè)方法:

List,將掃描包之后獲取到的Class對(duì)象作為參數(shù),返回一個(gè)UrlMethodMapping集合就好了。代碼如下:

/**
 * 通過(guò)解析Class 獲取映射
 *
 * @param aClass
 * @return
 */
public List<UrlMethodMapping> getUrlMethodMappingListByClass(Class<Request> aClass) {
  List<UrlMethodMapping> mappings = new ArrayList<>();
  Request request = aClass.getDeclaredAnnotation(Request.class);
  if (request == null) {
    return mappings;
  }
  String basePath = request.value();
  for (Method classMethod : aClass.getDeclaredMethods()) {
    UrlMethodMapping urlMethodMapping = getUrlMethodMappingListByMethod(classMethod);
    if (urlMethodMapping == null) {
      continue;
    }
    //將添加在class上的Request中的path作為基礎(chǔ)路徑
    String url = UrlUtils.makeUrl(basePath + "/" + urlMethodMapping.getUrl());
    urlMethodMapping.setUrl(url);
    mappings.add(urlMethodMapping);
  }
  return mappings;
}

/**
 * 通過(guò)解析Method 獲取映射
 * 注解Request不存在時(shí)跳出
 *
 * @param method
 * @return
 */
private UrlMethodMapping getUrlMethodMappingListByMethod(Method method) {
  Request request = method.getDeclaredAnnotation(Request.class);
  if (request == null) {
    return null;
  }
  Class<?> declaringClass = method.getDeclaringClass();
  String path = request.value();
  for (char c : path.toCharArray()) {
    Assert.isTrue(c != ' ', declaringClass + "." + method.getName() + "請(qǐng)求路徑異常:" + path + " !");
  }
  return getUrlMethodMapping(
      path,
      request.type(),
      declaringClass,
      method,
      method.getParameterTypes()
  );
}

在這里校驗(yàn)了一下注解Request中的value的值,如果中間有空格的話(huà)會(huì)拋出異常。UrlUtils.makeUrl() 這個(gè)方法主要是將url中的多余”/”去掉,代碼長(zhǎng)這個(gè)樣子:

private static final String SLASH = "/";

/**
 * 處理url
 * 1:去掉連接中相鄰并重復(fù)的“/”,
 * 2:鏈接開(kāi)頭沒(méi)有“/”,則添加。
 * 3:鏈接結(jié)尾有“/”,則去掉。
 *
 * @param url
 * @return
 */
public static String makeUrl(@NonNull String url) {
  char[] chars = url.toCharArray();
  StringBuilder newUrl = new StringBuilder();
  if (!url.startsWith(SLASH)) {
    newUrl.append(SLASH);
  }
  for (int i = 0; i < chars.length; i++) {
    if (i != 0 && chars[i] == chars[i - 1] && chars[i] == '/') {
      continue;
    }
    if (i == chars.length - 1 && chars[i] == '/') {
      continue;
    }
    newUrl.append(chars[i]);
  }
  return newUrl.toString();
}

這樣通過(guò)注解獲取UrlMethodMapping的工廠方法就寫(xiě)完了,下面開(kāi)始修改加載框架的代碼。

修改Application中的init

這里因?yàn)樘砑恿艘环N使用注解方式獲取UrlMethodMapping的方法,所以新建一個(gè)方法:

void addApplicationUrlMappingByAnnotationConfig(JSONObject configJson) 。在這里獲取框架配置中的包名以及做一些配置上的校驗(yàn),代碼如下:

/**
 * 使用注解來(lái)加載UrlMethodMapping
 *
 * @param configJson
 */
private void addApplicationUrlMappingByAnnotationConfig(JSONObject configJson) {
  String annotationPackage = configJson.getString(ANNOTATION_PACKAGE_NODE);
  Assert.notNull(annotationPackage, ANNOTATION_PACKAGE_NODE + NOT_FIND);
  //獲取添加了@Request的類(lèi)
  Set<Class> classes = new HashSet<>();
  ClassUtils.getClassByPackage(annotationPackage, classes);
  Iterator<Class> iterator = classes.iterator();
  while (iterator.hasNext()) {
    Class aClass = iterator.next();
    List<UrlMethodMapping> mappings = urlMethodMappingFactory.getUrlMethodMappingListByClass(aClass);
    if (mappings.size() == 0) {
      continue;
    }
    for (UrlMethodMapping mapping : mappings) {
      addApplicationUrlMapping(mapping);
    }
  }
}

之后把先前寫(xiě)的讀取json配置生成urlMappin的代碼摘出來(lái),單獨(dú)寫(xiě)一個(gè)方法:

void addApplicationUrlMappingByJsonConfig(JSONObject configJson),這樣使代碼中的每個(gè)方法的功能都獨(dú)立出來(lái),看起來(lái)比較整潔,清楚。代碼如下:

/**
 * 使用文件配置來(lái)加載UrlMethodMapping
 * 配置中找不到的話(huà)不執(zhí)行。
 *
 * @param configJson
 */
private void addApplicationUrlMappingByJsonConfig(JSONObject configJson) {
  JSONArray jsonArray = configJson.getJSONArray(MAPPING_NODE);
  if (jsonArray == null || jsonArray.size() == 0) {
    return;
  }
  for (int i = 0; i < jsonArray.size(); i++) {
    UrlMethodMapping mapping = urlMethodMappingFactory.getUrlMethodMappingByJson(jsonArray.getJSONObject(i));
    addApplicationUrlMapping(mapping);
  }
}

最后只要吧init()稍微修改一下就好了,修改完之后是這樣的:

/**
 * 初始化配置
 */
@SneakyThrows(IOException.class)
protected void init() {
  String configFileName = applicationName + ".json";
  InputStream inputStream = ClassUtils.getClassLoader().getResourceAsStream(configFileName);
  byte[] bytes = new byte[inputStream.available()];
  inputStream.read(bytes);
  String config = new String(bytes, "utf-8");
  //應(yīng)用配置
  JSONObject configJson = JSONObject.parseObject(config);

  //TODO:生成對(duì)象的工廠類(lèi)(先默認(rèn)為每次都new一個(gè)新的對(duì)象)
  this.objectFactory = new AlwaysNewObjectFactory();
  //TODO:不同的入?yún)⒚Q(chēng)獲取類(lèi)(當(dāng)前默認(rèn)為asm)
  urlMethodMappingFactory.setParamNameGetter(new AsmParamNameGetter());
  //通過(guò)文件配置加載
  addApplicationUrlMappingByJsonConfig(configJson);
  //是否開(kāi)啟注解支持
  Boolean annotationSupport = configJson.getBoolean(ANNOTATION_SUPPORT_NODE);
  Assert.notNull(annotationSupport, ANNOTATION_SUPPORT_NODE + NOT_FIND);
  if (annotationSupport) {
    addApplicationUrlMappingByAnnotationConfig(configJson);
  }
}

相關(guān)文章

  • webapi中如何使用依賴(lài)注入

    webapi中如何使用依賴(lài)注入

    本篇將要和大家分享的是webapi中如何使用依賴(lài)注入,依賴(lài)注入這個(gè)東西在接口中常用,實(shí)際工作中也用的比較頻繁,因此這里分享兩種在api中依賴(lài)注入的方式Ninject和Unity。下面跟著小編一起來(lái)看下吧
    2017-02-02
  • ASP.NET Core3.1 Ocelot認(rèn)證的實(shí)現(xiàn)

    ASP.NET Core3.1 Ocelot認(rèn)證的實(shí)現(xiàn)

    這篇文章主要介紹了ASP.NET Core3.1 Ocelot認(rèn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Request.UrlReferrer中文亂碼解決方法

    Request.UrlReferrer中文亂碼解決方法

    參考了網(wǎng)絡(luò)大部分的解決方案,沒(méi)一個(gè)能搞定的,如果窮途末路,試試下面的方法:將獲得的前一頁(yè)面的URL分成兩段,后面的參數(shù)部分進(jìn)行編碼(直接對(duì)URL編碼是不行的),然后再組合一下就可以了,需要的朋友可以了解下
    2012-12-12
  • .Net獲取IP地址的方法

    .Net獲取IP地址的方法

    這篇文章主要介紹了.Net獲取IP地址的方法,本文給大家介紹的非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • ASP.NET?Core項(xiàng)目使用xUnit進(jìn)行單元測(cè)試

    ASP.NET?Core項(xiàng)目使用xUnit進(jìn)行單元測(cè)試

    這篇文章介紹了ASP.NET?Core項(xiàng)目使用xUnit進(jìn)行單元測(cè)試的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • .net基礎(chǔ)收集匯總

    .net基礎(chǔ)收集匯總

    最近的面試讓我知道基礎(chǔ)知識(shí)的重要性,而我也每天都在網(wǎng)上找一些基礎(chǔ)題來(lái)看。其實(shí)面試無(wú)非都是一些理論基礎(chǔ),只有基礎(chǔ)過(guò)關(guān)了,才會(huì)被問(wèn)到技術(shù)性的問(wèn)題,所以第一關(guān)一定要打好
    2013-07-07
  • ASP.NET實(shí)現(xiàn)進(jìn)度條效果

    ASP.NET實(shí)現(xiàn)進(jìn)度條效果

    這篇文章主要為大家詳細(xì)介紹了ASP.NET實(shí)現(xiàn)簡(jiǎn)單的進(jìn)度條效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • .NET獲取客戶(hù)端的操作系統(tǒng)版本、瀏覽器版本和IP地址

    .NET獲取客戶(hù)端的操作系統(tǒng)版本、瀏覽器版本和IP地址

    這篇文章主要為大家詳細(xì)介紹了.NET如何獲取客戶(hù)端的操作系統(tǒng)版本、瀏覽器版本和IP地址,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • ASP.NET Core 數(shù)據(jù)保護(hù)(Data Protection 集群場(chǎng)景)下篇

    ASP.NET Core 數(shù)據(jù)保護(hù)(Data Protection 集群場(chǎng)景)下篇

    這篇文章主要為大家再一次介紹了ASP.NET Core 數(shù)據(jù)保護(hù)(Data Protection),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 在Asp.net網(wǎng)頁(yè)上寫(xiě)讀Cookie的兩種不同語(yǔ)法介紹

    在Asp.net網(wǎng)頁(yè)上寫(xiě)讀Cookie的兩種不同語(yǔ)法介紹

    asp.net開(kāi)發(fā)時(shí),為了存儲(chǔ)一些信息通常是Session與Cookie同時(shí)使用,本文將會(huì)補(bǔ)充一下Cookie相關(guān)的資料,感興趣的朋友可以了解一下在網(wǎng)頁(yè)上寫(xiě)讀Cookie的實(shí)現(xiàn),希望本文對(duì)你有所幫助
    2013-01-01

最新評(píng)論