1.手写springMVC框架

本篇我们通过两种方式来加载控制器,一种是配置文件的方式;另外一种是通过注解的形式。

1.配置文件方式

1.自定义Controller配置文件XML

我定义的格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<package name="wangzg"><constants><viewSuffix>.html</viewSuffix></constants><action name="index" method="index" class="controller.UserController" type="text/html" page="index" /><action name="login" method="login" class="controller.UserController" type="text/html" page="login" />
</package>

用过Struts2的伙伴应该一眼可以看出来,很容易理解。如果没用过也没关系,我简单解释一下:

package: 定义包名称,不同块的控制器通过此属性区分。

constants: 定义一些常量。

viewSuffix:定义返回视图的文件结尾。

action:定义一个控制器。

name: 控制器对应的名称。

method: 控制器对应class的方法名。

class: 控制器class的名称。

type: 返回视图的类型。

page: 返回视图的前端页面名称。

2.解析xml文件

定义常量:

 private final static String CONFIG_PATH = "/config/webConfig.xml";//配置文件存放的路径private final static String CONSTANT_LABEL = "constants";private final static String ACTION_LABEL = "action";private final static String ACTION_PROP_NAME = "name";private final static String ACTION_PROP_METHOD = "method";private final static String ACTION_PROP_CLASS = "class";private final static String ACTION_PROP_TYPE = "type";private final static String ACTION_PROP_PAGE = "page";

使用dom4j解析xml文件,代码如下:

      // 创建SAXReader的对象readerSAXReader reader = new SAXReader();try {String userPath = this.getClass().getClassLoader().getResource("").getPath();// 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。Document document = reader.read(new File( userPath + CONFIG_PATH));Element configPackage = document.getRootElement();String packageName = configPackage.getName();// 通过element对象的elementIterator方法获取迭代器Iterator it = configPackage.elementIterator();// 遍历迭代器,获取根节点中的信息(书籍)while (it.hasNext()) {Element element = (Element) it.next();if(CONSTANT_LABEL.equals(element.getName())){//解析常量Iterator itt = element.elementIterator();while (itt.hasNext()) {Element subElement = (Element) itt.next();constants.put(subElement.getName(),  subElement.getStringValue());}}else if(ACTION_LABEL.equals(element.getName())){//解析action的配置// 获取action的属性名以及 属性值List<Attribute> actionAttrs = element.attributes();ViewBean viewMapper = setAttrByAttribute(actionAttrs);//设置包名viewMapper.setPackageName(packageName);resultViews.add(viewMapper);}}} catch (DocumentException e) {e.printStackTrace();}

最后将解析的常量信息,action的配置信息存起来:

    //配置文件中常用参数集合public  static Map<String, String> constants = new HashMap<>();//action的视图配置信息的集合public static List<ViewBean> resultViews = new ArrayList<>();

2.通过注解方式实现

这里简单描述一下,通过注解方式,解析控制器的配置信息的流程。

1. 创建自定义注解Action;

2. 解析所有方法包含@Action的class类

3. 存储解析的配置信息

1.创建自定义注解

/*** Created by wangzhiguo on 2019/2/13 0013.* controller方法的注解*/
@Documented
@Inherited
@Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {public String value() default "";
}

2.解析所有方法包含@Action的类

