代码先锋网 代码片段及技术文章聚合

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

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的对象reader
        SAXReader 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对象添加到resultViews
                                    resultViews.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.class
            int classPackageIndex = fullFileName.indexOf(JAVA_FILE_STORAGE);
            String fullClassName = StringUtils.substring(fullFileName, classPackageIndex + JAVA_FILE_STORAGE.length() + 1);
            // 处理完路径是这样的:annotation\Action.class
            if(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框架

版权声明:本文为huaairen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/huaairen/article/details/87541877

智能推荐

SpringMVC实战(三种控制器方式)

   1.前言 上篇博客着重说了一下SpringMVC中几种处理映射的方式,这篇博客来说一下SpringMVC中几种经常使用的控制器.  2.经常使用控制器 2.1 ParameterizableViewController(參数控制器) > <beans xmlns="http://www.springframework.org/sc...

bboss mvc控制器实现etag和last modify两种http缓存机制

bboss mvc控制器实现etag和last modify两种http缓存机制(本文参考《[url=http://jinnianshilongnian.iteye.com/blog/2319573]聊聊高并发系统之HTTP缓存[/url]》编写) [size=large][b]1.缓存控制器实现[/b][/size] 缓存控制器的类文件: [url=https://github.com/bbos...

bboss mvc控制器实现etag和last modify两种http缓存机制

bboss mvc控制器实现etag和last modify两种http缓存机制(本文参考《聊聊高并发系统之HTTP缓存》编写) 1.缓存控制器实现 缓存控制器的类文件: HttpCache.java 实现etag和last modify两种http缓存机制方法分别如下: last modify etag 运行和访问实例 启动示例应用之前,必须先安装好gradle并配置好gradle环境变量,至少...

SpringMVC中Controller控制器的三种实现方式

1.实现Controller接口 2.@Controller注解 3.实现HttpRequestHandler接口...

SpringMVC 基础入门 Controller控制器实现的3种方式

4.Controller控制器实现的3种方式 现在只用第三种,全注解 4.1.第一种实现Controller接口: 配置 4.2.第二种实现HttpRequestHandler接口: 配置 4.3.第三种普通类和注解:建议使用(请看后面的全注解配置) POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean 没有继承类,也没有实现类 配置(只...

猜你喜欢

链式加载(两种实现方式)

链式加载(两种实现方式) 准备工作 建一个java工程 建一个实体类(也就是我们所说的pojo,或者说是entity) 1.第一种方式,传统的方式 entity 步骤: 1.自动生成get,set,toString方法 2.改造set方法,返回值为entity本身 测试 控制台打印: Demo [id=1, name=demo的name] 2.第二种方式,使用lombok 准备工作 1.eclip...

MVP框架两种实现方式

第一种MVP: MVP框架:      View层:BaseActivity      Model层:BaseModel      Presenter层:BasePresenter      契约接口...

通过ApplicationContextAwareSpring实现手工加载配置的javabean

        在做一个多线程的数据采集器实现的过程中,由于框架是集成srping,因此希望统一使用原有的数据库配置信息,但是需要手工获取数据库配置bean。我们可以通过继承ApplicationContextAwareSpring类,并实现一个能够读取所有配置的javabean。     &nbs...

手工方式实现Spring工厂创建对象

Sping的主要功能就是省去了我们自己创建对象的麻烦,下面就用一个简单的例子,利用Java的DOM解析、反射机制简单实现Spring工厂。当然这是简单实现,没有实际spring工厂那么复杂。但是原理基本就是这样了。 1.在eclipse跟目录中创建我们所熟悉的beans.xml文件:我存放的路径为根目录。 2.在com.lwk.springbean包路径下创建User类 3.在com.lwk.de...

SpringMvc加载配置文件的两种方式

1.加载默认配置文件,但是路径必须在WEB-INF下,命名规范是springmvc-servlet.xml 2.加载自定义配置文件,在web.xml中配置: 其中init-param标签中是自定义配置文件的配置,其他是DispatcherServlet前端控制器...