获取当前路径下的所有class信息,通过反射机制判断java类是否包含Action注解。

 ControllerContext context = new ControllerContext();//获取源码路径String userPath = this.getClass().getClassLoader().getResource("").getPath();//1.解析路径下的所有class,是否包含Action的注解if(StringUtils.isNotEmpty(userPath)){List<File> files = getFileList(userPath);//递归调用,后去文件夹下的所有文件for(File file: files){//过滤文件,末尾为*.java,并且不是文件夹if(null != file){String filePath = file.getAbsolutePath();try {String [] classNameAndPackage = packageName(filePath);String packageName = classNameAndPackage[0];String className = classNameAndPackage[1];if(null != classNameAndPackage){//读取文件第一行包名,+文件名 = 完整class的路径Class clazz = Class.forName(packageName + JAVA_CLASS_PATH_SEPARATE + className);Method[] methods = clazz.getMethods();for(Method method: methods){if(method.isAnnotationPresent(Action.class)){//2.若有Action注解,解析内容,并组装ViewBean对象ViewBean viewBean = new ViewBean();viewBean.setPackageName(packageName);Action action = method.getAnnotation(Action.class);viewBean.setActionName(action.value());viewBean.setControllerClass(packageName + JAVA_CLASS_PATH_SEPARATE + className);viewBean.setControllerClassMethod(method.getName());Object controller = clazz.newInstance();String returnView = (String)method.invoke(controller,context);viewBean.setViewName(returnView);//annotationTest//3.将组装好的ViewBean对象添加到resultViewsresultViews.add(viewBean);}}}} catch (Exception e) {e.printStackTrace();}}}}

通过递归方式获取某一路径下的所有class文件。

/*** 递归调用获取路径下的所有文件* @param sourcePath*/public static List<File> getFileList(String sourcePath) {File dir = new File(sourcePath);File[] files = dir.listFiles(); // 该文件目录下文件全部放入数组if (files != null) {for (int i = 0; i < files.length; i++) {String fileName = files[i].getName();if (files[i].isDirectory()) { // 判断是文件还是文件夹getFileList(files[i].getAbsolutePath()); // 获取文件绝对路径} else if (fileName.endsWith(JAVA_FILE_TAIL)) { // 判断文件名是否以.java结尾String strFileName = files[i].getAbsolutePath();System.out.println("---" + strFileName);filelist.add(files[i]);} else {continue;}}}return filelist;}

获取class的包名和类名,通过数组形式返回。

 /*** 获取class的包名及类名* @param fullFileName* @return*/public String[] packageName(String fullFileName) throws Exception{String [] classNameAndPackage = new String[2];if(StringUtils.isNotEmpty(fullFileName)){//例如这样的文件路径:D:\devEnv\technologyStudy\remoteGitProject\ManualWeb\target\classes\annotation\Action.classint classPackageIndex = fullFileName.indexOf(JAVA_FILE_STORAGE);String fullClassName = StringUtils.substring(fullFileName, classPackageIndex + JAVA_FILE_STORAGE.length() + 1);// 处理完路径是这样的:annotation\Action.classif(StringUtils.isNotEmpty(fullClassName)){int lastSepateIndex = fullClassName.lastIndexOf(JAVA_FILE_PATH_SEPARATE);classNameAndPackage[1] = fullClassName.substring(lastSepateIndex + 1, fullClassName.length() - JAVA_FILE_TAIL.length());classNameAndPackage[0] = fullClassName.substring(0, lastSepateIndex).replace(JAVA_FILE_PATH_SEPARATE, JAVA_CLASS_PATH_SEPARATE);}}return classNameAndPackage;}

3.存储解析的配置信息

 public static List<ViewBean> resultViews = new ArrayList<>();

以上是我基于Netty手工实现springMVC框架之解析控制器的两种方式。写的不好的欢迎给出意见和建议。

源码路径:手工制作SpringMVC框架

推荐阅读:

基于Netty手工实现springMVC框架

基于Netty手工实现springMVC框架-----两种方式加载控制器相关推荐

  1. Webpack/Vue-cli两种方式加载markdown文件并实现代码高亮

    准备的资源: highlight.js : 实现代码高亮,通过npm install highlight.js -D安装 vue-markdown-loader:解析md文件的必备loader,通过n ...

  2. unity 3D里有两种动态加载机制

    unity 3D里有两种动态加载机制: 一是Resources.Load: 一是通过AssetBundle: 其实两者本质上没有什么区别.Resources.Load就是从一个缺省打进程序包里的Ass ...

  3. ThinkPHP框架中解决无法加载控制器的问题—原因之一

    相信许多PHP开发者在使用ThinkPHP框架进行快速开发的时候遇到过通过URL访问控制器方法时遇到图上的这种问题. 为什么会无法加载控制器呢,原因有很多,但是据我所了解的来看,最有可能的还是: 你的 ...

  4. JavaEE SSH集成框架(两) struts2 本地加载dtd文件,action组态

    1. 载入中struts2的dtd文件.使struts.xml网络无法验证,和eclipse有技巧 在src在创建struts.xml: <? xmlversion="1.0" ...

  5. 微信小程序两种loading加载中显示方式

    在微信开发中,为了用户更加友好的体验,一般在数据请求的时候就显示动态加载中的显示字样,表示数据正在加载,用户请耐心等待. 一般有两种显示方式(其实是三种,showToast和showLoading写法 ...

  6. 动态网页常用的两种数据加载方式ajax和js动态请求

    欢迎关注"生信修炼手册"! 对于静态网页,我们只需要访问对应的URL就可以获得全部的数据了,动态网页则没有这么简单.比如以下网站 http://q.10jqka.com.cn/zj ...

  7. pythonflask configlist.py_Python+Flask.0004.FLASK配置管理之三种方式加载外部配置

    简单介绍: 说明: 复杂的项目需要配置各种环境,若设置少可直接硬编码,设置多的话可通过加载配置/加载文件/加载变量的方式来设置 1 2 3 app.config.update( DEBUG=True, ...

  8. 基于aspectj实现AOP操作的两种方式——xml配置

    1. 要导入的 jar 包: 常用的aspectj表达式: 权限修饰符可以省略,以下表示:返回值类型为任意,com.chy.service包以及其子包下的.任意类的.参数任意的.任意方法 execut ...

  9. 基于AVFoundation实现视频录制的两种方式

    文章目录 一.前言 二.方案一:AVCaptureSession + AVCaptureMovieFileOutput 1.创建AVCaptureSession 2.设置音频.视频输入 3.设置文件输 ...

最新文章

  1. 笔记本怎么桌面显示计算机,笔记本电脑桌面不显示了如何解决
  2. 设置css3动画的顺序,CSS3 “瓷砖”顺序飘落的动画
  3. (转)离散化:两种离散化方式详解
  4. MSF(三):信息收集
  5. python模拟足球_使用K-Means算法划分亚洲国家的三个足球梯队
  6. Problem D. Nothing is Impossible
  7. 味美多网址导航php,味多美网址导航源码程序按来路自动显示 2010.0329
  8. k线形态python_Python量化分析之K线模式识别
  9. Mac系统升级后,无法安装Cornerstone解决办法
  10. Unity 3D Generic动画类型,对于应用RootMotion的设置
  11. easyswoole not controller class match
  12. 无人机,diyDrones,3dr,pixhawk,Chris Anderson, 这几个概念是什么关系?
  13. python多线程爬取王者荣耀高清壁纸过程
  14. Windows64位操作环境下,eclipse使用32位JDK
  15. C#中实现两个程序的通信
  16. c# distinct用法
  17. 用Python求e的近似值
  18. obs有没有android版本,obs插件手机版下载-obs插件 安卓版v1.0.0-pc6手机下载
  19. 网络操作系统及配置管理课程
  20. 腾讯音乐 知乎 微信公众账户 搜狗

热门文章

  1. 爬虫实战:百度失信人名单
  2. 简单介绍js中的confirm()方法的使用
  3. confirm中显示换行_js confirm用法,换行与参数详解
  4. 股票上市代码及上市时间
  5. togglebutton用法 java_ToggleButton 基本使用方法
  6. 【灰狼算法】基于布谷鸟搜索混合灰狼优化算法求解单目标优化问题(AGWOCS)含Matlab源码
  7. 自动化测试,除了coding还需要掌握什么?
  8. Code:Blocks 中文乱码问题原因分析和解决方法!
  9. listbox 表头自动换行_WPF让ListView或ListBox中的WrapPanel 自动换行
  10. d3drm.dll修复方法 很简单 其实就是复制而已